From 081afca3f065dfd91e157d7c9a9477e2d914c99d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C5=A0pa=C4=8Dek?= Date: Fri, 24 May 2024 22:04:04 +0200 Subject: [PATCH] stm32/rcc: replace generated enable/disable code with runtime info --- embassy-stm32/build.rs | 195 +++++++-------------- embassy-stm32/src/adc/f1.rs | 6 +- embassy-stm32/src/adc/f3.rs | 6 +- embassy-stm32/src/adc/f3_v1_1.rs | 6 +- embassy-stm32/src/adc/g4.rs | 4 +- embassy-stm32/src/adc/v1.rs | 6 +- embassy-stm32/src/adc/v2.rs | 6 +- embassy-stm32/src/adc/v3.rs | 4 +- embassy-stm32/src/adc/v4.rs | 4 +- embassy-stm32/src/can/bxcan/mod.rs | 6 +- embassy-stm32/src/can/fdcan.rs | 4 +- embassy-stm32/src/cordic/mod.rs | 6 +- embassy-stm32/src/crc/v1.rs | 5 +- embassy-stm32/src/crc/v2v3.rs | 5 +- embassy-stm32/src/cryp/mod.rs | 4 +- embassy-stm32/src/dac/mod.rs | 16 +- embassy-stm32/src/dcmi.rs | 4 +- embassy-stm32/src/dsihost.rs | 4 +- embassy-stm32/src/fmc.rs | 8 +- embassy-stm32/src/gpio.rs | 2 +- embassy-stm32/src/hash/mod.rs | 5 +- embassy-stm32/src/hrtim/mod.rs | 4 +- embassy-stm32/src/i2c/mod.rs | 8 +- embassy-stm32/src/i2c/v1.rs | 2 +- embassy-stm32/src/i2c/v2.rs | 2 +- embassy-stm32/src/ipcc.rs | 5 +- embassy-stm32/src/lib.rs | 7 +- embassy-stm32/src/ltdc.rs | 4 +- embassy-stm32/src/ospi/mod.rs | 6 +- embassy-stm32/src/qspi/mod.rs | 4 +- embassy-stm32/src/rcc/hsi48.rs | 4 +- embassy-stm32/src/rcc/mod.rs | 252 +++++++++++++++++++++------ embassy-stm32/src/rng.rs | 4 +- embassy-stm32/src/rtc/mod.rs | 2 +- embassy-stm32/src/sai/mod.rs | 6 +- embassy-stm32/src/sdmmc/mod.rs | 4 +- embassy-stm32/src/spi/mod.rs | 10 +- embassy-stm32/src/time_driver.rs | 4 +- embassy-stm32/src/timer/low_level.rs | 5 +- embassy-stm32/src/tsc/mod.rs | 6 +- embassy-stm32/src/ucpd.rs | 8 +- embassy-stm32/src/usart/buffered.rs | 9 +- embassy-stm32/src/usart/mod.rs | 14 +- embassy-stm32/src/usb/mod.rs | 4 +- embassy-stm32/src/usb/otg.rs | 4 +- 45 files changed, 379 insertions(+), 305 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 7bf6ffba2..6c524ced6 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -367,9 +367,6 @@ fn main() { .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(); // ======== @@ -388,7 +385,6 @@ fn main() { rcc_registers: &'a PeripheralRegisters, chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>, - refcount_statics: BTreeSet, clock_names: BTreeSet, muxes: BTreeSet<(Ident, Ident, Ident)>, } @@ -397,7 +393,6 @@ fn main() { rcc_registers, chained_muxes: HashMap::new(), - refcount_statics: BTreeSet::new(), clock_names: BTreeSet::new(), muxes: BTreeSet::new(), }; @@ -516,80 +511,64 @@ fn main() { } } + let mut refcount_idxs = HashMap::new(); + for p in METADATA.peripherals { if !singletons.contains(&p.name.to_string()) { continue; } if let Some(rcc) = &p.rcc { - let en = rcc.enable.as_ref().unwrap(); - - let (start_rst, end_rst) = match &rcc.reset { - Some(rst) => { - let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase()); - let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase()); - ( - quote! { - crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true)); - }, - quote! { - crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false)); - }, - ) - } - None => (TokenStream::new(), TokenStream::new()), - }; - + let rst_reg = rcc.reset.as_ref(); + let en_reg = rcc.enable.as_ref().unwrap(); 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 get_offset_and_bit = |reg: &PeripheralRccRegister| -> TokenStream { + let reg_offset = rcc_block + .items + .iter() + .find(|i| i.name.eq_ignore_ascii_case(reg.register)) + .unwrap() + .byte_offset; + let reg_offset: u8 = (reg_offset / 4).try_into().unwrap(); + + let bit_offset = &rcc_registers + .ir + .fieldsets + .iter() + .find(|i| i.name.eq_ignore_ascii_case(reg.register)) + .unwrap() + .fields + .iter() + .find(|i| i.name.eq_ignore_ascii_case(reg.field)) + .unwrap() + .bit_offset; + let BitOffset::Regular(bit_offset) = bit_offset else { + panic!("cursed bit offset") + }; + let bit_offset: u8 = bit_offset.offset.try_into().unwrap(); + + quote! { (#reg_offset, #bit_offset) } }; - let en_bit_offs: u8 = en_bit_offs.offset.try_into().unwrap(); - let refcount = *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1; - let (before_enable, before_disable) = if refcount { - let refcount_static = - format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); + let reset_offset_and_bit = match rst_reg { + Some(rst_reg) => { + let reset_offset_and_bit = get_offset_and_bit(rst_reg); + quote! { Some(#reset_offset_and_bit) } + } + None => quote! { None }, + }; + let enable_offset_and_bit = get_offset_and_bit(en_reg); - clock_gen.refcount_statics.insert(refcount_static.clone()); - - ( - quote! { - unsafe { refcount_statics::#refcount_static += 1 }; - if unsafe { refcount_statics::#refcount_static } > 1 { - return; - } - }, - quote! { - unsafe { refcount_statics::#refcount_static -= 1 }; - if unsafe { refcount_statics::#refcount_static } > 0 { - return; - } - }, - ) + let needs_refcount = *rcc_field_count.get(&(en_reg.register, en_reg.field)).unwrap() > 1; + let refcount_idx = if needs_refcount { + let next_refcount_idx = refcount_idxs.len() as u8; + let refcount_idx = *refcount_idxs + .entry((en_reg.register, en_reg.field)) + .or_insert(next_refcount_idx); + quote! { Some(#refcount_idx) } } else { - (TokenStream::new(), TokenStream::new()) + quote! { None } }; let clock_frequency = match &rcc.kernel_clock { @@ -599,24 +578,10 @@ fn main() { // A refcount leak can result if the same field is shared by peripherals with different stop modes // This condition should be checked in stm32-data - let stop_refcount = match rcc.stop_mode { - StopMode::Standby => None, - StopMode::Stop2 => Some(quote! { REFCOUNT_STOP2 }), - StopMode::Stop1 => Some(quote! { REFCOUNT_STOP1 }), - }; - - let (incr_stop_refcount, decr_stop_refcount) = match stop_refcount { - Some(stop_refcount) => ( - quote! { - #[cfg(feature = "low-power")] - unsafe { crate::rcc::#stop_refcount += 1 }; - }, - quote! { - #[cfg(feature = "low-power")] - unsafe { crate::rcc::#stop_refcount -= 1 }; - }, - ), - None => (TokenStream::new(), TokenStream::new()), + let stop_mode = match rcc.stop_mode { + StopMode::Standby => quote! { crate::rcc::StopMode::Standby }, + StopMode::Stop2 => quote! { crate::rcc::StopMode::Stop2 }, + StopMode::Stop1 => quote! { crate::rcc::StopMode::Stop1 }, }; g.extend(quote! { @@ -624,34 +589,16 @@ fn main() { fn frequency() -> crate::time::Hertz { #clock_frequency } - fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) { - #before_enable - #incr_stop_refcount - #start_rst - - crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); - - // we must wait two peripheral clock cycles before the clock is active - // this seems to work, but might be incorrect - // see http://efton.sk/STM32/gotcha/g183.html - - // dummy read (like in the ST HALs) - let _ = crate::pac::RCC.#en_reg().read(); - - // DSB for good measure - cortex_m::asm::dsb(); - - #end_rst - } - fn disable_with_cs(_cs: critical_section::CriticalSection) { - #before_disable - crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); - #decr_stop_refcount - } - - const ENABLE_BIT: crate::rcc::ClockEnableBit = - unsafe { crate::rcc::ClockEnableBit::new(#en_reg_offs, #en_bit_offs) }; + const RCC_INFO: crate::rcc::RccInfo = unsafe { + crate::rcc::RccInfo::new( + #reset_offset_and_bit, + #enable_offset_and_bit, + #refcount_idx, + #[cfg(feature = "low-power")] + #stop_mode, + ) + }; } impl crate::rcc::RccPeripheral for peripherals::#pname {} @@ -659,6 +606,14 @@ fn main() { } } + g.extend({ + let refcounts_len = refcount_idxs.len(); + let refcount_zeros: TokenStream = refcount_idxs.iter().map(|_| quote! { 0u8, }).collect(); + quote! { + pub(crate) static mut REFCOUNTS: [u8; #refcounts_len] = [#refcount_zeros]; + } + }); + let struct_fields: Vec<_> = clock_gen .muxes .iter() @@ -762,22 +717,6 @@ fn main() { } ); - let refcount_mod: TokenStream = clock_gen - .refcount_statics - .iter() - .map(|refcount_static| { - quote! { - pub(crate) static mut #refcount_static: u8 = 0; - } - }) - .collect(); - - g.extend(quote! { - mod refcount_statics { - #refcount_mod - } - }); - // ======== // Generate fns to enable GPIO, DMA in RCC diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index 3822d5032..b37ec260f 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -7,7 +7,7 @@ use embassy_hal_internal::into_ref; use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; use crate::time::Hertz; -use crate::{interrupt, Peripheral}; +use crate::{interrupt, rcc, Peripheral}; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; @@ -50,7 +50,7 @@ impl super::SealedAdcChannel for Temperature { impl<'d, T: Instance> Adc<'d, T> { pub fn new(adc: impl Peripheral

+ 'd) -> Self { into_ref!(adc); - T::enable_and_reset(); + rcc::enable_and_reset::(); T::regs().cr2().modify(|reg| reg.set_adon(true)); // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) @@ -169,6 +169,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> { fn drop(&mut self) { T::regs().cr2().modify(|reg| reg.set_adon(false)); - T::disable(); + rcc::disable::(); } } diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 3f076d64b..ac88c9742 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -8,7 +8,7 @@ use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::time::Hertz; -use crate::{interrupt, Peripheral}; +use crate::{interrupt, rcc, Peripheral}; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; @@ -63,7 +63,7 @@ impl<'d, T: Instance> Adc<'d, T> { into_ref!(adc); - T::enable_and_reset(); + rcc::enable_and_reset::(); // Enable the adc regulator T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE)); @@ -188,6 +188,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> { T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE)); T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::DISABLED)); - T::disable(); + rcc::disable::(); } } diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs index 106956989..689c2871d 100644 --- a/embassy-stm32/src/adc/f3_v1_1.rs +++ b/embassy-stm32/src/adc/f3_v1_1.rs @@ -10,7 +10,7 @@ use super::Resolution; use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::time::Hertz; -use crate::{interrupt, Peripheral}; +use crate::{interrupt, rcc, Peripheral}; const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ; @@ -143,7 +143,7 @@ impl<'d, T: Instance> Adc<'d, T> { ) -> Self { into_ref!(adc); - T::enable_and_reset(); + rcc::enable_and_reset::(); //let r = T::regs(); //r.cr2().write(|w| w.set_align(true)); @@ -403,6 +403,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> { T::regs().cr2().modify(|w| w.set_adon(false)); - T::disable(); + rcc::disable::(); } } diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index ce7f5db70..6569361fe 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -4,7 +4,7 @@ use pac::adccommon::vals::Presc; use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime}; use crate::time::Hertz; -use crate::{pac, Peripheral}; +use crate::{pac, rcc, Peripheral}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -130,7 +130,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// Create a new ADC driver. pub fn new(adc: impl Peripheral

+ 'd) -> Self { embassy_hal_internal::into_ref!(adc); - T::enable_and_reset(); + rcc::enable_and_reset::(); let prescaler = Prescaler::from_ker_ck(T::frequency()); diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 090790c39..9bec2e13b 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -10,7 +10,7 @@ use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC1; -use crate::{interrupt, Peripheral}; +use crate::{interrupt, rcc, Peripheral}; pub const VDDA_CALIB_MV: u32 = 3300; pub const VREF_INT: u32 = 1230; @@ -67,7 +67,7 @@ impl<'d, T: Instance> Adc<'d, T> { _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { into_ref!(adc); - T::enable_and_reset(); + rcc::enable_and_reset::(); // Delay 1μs when using HSI14 as the ADC clock. // @@ -199,6 +199,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> { T::regs().cr().modify(|reg| reg.set_addis(true)); while T::regs().cr().read().aden() {} - T::disable(); + rcc::disable::(); } } diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 033108195..77e8bb56f 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -4,7 +4,7 @@ use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; use crate::peripherals::ADC1; use crate::time::Hertz; -use crate::Peripheral; +use crate::{rcc, Peripheral}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -96,7 +96,7 @@ where { pub fn new(adc: impl Peripheral

+ 'd) -> Self { into_ref!(adc); - T::enable_and_reset(); + rcc::enable_and_reset::(); let presc = Prescaler::from_pclk2(T::frequency()); T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); @@ -206,6 +206,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> { reg.set_adon(false); }); - T::disable(); + rcc::disable::(); } } diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index be857f4dd..398c57a92 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -3,7 +3,7 @@ use embassy_hal_internal::into_ref; use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; -use crate::Peripheral; +use crate::{rcc, Peripheral}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -94,7 +94,7 @@ cfg_if! { impl<'d, T: Instance> Adc<'d, T> { pub fn new(adc: impl Peripheral

+ 'd) -> Self { into_ref!(adc); - T::enable_and_reset(); + rcc::enable_and_reset::(); T::regs().cr().modify(|reg| { #[cfg(not(any(adc_g0, adc_u0)))] reg.set_deeppwd(false); diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index f564114c2..50db646fe 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -4,7 +4,7 @@ use pac::adccommon::vals::Presc; use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime}; use crate::time::Hertz; -use crate::{pac, Peripheral}; +use crate::{pac, rcc, Peripheral}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -130,7 +130,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// Create a new ADC driver. pub fn new(adc: impl Peripheral

+ 'd) -> Self { embassy_hal_internal::into_ref!(adc); - T::enable_and_reset(); + rcc::enable_and_reset::(); let prescaler = Prescaler::from_ker_ck(T::frequency()); diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs index 912634b84..f6657f57e 100644 --- a/embassy-stm32/src/can/bxcan/mod.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs @@ -19,7 +19,7 @@ use super::util; use crate::can::enums::{BusError, TryReadError}; use crate::gpio::AFType; use crate::interrupt::typelevel::Interrupt; -use crate::rcc::RccPeripheral; +use crate::rcc::{self, RccPeripheral}; use crate::{interrupt, peripherals, Peripheral}; /// Interrupt handler. @@ -183,7 +183,7 @@ impl<'d, T: Instance> Can<'d, T> { rx.set_as_af(rx.af_num(), AFType::Input); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - T::enable_and_reset(); + rcc::enable_and_reset::(); { T::regs().ier().write(|w| { @@ -720,7 +720,7 @@ impl<'d, T: Instance> Drop for Can<'d, T> { // Cannot call `free()` because it moves the instance. // Manually reset the peripheral. T::regs().mcr().write(|w| w.set_reset(true)); - T::disable(); + rcc::disable::(); } } diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 81ceb06aa..d7b15274c 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -11,7 +11,7 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::can::fd::peripheral::Registers; use crate::gpio::AFType; use crate::interrupt::typelevel::Interrupt; -use crate::rcc::RccPeripheral; +use crate::rcc::{self, RccPeripheral}; use crate::{interrupt, peripherals, Peripheral}; pub(crate) mod fd; @@ -180,7 +180,7 @@ impl<'d, T: Instance> CanConfigurator<'d, T> { rx.set_as_af(rx.af_num(), AFType::Input); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - T::enable_and_reset(); + rcc::enable_and_reset::(); let mut config = crate::can::fd::config::FdCanConfig::default(); config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1); diff --git a/embassy-stm32/src/cordic/mod.rs b/embassy-stm32/src/cordic/mod.rs index 29b11735e..fb342d2e7 100644 --- a/embassy-stm32/src/cordic/mod.rs +++ b/embassy-stm32/src/cordic/mod.rs @@ -4,7 +4,7 @@ use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; use crate::pac::cordic::vals; -use crate::{dma, peripherals}; +use crate::{dma, peripherals, rcc}; mod enums; pub use enums::*; @@ -199,7 +199,7 @@ impl<'d, T: Instance> Cordic<'d, T> { /// If you need a peripheral -> CORDIC -> peripheral mode, /// you may want to set Cordic into [Mode::ZeroOverhead] mode, and add extra arguments with [Self::extra_config] pub fn new(peri: impl Peripheral

+ 'd, config: Config) -> Self { - T::enable_and_reset(); + rcc::enable_and_reset::(); into_ref!(peri); @@ -259,7 +259,7 @@ impl<'d, T: Instance> Cordic<'d, T> { impl<'d, T: Instance> Drop for Cordic<'d, T> { fn drop(&mut self) { - T::disable(); + rcc::disable::(); } } diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs index e8e0270af..f3d13de7c 100644 --- a/embassy-stm32/src/crc/v1.rs +++ b/embassy-stm32/src/crc/v1.rs @@ -2,8 +2,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use crate::pac::CRC as PAC_CRC; use crate::peripherals::CRC; -use crate::rcc::SealedRccPeripheral; -use crate::Peripheral; +use crate::{rcc, Peripheral}; /// CRC driver. pub struct Crc<'d> { @@ -17,7 +16,7 @@ impl<'d> Crc<'d> { // Note: enable and reset come from RccPeripheral. // enable CRC clock in RCC. - CRC::enable_and_reset(); + rcc::enable_and_reset::(); // Peripheral the peripheral let mut instance = Self { _peri: peripheral }; instance.reset(); diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs index ad7c79f12..09d956d7c 100644 --- a/embassy-stm32/src/crc/v2v3.rs +++ b/embassy-stm32/src/crc/v2v3.rs @@ -3,8 +3,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use crate::pac::crc::vals; use crate::pac::CRC as PAC_CRC; use crate::peripherals::CRC; -use crate::rcc::SealedRccPeripheral; -use crate::Peripheral; +use crate::{rcc, Peripheral}; /// CRC driver. pub struct Crc<'d> { @@ -84,7 +83,7 @@ impl<'d> Crc<'d> { pub fn new(peripheral: impl Peripheral

+ 'd, config: Config) -> Self { // Note: enable and reset come from RccPeripheral. // reset to default values and enable CRC clock in RCC. - CRC::enable_and_reset(); + rcc::enable_and_reset::(); into_ref!(peripheral); let mut instance = Self { _peripheral: peripheral, diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index f19c94fda..01ea57d8e 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::dma::{NoDma, Transfer, TransferOptions}; use crate::interrupt::typelevel::Interrupt; -use crate::{interrupt, pac, peripherals, Peripheral}; +use crate::{interrupt, pac, peripherals, rcc, Peripheral}; const DES_BLOCK_SIZE: usize = 8; // 64 bits const AES_BLOCK_SIZE: usize = 16; // 128 bits @@ -1029,7 +1029,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { outdma: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { - T::enable_and_reset(); + rcc::enable_and_reset::(); into_ref!(peri, indma, outdma); let instance = Self { _peripheral: peri, diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 8a748ad72..cdd8d1fd7 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -8,7 +8,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use crate::dma::NoDma; #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] use crate::pac::dac; -use crate::rcc::RccPeripheral; +use crate::rcc::{self, RccPeripheral}; use crate::{peripherals, Peripheral}; mod tsel; @@ -131,7 +131,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { ) -> Self { into_ref!(dma, pin); pin.set_as_analog(); - T::enable_and_reset(); + rcc::enable_and_reset::(); let mut dac = Self { phantom: PhantomData, dma, @@ -157,7 +157,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] pub fn new_internal(_peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd) -> Self { into_ref!(dma); - T::enable_and_reset(); + rcc::enable_and_reset::(); let mut dac = Self { phantom: PhantomData, dma, @@ -356,7 +356,7 @@ impl_dma_methods!(2, DacDma2); impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> { fn drop(&mut self) { - T::disable(); + rcc::disable::(); } } @@ -400,8 +400,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { pin_ch2.set_as_analog(); // Enable twice to increment the DAC refcount for each channel. - T::enable_and_reset(); - T::enable_and_reset(); + rcc::enable_and_reset::(); + rcc::enable_and_reset::(); let mut ch1 = DacCh1 { phantom: PhantomData, @@ -444,8 +444,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { ) -> Self { into_ref!(dma_ch1, dma_ch2); // Enable twice to increment the DAC refcount for each channel. - T::enable_and_reset(); - T::enable_and_reset(); + rcc::enable_and_reset::(); + rcc::enable_and_reset::(); let mut ch1 = DacCh1 { phantom: PhantomData, diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index 646ee2ce2..858ae49ca 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs @@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::dma::Transfer; use crate::gpio::{AFType, Speed}; use crate::interrupt::typelevel::Interrupt; -use crate::{interrupt, Peripheral}; +use crate::{interrupt, rcc, Peripheral}; /// Interrupt handler. pub struct InterruptHandler { @@ -350,7 +350,7 @@ where use_embedded_synchronization: bool, edm: u8, ) -> Self { - T::enable_and_reset(); + rcc::enable_and_reset::(); peri.regs().cr().modify(|r| { r.set_cm(true); // disable continuous mode (snapshot mode) diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs index f1c737fdc..447665669 100644 --- a/embassy-stm32/src/dsihost.rs +++ b/embassy-stm32/src/dsihost.rs @@ -6,7 +6,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; //use crate::gpio::{AnyPin, SealedPin}; use crate::gpio::{AFType, AnyPin, Pull, Speed}; -use crate::rcc::RccPeripheral; +use crate::rcc::{self, RccPeripheral}; use crate::{peripherals, Peripheral}; /// Performs a busy-wait delay for a specified number of microseconds. @@ -77,7 +77,7 @@ impl<'d, T: Instance> DsiHost<'d, T> { pub fn new(_peri: impl Peripheral

+ 'd, te: impl Peripheral

> + 'd) -> Self { into_ref!(te); - T::enable_and_reset(); + rcc::enable_and_reset::(); // Set Tearing Enable pin according to CubeMx example te.set_as_af_pull(te.af_num(), AFType::OutputPushPull, Pull::None); diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs index aced69878..0df64f711 100644 --- a/embassy-stm32/src/fmc.rs +++ b/embassy-stm32/src/fmc.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use embassy_hal_internal::into_ref; use crate::gpio::{AFType, Pull, Speed}; -use crate::Peripheral; +use crate::{rcc, Peripheral}; /// FMC driver pub struct Fmc<'d, T: Instance> { @@ -27,7 +27,7 @@ where /// Enable the FMC peripheral and reset it. pub fn enable(&mut self) { - T::enable_and_reset(); + rcc::enable_and_reset::(); } /// Enable the memory controller on applicable chips. @@ -54,7 +54,7 @@ where const REGISTERS: *const () = T::REGS.as_ptr() as *const _; fn enable(&mut self) { - T::enable_and_reset(); + rcc::enable_and_reset::(); } fn memory_controller_enable(&mut self) { @@ -200,7 +200,7 @@ impl<'d, T: Instance> Fmc<'d, T> { )); } -trait SealedInstance: crate::rcc::SealedRccPeripheral { +trait SealedInstance: crate::rcc::RccPeripheral { const REGS: crate::pac::fmc::Fmc; } diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 808a5bc82..1c5d3fc76 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -813,7 +813,7 @@ foreach_pin!( pub(crate) unsafe fn init(_cs: CriticalSection) { #[cfg(afio)] - ::enable_and_reset_with_cs(_cs); + crate::rcc::enable_and_reset_with_cs::(_cs); crate::_generated::init_gpio(); } diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index 787d5b1c9..4d4a8ec5b 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -17,8 +17,7 @@ use crate::dma::NoDma; use crate::dma::Transfer; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::HASH; -use crate::rcc::SealedRccPeripheral; -use crate::{interrupt, pac, peripherals, Peripheral}; +use crate::{interrupt, pac, peripherals, rcc, Peripheral}; #[cfg(hash_v1)] const NUM_CONTEXT_REGS: usize = 51; @@ -130,7 +129,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { dma: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { - HASH::enable_and_reset(); + rcc::enable_and_reset::(); into_ref!(peripheral, dma); let instance = Self { _peripheral: peripheral, diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 02e45819c..c9d5bff17 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -9,7 +9,7 @@ pub use traits::Instance; use crate::gpio::{AFType, AnyPin}; use crate::time::Hertz; -use crate::Peripheral; +use crate::{rcc, Peripheral}; /// HRTIM burst controller instance. pub struct BurstController { @@ -172,7 +172,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> { fn new_inner(tim: impl Peripheral

+ 'd) -> Self { into_ref!(tim); - T::enable_and_reset(); + rcc::enable_and_reset::(); #[cfg(stm32f334)] if crate::pac::RCC.cfgr3().read().hrtim1sw() == crate::pac::rcc::vals::Timsw::PLL1_P { diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index ef5fd0972..0bf57ef8a 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -18,7 +18,7 @@ use crate::dma::ChannelAndRequest; use crate::gpio::{AFType, Pull}; use crate::interrupt::typelevel::Interrupt; use crate::mode::{Async, Blocking, Mode}; -use crate::rcc::{ClockEnableBit, SealedRccPeripheral}; +use crate::rcc::{self, RccInfo, SealedRccPeripheral}; use crate::time::Hertz; use crate::{interrupt, peripherals}; @@ -128,7 +128,7 @@ impl<'d, M: Mode> I2c<'d, M> { ) -> Self { into_ref!(scl, sda); - T::enable_and_reset(); + rcc::enable_and_reset::(); scl.set_as_af_pull( scl.af_num(), @@ -224,7 +224,7 @@ impl State { struct Info { regs: crate::pac::i2c::I2c, - pub(crate) enable_bit: ClockEnableBit, + rcc: RccInfo, } peri_trait!( @@ -265,7 +265,7 @@ foreach_peripheral!( fn info() -> &'static Info { static INFO: Info = Info{ regs: crate::pac::$inst, - enable_bit: crate::peripherals::$inst::ENABLE_BIT, + rcc: crate::peripherals::$inst::RCC_INFO, }; &INFO } diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 0269e53aa..0e2bd2e40 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -702,7 +702,7 @@ impl<'d> I2c<'d, Async> { impl<'d, M: PeriMode> Drop for I2c<'d, M> { fn drop(&mut self) { - self.info.enable_bit.disable() + self.info.rcc.disable() } } diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index aa6daf786..193f29733 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -673,7 +673,7 @@ impl<'d> I2c<'d, Async> { impl<'d, M: Mode> Drop for I2c<'d, M> { fn drop(&mut self) { - self.info.enable_bit.disable(); + self.info.rcc.disable(); } } diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 4d535cce2..6c8347311 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs @@ -6,10 +6,9 @@ use core::task::Poll; use embassy_sync::waitqueue::AtomicWaker; -use crate::interrupt; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::IPCC; -use crate::rcc::SealedRccPeripheral; +use crate::{interrupt, rcc}; /// Interrupt handler. pub struct ReceiveInterruptHandler {} @@ -102,7 +101,7 @@ pub struct Ipcc; impl Ipcc { /// Enable IPCC. pub fn enable(_config: Config) { - IPCC::enable_and_reset(); + rcc::enable_and_reset::(); IPCC::set_cpu2(true); // set RF wake-up clock = LSE diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 81ee60c1c..fe9c0dcb5 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -194,7 +194,6 @@ pub(crate) use stm32_metapac as pac; use crate::interrupt::Priority; #[cfg(feature = "rt")] pub use crate::pac::NVIC_PRIO_BITS; -use crate::rcc::SealedRccPeripheral; /// `embassy-stm32` global configuration. #[non_exhaustive] @@ -310,11 +309,11 @@ pub fn init(config: Config) -> Peripherals { }); #[cfg(not(any(stm32f1, stm32wb, stm32wl)))] - peripherals::SYSCFG::enable_and_reset_with_cs(cs); + rcc::enable_and_reset_with_cs::(cs); #[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))] - peripherals::PWR::enable_and_reset_with_cs(cs); + rcc::enable_and_reset_with_cs::(cs); #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs)))] - peripherals::FLASH::enable_and_reset_with_cs(cs); + rcc::enable_and_reset_with_cs::(cs); // Enable the VDDIO2 power supply on chips that have it. // Note that this requires the PWR peripheral to be enabled first. diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs index 0cc8a0557..ac5decb03 100644 --- a/embassy-stm32/src/ltdc.rs +++ b/embassy-stm32/src/ltdc.rs @@ -1,7 +1,7 @@ //! LTDC use core::marker::PhantomData; -use crate::rcc::RccPeripheral; +use crate::rcc::{self, RccPeripheral}; use crate::{peripherals, Peripheral}; /// LTDC driver. @@ -60,7 +60,7 @@ impl<'d, T: Instance> Ltdc<'d, T> { .modify(|w| w.set_pllsaidivr(stm32_metapac::rcc::vals::Pllsaidivr::DIV2)); }); - T::enable_and_reset(); + rcc::enable_and_reset::(); //new_pin!(clk, AFType::OutputPushPull, Speed::VeryHigh, Pull::None); diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index 536da4ca0..882781cce 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -16,7 +16,7 @@ use crate::dma::{word, ChannelAndRequest}; use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::octospi::{vals, Octospi as Regs}; -use crate::rcc::RccPeripheral; +use crate::rcc::{self, RccPeripheral}; use crate::{peripherals, Peripheral}; /// OPSI driver config. @@ -198,7 +198,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { into_ref!(peri); // System configuration - T::enable_and_reset(); + rcc::enable_and_reset::(); while T::REGS.sr().read().busy() {} // Device configuration @@ -1013,7 +1013,7 @@ impl<'d, T: Instance, M: PeriMode> Drop for Ospi<'d, T, M> { self.nss.as_ref().map(|x| x.set_as_disconnected()); self.dqs.as_ref().map(|x| x.set_as_disconnected()); - T::disable(); + rcc::disable::(); } } diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index a82e93b5b..06c8f4812 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -13,7 +13,7 @@ use crate::dma::ChannelAndRequest; use crate::gpio::{AFType, AnyPin, Pull, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::quadspi::Quadspi as Regs; -use crate::rcc::RccPeripheral; +use crate::rcc::{self, RccPeripheral}; use crate::{peripherals, Peripheral}; /// QSPI transfer configuration. @@ -102,7 +102,7 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> { ) -> Self { into_ref!(peri); - T::enable_and_reset(); + rcc::enable_and_reset::(); while T::REGS.sr().read().busy() {} diff --git a/embassy-stm32/src/rcc/hsi48.rs b/embassy-stm32/src/rcc/hsi48.rs index da81abc34..efabd059f 100644 --- a/embassy-stm32/src/rcc/hsi48.rs +++ b/embassy-stm32/src/rcc/hsi48.rs @@ -2,7 +2,7 @@ use crate::pac::crs::vals::Syncsrc; use crate::pac::{CRS, RCC}; -use crate::rcc::SealedRccPeripheral; +use crate::rcc::{self, SealedRccPeripheral}; use crate::time::Hertz; /// HSI48 speed @@ -44,7 +44,7 @@ pub(crate) fn init_hsi48(config: Hsi48Config) -> Hertz { while r.read().hsi48rdy() == false {} if config.sync_from_usb { - crate::peripherals::CRS::enable_and_reset(); + rcc::enable_and_reset::(); CRS.cfgr().modify(|w| { w.set_syncsrc(Syncsrc::USB); diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 28816256c..0bf344c40 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -67,23 +67,185 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks { } pub(crate) trait SealedRccPeripheral { - const ENABLE_BIT: ClockEnableBit; - fn frequency() -> Hertz; - fn enable_and_reset_with_cs(cs: CriticalSection); - fn disable_with_cs(cs: CriticalSection); - - fn enable_and_reset() { - critical_section::with(|cs| Self::enable_and_reset_with_cs(cs)) - } - fn disable() { - critical_section::with(|cs| Self::disable_with_cs(cs)) - } + const RCC_INFO: RccInfo; } #[allow(private_bounds)] pub trait RccPeripheral: SealedRccPeripheral + 'static {} +/// Runtime information necessary to reset, enable and disable a peripheral. +pub(crate) struct RccInfo { + /// Offset in 32-bit words of the xxxRSTR register into the RCC register block, or 0xff if the + /// peripheral has no reset bit (we don't use an `Option` to save one byte of storage). + reset_offset_or_0xff: u8, + /// Position of the xxxRST bit within the xxxRSTR register (0..=31). + reset_bit: u8, + /// Offset in 32-bit words of the xxxENR register into the RCC register block. + enable_offset: u8, + /// Position of the xxxEN bit within the xxxENR register (0..=31). + enable_bit: u8, + /// If this peripheral shares the same xxxRSTR bit and xxxEN bit with other peripherals, we + /// maintain a refcount in `crate::_generated::REFCOUNTS` at this index. If the bit is not + /// shared, this is 0xff (we don't use an `Option` to save one byte of storage). + refcount_idx_or_0xff: u8, + /// Stop mode of the peripheral, used to maintain `REFCOUNT_STOP1` and `REFCOUNT_STOP2`. + #[cfg(feature = "low-power")] + stop_mode: StopMode, +} + +#[cfg(feature = "low-power")] +#[allow(dead_code)] +pub(crate) enum StopMode { + Standby, + Stop2, + Stop1, +} + +impl RccInfo { + /// Safety: + /// - `reset_offset_and_bit`, if set, must correspond to valid xxxRST bit + /// - `enable_offset_and_bit` must correspond to valid xxxEN bit + /// - `refcount_idx`, if set, must correspond to valid refcount in `_generated::REFCOUNTS` + /// - `stop_mode` must be valid + pub(crate) const unsafe fn new( + reset_offset_and_bit: Option<(u8, u8)>, + enable_offset_and_bit: (u8, u8), + refcount_idx: Option, + #[cfg(feature = "low-power")] stop_mode: StopMode, + ) -> Self { + let (reset_offset_or_0xff, reset_bit) = match reset_offset_and_bit { + Some((offset, bit)) => (offset, bit), + None => (0xff, 0xff), + }; + let (enable_offset, enable_bit) = enable_offset_and_bit; + let refcount_idx_or_0xff = match refcount_idx { + Some(idx) => idx, + None => 0xff, + }; + Self { + reset_offset_or_0xff, + reset_bit, + enable_offset, + enable_bit, + refcount_idx_or_0xff, + #[cfg(feature = "low-power")] + stop_mode, + } + } + + // TODO: should this be `unsafe`? + pub(crate) fn enable_and_reset_with_cs(&self, _cs: CriticalSection) { + if self.refcount_idx_or_0xff != 0xff { + let refcount_idx = self.refcount_idx_or_0xff as usize; + unsafe { + crate::_generated::REFCOUNTS[refcount_idx] += 1; + } + if unsafe { crate::_generated::REFCOUNTS[refcount_idx] } > 1 { + return; + } + } + + #[cfg(feature = "low-power")] + match self.stop_mode { + StopMode::Standby => {} + StopMode::Stop2 => unsafe { + REFCOUNT_STOP2 += 1; + }, + StopMode::Stop1 => unsafe { + REFCOUNT_STOP1 += 1; + }, + } + + // set the xxxRST bit + let reset_ptr = self.reset_ptr(); + if let Some(reset_ptr) = reset_ptr { + unsafe { + let val = reset_ptr.read_volatile(); + reset_ptr.write_volatile(val | 1u32 << self.reset_bit); + } + } + + // set the xxxEN bit + let enable_ptr = self.enable_ptr(); + unsafe { + let val = enable_ptr.read_volatile(); + enable_ptr.write_volatile(val | 1u32 << self.enable_bit); + } + + // we must wait two peripheral clock cycles before the clock is active + // this seems to work, but might be incorrect + // see http://efton.sk/STM32/gotcha/g183.html + + // dummy read (like in the ST HALs) + let _ = unsafe { enable_ptr.read_volatile() }; + + // DSB for good measure + cortex_m::asm::dsb(); + + // clear the xxxRST bit + if let Some(reset_ptr) = reset_ptr { + unsafe { + let val = reset_ptr.read_volatile(); + reset_ptr.write_volatile(val & !(1u32 << self.reset_bit)); + } + } + } + + // TODO: should this be `unsafe`? + pub(crate) fn disable_with_cs(&self, _cs: CriticalSection) { + if self.refcount_idx_or_0xff != 0xff { + let refcount_idx = self.refcount_idx_or_0xff as usize; + unsafe { + crate::_generated::REFCOUNTS[refcount_idx] -= 1; + } + if unsafe { crate::_generated::REFCOUNTS[refcount_idx] } > 0 { + return; + } + } + + #[cfg(feature = "low-power")] + match self.stop_mode { + StopMode::Standby => {} + StopMode::Stop2 => unsafe { + REFCOUNT_STOP2 -= 1; + }, + StopMode::Stop1 => unsafe { + REFCOUNT_STOP1 -= 1; + }, + } + + // clear the xxxEN bit + let enable_ptr = self.enable_ptr(); + unsafe { + let val = enable_ptr.read_volatile(); + enable_ptr.write_volatile(val & !(1u32 << self.enable_bit)); + } + } + + // TODO: should this be `unsafe`? + pub(crate) fn enable_and_reset(&self) { + critical_section::with(|cs| self.enable_and_reset_with_cs(cs)) + } + + // TODO: should this be `unsafe`? + pub(crate) fn disable(&self) { + critical_section::with(|cs| self.disable_with_cs(cs)) + } + + fn reset_ptr(&self) -> Option<*mut u32> { + if self.reset_offset_or_0xff != 0xff { + Some(unsafe { (RCC.as_ptr() as *mut u32).add(self.reset_offset_or_0xff as _) }) + } else { + None + } + } + + fn enable_ptr(&self) -> *mut u32 { + unsafe { (RCC.as_ptr() as *mut u32).add(self.enable_offset as _) } + } +} + #[allow(unused)] mod util { use crate::time::Hertz; @@ -128,8 +290,9 @@ pub fn frequency() -> Hertz { /// # Safety /// /// Peripheral must not be in use. -pub unsafe fn enable_and_reset() { - T::enable_and_reset(); +// TODO: should this be `unsafe`? +pub fn enable_and_reset_with_cs(cs: CriticalSection) { + T::RCC_INFO.enable_and_reset_with_cs(cs); } /// Disables peripheral `T`. @@ -137,52 +300,27 @@ pub unsafe fn enable_and_reset() { /// # Safety /// /// Peripheral must not be in use. -pub unsafe fn disable() { - T::disable(); +// TODO: should this be `unsafe`? +pub fn disable_with_cs(cs: CriticalSection) { + T::RCC_INFO.disable_with_cs(cs); } -/// 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, +/// Enables and resets peripheral `T`. +/// +/// # Safety +/// +/// Peripheral must not be in use. +// TODO: should this be `unsafe`? +pub fn enable_and_reset() { + T::RCC_INFO.enable_and_reset(); } -impl ClockEnableBit { - /// Safety: offset+bit must correspond to a valid xxxEN bit. - pub(crate) const 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)) - } +/// Disables peripheral `T`. +/// +/// # Safety +/// +/// Peripheral must not be in use. +// TODO: should this be `unsafe`? +pub fn disable() { + T::RCC_INFO.disable(); } diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 7a228e4a4..94491c32f 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -10,7 +10,7 @@ use embassy_sync::waitqueue::AtomicWaker; use rand_core::{CryptoRng, RngCore}; use crate::interrupt::typelevel::Interrupt; -use crate::{interrupt, pac, peripherals, Peripheral}; +use crate::{interrupt, pac, peripherals, rcc, Peripheral}; static RNG_WAKER: AtomicWaker = AtomicWaker::new(); @@ -52,7 +52,7 @@ impl<'d, T: Instance> Rng<'d, T> { inner: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { - T::enable_and_reset(); + rcc::enable_and_reset::(); into_ref!(inner); let mut random = Self { _inner: inner }; random.reset(); diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index b12a0db66..f3cd16b4f 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -205,7 +205,7 @@ impl Rtc { /// Create a new RTC instance. pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] - ::enable_and_reset(); + crate::rcc::enable_and_reset::(); let mut this = Self { #[cfg(feature = "low-power")] diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 54dd81524..3faecdc33 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -11,7 +11,7 @@ pub use crate::dma::word; use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; use crate::gpio::{AFType, AnyPin, SealedPin as _}; use crate::pac::sai::{vals, Sai as Regs}; -use crate::rcc::RccPeripheral; +use crate::rcc::{self, RccPeripheral}; use crate::{peripherals, Peripheral}; /// SAI error @@ -722,7 +722,7 @@ pub struct SubBlock<'d, T, S: SubBlockInstance> { /// You can then create a [`Sai`] driver for each each half. pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral

+ 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) { into_ref!(peri); - T::enable_and_reset(); + rcc::enable_and_reset::(); ( SubBlock { @@ -978,7 +978,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { /// Reset SAI operation. pub fn reset() { - T::enable_and_reset(); + rcc::enable_and_reset::(); } /// Flush. diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index f79a11606..9c14837e1 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -16,7 +16,7 @@ use crate::dma::NoDma; use crate::gpio::{AFType, AnyPin, Pull, SealedPin, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::pac::sdmmc::Sdmmc as RegBlock; -use crate::rcc::RccPeripheral; +use crate::rcc::{self, RccPeripheral}; use crate::time::Hertz; use crate::{interrupt, peripherals, Peripheral}; @@ -468,7 +468,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { ) -> Self { into_ref!(sdmmc, dma); - T::enable_and_reset(); + rcc::enable_and_reset::(); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 5fc8691ac..33be7a701 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -13,7 +13,7 @@ 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::{ClockEnableBit, SealedRccPeripheral}; +use crate::rcc::{self, RccInfo, SealedRccPeripheral}; use crate::time::Hertz; use crate::Peripheral; @@ -129,7 +129,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { let lsbfirst = config.raw_byte_order(); - T::enable_and_reset(); + rcc::enable_and_reset::(); #[cfg(any(spi_v1, spi_f1))] { @@ -738,7 +738,7 @@ impl<'d, M: PeriMode> Drop for Spi<'d, M> { self.mosi.as_ref().map(|x| x.set_as_disconnected()); self.miso.as_ref().map(|x| x.set_as_disconnected()); - self.info.enable_bit.disable(); + self.info.rcc.disable(); } } @@ -1118,7 +1118,7 @@ mod word_impl { pub(crate) struct Info { pub(crate) regs: Regs, - pub(crate) enable_bit: ClockEnableBit, + pub(crate) rcc: RccInfo, } struct State {} @@ -1145,7 +1145,7 @@ foreach_peripheral!( (spi, $inst:ident) => { peri_trait_impl!($inst, Info { regs: crate::pac::$inst, - enable_bit: crate::peripherals::$inst::ENABLE_BIT, + rcc: crate::peripherals::$inst::RCC_INFO, }); }; ); diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index e592fbf7d..f8041bf1e 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -12,7 +12,7 @@ use stm32_metapac::timer::{regs, TimGp16}; use crate::interrupt::typelevel::Interrupt; use crate::pac::timer::vals; -use crate::rcc::SealedRccPeripheral; +use crate::rcc::{self, SealedRccPeripheral}; #[cfg(feature = "low-power")] use crate::rtc::Rtc; use crate::timer::{CoreInstance, GeneralInstance1Channel}; @@ -276,7 +276,7 @@ impl RtcDriver { fn init(&'static self, cs: critical_section::CriticalSection) { let r = regs_gp16(); - ::enable_and_reset_with_cs(cs); + rcc::enable_and_reset_with_cs::(cs); let timer_freq = T::frequency(); diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index 7f533b75c..9932c04cd 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -10,6 +10,7 @@ use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; use super::*; use crate::pac::timer::vals; +use crate::rcc; use crate::time::Hertz; /// Input capture mode. @@ -181,7 +182,7 @@ pub struct Timer<'d, T: CoreInstance> { impl<'d, T: CoreInstance> Drop for Timer<'d, T> { fn drop(&mut self) { - T::disable() + rcc::disable::(); } } @@ -190,7 +191,7 @@ impl<'d, T: CoreInstance> Timer<'d, T> { pub fn new(tim: impl Peripheral

+ 'd) -> Self { into_ref!(tim); - T::enable_and_reset(); + rcc::enable_and_reset::(); Self { tim } } diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs index bf583f04c..045d6317c 100644 --- a/embassy-stm32/src/tsc/mod.rs +++ b/embassy-stm32/src/tsc/mod.rs @@ -72,7 +72,7 @@ pub use enums::*; use crate::gpio::{AFType, AnyPin}; use crate::pac::tsc::Tsc as Regs; -use crate::rcc::RccPeripheral; +use crate::rcc::{self, RccPeripheral}; use crate::{peripherals, Peripheral}; #[cfg(tsc_v1)] @@ -649,7 +649,7 @@ impl<'d, T: Instance> Tsc<'d, T> { ) -> Self { into_ref!(peri); - T::enable_and_reset(); + rcc::enable_and_reset::(); T::REGS.cr().modify(|w| { w.set_tsce(true); @@ -880,7 +880,7 @@ impl<'d, T: Instance> Tsc<'d, T> { impl<'d, T: Instance> Drop for Tsc<'d, T> { fn drop(&mut self) { - T::disable(); + rcc::disable::(); } } diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index d6d0682b9..89e2f5d49 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -28,7 +28,7 @@ use crate::interrupt; use crate::interrupt::typelevel::Interrupt; use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; -use crate::rcc::RccPeripheral; +use crate::rcc::{self, RccPeripheral}; pub(crate) fn init( _cs: critical_section::CriticalSection, @@ -103,7 +103,7 @@ impl<'d, T: Instance> Ucpd<'d, T> { cc1.set_as_analog(); cc2.set_as_analog(); - T::enable_and_reset(); + rcc::enable_and_reset::(); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; @@ -212,7 +212,7 @@ impl<'d, T: Instance> Drop for CcPhy<'d, T> { drop_not_ready.store(true, Ordering::Relaxed); } else { r.cfgr1().write(|w| w.set_ucpden(false)); - T::disable(); + rcc::disable::(); T::Interrupt::disable(); } } @@ -325,7 +325,7 @@ impl<'d, T: Instance> Drop for PdPhy<'d, T> { drop_not_ready.store(true, Ordering::Relaxed); } else { T::REGS.cfgr1().write(|w| w.set_ucpden(false)); - T::disable(); + rcc::disable::(); T::Interrupt::disable(); } } diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 492ad334b..eacf95002 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -18,6 +18,7 @@ use super::{ use crate::gpio::AFType; use crate::interrupt::typelevel::Interrupt as _; use crate::interrupt::{self, InterruptExt}; +use crate::rcc; use crate::time::Hertz; /// Interrupt handler. @@ -206,7 +207,7 @@ impl<'d> BufferedUart<'d> { rx_buffer: &'d mut [u8], config: Config, ) -> Result { - T::enable_and_reset(); + rcc::enable_and_reset::(); Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) } @@ -225,7 +226,7 @@ impl<'d> BufferedUart<'d> { ) -> Result { into_ref!(cts, rts); - T::enable_and_reset(); + rcc::enable_and_reset::(); rts.set_as_af(rts.af_num(), AFType::OutputPushPull); cts.set_as_af(cts.af_num(), AFType::Input); @@ -251,7 +252,7 @@ impl<'d> BufferedUart<'d> { ) -> Result { into_ref!(de); - T::enable_and_reset(); + rcc::enable_and_reset::(); de.set_as_af(de.af_num(), AFType::OutputPushPull); T::info().regs.cr3().write(|w| { @@ -545,7 +546,7 @@ fn drop_tx_rx(info: &Info, state: &State) { refcount == 1 }); if is_last_drop { - info.enable_bit.disable(); + info.rcc.disable(); } } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index b24335f3a..2a39c6301 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -28,7 +28,7 @@ use crate::pac::usart::Lpuart as Regs; #[cfg(any(usart_v1, usart_v2))] use crate::pac::usart::Usart as Regs; use crate::pac::usart::{regs, vals}; -use crate::rcc::{ClockEnableBit, SealedRccPeripheral}; +use crate::rcc::{self, RccInfo, SealedRccPeripheral}; use crate::time::Hertz; use crate::Peripheral; @@ -429,7 +429,7 @@ impl<'d, M: Mode> UartTx<'d, M> { tx_dma: Option>, config: Config, ) -> Result { - T::enable_and_reset(); + rcc::enable_and_reset::(); let info = T::info(); let state = T::state(); @@ -775,7 +775,7 @@ impl<'d, M: Mode> UartRx<'d, M> { rx_dma: Option>, config: Config, ) -> Result { - T::enable_and_reset(); + rcc::enable_and_reset::(); let info = T::info(); let state = T::state(); @@ -916,7 +916,7 @@ fn drop_tx_rx(info: &Info, state: &State) { refcount == 1 }); if is_last_drop { - info.enable_bit.disable(); + info.rcc.disable(); } } @@ -1228,7 +1228,7 @@ impl<'d, M: Mode> Uart<'d, M> { rx_dma: Option>, config: Config, ) -> Result { - T::enable_and_reset(); + rcc::enable_and_reset::(); let info = T::info(); let state = T::state(); @@ -1718,7 +1718,7 @@ impl State { struct Info { regs: Regs, - enable_bit: ClockEnableBit, + rcc: RccInfo, interrupt: Interrupt, kind: Kind, } @@ -1754,7 +1754,7 @@ macro_rules! impl_usart { fn info() -> &'static Info { static INFO: Info = Info { regs: unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) }, - enable_bit: crate::peripherals::$inst::ENABLE_BIT, + rcc: crate::peripherals::$inst::RCC_INFO, interrupt: crate::interrupt::typelevel::$irq::IRQ, kind: $kind, }; diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index 349438ec5..ce9fe0a9b 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs @@ -6,7 +6,7 @@ mod _version; pub use _version::*; use crate::interrupt::typelevel::Interrupt; -use crate::rcc::SealedRccPeripheral; +use crate::rcc; /// clock, power initialization stuff that's common for USB and OTG. fn common_init() { @@ -65,5 +65,5 @@ fn common_init() { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - ::enable_and_reset(); + rcc::enable_and_reset::(); } diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 3debd5079..e5131250a 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -13,7 +13,7 @@ use embassy_usb_synopsys_otg::{ use crate::gpio::AFType; use crate::interrupt; use crate::interrupt::typelevel::Interrupt; -use crate::rcc::{RccPeripheral, SealedRccPeripheral}; +use crate::rcc::{self, RccPeripheral}; const MAX_EP_COUNT: usize = 9; @@ -246,7 +246,7 @@ impl<'d, T: Instance> Bus<'d, T> { fn disable(&mut self) { T::Interrupt::disable(); - ::disable(); + rcc::disable::(); self.inited = false; #[cfg(stm32l4)]