From eeb6ffce4cfa0e0055da8d6738f6d28c3fa43f15 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 20 May 2024 23:36:21 +0200 Subject: [PATCH 1/3] stm32/rcc: add ClockEnableBit struct. --- embassy-stm32/build.rs | 32 +++++++++++++++++++++++ embassy-stm32/src/rcc/mod.rs | 50 +++++++++++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index dbc8f9153..f17c6bef6 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -7,6 +7,7 @@ use std::{env, fs}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; +use stm32_metapac::metadata::ir::BitOffset; use stm32_metapac::metadata::{ MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, METADATA, }; @@ -359,12 +360,17 @@ fn main() { // ======== // Extract the rcc registers + let rcc_registers = METADATA .peripherals .iter() .filter_map(|p| p.registers.as_ref()) .find(|r| r.kind == "rcc") .unwrap(); + for b in rcc_registers.ir.blocks { + eprintln!("{}", b.name); + } + let rcc_block = rcc_registers.ir.blocks.iter().find(|b| b.name == "Rcc").unwrap(); // ======== // Generate RccPeripheral impls @@ -540,6 +546,29 @@ fn main() { let pname = format_ident!("{}", p.name); let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); + let en_reg_offs = rcc_block + .items + .iter() + .find(|i| i.name.eq_ignore_ascii_case(en.register)) + .unwrap() + .byte_offset; + let en_reg_offs: u8 = (en_reg_offs / 4).try_into().unwrap(); + + let en_bit_offs = &rcc_registers + .ir + .fieldsets + .iter() + .find(|i| i.name.eq_ignore_ascii_case(en.register)) + .unwrap() + .fields + .iter() + .find(|i| i.name.eq_ignore_ascii_case(en.field)) + .unwrap() + .bit_offset; + let BitOffset::Regular(en_bit_offs) = en_bit_offs else { + panic!("cursed bit offset") + }; + let en_bit_offs: u8 = en_bit_offs.offset.try_into().unwrap(); let refcount = clock_gen.force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1; @@ -624,6 +653,9 @@ fn main() { crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); #decr_stop_refcount } + fn enable_bit() -> crate::rcc::ClockEnableBit { + unsafe { crate::rcc::ClockEnableBit::new(#en_reg_offs, #en_bit_offs) } + } } impl crate::rcc::RccPeripheral for peripherals::#pname {} diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index a585940bc..c413b62ef 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -31,6 +31,7 @@ pub use hsi48::*; mod _version; pub use _version::*; +use stm32_metapac::RCC; pub use crate::_generated::{mux, Clocks}; use crate::time::Hertz; @@ -66,9 +67,10 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks { } pub(crate) trait SealedRccPeripheral { - fn frequency() -> crate::time::Hertz; + fn frequency() -> Hertz; fn enable_and_reset_with_cs(cs: CriticalSection); fn disable_with_cs(cs: CriticalSection); + fn enable_bit() -> ClockEnableBit; fn enable_and_reset() { critical_section::with(|cs| Self::enable_and_reset_with_cs(cs)) @@ -137,3 +139,49 @@ pub unsafe fn enable_and_reset() { pub unsafe fn disable() { T::disable(); } + +/// Struct representing some clock enable bit (xxxENR.xxEN), only known at runtime. +#[derive(Clone, Copy)] +pub(crate) struct ClockEnableBit { + /// offset in 32bit words of the xxxENR register into the RCC register block. + offset: u8, + /// bit within the register (0..=31) + bit: u8, +} + +impl ClockEnableBit { + /// Safety: offset+bit must correspond to a valid xxxEN bit. + pub(crate) unsafe fn new(offset: u8, bit: u8) -> Self { + Self { offset, bit } + } + + fn ptr(self) -> *mut u32 { + unsafe { (RCC.as_ptr() as *mut u32).add(self.offset as _) } + } + + #[allow(unused)] + pub(crate) fn enable_with_cs(self, _cs: CriticalSection) { + let p = self.ptr(); + unsafe { + let val = p.read_volatile(); + p.write_volatile(val | 1u32 << self.bit); + } + } + + pub(crate) fn disable_with_cs(self, _cs: CriticalSection) { + let p = self.ptr(); + unsafe { + let val = p.read_volatile(); + p.write_volatile(val & !(1u32 << self.bit)); + } + } + + #[allow(unused)] + pub(crate) fn enable(self) { + critical_section::with(|cs| self.enable_with_cs(cs)) + } + + pub(crate) fn disable(self) { + critical_section::with(|cs| self.disable_with_cs(cs)) + } +} From ca2eef5387b521a0ea95f26bae530d9bdfbba4d7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 18 Apr 2024 19:08:24 +0200 Subject: [PATCH 2/3] stm32/spi: remove peripheral generic param. --- embassy-stm32/src/i2s.rs | 14 +- embassy-stm32/src/macros.rs | 25 ++ embassy-stm32/src/spi/mod.rs | 237 +++++++++--------- examples/stm32h7/src/bin/spi.rs | 3 +- examples/stm32h7/src/bin/spi_bdma.rs | 4 +- examples/stm32h7/src/bin/spi_dma.rs | 4 +- examples/stm32h7rs/src/bin/spi.rs | 3 +- examples/stm32h7rs/src/bin/spi_dma.rs | 4 +- .../src/bin/spe_adin1110_http_server.rs | 2 +- 9 files changed, 161 insertions(+), 135 deletions(-) diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index 9b80dc1d0..c102c0035 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -153,17 +153,17 @@ impl Default for Config { } /// I2S driver. -pub struct I2S<'d, T: Instance> { - _peri: Spi<'d, T, Async>, +pub struct I2S<'d> { + _peri: Spi<'d, Async>, sd: Option>, ws: Option>, ck: Option>, mck: Option>, } -impl<'d, T: Instance> I2S<'d, T> { +impl<'d> I2S<'d> { /// Note: Full-Duplex modes are not supported at this time - pub fn new( + pub fn new( peri: impl Peripheral

+ 'd, sd: impl Peripheral

> + 'd, ws: impl Peripheral

> + 'd, @@ -208,7 +208,7 @@ impl<'d, T: Instance> I2S<'d, T> { // rate to reach the proper audio sample frequency. The ODD bit in the SPI_I2SPR // register also has to be defined. - T::REGS.i2spr().modify(|w| { + spi.regs.i2spr().modify(|w| { w.set_i2sdiv(div); w.set_odd(match odd { true => Odd::ODD, @@ -235,7 +235,7 @@ impl<'d, T: Instance> I2S<'d, T> { // 5. The I2SE bit in SPI_I2SCFGR register must be set. - T::REGS.i2scfgr().modify(|w| { + spi.regs.i2scfgr().modify(|w| { w.set_ckpol(config.clock_polarity.ckpol()); w.set_i2smod(true); @@ -276,7 +276,7 @@ impl<'d, T: Instance> I2S<'d, T> { } } -impl<'d, T: Instance> Drop for I2S<'d, T> { +impl<'d> Drop for I2S<'d> { fn drop(&mut self) { self.sd.as_ref().map(|x| x.set_as_disconnected()); self.ws.as_ref().map(|x| x.set_as_disconnected()); diff --git a/embassy-stm32/src/macros.rs b/embassy-stm32/src/macros.rs index 02dce1266..9c459a932 100644 --- a/embassy-stm32/src/macros.rs +++ b/embassy-stm32/src/macros.rs @@ -1,5 +1,30 @@ #![macro_use] +macro_rules! peri_trait { + () => { + #[allow(private_interfaces)] + pub(crate) trait SealedInstance { + const INFO: Info; + const STATE: &'static State; + } + + /// SPI instance trait. + #[allow(private_bounds)] + pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral {} + }; +} + +macro_rules! peri_trait_impl { + ($instance:ident, $info:expr) => { + #[allow(private_interfaces)] + impl SealedInstance for crate::peripherals::$instance { + const INFO: Info = $info; + const STATE: &'static State = &State::new(); + } + impl Instance for crate::peripherals::$instance {} + }; +} + macro_rules! pin_trait { ($signal:ident, $instance:path $(, $mode:path)?) => { #[doc = concat!(stringify!($signal), " pin trait")] diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index c39ef1913..5a2ee105d 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -6,16 +6,16 @@ use core::ptr; use embassy_embedded_hal::SetConfig; use embassy_futures::join::join; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::PeripheralRef; pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use crate::dma::{slice_ptr_parts, word, ChannelAndRequest}; use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::spi::{regs, vals, Spi as Regs}; -use crate::rcc::RccPeripheral; +use crate::rcc::{ClockEnableBit, RccPeripheral}; use crate::time::Hertz; -use crate::{peripherals, Peripheral}; +use crate::Peripheral; /// SPI error. #[derive(Debug, PartialEq, Eq)] @@ -92,8 +92,10 @@ impl Config { } } /// SPI driver. -pub struct Spi<'d, T: Instance, M: PeriMode> { - _peri: PeripheralRef<'d, T>, +pub struct Spi<'d, M: PeriMode> { + pub(crate) regs: Regs, + enable_bit: ClockEnableBit, + kernel_clock: Hertz, sck: Option>, mosi: Option>, miso: Option>, @@ -103,9 +105,9 @@ pub struct Spi<'d, T: Instance, M: PeriMode> { current_word_size: word_impl::Config, } -impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { - fn new_inner( - peri: impl Peripheral

