diff options
| author | Bob McWhirter <[email protected]> | 2021-07-21 16:45:43 -0400 |
|---|---|---|
| committer | Bob McWhirter <[email protected]> | 2021-07-23 13:22:39 -0400 |
| commit | b07325b47600283113ffb8aa99c50080ca092abb (patch) | |
| tree | d5cf728dc187dbcac456035d2089df68f4525f77 | |
| parent | 8ab82191b76290a69ae068ed99da0e81d07cba12 (diff) | |
Enable DMA for SPIv1 on F4's etc.
| -rw-r--r-- | embassy-stm32/src/dma/dma.rs | 5 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/mod.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/v1.rs | 211 | ||||
| -rw-r--r-- | examples/stm32f4/.cargo/config.toml | 3 | ||||
| -rw-r--r-- | examples/stm32f4/memory.x | 4 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/spi.rs | 3 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/spi_dma.rs | 85 |
7 files changed, 299 insertions, 16 deletions
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 72502043d..c5695baca 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs | |||
| @@ -98,16 +98,17 @@ pub(crate) unsafe fn do_transfer( | |||
| 98 | w.set_tcie(true); | 98 | w.set_tcie(true); |
| 99 | #[cfg(dma_v1)] | 99 | #[cfg(dma_v1)] |
| 100 | w.set_trbuff(true); | 100 | w.set_trbuff(true); |
| 101 | w.set_en(true); | ||
| 102 | 101 | ||
| 103 | #[cfg(dma_v2)] | 102 | #[cfg(dma_v2)] |
| 104 | w.set_chsel(request); | 103 | w.set_chsel(request); |
| 104 | |||
| 105 | w.set_en(true); | ||
| 105 | }); | 106 | }); |
| 106 | } | 107 | } |
| 107 | 108 | ||
| 108 | async move { | 109 | async move { |
| 109 | let res = poll_fn(|cx| { | 110 | let res = poll_fn(|cx| { |
| 110 | let n = channel_number as usize; | 111 | let n = state_number as usize; |
| 111 | STATE.ch_wakers[n].register(cx.waker()); | 112 | STATE.ch_wakers[n].register(cx.waker()); |
| 112 | match STATE.ch_status[n].load(Ordering::Acquire) { | 113 | match STATE.ch_status[n].load(Ordering::Acquire) { |
| 113 | CH_STATUS_NONE => Poll::Pending, | 114 | CH_STATUS_NONE => Poll::Pending, |
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 9bb5a729c..237a07209 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | #[cfg_attr(spi_v1, path = "v1.rs")] | 3 | #[cfg_attr(spi_v1, path = "v1.rs")] |
| 4 | #[cfg_attr(spi_v2, path = "v2.rs")] | 4 | //#[cfg_attr(spi_v2, path = "v2.rs")] |
| 5 | #[cfg_attr(spi_v3, path = "v3.rs")] | 5 | //#[cfg_attr(spi_v3, path = "v3.rs")] |
| 6 | mod _version; | 6 | mod _version; |
| 7 | use crate::{dma, peripherals, rcc::RccPeripheral}; | 7 | use crate::{dma, peripherals, rcc::RccPeripheral}; |
| 8 | pub use _version::*; | 8 | pub use _version::*; |
diff --git a/embassy-stm32/src/spi/v1.rs b/embassy-stm32/src/spi/v1.rs index 01cbf86b6..72bde898d 100644 --- a/embassy-stm32/src/spi/v1.rs +++ b/embassy-stm32/src/spi/v1.rs | |||
| @@ -1,14 +1,21 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | use crate::dma::NoDma; | ||
| 3 | use crate::gpio::{sealed::Pin, AnyPin}; | 4 | use crate::gpio::{sealed::Pin, AnyPin}; |
| 4 | use crate::pac::spi; | 5 | use crate::pac::spi; |
| 5 | use crate::spi::{ByteOrder, Config, Error, Instance, MisoPin, MosiPin, SckPin, WordSize}; | 6 | use crate::spi::{ |
| 7 | ByteOrder, Config, Error, Instance, MisoPin, MosiPin, RxDmaChannel, SckPin, TxDmaChannel, | ||
| 8 | WordSize, | ||
| 9 | }; | ||
| 6 | use crate::time::Hertz; | 10 | use crate::time::Hertz; |
| 11 | use core::future::Future; | ||
| 7 | use core::marker::PhantomData; | 12 | use core::marker::PhantomData; |
| 8 | use core::ptr; | 13 | use core::ptr; |
| 9 | use embassy::util::Unborrow; | 14 | use embassy::util::Unborrow; |
| 10 | use embassy_extras::unborrow; | 15 | use embassy_extras::unborrow; |
| 16 | use embassy_traits::spi as traits; | ||
| 11 | pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | 17 | pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; |
| 18 | use futures::future::join3; | ||
| 12 | 19 | ||
| 13 | impl WordSize { | 20 | impl WordSize { |
| 14 | fn dff(&self) -> spi::vals::Dff { | 21 | fn dff(&self) -> spi::vals::Dff { |
| @@ -19,27 +26,31 @@ impl WordSize { | |||
| 19 | } | 26 | } |
| 20 | } | 27 | } |
| 21 | 28 | ||
| 22 | pub struct Spi<'d, T: Instance> { | 29 | pub struct Spi<'d, T: Instance, Tx, Rx> { |
| 23 | sck: AnyPin, | 30 | sck: AnyPin, |
| 24 | mosi: AnyPin, | 31 | mosi: AnyPin, |
| 25 | miso: AnyPin, | 32 | miso: AnyPin, |
| 33 | txdma: Tx, | ||
| 34 | rxdma: Rx, | ||
| 26 | current_word_size: WordSize, | 35 | current_word_size: WordSize, |
| 27 | phantom: PhantomData<&'d mut T>, | 36 | phantom: PhantomData<&'d mut T>, |
| 28 | } | 37 | } |
| 29 | 38 | ||
| 30 | impl<'d, T: Instance> Spi<'d, T> { | 39 | impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { |
| 31 | pub fn new<F>( | 40 | pub fn new<F>( |
| 32 | _peri: impl Unborrow<Target = T> + 'd, | 41 | _peri: impl Unborrow<Target = T> + 'd, |
| 33 | sck: impl Unborrow<Target = impl SckPin<T>>, | 42 | sck: impl Unborrow<Target = impl SckPin<T>>, |
| 34 | mosi: impl Unborrow<Target = impl MosiPin<T>>, | 43 | mosi: impl Unborrow<Target = impl MosiPin<T>>, |
| 35 | miso: impl Unborrow<Target = impl MisoPin<T>>, | 44 | miso: impl Unborrow<Target = impl MisoPin<T>>, |
| 45 | txdma: impl Unborrow<Target = Tx>, | ||
| 46 | rxdma: impl Unborrow<Target = Rx>, | ||
| 36 | freq: F, | 47 | freq: F, |
| 37 | config: Config, | 48 | config: Config, |
| 38 | ) -> Self | 49 | ) -> Self |
| 39 | where | 50 | where |
| 40 | F: Into<Hertz>, | 51 | F: Into<Hertz>, |
| 41 | { | 52 | { |
| 42 | unborrow!(sck, mosi, miso); | 53 | unborrow!(sck, mosi, miso, txdma, rxdma); |
| 43 | 54 | ||
| 44 | unsafe { | 55 | unsafe { |
| 45 | sck.set_as_af(sck.af_num()); | 56 | sck.set_as_af(sck.af_num()); |
| @@ -94,6 +105,8 @@ impl<'d, T: Instance> Spi<'d, T> { | |||
| 94 | sck, | 105 | sck, |
| 95 | mosi, | 106 | mosi, |
| 96 | miso, | 107 | miso, |
| 108 | txdma, | ||
| 109 | rxdma, | ||
| 97 | current_word_size: WordSize::EightBit, | 110 | current_word_size: WordSize::EightBit, |
| 98 | phantom: PhantomData, | 111 | phantom: PhantomData, |
| 99 | } | 112 | } |
| @@ -128,9 +141,150 @@ impl<'d, T: Instance> Spi<'d, T> { | |||
| 128 | self.current_word_size = word_size; | 141 | self.current_word_size = word_size; |
| 129 | } | 142 | } |
| 130 | } | 143 | } |
| 144 | |||
| 145 | #[allow(unused)] | ||
| 146 | async fn write_dma_u8(&mut self, write: &[u8]) -> Result<(), Error> | ||
| 147 | where | ||
| 148 | Tx: TxDmaChannel<T>, | ||
| 149 | { | ||
| 150 | unsafe { | ||
| 151 | T::regs().cr1().modify(|w| { | ||
| 152 | w.set_spe(false); | ||
| 153 | }); | ||
| 154 | T::regs().cr2().modify(|reg| { | ||
| 155 | reg.set_rxdmaen(true); | ||
| 156 | }); | ||
| 157 | } | ||
| 158 | self.set_word_size(WordSize::EightBit); | ||
| 159 | |||
| 160 | let request = self.txdma.request(); | ||
| 161 | let dst = T::regs().dr().ptr() as *mut u8; | ||
| 162 | let f = self.txdma.write(request, write, dst); | ||
| 163 | |||
| 164 | unsafe { | ||
| 165 | T::regs().cr2().modify(|reg| { | ||
| 166 | reg.set_txdmaen(true); | ||
| 167 | }); | ||
| 168 | T::regs().cr1().modify(|w| { | ||
| 169 | w.set_spe(true); | ||
| 170 | }); | ||
| 171 | } | ||
| 172 | |||
| 173 | f.await; | ||
| 174 | Ok(()) | ||
| 175 | } | ||
| 176 | |||
| 177 | #[allow(unused)] | ||
| 178 | async fn read_dma_u8(&mut self, read: &mut [u8]) -> Result<(), Error> | ||
| 179 | where | ||
| 180 | Tx: TxDmaChannel<T>, | ||
| 181 | Rx: RxDmaChannel<T>, | ||
| 182 | { | ||
| 183 | unsafe { | ||
| 184 | T::regs().cr1().modify(|w| { | ||
| 185 | w.set_spe(false); | ||
| 186 | }); | ||
| 187 | T::regs().cr2().modify(|reg| { | ||
| 188 | reg.set_rxdmaen(true); | ||
| 189 | }); | ||
| 190 | } | ||
| 191 | self.set_word_size(WordSize::EightBit); | ||
| 192 | |||
| 193 | let clock_byte_count = read.len(); | ||
| 194 | |||
| 195 | let rx_request = self.rxdma.request(); | ||
| 196 | let rx_src = T::regs().dr().ptr() as *mut u8; | ||
| 197 | let rx_f = self.rxdma.read(rx_request, rx_src, read); | ||
| 198 | |||
| 199 | let tx_request = self.txdma.request(); | ||
| 200 | let tx_dst = T::regs().dr().ptr() as *mut u8; | ||
| 201 | let clock_byte = 0x00; | ||
| 202 | let tx_f = self | ||
| 203 | .txdma | ||
| 204 | .write_x(tx_request, &clock_byte, clock_byte_count, tx_dst); | ||
| 205 | |||
| 206 | unsafe { | ||
| 207 | T::regs().cr2().modify(|reg| { | ||
| 208 | reg.set_txdmaen(true); | ||
| 209 | }); | ||
| 210 | T::regs().cr1().modify(|w| { | ||
| 211 | w.set_spe(true); | ||
| 212 | }); | ||
| 213 | } | ||
| 214 | |||
| 215 | join3(tx_f, rx_f, Self::wait_for_idle()).await; | ||
| 216 | |||
| 217 | unsafe { | ||
| 218 | T::regs().cr2().modify(|reg| { | ||
| 219 | reg.set_txdmaen(false); | ||
| 220 | reg.set_rxdmaen(false); | ||
| 221 | }); | ||
| 222 | T::regs().cr1().modify(|w| { | ||
| 223 | w.set_spe(false); | ||
| 224 | }); | ||
| 225 | } | ||
| 226 | |||
| 227 | Ok(()) | ||
| 228 | } | ||
| 229 | |||
| 230 | #[allow(unused)] | ||
| 231 | async fn read_write_dma_u8(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> | ||
| 232 | where | ||
| 233 | Tx: TxDmaChannel<T>, | ||
| 234 | Rx: RxDmaChannel<T>, | ||
| 235 | { | ||
| 236 | unsafe { | ||
| 237 | T::regs().cr1().modify(|w| { | ||
| 238 | w.set_spe(false); | ||
| 239 | }); | ||
| 240 | T::regs().cr2().modify(|reg| { | ||
| 241 | reg.set_rxdmaen(true); | ||
| 242 | }); | ||
| 243 | } | ||
| 244 | self.set_word_size(WordSize::EightBit); | ||
| 245 | |||
| 246 | let rx_request = self.rxdma.request(); | ||
| 247 | let rx_src = T::regs().dr().ptr() as *mut u8; | ||
| 248 | let rx_f = self.rxdma.read(rx_request, rx_src, read); | ||
| 249 | |||
| 250 | let tx_request = self.txdma.request(); | ||
| 251 | let tx_dst = T::regs().dr().ptr() as *mut u8; | ||
| 252 | let tx_f = self.txdma.write(tx_request, write, tx_dst); | ||
| 253 | |||
| 254 | unsafe { | ||
| 255 | T::regs().cr2().modify(|reg| { | ||
| 256 | reg.set_txdmaen(true); | ||
| 257 | }); | ||
| 258 | T::regs().cr1().modify(|w| { | ||
| 259 | w.set_spe(true); | ||
| 260 | }); | ||
| 261 | } | ||
| 262 | |||
| 263 | join3(tx_f, rx_f, Self::wait_for_idle()).await; | ||
| 264 | |||
| 265 | unsafe { | ||
| 266 | T::regs().cr2().modify(|reg| { | ||
| 267 | reg.set_txdmaen(false); | ||
| 268 | reg.set_rxdmaen(false); | ||
| 269 | }); | ||
| 270 | T::regs().cr1().modify(|w| { | ||
| 271 | w.set_spe(false); | ||
| 272 | }); | ||
| 273 | } | ||
| 274 | |||
| 275 | Ok(()) | ||
| 276 | } | ||
| 277 | |||
| 278 | async fn wait_for_idle() { | ||
| 279 | unsafe { | ||
| 280 | while T::regs().sr().read().bsy() { | ||
| 281 | // spin | ||
| 282 | } | ||
| 283 | } | ||
| 284 | } | ||
| 131 | } | 285 | } |
| 132 | 286 | ||
| 133 | impl<'d, T: Instance> Drop for Spi<'d, T> { | 287 | impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { |
| 134 | fn drop(&mut self) { | 288 | fn drop(&mut self) { |
| 135 | unsafe { | 289 | unsafe { |
| 136 | self.sck.set_as_analog(); | 290 | self.sck.set_as_analog(); |
| @@ -140,7 +294,7 @@ impl<'d, T: Instance> Drop for Spi<'d, T> { | |||
| 140 | } | 294 | } |
| 141 | } | 295 | } |
| 142 | 296 | ||
| 143 | impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T> { | 297 | impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T, NoDma, NoDma> { |
| 144 | type Error = Error; | 298 | type Error = Error; |
| 145 | 299 | ||
| 146 | fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { | 300 | fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { |
| @@ -176,7 +330,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T> { | |||
| 176 | } | 330 | } |
| 177 | } | 331 | } |
| 178 | 332 | ||
| 179 | impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T> { | 333 | impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T, NoDma, NoDma> { |
| 180 | type Error = Error; | 334 | type Error = Error; |
| 181 | 335 | ||
| 182 | fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { | 336 | fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { |
| @@ -217,7 +371,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T> { | |||
| 217 | } | 371 | } |
| 218 | } | 372 | } |
| 219 | 373 | ||
| 220 | impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T> { | 374 | impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T, NoDma, NoDma> { |
| 221 | type Error = Error; | 375 | type Error = Error; |
| 222 | 376 | ||
| 223 | fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> { | 377 | fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> { |
| @@ -253,7 +407,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T> { | |||
| 253 | } | 407 | } |
| 254 | } | 408 | } |
| 255 | 409 | ||
| 256 | impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T> { | 410 | impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T, NoDma, NoDma> { |
| 257 | type Error = Error; | 411 | type Error = Error; |
| 258 | 412 | ||
| 259 | fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> { | 413 | fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> { |
| @@ -291,3 +445,42 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T> | |||
| 291 | Ok(words) | 445 | Ok(words) |
| 292 | } | 446 | } |
| 293 | } | 447 | } |
| 448 | |||
| 449 | impl<'d, T: Instance, Tx, Rx> traits::Spi<u8> for Spi<'d, T, Tx, Rx> { | ||
| 450 | type Error = super::Error; | ||
| 451 | } | ||
| 452 | |||
| 453 | impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx> traits::Write<u8> for Spi<'d, T, Tx, Rx> { | ||
| 454 | #[rustfmt::skip] | ||
| 455 | type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; | ||
| 456 | |||
| 457 | fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 458 | self.write_dma_u8(data) | ||
| 459 | } | ||
| 460 | } | ||
| 461 | |||
| 462 | impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx: RxDmaChannel<T>> traits::Read<u8> | ||
| 463 | for Spi<'d, T, Tx, Rx> | ||
| 464 | { | ||
| 465 | #[rustfmt::skip] | ||
| 466 | type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; | ||
| 467 | |||
| 468 | fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 469 | self.read_dma_u8(data) | ||
| 470 | } | ||
| 471 | } | ||
| 472 | |||
| 473 | impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx: RxDmaChannel<T>> traits::FullDuplex<u8> | ||
| 474 | for Spi<'d, T, Tx, Rx> | ||
| 475 | { | ||
| 476 | #[rustfmt::skip] | ||
| 477 | type WriteReadFuture<'a> where Self: 'a = impl Future<Output=Result<(), Self::Error>> + 'a; | ||
| 478 | |||
| 479 | fn read_write<'a>( | ||
| 480 | &'a mut self, | ||
| 481 | read: &'a mut [u8], | ||
| 482 | write: &'a [u8], | ||
| 483 | ) -> Self::WriteReadFuture<'a> { | ||
| 484 | self.read_write_dma_u8(read, write) | ||
| 485 | } | ||
| 486 | } | ||
diff --git a/examples/stm32f4/.cargo/config.toml b/examples/stm32f4/.cargo/config.toml index 8704a9ba5..f7173a194 100644 --- a/examples/stm32f4/.cargo/config.toml +++ b/examples/stm32f4/.cargo/config.toml | |||
| @@ -3,7 +3,8 @@ build-std = ["core"] | |||
| 3 | 3 | ||
| 4 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | 4 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] |
| 5 | # replace STM32F429ZITx with your chip as listed in `probe-run --list-chips` | 5 | # replace STM32F429ZITx with your chip as listed in `probe-run --list-chips` |
| 6 | runner = "probe-run --chip STM32F429ZITx" | 6 | #runner = "probe-run --chip STM32F429ZITx" |
| 7 | runner = "probe-run --chip STM32F401RE" | ||
| 7 | 8 | ||
| 8 | rustflags = [ | 9 | rustflags = [ |
| 9 | # LLD (shipped with the Rust toolchain) is used as the default linker | 10 | # LLD (shipped with the Rust toolchain) is used as the default linker |
diff --git a/examples/stm32f4/memory.x b/examples/stm32f4/memory.x index f21e32572..bcd2bbcd4 100644 --- a/examples/stm32f4/memory.x +++ b/examples/stm32f4/memory.x | |||
| @@ -2,6 +2,6 @@ MEMORY | |||
| 2 | { | 2 | { |
| 3 | /* NOTE 1 K = 1 KiBi = 1024 bytes */ | 3 | /* NOTE 1 K = 1 KiBi = 1024 bytes */ |
| 4 | /* These values correspond to the STM32F429ZI */ | 4 | /* These values correspond to the STM32F429ZI */ |
| 5 | FLASH : ORIGIN = 0x08000000, LENGTH = 2048K | 5 | FLASH : ORIGIN = 0x08000000, LENGTH = 512K |
| 6 | RAM : ORIGIN = 0x20000000, LENGTH = 192K | 6 | RAM : ORIGIN = 0x20000000, LENGTH = 96K |
| 7 | } | 7 | } |
diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs index 88fc84bc0..604283877 100644 --- a/examples/stm32f4/src/bin/spi.rs +++ b/examples/stm32f4/src/bin/spi.rs | |||
| @@ -18,6 +18,7 @@ use embassy_stm32::dbgmcu::Dbgmcu; | |||
| 18 | use embassy_stm32::spi::{Config, Spi}; | 18 | use embassy_stm32::spi::{Config, Spi}; |
| 19 | use embassy_stm32::time::Hertz; | 19 | use embassy_stm32::time::Hertz; |
| 20 | use embedded_hal::blocking::spi::Transfer; | 20 | use embedded_hal::blocking::spi::Transfer; |
| 21 | use embassy_stm32::dma::NoDma; | ||
| 21 | 22 | ||
| 22 | #[entry] | 23 | #[entry] |
| 23 | fn main() -> ! { | 24 | fn main() -> ! { |
| @@ -34,6 +35,8 @@ fn main() -> ! { | |||
| 34 | p.PC10, | 35 | p.PC10, |
| 35 | p.PC12, | 36 | p.PC12, |
| 36 | p.PC11, | 37 | p.PC11, |
| 38 | NoDma, | ||
| 39 | NoDma, | ||
| 37 | Hertz(1_000_000), | 40 | Hertz(1_000_000), |
| 38 | Config::default(), | 41 | Config::default(), |
| 39 | ); | 42 | ); |
diff --git a/examples/stm32f4/src/bin/spi_dma.rs b/examples/stm32f4/src/bin/spi_dma.rs new file mode 100644 index 000000000..db6b69c85 --- /dev/null +++ b/examples/stm32f4/src/bin/spi_dma.rs | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(trait_alias)] | ||
| 4 | #![feature(min_type_alias_impl_trait)] | ||
| 5 | #![feature(impl_trait_in_bindings)] | ||
| 6 | #![feature(type_alias_impl_trait)] | ||
| 7 | #![allow(incomplete_features)] | ||
| 8 | |||
| 9 | #[path = "../example_common.rs"] | ||
| 10 | mod example_common; | ||
| 11 | use core::fmt::Write; | ||
| 12 | use cortex_m_rt::entry; | ||
| 13 | use embassy::executor::Executor; | ||
| 14 | use embassy::time::Clock; | ||
| 15 | use embassy::util::Forever; | ||
| 16 | use example_common::*; | ||
| 17 | use embassy_traits::spi::FullDuplex; | ||
| 18 | use heapless::String; | ||
| 19 | use embassy_stm32::spi::{Spi, Config}; | ||
| 20 | use embassy_stm32::pac; | ||
| 21 | use embassy_stm32::time::Hertz; | ||
| 22 | use core::str::from_utf8; | ||
| 23 | |||
| 24 | #[embassy::task] | ||
| 25 | async fn main_task() { | ||
| 26 | let p = embassy_stm32::init(Default::default()); | ||
| 27 | |||
| 28 | let mut spi = Spi::new( | ||
| 29 | p.SPI1, | ||
| 30 | p.PB3, | ||
| 31 | p.PA7, | ||
| 32 | p.PA6, | ||
| 33 | p.DMA2_CH3, | ||
| 34 | p.DMA2_CH2, | ||
| 35 | Hertz(1_000_000), | ||
| 36 | Config::default(), | ||
| 37 | ); | ||
| 38 | |||
| 39 | for n in 0u32.. { | ||
| 40 | let mut write: String<128> = String::new(); | ||
| 41 | let mut read = [0;128]; | ||
| 42 | core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); | ||
| 43 | spi.read_write(&mut read[0..write.len()], write.as_bytes()).await.ok(); | ||
| 44 | info!("read via spi+dma: {}", from_utf8(&read).unwrap()); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | struct ZeroClock; | ||
| 49 | |||
| 50 | impl Clock for ZeroClock { | ||
| 51 | fn now(&self) -> u64 { | ||
| 52 | 0 | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | static EXECUTOR: Forever<Executor> = Forever::new(); | ||
| 57 | |||
| 58 | #[entry] | ||
| 59 | fn main() -> ! { | ||
| 60 | info!("Hello World!"); | ||
| 61 | unsafe { | ||
| 62 | pac::DBGMCU.cr().modify(|w| { | ||
| 63 | w.set_dbg_sleep(true); | ||
| 64 | w.set_dbg_standby(true); | ||
| 65 | w.set_dbg_stop(true); | ||
| 66 | }); | ||
| 67 | |||
| 68 | pac::RCC.ahb1enr().modify(|w| { | ||
| 69 | w.set_gpioaen(true); | ||
| 70 | w.set_gpioben(true); | ||
| 71 | w.set_gpiocen(true); | ||
| 72 | w.set_gpioden(true); | ||
| 73 | w.set_gpioeen(true); | ||
| 74 | w.set_gpiofen(true); | ||
| 75 | }); | ||
| 76 | } | ||
| 77 | |||
| 78 | unsafe { embassy::time::set_clock(&ZeroClock) }; | ||
| 79 | |||
| 80 | let executor = EXECUTOR.put(Executor::new()); | ||
| 81 | |||
| 82 | executor.run(|spawner| { | ||
| 83 | unwrap!(spawner.spawn(main_task())); | ||
| 84 | }) | ||
| 85 | } | ||
