Make SPIv3 work with DMA.
Add both DMA and non-DMA example to H7.
This commit is contained in:
		| @@ -88,7 +88,11 @@ pub(crate) unsafe fn do_transfer( | ||||
|             w.set_dir(dir); | ||||
|             w.set_msize(vals::Size::BITS8); | ||||
|             w.set_psize(vals::Size::BITS8); | ||||
|             w.set_minc(vals::Inc::INCREMENTED); | ||||
|             if incr_mem { | ||||
|                 w.set_minc(vals::Inc::INCREMENTED); | ||||
|             } else { | ||||
|                 w.set_minc(vals::Inc::FIXED); | ||||
|             } | ||||
|             w.set_pinc(vals::Inc::FIXED); | ||||
|             w.set_teie(true); | ||||
|             w.set_tcie(true); | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| #![macro_use] | ||||
|  | ||||
| #[cfg_attr(spi_v1, path = "v1.rs")] | ||||
| #[cfg_attr(spi_v2, path = "v2.rs")] | ||||
| //#[cfg_attr(spi_v1, path = "v1.rs")] | ||||
| //#[cfg_attr(spi_v2, path = "v2.rs")] | ||||
| #[cfg_attr(spi_v3, path = "v3.rs")] | ||||
| mod _version; | ||||
| use crate::{dma, peripherals, rcc::RccPeripheral}; | ||||
|   | ||||
| @@ -18,7 +18,7 @@ use embassy_extras::unborrow; | ||||
| use embassy_traits::spi as traits; | ||||
| pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | ||||
|  | ||||
| use futures::future::join; | ||||
| use futures::future::join3; | ||||
|  | ||||
| impl WordSize { | ||||
|     fn dsize(&self) -> u8 { | ||||
| @@ -110,7 +110,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|                 w.set_crcen(false); | ||||
|                 w.set_mbr(spi::vals::Mbr(br)); | ||||
|                 w.set_dsize(WordSize::EightBit.dsize()); | ||||
|                 //w.set_fthlv(WordSize::EightBit.frxth()); | ||||
|             }); | ||||
|             T::regs().cr2().modify(|w| { | ||||
|                 w.set_tsize(0); | ||||
| @@ -182,16 +181,40 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|     where | ||||
|         Tx: TxDmaChannel<T>, | ||||
|     { | ||||
|         Self::set_word_size(WordSize::EightBit); | ||||
|         unsafe { | ||||
|             T::regs().cr1().modify(|w| { | ||||
|                 w.set_spe(false); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         let request = self.txdma.request(); | ||||
|         let dst = T::regs().txdr().ptr() as *mut u8; | ||||
|         let f = self.txdma.write(request, write, dst); | ||||
|  | ||||
|         unsafe { | ||||
|             T::regs().cfg1().modify(|reg| { | ||||
|                 reg.set_txdmaen(true); | ||||
|             }); | ||||
|             T::regs().cr1().modify(|w| { | ||||
|                 w.set_spe(true); | ||||
|             }); | ||||
|             T::regs().cr1().modify(|w| { | ||||
|                 w.set_cstart(true); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         f.await; | ||||
|         unsafe { | ||||
|             T::regs().cfg1().modify(|reg| { | ||||
|                 reg.set_rxdmaen(false); | ||||
|                 reg.set_txdmaen(false); | ||||
|             }); | ||||
|             T::regs().cr1().modify(|w| { | ||||
|                 w.set_spe(false); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
| @@ -201,6 +224,16 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|         Tx: TxDmaChannel<T>, | ||||
|         Rx: RxDmaChannel<T>, | ||||
|     { | ||||
|         Self::set_word_size(WordSize::EightBit); | ||||
|         unsafe { | ||||
|             T::regs().cr1().modify(|w| { | ||||
|                 w.set_spe(false); | ||||
|             }); | ||||
|             T::regs().cfg1().modify(|reg| { | ||||
|                 reg.set_rxdmaen(true); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         let clock_byte_count = read.len(); | ||||
|  | ||||
|         let rx_request = self.rxdma.request(); | ||||
| @@ -217,11 +250,25 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|         unsafe { | ||||
|             T::regs().cfg1().modify(|reg| { | ||||
|                 reg.set_txdmaen(true); | ||||
|                 reg.set_rxdmaen(true); | ||||
|             }); | ||||
|             T::regs().cr1().modify(|w| { | ||||
|                 w.set_spe(true); | ||||
|             }); | ||||
|             T::regs().cr1().modify(|w| { | ||||
|                 w.set_cstart(true); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         let r = join(tx_f, rx_f).await; | ||||
|         join3(tx_f, rx_f, Self::wait_for_idle()).await; | ||||
|         unsafe { | ||||
|             T::regs().cfg1().modify(|reg| { | ||||
|                 reg.set_rxdmaen(false); | ||||
|                 reg.set_txdmaen(false); | ||||
|             }); | ||||
|             T::regs().cr1().modify(|w| { | ||||
|                 w.set_spe(false); | ||||
|             }); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
| @@ -231,11 +278,21 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | ||||
|         Tx: TxDmaChannel<T>, | ||||
|         Rx: RxDmaChannel<T>, | ||||
|     { | ||||
|         let clock_byte_count = read.len(); | ||||
|         Self::set_word_size(WordSize::EightBit); | ||||
|         unsafe { | ||||
|             T::regs().cr1().modify(|w| { | ||||
|                 w.set_spe(false); | ||||
|             }); | ||||
|             T::regs().cfg1().modify(|reg| { | ||||
|                 reg.set_rxdmaen(true); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         let rx_request = self.rxdma.request(); | ||||
|         let rx_src = T::regs().rxdr().ptr() as *mut u8; | ||||
|         let rx_f = self.rxdma.read(rx_request, rx_src, read); | ||||
|         let rx_f = self | ||||
|             .rxdma | ||||
|             .read(rx_request, rx_src, &mut read[0..write.len()]); | ||||
|  | ||||
|         let tx_request = self.txdma.request(); | ||||
|         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> { | ||||
|         unsafe { | ||||
|             T::regs().cfg1().modify(|reg| { | ||||
|                 reg.set_txdmaen(true); | ||||
|                 reg.set_rxdmaen(true); | ||||
|             }); | ||||
|             T::regs().cr1().modify(|w| { | ||||
|                 w.set_spe(true); | ||||
|             }); | ||||
|             T::regs().cr1().modify(|w| { | ||||
|                 w.set_cstart(true); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         let r = join(tx_f, rx_f).await; | ||||
|         join3(tx_f, rx_f, Self::wait_for_idle()).await; | ||||
|         unsafe { | ||||
|             T::regs().cfg1().modify(|reg| { | ||||
|                 reg.set_rxdmaen(false); | ||||
|                 reg.set_txdmaen(false); | ||||
|             }); | ||||
|             T::regs().cr1().modify(|w| { | ||||
|                 w.set_spe(false); | ||||
|             }); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     async fn wait_for_idle() { | ||||
|         unsafe { | ||||
|             while !T::regs().sr().read().txc() { | ||||
|                 // spin | ||||
|             } | ||||
|             while T::regs().sr().read().rxplvl().0 > 0 { | ||||
|                 // spin | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { | ||||
|   | ||||
							
								
								
									
										112
									
								
								examples/stm32h7/src/bin/spi.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								examples/stm32h7/src/bin/spi.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| #![feature(trait_alias)] | ||||
| #![feature(min_type_alias_impl_trait)] | ||||
| #![feature(impl_trait_in_bindings)] | ||||
| #![feature(type_alias_impl_trait)] | ||||
| #![allow(incomplete_features)] | ||||
|  | ||||
| #[path = "../example_common.rs"] | ||||
| mod example_common; | ||||
|  | ||||
| use core::fmt::Write; | ||||
| use embassy::executor::Executor; | ||||
| use embassy::time::Clock; | ||||
| use embassy::util::Forever; | ||||
| use embassy_stm32::dma::NoDma; | ||||
| use example_common::*; | ||||
| use embedded_hal::blocking::spi::Transfer; | ||||
|  | ||||
| use hal::prelude::*; | ||||
| use stm32h7xx_hal as hal; | ||||
|  | ||||
| use cortex_m_rt::entry; | ||||
| use stm32h7::stm32h743 as pac; | ||||
| use heapless::String; | ||||
| use embassy_stm32::spi::{Spi, Config}; | ||||
| use embassy_stm32::time::Hertz; | ||||
|  | ||||
| #[embassy::task] | ||||
| async fn main_task() { | ||||
|     let p = embassy_stm32::init(Default::default()); | ||||
|  | ||||
|     let mut spi = Spi::new( | ||||
|         p.SPI3, | ||||
|         p.PB3, | ||||
|         p.PB5, | ||||
|         p.PB4, | ||||
|         NoDma, | ||||
|         NoDma, | ||||
|         Hertz(1_000_000), | ||||
|         Config::default(), | ||||
|     ); | ||||
|  | ||||
|     for n in 0u32.. { | ||||
|         let mut write: String<128> = String::new(); | ||||
|         core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); | ||||
|         unsafe { | ||||
|             let result = spi.transfer(write.as_bytes_mut()); | ||||
|             if let Err(_) = result { | ||||
|                 defmt::panic!("crap"); | ||||
|             } | ||||
|         } | ||||
|         info!("read via spi: {}", write.as_bytes()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct ZeroClock; | ||||
|  | ||||
| impl Clock for ZeroClock { | ||||
|     fn now(&self) -> u64 { | ||||
|         0 | ||||
|     } | ||||
| } | ||||
|  | ||||
| static EXECUTOR: Forever<Executor> = Forever::new(); | ||||
|  | ||||
| #[entry] | ||||
| fn main() -> ! { | ||||
|     info!("Hello World!"); | ||||
|  | ||||
|     let pp = pac::Peripherals::take().unwrap(); | ||||
|  | ||||
|     let pwrcfg = pp.PWR.constrain().freeze(); | ||||
|  | ||||
|     let rcc = pp.RCC.constrain(); | ||||
|  | ||||
|     rcc.sys_ck(96.mhz()) | ||||
|         .pclk1(48.mhz()) | ||||
|         .pclk2(48.mhz()) | ||||
|         .pclk3(48.mhz()) | ||||
|         .pclk4(48.mhz()) | ||||
|         .pll1_q_ck(48.mhz()) | ||||
|         .freeze(pwrcfg, &pp.SYSCFG); | ||||
|  | ||||
|     let pp = unsafe { pac::Peripherals::steal() }; | ||||
|  | ||||
|     pp.DBGMCU.cr.modify(|_, w| { | ||||
|         w.dbgsleep_d1().set_bit(); | ||||
|         w.dbgstby_d1().set_bit(); | ||||
|         w.dbgstop_d1().set_bit(); | ||||
|         w.d1dbgcken().set_bit(); | ||||
|         w | ||||
|     }); | ||||
|  | ||||
|     pp.RCC.ahb4enr.modify(|_, w| { | ||||
|         w.gpioaen().set_bit(); | ||||
|         w.gpioben().set_bit(); | ||||
|         w.gpiocen().set_bit(); | ||||
|         w.gpioden().set_bit(); | ||||
|         w.gpioeen().set_bit(); | ||||
|         w.gpiofen().set_bit(); | ||||
|         w | ||||
|     }); | ||||
|  | ||||
|     unsafe { embassy::time::set_clock(&ZeroClock) }; | ||||
|  | ||||
|     let executor = EXECUTOR.put(Executor::new()); | ||||
|  | ||||
|     executor.run(|spawner| { | ||||
|         unwrap!(spawner.spawn(main_task())); | ||||
|     }) | ||||
| } | ||||
							
								
								
									
										109
									
								
								examples/stm32h7/src/bin/spi_dma.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								examples/stm32h7/src/bin/spi_dma.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | ||||
| #![no_std] | ||||
| #![no_main] | ||||
| #![feature(trait_alias)] | ||||
| #![feature(min_type_alias_impl_trait)] | ||||
| #![feature(impl_trait_in_bindings)] | ||||
| #![feature(type_alias_impl_trait)] | ||||
| #![allow(incomplete_features)] | ||||
|  | ||||
| #[path = "../example_common.rs"] | ||||
| mod example_common; | ||||
| use core::fmt::Write; | ||||
| use embassy::executor::Executor; | ||||
| use embassy::time::Clock; | ||||
| use embassy::util::Forever; | ||||
| use example_common::*; | ||||
| use embassy_traits::spi::FullDuplex; | ||||
|  | ||||
| use hal::prelude::*; | ||||
| use stm32h7xx_hal as hal; | ||||
|  | ||||
| use cortex_m_rt::entry; | ||||
| use stm32h7::stm32h743 as pac; | ||||
| use heapless::String; | ||||
| use embassy_stm32::spi::{Spi, Config}; | ||||
| use embassy_stm32::time::Hertz; | ||||
| use core::str::from_utf8; | ||||
|  | ||||
| #[embassy::task] | ||||
| async fn main_task() { | ||||
|     let p = embassy_stm32::init(Default::default()); | ||||
|  | ||||
|     let mut spi = Spi::new( | ||||
|         p.SPI3, | ||||
|         p.PB3, | ||||
|         p.PB5, | ||||
|         p.PB4, | ||||
|         p.DMA1_CH3, | ||||
|         p.DMA1_CH4, | ||||
|         Hertz(1_000_000), | ||||
|         Config::default(), | ||||
|     ); | ||||
|  | ||||
|     for n in 0u32.. { | ||||
|         let mut write: String<128> = String::new(); | ||||
|         let mut read = [0;128]; | ||||
|         core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); | ||||
|         // read_write will slice the &mut read down to &write's actual length. | ||||
|         spi.read_write(&mut read, write.as_bytes()).await.ok(); | ||||
|         info!("read via spi+dma: {}", from_utf8(&read).unwrap()); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| struct ZeroClock; | ||||
|  | ||||
| impl Clock for ZeroClock { | ||||
|     fn now(&self) -> u64 { | ||||
|         0 | ||||
|     } | ||||
| } | ||||
|  | ||||
| static EXECUTOR: Forever<Executor> = Forever::new(); | ||||
|  | ||||
| #[entry] | ||||
| fn main() -> ! { | ||||
|     info!("Hello World!"); | ||||
|  | ||||
|     let pp = pac::Peripherals::take().unwrap(); | ||||
|  | ||||
|     let pwrcfg = pp.PWR.constrain().freeze(); | ||||
|  | ||||
|     let rcc = pp.RCC.constrain(); | ||||
|  | ||||
|     rcc.sys_ck(96.mhz()) | ||||
|         .pclk1(48.mhz()) | ||||
|         .pclk2(48.mhz()) | ||||
|         .pclk3(48.mhz()) | ||||
|         .pclk4(48.mhz()) | ||||
|         .pll1_q_ck(48.mhz()) | ||||
|         .freeze(pwrcfg, &pp.SYSCFG); | ||||
|  | ||||
|     let pp = unsafe { pac::Peripherals::steal() }; | ||||
|  | ||||
|     pp.DBGMCU.cr.modify(|_, w| { | ||||
|         w.dbgsleep_d1().set_bit(); | ||||
|         w.dbgstby_d1().set_bit(); | ||||
|         w.dbgstop_d1().set_bit(); | ||||
|         w.d1dbgcken().set_bit(); | ||||
|         w | ||||
|     }); | ||||
|  | ||||
|     pp.RCC.ahb4enr.modify(|_, w| { | ||||
|         w.gpioaen().set_bit(); | ||||
|         w.gpioben().set_bit(); | ||||
|         w.gpiocen().set_bit(); | ||||
|         w.gpioden().set_bit(); | ||||
|         w.gpioeen().set_bit(); | ||||
|         w.gpiofen().set_bit(); | ||||
|         w | ||||
|     }); | ||||
|  | ||||
|     unsafe { embassy::time::set_clock(&ZeroClock) }; | ||||
|  | ||||
|     let executor = EXECUTOR.put(Executor::new()); | ||||
|  | ||||
|     executor.run(|spawner| { | ||||
|         unwrap!(spawner.spawn(main_task())); | ||||
|     }) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user