+ 'd, +impl<'d, M: PeriMode> Spi<'d, M> { + fn new_inner( + _peri: impl Peripheral

+ 'd, sck: Option>, mosi: Option>, miso: Option>, @@ -113,11 +115,9 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { rx_dma: Option>, config: Config, ) -> Self { - into_ref!(peri); - - let pclk = T::frequency(); - let freq = config.frequency; - let br = compute_baud_rate(pclk, freq); + let regs = T::INFO.regs; + let kernel_clock = T::frequency(); + let br = compute_baud_rate(kernel_clock, config.frequency); let cpha = config.raw_phase(); let cpol = config.raw_polarity(); @@ -128,10 +128,10 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { #[cfg(any(spi_v1, spi_f1))] { - T::REGS.cr2().modify(|w| { + regs.cr2().modify(|w| { w.set_ssoe(false); }); - T::REGS.cr1().modify(|w| { + regs.cr1().modify(|w| { w.set_cpha(cpha); w.set_cpol(cpol); @@ -151,13 +151,13 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { } #[cfg(spi_v2)] { - T::REGS.cr2().modify(|w| { + regs.cr2().modify(|w| { let (ds, frxth) = ::CONFIG; w.set_frxth(frxth); w.set_ds(ds); w.set_ssoe(false); }); - T::REGS.cr1().modify(|w| { + regs.cr1().modify(|w| { w.set_cpha(cpha); w.set_cpol(cpol); @@ -173,8 +173,8 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { } #[cfg(any(spi_v3, spi_v4, spi_v5))] { - T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff); - T::REGS.cfg2().modify(|w| { + regs.ifcr().write(|w| w.0 = 0xffff_ffff); + regs.cfg2().modify(|w| { //w.set_ssoe(true); w.set_ssoe(false); w.set_cpha(cpha); @@ -189,23 +189,25 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { w.set_afcntr(true); w.set_ssiop(vals::Ssiop::ACTIVEHIGH); }); - T::REGS.cfg1().modify(|w| { + regs.cfg1().modify(|w| { w.set_crcen(false); w.set_mbr(br); w.set_dsize(::CONFIG); w.set_fthlv(vals::Fthlv::ONEFRAME); }); - T::REGS.cr2().modify(|w| { + regs.cr2().modify(|w| { w.set_tsize(0); }); - T::REGS.cr1().modify(|w| { + regs.cr1().modify(|w| { w.set_ssi(false); w.set_spe(true); }); } Self { - _peri: peri, + regs, + enable_bit: T::enable_bit(), + kernel_clock, sck, mosi, miso, @@ -223,12 +225,10 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { let lsbfirst = config.raw_byte_order(); - let pclk = T::frequency(); - let freq = config.frequency; - let br = compute_baud_rate(pclk, freq); + let br = compute_baud_rate(self.kernel_clock, config.frequency); #[cfg(any(spi_v1, spi_f1, spi_v2))] - T::REGS.cr1().modify(|w| { + self.regs.cr1().modify(|w| { w.set_cpha(cpha); w.set_cpol(cpol); w.set_br(br); @@ -237,12 +237,12 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { #[cfg(any(spi_v3, spi_v4, spi_v5))] { - T::REGS.cfg2().modify(|w| { + self.regs.cfg2().modify(|w| { w.set_cpha(cpha); w.set_cpol(cpol); w.set_lsbfirst(lsbfirst); }); - T::REGS.cfg1().modify(|w| { + self.regs.cfg1().modify(|w| { w.set_mbr(br); }); } @@ -252,11 +252,11 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { /// Get current SPI configuration. pub fn get_current_config(&self) -> Config { #[cfg(any(spi_v1, spi_f1, spi_v2))] - let cfg = T::REGS.cr1().read(); + let cfg = self.regs.cr1().read(); #[cfg(any(spi_v3, spi_v4, spi_v5))] - let cfg = T::REGS.cfg2().read(); + let cfg = self.regs.cfg2().read(); #[cfg(any(spi_v3, spi_v4, spi_v5))] - let cfg1 = T::REGS.cfg1().read(); + let cfg1 = self.regs.cfg1().read(); let polarity = if cfg.cpol() == vals::Cpol::IDLELOW { Polarity::IdleLow @@ -280,8 +280,7 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { #[cfg(any(spi_v3, spi_v4, spi_v5))] let br = cfg1.mbr(); - let pclk = T::frequency(); - let frequency = compute_frequency(pclk, br); + let frequency = compute_frequency(self.kernel_clock, br); Config { mode: Mode { polarity, phase }, @@ -297,40 +296,40 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { #[cfg(any(spi_v1, spi_f1))] { - T::REGS.cr1().modify(|reg| { + self.regs.cr1().modify(|reg| { reg.set_spe(false); reg.set_dff(word_size) }); - T::REGS.cr1().modify(|reg| { + self.regs.cr1().modify(|reg| { reg.set_spe(true); }); } #[cfg(spi_v2)] { - T::REGS.cr1().modify(|w| { + self.regs.cr1().modify(|w| { w.set_spe(false); }); - T::REGS.cr2().modify(|w| { + self.regs.cr2().modify(|w| { w.set_frxth(word_size.1); w.set_ds(word_size.0); }); - T::REGS.cr1().modify(|w| { + self.regs.cr1().modify(|w| { w.set_spe(true); }); } #[cfg(any(spi_v3, spi_v4, spi_v5))] { - T::REGS.cr1().modify(|w| { + self.regs.cr1().modify(|w| { w.set_csusp(true); }); - while T::REGS.sr().read().eot() {} - T::REGS.cr1().modify(|w| { + while self.regs.sr().read().eot() {} + self.regs.cr1().modify(|w| { w.set_spe(false); }); - T::REGS.cfg1().modify(|w| { + self.regs.cfg1().modify(|w| { w.set_dsize(word_size); }); - T::REGS.cr1().modify(|w| { + self.regs.cr1().modify(|w| { w.set_csusp(false); w.set_spe(true); }); @@ -341,22 +340,22 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { /// Blocking write. pub fn blocking_write(&mut self, words: &[W]) -> Result<(), Error> { - T::REGS.cr1().modify(|w| w.set_spe(true)); - flush_rx_fifo(T::REGS); + self.regs.cr1().modify(|w| w.set_spe(true)); + flush_rx_fifo(self.regs); self.set_word_size(W::CONFIG); for word in words.iter() { - let _ = transfer_word(T::REGS, *word)?; + let _ = transfer_word(self.regs, *word)?; } Ok(()) } /// Blocking read. pub fn blocking_read(&mut self, words: &mut [W]) -> Result<(), Error> { - T::REGS.cr1().modify(|w| w.set_spe(true)); - flush_rx_fifo(T::REGS); + self.regs.cr1().modify(|w| w.set_spe(true)); + flush_rx_fifo(self.regs); self.set_word_size(W::CONFIG); for word in words.iter_mut() { - *word = transfer_word(T::REGS, W::default())?; + *word = transfer_word(self.regs, W::default())?; } Ok(()) } @@ -365,11 +364,11 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { /// /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. pub fn blocking_transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Error> { - T::REGS.cr1().modify(|w| w.set_spe(true)); - flush_rx_fifo(T::REGS); + self.regs.cr1().modify(|w| w.set_spe(true)); + flush_rx_fifo(self.regs); self.set_word_size(W::CONFIG); for word in words.iter_mut() { - *word = transfer_word(T::REGS, *word)?; + *word = transfer_word(self.regs, *word)?; } Ok(()) } @@ -381,13 +380,13 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. /// If `write` is shorter it is padded with zero bytes. pub fn blocking_transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { - T::REGS.cr1().modify(|w| w.set_spe(true)); - flush_rx_fifo(T::REGS); + self.regs.cr1().modify(|w| w.set_spe(true)); + flush_rx_fifo(self.regs); self.set_word_size(W::CONFIG); let len = read.len().max(write.len()); for i in 0..len { let wb = write.get(i).copied().unwrap_or_default(); - let rb = transfer_word(T::REGS, wb)?; + let rb = transfer_word(self.regs, wb)?; if let Some(r) = read.get_mut(i) { *r = rb; } @@ -396,9 +395,9 @@ impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> { } } -impl<'d, T: Instance> Spi<'d, T, Blocking> { +impl<'d> Spi<'d, Blocking> { /// Create a new blocking SPI driver. - pub fn new_blocking( + pub fn new_blocking( peri: impl Peripheral

