diff options
| -rw-r--r-- | embassy-stm32/src/dma/bdma.rs | 6 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/mod.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/v2.rs | 217 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/v3.rs | 28 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/spi.rs | 3 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/spi_dma.rs | 103 |
6 files changed, 344 insertions, 17 deletions
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 46670e1be..adb288eb0 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs | |||
| @@ -89,7 +89,11 @@ pub(crate) unsafe fn do_transfer( | |||
| 89 | ch.cr().write(|w| { | 89 | ch.cr().write(|w| { |
| 90 | w.set_psize(vals::Size::BITS8); | 90 | w.set_psize(vals::Size::BITS8); |
| 91 | w.set_msize(vals::Size::BITS8); | 91 | w.set_msize(vals::Size::BITS8); |
| 92 | w.set_minc(vals::Inc::ENABLED); | 92 | if incr_mem { |
| 93 | w.set_minc(vals::Inc::ENABLED); | ||
| 94 | } else { | ||
| 95 | w.set_minc(vals::Inc::DISABLED); | ||
| 96 | } | ||
| 93 | w.set_dir(dir); | 97 | w.set_dir(dir); |
| 94 | w.set_teie(true); | 98 | w.set_teie(true); |
| 95 | w.set_tcie(true); | 99 | w.set_tcie(true); |
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 9bb5a729c..046ec0fe7 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/v2.rs b/embassy-stm32/src/spi/v2.rs index 4e135e9df..400fd89af 100644 --- a/embassy-stm32/src/spi/v2.rs +++ b/embassy-stm32/src/spi/v2.rs | |||
| @@ -1,16 +1,23 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | use crate::dma::NoDma; | ||
| 3 | use crate::gpio::{AnyPin, Pin}; | 4 | use crate::gpio::{AnyPin, Pin}; |
| 4 | use crate::pac::gpio::vals::{Afr, Moder}; | 5 | use crate::pac::gpio::vals::{Afr, Moder}; |
| 5 | use crate::pac::gpio::Gpio; | 6 | use crate::pac::gpio::Gpio; |
| 6 | use crate::pac::spi; | 7 | use crate::pac::spi; |
| 7 | use crate::spi::{ByteOrder, Config, Error, Instance, MisoPin, MosiPin, SckPin, WordSize}; | 8 | use crate::spi::{ |
| 9 | ByteOrder, Config, Error, Instance, MisoPin, MosiPin, RxDmaChannel, SckPin, TxDmaChannel, | ||
| 10 | WordSize, | ||
| 11 | }; | ||
| 8 | use crate::time::Hertz; | 12 | use crate::time::Hertz; |
| 13 | use core::future::Future; | ||
| 9 | use core::marker::PhantomData; | 14 | use core::marker::PhantomData; |
| 10 | use core::ptr; | 15 | use core::ptr; |
| 11 | use embassy::util::Unborrow; | 16 | use embassy::util::Unborrow; |
| 12 | use embassy_extras::unborrow; | 17 | use embassy_extras::unborrow; |
| 18 | use embassy_traits::spi as traits; | ||
| 13 | pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | 19 | pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; |
| 20 | use futures::future::join3; | ||
| 14 | 21 | ||
| 15 | impl WordSize { | 22 | impl WordSize { |
| 16 | fn ds(&self) -> spi::vals::Ds { | 23 | fn ds(&self) -> spi::vals::Ds { |
| @@ -28,26 +35,30 @@ impl WordSize { | |||
| 28 | } | 35 | } |
| 29 | } | 36 | } |
| 30 | 37 | ||
| 31 | pub struct Spi<'d, T: Instance> { | 38 | pub struct Spi<'d, T: Instance, Tx, Rx> { |
| 32 | sck: AnyPin, | 39 | sck: AnyPin, |
| 33 | mosi: AnyPin, | 40 | mosi: AnyPin, |
| 34 | miso: AnyPin, | 41 | miso: AnyPin, |
| 42 | txdma: Tx, | ||
| 43 | rxdma: Rx, | ||
| 35 | phantom: PhantomData<&'d mut T>, | 44 | phantom: PhantomData<&'d mut T>, |
| 36 | } | 45 | } |
| 37 | 46 | ||
| 38 | impl<'d, T: Instance> Spi<'d, T> { | 47 | impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { |
| 39 | pub fn new<F>( | 48 | pub fn new<F>( |
| 40 | _peri: impl Unborrow<Target = T> + 'd, | 49 | _peri: impl Unborrow<Target = T> + 'd, |
| 41 | sck: impl Unborrow<Target = impl SckPin<T>>, | 50 | sck: impl Unborrow<Target = impl SckPin<T>>, |
| 42 | mosi: impl Unborrow<Target = impl MosiPin<T>>, | 51 | mosi: impl Unborrow<Target = impl MosiPin<T>>, |
| 43 | miso: impl Unborrow<Target = impl MisoPin<T>>, | 52 | miso: impl Unborrow<Target = impl MisoPin<T>>, |
| 53 | txdma: impl Unborrow<Target = Tx>, | ||
| 54 | rxdma: impl Unborrow<Target = Rx>, | ||
| 44 | freq: F, | 55 | freq: F, |
| 45 | config: Config, | 56 | config: Config, |
| 46 | ) -> Self | 57 | ) -> Self |
| 47 | where | 58 | where |
| 48 | F: Into<Hertz>, | 59 | F: Into<Hertz>, |
| 49 | { | 60 | { |
| 50 | unborrow!(sck, mosi, miso); | 61 | unborrow!(sck, mosi, miso, txdma, rxdma); |
| 51 | 62 | ||
| 52 | unsafe { | 63 | unsafe { |
| 53 | Self::configure_pin(sck.block(), sck.pin() as _, sck.af_num()); | 64 | Self::configure_pin(sck.block(), sck.pin() as _, sck.af_num()); |
| @@ -98,6 +109,8 @@ impl<'d, T: Instance> Spi<'d, T> { | |||
| 98 | sck, | 109 | sck, |
| 99 | mosi, | 110 | mosi, |
| 100 | miso, | 111 | miso, |
| 112 | txdma, | ||
| 113 | rxdma, | ||
| 101 | phantom: PhantomData, | 114 | phantom: PhantomData, |
| 102 | } | 115 | } |
| 103 | } | 116 | } |
| @@ -140,9 +153,156 @@ impl<'d, T: Instance> Spi<'d, T> { | |||
| 140 | }); | 153 | }); |
| 141 | } | 154 | } |
| 142 | } | 155 | } |
| 156 | |||
| 157 | #[allow(unused)] | ||
| 158 | async fn write_dma_u8(&mut self, write: &[u8]) -> Result<(), Error> | ||
| 159 | where | ||
| 160 | Tx: TxDmaChannel<T>, | ||
| 161 | { | ||
| 162 | unsafe { | ||
| 163 | T::regs().cr1().modify(|w| { | ||
| 164 | w.set_spe(false); | ||
| 165 | }); | ||
| 166 | T::regs().cr2().modify(|reg| { | ||
| 167 | reg.set_rxdmaen(true); | ||
| 168 | }); | ||
| 169 | } | ||
| 170 | Self::set_word_size(WordSize::EightBit); | ||
| 171 | |||
| 172 | let request = self.txdma.request(); | ||
| 173 | let dst = T::regs().dr().ptr() as *mut u8; | ||
| 174 | let f = self.txdma.write(request, write, dst); | ||
| 175 | |||
| 176 | unsafe { | ||
| 177 | T::regs().cr2().modify(|reg| { | ||
| 178 | reg.set_txdmaen(true); | ||
| 179 | }); | ||
| 180 | T::regs().cr1().modify(|w| { | ||
| 181 | w.set_spe(true); | ||
| 182 | }); | ||
| 183 | } | ||
| 184 | |||
| 185 | f.await; | ||
| 186 | Ok(()) | ||
| 187 | } | ||
| 188 | |||
| 189 | #[allow(unused)] | ||
| 190 | async fn read_dma_u8(&mut self, read: &mut [u8]) -> Result<(), Error> | ||
| 191 | where | ||
| 192 | Tx: TxDmaChannel<T>, | ||
| 193 | Rx: RxDmaChannel<T>, | ||
| 194 | { | ||
| 195 | unsafe { | ||
| 196 | T::regs().cr1().modify(|w| { | ||
| 197 | w.set_spe(false); | ||
| 198 | }); | ||
| 199 | T::regs().cr2().modify(|reg| { | ||
| 200 | reg.set_rxdmaen(true); | ||
| 201 | }); | ||
| 202 | } | ||
| 203 | Self::set_word_size(WordSize::EightBit); | ||
| 204 | |||
| 205 | let clock_byte_count = read.len(); | ||
| 206 | |||
| 207 | let rx_request = self.rxdma.request(); | ||
| 208 | let rx_src = T::regs().dr().ptr() as *mut u8; | ||
| 209 | let rx_f = self.rxdma.read(rx_request, rx_src, read); | ||
| 210 | |||
| 211 | let tx_request = self.txdma.request(); | ||
| 212 | let tx_dst = T::regs().dr().ptr() as *mut u8; | ||
| 213 | let clock_byte = 0x00; | ||
| 214 | let tx_f = self | ||
| 215 | .txdma | ||
| 216 | .write_x(tx_request, &clock_byte, clock_byte_count, tx_dst); | ||
| 217 | |||
| 218 | unsafe { | ||
| 219 | T::regs().cr2().modify(|reg| { | ||
| 220 | reg.set_txdmaen(true); | ||
| 221 | }); | ||
| 222 | T::regs().cr1().modify(|w| { | ||
| 223 | w.set_spe(true); | ||
| 224 | }); | ||
| 225 | } | ||
| 226 | |||
| 227 | join3(tx_f, rx_f, Self::wait_for_idle()).await; | ||
| 228 | |||
| 229 | unsafe { | ||
| 230 | T::regs().cr2().modify(|reg| { | ||
| 231 | reg.set_txdmaen(false); | ||
| 232 | reg.set_rxdmaen(false); | ||
| 233 | }); | ||
| 234 | T::regs().cr1().modify(|w| { | ||
| 235 | w.set_spe(false); | ||
| 236 | }); | ||
| 237 | } | ||
| 238 | |||
| 239 | Ok(()) | ||
| 240 | } | ||
| 241 | |||
| 242 | #[allow(unused)] | ||
| 243 | async fn read_write_dma_u8(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> | ||
| 244 | where | ||
| 245 | Tx: TxDmaChannel<T>, | ||
| 246 | Rx: RxDmaChannel<T>, | ||
| 247 | { | ||
| 248 | unsafe { | ||
| 249 | T::regs().cr1().modify(|w| { | ||
| 250 | w.set_spe(false); | ||
| 251 | }); | ||
| 252 | T::regs().cr2().modify(|reg| { | ||
| 253 | reg.set_rxdmaen(true); | ||
| 254 | }); | ||
| 255 | } | ||
| 256 | Self::set_word_size(WordSize::EightBit); | ||
| 257 | |||
| 258 | let rx_request = self.rxdma.request(); | ||
| 259 | let rx_src = T::regs().dr().ptr() as *mut u8; | ||
| 260 | let rx_f = self.rxdma.read(rx_request, rx_src, read); | ||
| 261 | |||
| 262 | let tx_request = self.txdma.request(); | ||
| 263 | let tx_dst = T::regs().dr().ptr() as *mut u8; | ||
| 264 | let tx_f = self.txdma.write(tx_request, write, tx_dst); | ||
| 265 | |||
| 266 | unsafe { | ||
| 267 | T::regs().cr2().modify(|reg| { | ||
| 268 | reg.set_txdmaen(true); | ||
| 269 | }); | ||
| 270 | T::regs().cr1().modify(|w| { | ||
| 271 | w.set_spe(true); | ||
| 272 | }); | ||
| 273 | } | ||
| 274 | |||
| 275 | join3(tx_f, rx_f, Self::wait_for_idle()).await; | ||
| 276 | |||
| 277 | unsafe { | ||
| 278 | T::regs().cr2().modify(|reg| { | ||
| 279 | reg.set_txdmaen(false); | ||
| 280 | reg.set_rxdmaen(false); | ||
| 281 | }); | ||
| 282 | T::regs().cr1().modify(|w| { | ||
| 283 | w.set_spe(false); | ||
| 284 | }); | ||
| 285 | } | ||
| 286 | |||
| 287 | Ok(()) | ||
| 288 | } | ||
| 289 | |||
| 290 | async fn wait_for_idle() { | ||
| 291 | unsafe { | ||
| 292 | while T::regs().sr().read().ftlvl() > 0 { | ||
| 293 | // spin | ||
| 294 | } | ||
| 295 | while T::regs().sr().read().frlvl() > 0 { | ||
| 296 | // spin | ||
| 297 | } | ||
| 298 | while T::regs().sr().read().bsy() { | ||
| 299 | // spin | ||
| 300 | } | ||
| 301 | } | ||
| 302 | } | ||
| 143 | } | 303 | } |
| 144 | 304 | ||
| 145 | impl<'d, T: Instance> Drop for Spi<'d, T> { | 305 | impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { |
| 146 | fn drop(&mut self) { | 306 | fn drop(&mut self) { |
| 147 | unsafe { | 307 | unsafe { |
| 148 | Self::unconfigure_pin(self.sck.block(), self.sck.pin() as _); | 308 | Self::unconfigure_pin(self.sck.block(), self.sck.pin() as _); |
| @@ -200,7 +360,7 @@ fn read_word<W: Word>(regs: &'static crate::pac::spi::Spi) -> Result<W, Error> { | |||
| 200 | } | 360 | } |
| 201 | } | 361 | } |
| 202 | 362 | ||
| 203 | impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T> { | 363 | impl<'d, T: Instance, Rx> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T, NoDma, Rx> { |
| 204 | type Error = Error; | 364 | type Error = Error; |
| 205 | 365 | ||
| 206 | fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { | 366 | fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { |
| @@ -216,7 +376,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T> { | |||
| 216 | } | 376 | } |
| 217 | } | 377 | } |
| 218 | 378 | ||
| 219 | impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T> { | 379 | impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T, NoDma, NoDma> { |
| 220 | type Error = Error; | 380 | type Error = Error; |
| 221 | 381 | ||
| 222 | fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { | 382 | fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { |
| @@ -232,7 +392,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T> { | |||
| 232 | } | 392 | } |
| 233 | } | 393 | } |
| 234 | 394 | ||
| 235 | impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T> { | 395 | impl<'d, T: Instance, Rx> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T, NoDma, Rx> { |
| 236 | type Error = Error; | 396 | type Error = Error; |
| 237 | 397 | ||
| 238 | fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> { | 398 | fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> { |
| @@ -248,7 +408,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T> { | |||
| 248 | } | 408 | } |
| 249 | } | 409 | } |
| 250 | 410 | ||
| 251 | impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T> { | 411 | impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T, NoDma, NoDma> { |
| 252 | type Error = Error; | 412 | type Error = Error; |
| 253 | 413 | ||
| 254 | fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> { | 414 | fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> { |
| @@ -263,3 +423,42 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T> | |||
| 263 | Ok(words) | 423 | Ok(words) |
| 264 | } | 424 | } |
| 265 | } | 425 | } |
| 426 | |||
| 427 | impl<'d, T: Instance, Tx, Rx> traits::Spi<u8> for Spi<'d, T, Tx, Rx> { | ||
| 428 | type Error = super::Error; | ||
| 429 | } | ||
| 430 | |||
| 431 | impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx> traits::Write<u8> for Spi<'d, T, Tx, Rx> { | ||
| 432 | #[rustfmt::skip] | ||
| 433 | type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; | ||
| 434 | |||
| 435 | fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 436 | self.write_dma_u8(data) | ||
| 437 | } | ||
| 438 | } | ||
| 439 | |||
| 440 | impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx: RxDmaChannel<T>> traits::Read<u8> | ||
| 441 | for Spi<'d, T, Tx, Rx> | ||
| 442 | { | ||
| 443 | #[rustfmt::skip] | ||
| 444 | type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; | ||
| 445 | |||
| 446 | fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 447 | self.read_dma_u8(data) | ||
| 448 | } | ||
| 449 | } | ||
| 450 | |||
| 451 | impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx: RxDmaChannel<T>> traits::FullDuplex<u8> | ||
| 452 | for Spi<'d, T, Tx, Rx> | ||
| 453 | { | ||
| 454 | #[rustfmt::skip] | ||
| 455 | type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; | ||
| 456 | |||
| 457 | fn read_write<'a>( | ||
| 458 | &'a mut self, | ||
| 459 | read: &'a mut [u8], | ||
| 460 | write: &'a [u8], | ||
| 461 | ) -> Self::WriteReadFuture<'a> { | ||
| 462 | self.read_write_dma_u8(read, write) | ||
| 463 | } | ||
| 464 | } | ||
diff --git a/embassy-stm32/src/spi/v3.rs b/embassy-stm32/src/spi/v3.rs index eb8df44ae..fb2a46f3e 100644 --- a/embassy-stm32/src/spi/v3.rs +++ b/embassy-stm32/src/spi/v3.rs | |||
| @@ -201,7 +201,28 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 201 | Tx: TxDmaChannel<T>, | 201 | Tx: TxDmaChannel<T>, |
| 202 | Rx: RxDmaChannel<T>, | 202 | Rx: RxDmaChannel<T>, |
| 203 | { | 203 | { |
| 204 | unimplemented!() | 204 | let clock_byte_count = read.len(); |
| 205 | |||
| 206 | let rx_request = self.rxdma.request(); | ||
| 207 | let rx_src = T::regs().rxdr().ptr() as *mut u8; | ||
| 208 | let rx_f = self.rxdma.read(rx_request, rx_src, read); | ||
| 209 | |||
| 210 | let tx_request = self.txdma.request(); | ||
| 211 | let tx_dst = T::regs().txdr().ptr() as *mut u8; | ||
| 212 | let clock_byte = 0x00; | ||
| 213 | let tx_f = self | ||
| 214 | .txdma | ||
| 215 | .write_x(tx_request, &clock_byte, clock_byte_count, tx_dst); | ||
| 216 | |||
| 217 | unsafe { | ||
| 218 | T::regs().cfg1().modify(|reg| { | ||
| 219 | reg.set_txdmaen(true); | ||
| 220 | reg.set_rxdmaen(true); | ||
| 221 | }); | ||
| 222 | } | ||
| 223 | |||
| 224 | let r = join(tx_f, rx_f).await; | ||
| 225 | Ok(()) | ||
| 205 | } | 226 | } |
| 206 | 227 | ||
| 207 | #[allow(unused)] | 228 | #[allow(unused)] |
| @@ -218,10 +239,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 218 | 239 | ||
| 219 | let tx_request = self.txdma.request(); | 240 | let tx_request = self.txdma.request(); |
| 220 | let tx_dst = T::regs().txdr().ptr() as *mut u8; | 241 | let tx_dst = T::regs().txdr().ptr() as *mut u8; |
| 221 | let clock_byte = 0x00; | 242 | let tx_f = self.txdma.write(tx_request, write, tx_dst); |
| 222 | let tx_f = self | ||
| 223 | .txdma | ||
| 224 | .write_x(tx_request, &clock_byte, clock_byte_count, tx_dst); | ||
| 225 | 243 | ||
| 226 | unsafe { | 244 | unsafe { |
| 227 | T::regs().cfg1().modify(|reg| { | 245 | T::regs().cfg1().modify(|reg| { |
diff --git a/examples/stm32l4/src/bin/spi.rs b/examples/stm32l4/src/bin/spi.rs index 8702fe0cc..14605283b 100644 --- a/examples/stm32l4/src/bin/spi.rs +++ b/examples/stm32l4/src/bin/spi.rs | |||
| @@ -17,6 +17,7 @@ use embassy_stm32::time::Hertz; | |||
| 17 | use embedded_hal::blocking::spi::Transfer; | 17 | use embedded_hal::blocking::spi::Transfer; |
| 18 | use embedded_hal::digital::v2::OutputPin; | 18 | use embedded_hal::digital::v2::OutputPin; |
| 19 | use example_common::*; | 19 | use example_common::*; |
| 20 | use embassy_stm32::dma::NoDma; | ||
| 20 | 21 | ||
| 21 | #[entry] | 22 | #[entry] |
| 22 | fn main() -> ! { | 23 | fn main() -> ! { |
| @@ -41,6 +42,8 @@ fn main() -> ! { | |||
| 41 | p.PC10, | 42 | p.PC10, |
| 42 | p.PC12, | 43 | p.PC12, |
| 43 | p.PC11, | 44 | p.PC11, |
| 45 | NoDma, | ||
| 46 | NoDma, | ||
| 44 | Hertz(1_000_000), | 47 | Hertz(1_000_000), |
| 45 | Config::default(), | 48 | Config::default(), |
| 46 | ); | 49 | ); |
diff --git a/examples/stm32l4/src/bin/spi_dma.rs b/examples/stm32l4/src/bin/spi_dma.rs new file mode 100644 index 000000000..ca77c2f9b --- /dev/null +++ b/examples/stm32l4/src/bin/spi_dma.rs | |||
| @@ -0,0 +1,103 @@ | |||
| 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 | |||
| 12 | use cortex_m_rt::entry; | ||
| 13 | use embassy::executor::Executor; | ||
| 14 | use embassy::time::Clock; | ||
| 15 | use embassy::util::Forever; | ||
| 16 | use embassy_stm32::pac; | ||
| 17 | use example_common::*; | ||
| 18 | use embassy_stm32::spi::{Spi, Config}; | ||
| 19 | use embassy_traits::spi::FullDuplex; | ||
| 20 | use embassy_stm32::time::Hertz; | ||
| 21 | use embassy_stm32::gpio::{Output, Level, Speed}; | ||
| 22 | use embedded_hal::digital::v2::OutputPin; | ||
| 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.SPI3, | ||
| 30 | p.PC10, | ||
| 31 | p.PC12, | ||
| 32 | p.PC11, | ||
| 33 | p.DMA1_CH0, | ||
| 34 | p.DMA1_CH1, | ||
| 35 | Hertz(1_000_000), | ||
| 36 | Config::default(), | ||
| 37 | ); | ||
| 38 | |||
| 39 | let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); | ||
| 40 | |||
| 41 | loop { | ||
| 42 | let write = [0x0A; 10]; | ||
| 43 | let mut read = [0; 10]; | ||
| 44 | unwrap!(cs.set_low()); | ||
| 45 | spi.read_write(&mut read, &write).await.ok(); | ||
| 46 | unwrap!(cs.set_high()); | ||
| 47 | info!("xfer {=[u8]:x}", read); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | struct ZeroClock; | ||
| 52 | |||
| 53 | impl Clock for ZeroClock { | ||
| 54 | fn now(&self) -> u64 { | ||
| 55 | 0 | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | static EXECUTOR: Forever<Executor> = Forever::new(); | ||
| 60 | |||
| 61 | #[entry] | ||
| 62 | fn main() -> ! { | ||
| 63 | info!("Hello World!"); | ||
| 64 | |||
| 65 | unsafe { | ||
| 66 | pac::DBGMCU.cr().modify(|w| { | ||
| 67 | w.set_dbg_sleep(true); | ||
| 68 | w.set_dbg_standby(true); | ||
| 69 | w.set_dbg_stop(true); | ||
| 70 | }); | ||
| 71 | |||
| 72 | //pac::RCC.apbenr().modify(|w| { | ||
| 73 | //w.set_spi3en(true); | ||
| 74 | // }); | ||
| 75 | |||
| 76 | pac::RCC.apb2enr().modify(|w| { | ||
| 77 | w.set_syscfgen(true); | ||
| 78 | }); | ||
| 79 | |||
| 80 | pac::RCC.ahb1enr().modify(|w| { | ||
| 81 | w.set_dmamux1en(true); | ||
| 82 | w.set_dma1en(true); | ||
| 83 | w.set_dma2en(true); | ||
| 84 | }); | ||
| 85 | |||
| 86 | pac::RCC.ahb2enr().modify(|w| { | ||
| 87 | w.set_gpioaen(true); | ||
| 88 | w.set_gpioben(true); | ||
| 89 | w.set_gpiocen(true); | ||
| 90 | w.set_gpioden(true); | ||
| 91 | w.set_gpioeen(true); | ||
| 92 | w.set_gpiofen(true); | ||
| 93 | }); | ||
| 94 | } | ||
| 95 | |||
| 96 | unsafe { embassy::time::set_clock(&ZeroClock) }; | ||
| 97 | |||
| 98 | let executor = EXECUTOR.put(Executor::new()); | ||
| 99 | |||
| 100 | executor.run(|spawner| { | ||
| 101 | unwrap!(spawner.spawn(main_task())); | ||
| 102 | }) | ||
| 103 | } | ||
