diff options
| -rw-r--r-- | embassy-stm32/src/dma/dma.rs | 6 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/mod.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/v3.rs | 98 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/spi.rs | 112 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/spi_dma.rs | 109 |
5 files changed, 318 insertions, 11 deletions
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 9ac6df159..72502043d 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs | |||
| @@ -88,7 +88,11 @@ pub(crate) unsafe fn do_transfer( | |||
| 88 | w.set_dir(dir); | 88 | w.set_dir(dir); |
| 89 | w.set_msize(vals::Size::BITS8); | 89 | w.set_msize(vals::Size::BITS8); |
| 90 | w.set_psize(vals::Size::BITS8); | 90 | w.set_psize(vals::Size::BITS8); |
| 91 | w.set_minc(vals::Inc::INCREMENTED); | 91 | if incr_mem { |
| 92 | w.set_minc(vals::Inc::INCREMENTED); | ||
| 93 | } else { | ||
| 94 | w.set_minc(vals::Inc::FIXED); | ||
| 95 | } | ||
| 92 | w.set_pinc(vals::Inc::FIXED); | 96 | w.set_pinc(vals::Inc::FIXED); |
| 93 | w.set_teie(true); | 97 | w.set_teie(true); |
| 94 | w.set_tcie(true); | 98 | w.set_tcie(true); |
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 9bb5a729c..9c259715d 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 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}; |
diff --git a/embassy-stm32/src/spi/v3.rs b/embassy-stm32/src/spi/v3.rs index fb2a46f3e..2d6f4a28f 100644 --- a/embassy-stm32/src/spi/v3.rs +++ b/embassy-stm32/src/spi/v3.rs | |||
| @@ -18,7 +18,7 @@ use embassy_extras::unborrow; | |||
| 18 | use embassy_traits::spi as traits; | 18 | use embassy_traits::spi as traits; |
| 19 | 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 | 20 | ||
| 21 | use futures::future::join; | 21 | use futures::future::join3; |
| 22 | 22 | ||
| 23 | impl WordSize { | 23 | impl WordSize { |
| 24 | fn dsize(&self) -> u8 { | 24 | fn dsize(&self) -> u8 { |
| @@ -110,7 +110,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 110 | w.set_crcen(false); | 110 | w.set_crcen(false); |
| 111 | w.set_mbr(spi::vals::Mbr(br)); | 111 | w.set_mbr(spi::vals::Mbr(br)); |
| 112 | w.set_dsize(WordSize::EightBit.dsize()); | 112 | w.set_dsize(WordSize::EightBit.dsize()); |
| 113 | //w.set_fthlv(WordSize::EightBit.frxth()); | ||
| 114 | }); | 113 | }); |
| 115 | T::regs().cr2().modify(|w| { | 114 | T::regs().cr2().modify(|w| { |
| 116 | w.set_tsize(0); | 115 | w.set_tsize(0); |
| @@ -182,16 +181,40 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 182 | where | 181 | where |
| 183 | Tx: TxDmaChannel<T>, | 182 | Tx: TxDmaChannel<T>, |
| 184 | { | 183 | { |
| 184 | Self::set_word_size(WordSize::EightBit); | ||
| 185 | unsafe { | ||
| 186 | T::regs().cr1().modify(|w| { | ||
| 187 | w.set_spe(false); | ||
| 188 | }); | ||
| 189 | } | ||
| 190 | |||
| 185 | let request = self.txdma.request(); | 191 | let request = self.txdma.request(); |
| 186 | let dst = T::regs().txdr().ptr() as *mut u8; | 192 | let dst = T::regs().txdr().ptr() as *mut u8; |
| 187 | let f = self.txdma.write(request, write, dst); | 193 | let f = self.txdma.write(request, write, dst); |
| 194 | |||
| 188 | unsafe { | 195 | unsafe { |
| 189 | T::regs().cfg1().modify(|reg| { | 196 | T::regs().cfg1().modify(|reg| { |
| 190 | reg.set_txdmaen(true); | 197 | reg.set_txdmaen(true); |
| 191 | }); | 198 | }); |
| 199 | T::regs().cr1().modify(|w| { | ||
| 200 | w.set_spe(true); | ||
| 201 | }); | ||
| 202 | T::regs().cr1().modify(|w| { | ||
| 203 | w.set_cstart(true); | ||
| 204 | }); | ||
| 192 | } | 205 | } |
| 193 | 206 | ||
| 194 | f.await; | 207 | f.await; |
| 208 | unsafe { | ||
| 209 | T::regs().cfg1().modify(|reg| { | ||
| 210 | reg.set_rxdmaen(false); | ||
| 211 | reg.set_txdmaen(false); | ||
| 212 | }); | ||
| 213 | T::regs().cr1().modify(|w| { | ||
| 214 | w.set_spe(false); | ||
| 215 | }); | ||
| 216 | } | ||
| 217 | |||
| 195 | Ok(()) | 218 | Ok(()) |
| 196 | } | 219 | } |
| 197 | 220 | ||
| @@ -201,6 +224,16 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 201 | Tx: TxDmaChannel<T>, | 224 | Tx: TxDmaChannel<T>, |
| 202 | Rx: RxDmaChannel<T>, | 225 | Rx: RxDmaChannel<T>, |
| 203 | { | 226 | { |
| 227 | Self::set_word_size(WordSize::EightBit); | ||
| 228 | unsafe { | ||
| 229 | T::regs().cr1().modify(|w| { | ||
| 230 | w.set_spe(false); | ||
| 231 | }); | ||
| 232 | T::regs().cfg1().modify(|reg| { | ||
| 233 | reg.set_rxdmaen(true); | ||
| 234 | }); | ||
| 235 | } | ||
| 236 | |||
| 204 | let clock_byte_count = read.len(); | 237 | let clock_byte_count = read.len(); |
| 205 | 238 | ||
| 206 | let rx_request = self.rxdma.request(); | 239 | let rx_request = self.rxdma.request(); |
| @@ -217,11 +250,25 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 217 | unsafe { | 250 | unsafe { |
| 218 | T::regs().cfg1().modify(|reg| { | 251 | T::regs().cfg1().modify(|reg| { |
| 219 | reg.set_txdmaen(true); | 252 | reg.set_txdmaen(true); |
| 220 | reg.set_rxdmaen(true); | 253 | }); |
| 254 | T::regs().cr1().modify(|w| { | ||
| 255 | w.set_spe(true); | ||
| 256 | }); | ||
| 257 | T::regs().cr1().modify(|w| { | ||
| 258 | w.set_cstart(true); | ||
| 221 | }); | 259 | }); |
| 222 | } | 260 | } |
| 223 | 261 | ||
| 224 | let r = join(tx_f, rx_f).await; | 262 | join3(tx_f, rx_f, Self::wait_for_idle()).await; |
| 263 | unsafe { | ||
| 264 | T::regs().cfg1().modify(|reg| { | ||
| 265 | reg.set_rxdmaen(false); | ||
| 266 | reg.set_txdmaen(false); | ||
| 267 | }); | ||
| 268 | T::regs().cr1().modify(|w| { | ||
| 269 | w.set_spe(false); | ||
| 270 | }); | ||
| 271 | } | ||
| 225 | Ok(()) | 272 | Ok(()) |
| 226 | } | 273 | } |
| 227 | 274 | ||
| @@ -231,11 +278,21 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 231 | Tx: TxDmaChannel<T>, | 278 | Tx: TxDmaChannel<T>, |
| 232 | Rx: RxDmaChannel<T>, | 279 | Rx: RxDmaChannel<T>, |
| 233 | { | 280 | { |
| 234 | let clock_byte_count = read.len(); | 281 | Self::set_word_size(WordSize::EightBit); |
| 282 | unsafe { | ||
| 283 | T::regs().cr1().modify(|w| { | ||
| 284 | w.set_spe(false); | ||
| 285 | }); | ||
| 286 | T::regs().cfg1().modify(|reg| { | ||
| 287 | reg.set_rxdmaen(true); | ||
| 288 | }); | ||
| 289 | } | ||
| 235 | 290 | ||
| 236 | let rx_request = self.rxdma.request(); | 291 | let rx_request = self.rxdma.request(); |
| 237 | let rx_src = T::regs().rxdr().ptr() as *mut u8; | 292 | let rx_src = T::regs().rxdr().ptr() as *mut u8; |
| 238 | let rx_f = self.rxdma.read(rx_request, rx_src, read); | 293 | let rx_f = self |
| 294 | .rxdma | ||
| 295 | .read(rx_request, rx_src, &mut read[0..write.len()]); | ||
| 239 | 296 | ||
| 240 | let tx_request = self.txdma.request(); | 297 | let tx_request = self.txdma.request(); |
| 241 | let tx_dst = T::regs().txdr().ptr() as *mut u8; | 298 | let tx_dst = T::regs().txdr().ptr() as *mut u8; |
| @@ -244,13 +301,38 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 244 | unsafe { | 301 | unsafe { |
| 245 | T::regs().cfg1().modify(|reg| { | 302 | T::regs().cfg1().modify(|reg| { |
| 246 | reg.set_txdmaen(true); | 303 | reg.set_txdmaen(true); |
| 247 | reg.set_rxdmaen(true); | 304 | }); |
| 305 | T::regs().cr1().modify(|w| { | ||
| 306 | w.set_spe(true); | ||
| 307 | }); | ||
| 308 | T::regs().cr1().modify(|w| { | ||
| 309 | w.set_cstart(true); | ||
| 248 | }); | 310 | }); |
| 249 | } | 311 | } |
| 250 | 312 | ||
| 251 | let r = join(tx_f, rx_f).await; | 313 | join3(tx_f, rx_f, Self::wait_for_idle()).await; |
| 314 | unsafe { | ||
| 315 | T::regs().cfg1().modify(|reg| { | ||
| 316 | reg.set_rxdmaen(false); | ||
| 317 | reg.set_txdmaen(false); | ||
| 318 | }); | ||
| 319 | T::regs().cr1().modify(|w| { | ||
| 320 | w.set_spe(false); | ||
| 321 | }); | ||
| 322 | } | ||
| 252 | Ok(()) | 323 | Ok(()) |
| 253 | } | 324 | } |
| 325 | |||
| 326 | async fn wait_for_idle() { | ||
| 327 | unsafe { | ||
| 328 | while !T::regs().sr().read().txc() { | ||
| 329 | // spin | ||
| 330 | } | ||
| 331 | while T::regs().sr().read().rxplvl().0 > 0 { | ||
| 332 | // spin | ||
| 333 | } | ||
| 334 | } | ||
| 335 | } | ||
| 254 | } | 336 | } |
| 255 | 337 | ||
| 256 | impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { | 338 | impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { |
diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs new file mode 100644 index 000000000..ac483a311 --- /dev/null +++ b/examples/stm32h7/src/bin/spi.rs | |||
| @@ -0,0 +1,112 @@ | |||
| 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 core::fmt::Write; | ||
| 13 | use embassy::executor::Executor; | ||
| 14 | use embassy::time::Clock; | ||
| 15 | use embassy::util::Forever; | ||
| 16 | use embassy_stm32::dma::NoDma; | ||
| 17 | use example_common::*; | ||
| 18 | use embedded_hal::blocking::spi::Transfer; | ||
| 19 | |||
| 20 | use hal::prelude::*; | ||
| 21 | use stm32h7xx_hal as hal; | ||
| 22 | |||
| 23 | use cortex_m_rt::entry; | ||
| 24 | use stm32h7::stm32h743 as pac; | ||
| 25 | use heapless::String; | ||
| 26 | use embassy_stm32::spi::{Spi, Config}; | ||
| 27 | use embassy_stm32::time::Hertz; | ||
| 28 | |||
| 29 | #[embassy::task] | ||
| 30 | async fn main_task() { | ||
| 31 | let p = embassy_stm32::init(Default::default()); | ||
| 32 | |||
| 33 | let mut spi = Spi::new( | ||
| 34 | p.SPI3, | ||
| 35 | p.PB3, | ||
| 36 | p.PB5, | ||
| 37 | p.PB4, | ||
| 38 | NoDma, | ||
| 39 | NoDma, | ||
| 40 | Hertz(1_000_000), | ||
| 41 | Config::default(), | ||
| 42 | ); | ||
| 43 | |||
| 44 | for n in 0u32.. { | ||
| 45 | let mut write: String<128> = String::new(); | ||
| 46 | core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); | ||
| 47 | unsafe { | ||
| 48 | let result = spi.transfer(write.as_bytes_mut()); | ||
| 49 | if let Err(_) = result { | ||
| 50 | defmt::panic!("crap"); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | info!("read via spi: {}", write.as_bytes()); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | struct ZeroClock; | ||
| 58 | |||
| 59 | impl Clock for ZeroClock { | ||
| 60 | fn now(&self) -> u64 { | ||
| 61 | 0 | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | static EXECUTOR: Forever<Executor> = Forever::new(); | ||
| 66 | |||
| 67 | #[entry] | ||
| 68 | fn main() -> ! { | ||
| 69 | info!("Hello World!"); | ||
| 70 | |||
| 71 | let pp = pac::Peripherals::take().unwrap(); | ||
| 72 | |||
| 73 | let pwrcfg = pp.PWR.constrain().freeze(); | ||
| 74 | |||
| 75 | let rcc = pp.RCC.constrain(); | ||
| 76 | |||
| 77 | rcc.sys_ck(96.mhz()) | ||
| 78 | .pclk1(48.mhz()) | ||
| 79 | .pclk2(48.mhz()) | ||
| 80 | .pclk3(48.mhz()) | ||
| 81 | .pclk4(48.mhz()) | ||
| 82 | .pll1_q_ck(48.mhz()) | ||
| 83 | .freeze(pwrcfg, &pp.SYSCFG); | ||
| 84 | |||
| 85 | let pp = unsafe { pac::Peripherals::steal() }; | ||
| 86 | |||
| 87 | pp.DBGMCU.cr.modify(|_, w| { | ||
| 88 | w.dbgsleep_d1().set_bit(); | ||
| 89 | w.dbgstby_d1().set_bit(); | ||
| 90 | w.dbgstop_d1().set_bit(); | ||
| 91 | w.d1dbgcken().set_bit(); | ||
| 92 | w | ||
| 93 | }); | ||
| 94 | |||
| 95 | pp.RCC.ahb4enr.modify(|_, w| { | ||
| 96 | w.gpioaen().set_bit(); | ||
| 97 | w.gpioben().set_bit(); | ||
| 98 | w.gpiocen().set_bit(); | ||
| 99 | w.gpioden().set_bit(); | ||
| 100 | w.gpioeen().set_bit(); | ||
| 101 | w.gpiofen().set_bit(); | ||
| 102 | w | ||
| 103 | }); | ||
| 104 | |||
| 105 | unsafe { embassy::time::set_clock(&ZeroClock) }; | ||
| 106 | |||
| 107 | let executor = EXECUTOR.put(Executor::new()); | ||
| 108 | |||
| 109 | executor.run(|spawner| { | ||
| 110 | unwrap!(spawner.spawn(main_task())); | ||
| 111 | }) | ||
| 112 | } | ||
diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs new file mode 100644 index 000000000..9dbfd0960 --- /dev/null +++ b/examples/stm32h7/src/bin/spi_dma.rs | |||
| @@ -0,0 +1,109 @@ | |||
| 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 embassy::executor::Executor; | ||
| 13 | use embassy::time::Clock; | ||
| 14 | use embassy::util::Forever; | ||
| 15 | use example_common::*; | ||
| 16 | use embassy_traits::spi::FullDuplex; | ||
| 17 | |||
| 18 | use hal::prelude::*; | ||
| 19 | use stm32h7xx_hal as hal; | ||
| 20 | |||
| 21 | use cortex_m_rt::entry; | ||
| 22 | use stm32h7::stm32h743 as pac; | ||
| 23 | use heapless::String; | ||
| 24 | use embassy_stm32::spi::{Spi, Config}; | ||
| 25 | use embassy_stm32::time::Hertz; | ||
| 26 | use core::str::from_utf8; | ||
| 27 | |||
| 28 | #[embassy::task] | ||
| 29 | async fn main_task() { | ||
| 30 | let p = embassy_stm32::init(Default::default()); | ||
| 31 | |||
| 32 | let mut spi = Spi::new( | ||
| 33 | p.SPI3, | ||
| 34 | p.PB3, | ||
| 35 | p.PB5, | ||
| 36 | p.PB4, | ||
| 37 | p.DMA1_CH3, | ||
| 38 | p.DMA1_CH4, | ||
| 39 | Hertz(1_000_000), | ||
| 40 | Config::default(), | ||
| 41 | ); | ||
| 42 | |||
| 43 | for n in 0u32.. { | ||
| 44 | let mut write: String<128> = String::new(); | ||
| 45 | let mut read = [0;128]; | ||
| 46 | core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); | ||
| 47 | // read_write will slice the &mut read down to &write's actual length. | ||
| 48 | spi.read_write(&mut read, write.as_bytes()).await.ok(); | ||
| 49 | info!("read via spi+dma: {}", from_utf8(&read).unwrap()); | ||
| 50 | } | ||
| 51 | |||
| 52 | } | ||
| 53 | |||
| 54 | struct ZeroClock; | ||
| 55 | |||
| 56 | impl Clock for ZeroClock { | ||
| 57 | fn now(&self) -> u64 { | ||
| 58 | 0 | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | static EXECUTOR: Forever<Executor> = Forever::new(); | ||
| 63 | |||
| 64 | #[entry] | ||
| 65 | fn main() -> ! { | ||
| 66 | info!("Hello World!"); | ||
| 67 | |||
| 68 | let pp = pac::Peripherals::take().unwrap(); | ||
| 69 | |||
| 70 | let pwrcfg = pp.PWR.constrain().freeze(); | ||
| 71 | |||
| 72 | let rcc = pp.RCC.constrain(); | ||
| 73 | |||
| 74 | rcc.sys_ck(96.mhz()) | ||
| 75 | .pclk1(48.mhz()) | ||
| 76 | .pclk2(48.mhz()) | ||
| 77 | .pclk3(48.mhz()) | ||
| 78 | .pclk4(48.mhz()) | ||
| 79 | .pll1_q_ck(48.mhz()) | ||
| 80 | .freeze(pwrcfg, &pp.SYSCFG); | ||
| 81 | |||
| 82 | let pp = unsafe { pac::Peripherals::steal() }; | ||
| 83 | |||
| 84 | pp.DBGMCU.cr.modify(|_, w| { | ||
| 85 | w.dbgsleep_d1().set_bit(); | ||
| 86 | w.dbgstby_d1().set_bit(); | ||
| 87 | w.dbgstop_d1().set_bit(); | ||
| 88 | w.d1dbgcken().set_bit(); | ||
| 89 | w | ||
| 90 | }); | ||
| 91 | |||
| 92 | pp.RCC.ahb4enr.modify(|_, w| { | ||
| 93 | w.gpioaen().set_bit(); | ||
| 94 | w.gpioben().set_bit(); | ||
| 95 | w.gpiocen().set_bit(); | ||
| 96 | w.gpioden().set_bit(); | ||
| 97 | w.gpioeen().set_bit(); | ||
| 98 | w.gpiofen().set_bit(); | ||
| 99 | w | ||
| 100 | }); | ||
| 101 | |||
| 102 | unsafe { embassy::time::set_clock(&ZeroClock) }; | ||
| 103 | |||
| 104 | let executor = EXECUTOR.put(Executor::new()); | ||
| 105 | |||
| 106 | executor.run(|spawner| { | ||
| 107 | unwrap!(spawner.spawn(main_task())); | ||
| 108 | }) | ||
| 109 | } | ||