+ 'd, sck: impl Peripheral

> + 'd, mosi: impl Peripheral

> + 'd, @@ -417,7 +416,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> { } /// Create a new blocking SPI driver, in RX-only mode (only MISO pin, no MOSI). - pub fn new_blocking_rxonly( + pub fn new_blocking_rxonly( peri: impl Peripheral

+ 'd, sck: impl Peripheral

> + 'd, miso: impl Peripheral

> + 'd, @@ -435,7 +434,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> { } /// Create a new blocking SPI driver, in TX-only mode (only MOSI pin, no MISO). - pub fn new_blocking_txonly( + pub fn new_blocking_txonly( peri: impl Peripheral

+ 'd, sck: impl Peripheral

> + 'd, mosi: impl Peripheral

> + 'd, @@ -455,7 +454,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> { /// Create a new SPI driver, in TX-only mode, without SCK pin. /// /// This can be useful for bit-banging non-SPI protocols. - pub fn new_blocking_txonly_nosck( + pub fn new_blocking_txonly_nosck( peri: impl Peripheral

+ 'd, mosi: impl Peripheral

> + 'd, config: Config, @@ -472,9 +471,9 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> { } } -impl<'d, T: Instance> Spi<'d, T, Async> { +impl<'d> Spi<'d, Async> { /// Create a new SPI driver. - pub fn new( + pub fn new( peri: impl Peripheral

+ 'd, sck: impl Peripheral

> + 'd, mosi: impl Peripheral

> + 'd, @@ -495,7 +494,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> { } /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI). - pub fn new_rxonly( + pub fn new_rxonly( peri: impl Peripheral

+ 'd, sck: impl Peripheral

> + 'd, miso: impl Peripheral

> + 'd, @@ -514,7 +513,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> { } /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO). - pub fn new_txonly( + pub fn new_txonly( peri: impl Peripheral

+ 'd, sck: impl Peripheral

> + 'd, mosi: impl Peripheral

> + 'd, @@ -535,7 +534,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> { /// Create a new SPI driver, in TX-only mode, without SCK pin. /// /// This can be useful for bit-banging non-SPI protocols. - pub fn new_txonly_nosck( + pub fn new_txonly_nosck( peri: impl Peripheral

+ 'd, mosi: impl Peripheral

> + 'd, tx_dma: impl Peripheral

> + 'd, @@ -554,7 +553,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> { #[cfg(stm32wl)] /// Useful for on chip peripherals like SUBGHZ which are hardwired. - pub fn new_subghz( + pub fn new_subghz( peri: impl Peripheral

+ 'd, tx_dma: impl Peripheral

> + 'd, rx_dma: impl Peripheral

> + 'd, @@ -562,7 +561,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> { // see RM0453 rev 1 section 7.2.13 page 291 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two. // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz. - let pclk3_freq = ::frequency().0; + let pclk3_freq = ::frequency().0; let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000)); let mut config = Config::default(); config.mode = MODE_0; @@ -573,7 +572,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> { } #[allow(dead_code)] - pub(crate) fn new_internal( + pub(crate) fn new_internal( peri: impl Peripheral

+ 'd, tx_dma: impl Peripheral

> + 'd, rx_dma: impl Peripheral

> + 'd, @@ -589,25 +588,25 @@ impl<'d, T: Instance> Spi<'d, T, Async> { } self.set_word_size(W::CONFIG); - T::REGS.cr1().modify(|w| { + self.regs.cr1().modify(|w| { w.set_spe(false); }); - let tx_dst = T::REGS.tx_ptr(); + let tx_dst = self.regs.tx_ptr(); let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) }; - set_txdmaen(T::REGS, true); - T::REGS.cr1().modify(|w| { + set_txdmaen(self.regs, true); + self.regs.cr1().modify(|w| { w.set_spe(true); }); #[cfg(any(spi_v3, spi_v4, spi_v5))] - T::REGS.cr1().modify(|w| { + self.regs.cr1().modify(|w| { w.set_cstart(true); }); tx_f.await; - finish_dma(T::REGS); + finish_dma(self.regs); Ok(()) } @@ -619,22 +618,22 @@ impl<'d, T: Instance> Spi<'d, T, Async> { } self.set_word_size(W::CONFIG); - T::REGS.cr1().modify(|w| { + self.regs.cr1().modify(|w| { w.set_spe(false); }); // SPIv3 clears rxfifo on SPE=0 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] - flush_rx_fifo(T::REGS); + flush_rx_fifo(self.regs); - set_rxdmaen(T::REGS, true); + set_rxdmaen(self.regs, true); let clock_byte_count = data.len(); - let rx_src = T::REGS.rx_ptr(); + let rx_src = self.regs.rx_ptr(); let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read(rx_src, data, Default::default()) }; - let tx_dst = T::REGS.tx_ptr(); + let tx_dst = self.regs.tx_ptr(); let clock_byte = 0x00u8; let tx_f = unsafe { self.tx_dma @@ -643,18 +642,18 @@ impl<'d, T: Instance> Spi<'d, T, Async> { .write_repeated(&clock_byte, clock_byte_count, tx_dst, Default::default()) }; - set_txdmaen(T::REGS, true); - T::REGS.cr1().modify(|w| { + set_txdmaen(self.regs, true); + self.regs.cr1().modify(|w| { w.set_spe(true); }); #[cfg(any(spi_v3, spi_v4, spi_v5))] - T::REGS.cr1().modify(|w| { + self.regs.cr1().modify(|w| { w.set_cstart(true); }); join(tx_f, rx_f).await; - finish_dma(T::REGS); + finish_dma(self.regs); Ok(()) } @@ -668,20 +667,20 @@ impl<'d, T: Instance> Spi<'d, T, Async> { } self.set_word_size(W::CONFIG); - T::REGS.cr1().modify(|w| { + self.regs.cr1().modify(|w| { w.set_spe(false); }); // SPIv3 clears rxfifo on SPE=0 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] - flush_rx_fifo(T::REGS); + flush_rx_fifo(self.regs); - set_rxdmaen(T::REGS, true); + set_rxdmaen(self.regs, true); - let rx_src = T::REGS.rx_ptr(); + let rx_src = self.regs.rx_ptr(); let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) }; - let tx_dst = T::REGS.tx_ptr(); + let tx_dst = self.regs.tx_ptr(); let tx_f = unsafe { self.tx_dma .as_mut() @@ -689,18 +688,18 @@ impl<'d, T: Instance> Spi<'d, T, Async> { .write_raw(write, tx_dst, Default::default()) }; - set_txdmaen(T::REGS, true); - T::REGS.cr1().modify(|w| { + set_txdmaen(self.regs, true); + self.regs.cr1().modify(|w| { w.set_spe(true); }); #[cfg(any(spi_v3, spi_v4, spi_v5))] - T::REGS.cr1().modify(|w| { + self.regs.cr1().modify(|w| { w.set_cstart(true); }); join(tx_f, rx_f).await; - finish_dma(T::REGS); + finish_dma(self.regs); Ok(()) } @@ -723,13 +722,13 @@ impl<'d, T: Instance> Spi<'d, T, Async> { } } -impl<'d, T: Instance, M: PeriMode> Drop for Spi<'d, T, M> { +impl<'d, M: PeriMode> Drop for Spi<'d, M> { fn drop(&mut self) { self.sck.as_ref().map(|x| x.set_as_disconnected()); self.mosi.as_ref().map(|x| x.set_as_disconnected()); self.miso.as_ref().map(|x| x.set_as_disconnected()); - T::disable(); + self.enable_bit.disable(); } } @@ -738,8 +737,8 @@ use vals::Br; #[cfg(any(spi_v3, spi_v4, spi_v5))] use vals::Mbr as Br; -fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br { - let val = match clocks.0 / freq.0 { +fn compute_baud_rate(kernel_clock: Hertz, freq: Hertz) -> Br { + let val = match kernel_clock.0 / freq.0 { 0 => panic!("You are trying to reach a frequency higher than the clock"), 1..=2 => 0b000, 3..=5 => 0b001, @@ -754,7 +753,7 @@ fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br { Br::from_bits(val) } -fn compute_frequency(clocks: Hertz, br: Br) -> Hertz { +fn compute_frequency(kernel_clock: Hertz, br: Br) -> Hertz { let div: u16 = match br { Br::DIV2 => 2, Br::DIV4 => 4, @@ -766,7 +765,7 @@ fn compute_frequency(clocks: Hertz, br: Br) -> Hertz { Br::DIV256 => 256, }; - clocks / div + kernel_clock / div } trait RegsExt { @@ -941,7 +940,7 @@ fn transfer_word(regs: Regs, tx_word: W) -> Result { // some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289 macro_rules! impl_blocking { ($w:ident) => { - impl<'d, T: Instance, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, T, M> { + impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M> { type Error = Error; fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> { @@ -949,7 +948,7 @@ macro_rules! impl_blocking { } } - impl<'d, T: Instance, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, T, M> { + impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M> { type Error = Error; fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> { @@ -963,11 +962,11 @@ macro_rules! impl_blocking { impl_blocking!(u8); impl_blocking!(u16); -impl<'d, T: Instance, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, T, M> { +impl<'d, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, M> { type Error = Error; } -impl<'d, T: Instance, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus for Spi<'d, T, M> { +impl<'d, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus for Spi<'d, M> { fn flush(&mut self) -> Result<(), Self::Error> { Ok(()) } @@ -1000,7 +999,7 @@ impl embedded_hal_1::spi::Error for Error { } } -impl<'d, T: Instance, W: Word> embedded_hal_async::spi::SpiBus for Spi<'d, T, Async> { +impl<'d, W: Word> embedded_hal_async::spi::SpiBus for Spi<'d, Async> { async fn flush(&mut self) -> Result<(), Self::Error> { Ok(()) } @@ -1022,10 +1021,6 @@ impl<'d, T: Instance, W: Word> embedded_hal_async::spi::SpiBus for Spi<'d, T, } } -pub(crate) trait SealedInstance { - const REGS: Regs; -} - trait SealedWord { const CONFIG: word_impl::Config; } @@ -1111,9 +1106,19 @@ mod word_impl { impl_word!(u32, 32 - 1); } -/// SPI instance trait. -#[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral {} +struct Info { + regs: Regs, +} + +struct State {} + +impl State { + const fn new() -> Self { + Self {} + } +} + +peri_trait!(); pin_trait!(SckPin, Instance); pin_trait!(MosiPin, Instance); @@ -1127,15 +1132,13 @@ dma_trait!(TxDma, Instance); foreach_peripheral!( (spi, $inst:ident) => { - impl SealedInstance for peripherals::$inst { - const REGS: Regs = crate::pac::$inst; - } - - impl Instance for peripherals::$inst {} + peri_trait_impl!($inst, Info { + regs: crate::pac::$inst, + }); }; ); -impl<'d, T: Instance, M: PeriMode> SetConfig for Spi<'d, T, M> { +impl<'d, M: PeriMode> SetConfig for Spi<'d, M> { type Config = Config; type ConfigError = (); fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs index aaebdc346..ad4a8aaf7 100644 --- a/examples/stm32h7/src/bin/spi.rs +++ b/examples/stm32h7/src/bin/spi.rs @@ -8,7 +8,6 @@ use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Blocking; -use embassy_stm32::peripherals::SPI3; use embassy_stm32::time::mhz; use embassy_stm32::{spi, Config}; use heapless::String; @@ -16,7 +15,7 @@ use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, SPI3, Blocking>) { +async fn main_task(mut spi: spi::Spi<'static, Blocking>) { for n in 0u32.. { let mut write: String<128> = String::new(); core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs index f968df4a7..b2e941078 100644 --- a/examples/stm32h7/src/bin/spi_bdma.rs +++ b/examples/stm32h7/src/bin/spi_bdma.rs @@ -9,7 +9,7 @@ use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Async; use embassy_stm32::time::mhz; -use embassy_stm32::{peripherals, spi, Config}; +use embassy_stm32::{spi, Config}; use heapless::String; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -19,7 +19,7 @@ use {defmt_rtt as _, panic_probe as _}; static mut RAM_D3: [u8; 64 * 1024] = [0u8; 64 * 1024]; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI6, Async>) { +async fn main_task(mut spi: spi::Spi<'static, Async>) { let read_buffer = unsafe { &mut RAM_D3[0..128] }; let write_buffer = unsafe { &mut RAM_D3[128..256] }; diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs index 3d3c724eb..731c7fef5 100644 --- a/examples/stm32h7/src/bin/spi_dma.rs +++ b/examples/stm32h7/src/bin/spi_dma.rs @@ -9,13 +9,13 @@ use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Async; use embassy_stm32::time::mhz; -use embassy_stm32::{peripherals, spi, Config}; +use embassy_stm32::{spi, Config}; use heapless::String; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI3, Async>) { +async fn main_task(mut spi: spi::Spi<'static, Async>) { for n in 0u32.. { let mut write: String<128> = String::new(); let mut read = [0; 128]; diff --git a/examples/stm32h7rs/src/bin/spi.rs b/examples/stm32h7rs/src/bin/spi.rs index a7767876d..8d6ccc58b 100644 --- a/examples/stm32h7rs/src/bin/spi.rs +++ b/examples/stm32h7rs/src/bin/spi.rs @@ -8,7 +8,6 @@ use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Blocking; -use embassy_stm32::peripherals::SPI3; use embassy_stm32::spi; use embassy_stm32::time::mhz; use heapless::String; @@ -16,7 +15,7 @@ use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, SPI3, Blocking>) { +async fn main_task(mut spi: spi::Spi<'static, Blocking>) { for n in 0u32.. { let mut write: String<128> = String::new(); core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); diff --git a/examples/stm32h7rs/src/bin/spi_dma.rs b/examples/stm32h7rs/src/bin/spi_dma.rs index 26b5d6751..cb305351b 100644 --- a/examples/stm32h7rs/src/bin/spi_dma.rs +++ b/examples/stm32h7rs/src/bin/spi_dma.rs @@ -8,14 +8,14 @@ use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Async; +use embassy_stm32::spi; use embassy_stm32::time::mhz; -use embassy_stm32::{peripherals, spi}; use heapless::String; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI3, Async>) { +async fn main_task(mut spi: spi::Spi<'static, Async>) { for n in 0u32.. { let mut write: String<128> = String::new(); let mut read = [0; 128]; diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 694629ede..985ac8171 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -55,7 +55,7 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24); // Listen port for the webserver const HTTP_LISTEN_PORT: u16 = 80; -pub type SpeSpi = Spi<'static, peripherals::SPI2, Async>; +pub type SpeSpi = Spi<'static, Async>; pub type SpeSpiCs = ExclusiveDevice, Delay>; pub type SpeInt = exti::ExtiInput<'static>; pub type SpeRst = Output<'static>; From 2b09f9efd7e621708cd00bc512ce981735907103 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 20 May 2024 23:41:02 +0200 Subject: [PATCH 3/3] stm32/spi: check that the RCC enable bit is disabled on drop. --- tests/stm32/src/bin/spi.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs index 59cb0cfd3..c1576bfeb 100644 --- a/tests/stm32/src/bin/spi.rs +++ b/tests/stm32/src/bin/spi.rs @@ -58,6 +58,14 @@ async fn main(_spawner: Spawner) { spi.blocking_read::(&mut []).unwrap(); spi.blocking_write::(&[]).unwrap(); + // Assert the RCC bit gets disabled on drop. + #[cfg(feature = "stm32f429zi")] + { + defmt::assert!(embassy_stm32::pac::RCC.apb2enr().read().spi1en()); + drop(spi); + defmt::assert!(!embassy_stm32::pac::RCC.apb2enr().read().spi1en()); + } + info!("Test OK"); cortex_m::asm::bkpt(); }