diff --git a/embassy-stm32/src/adc/g0.rs b/embassy-stm32/src/adc/g0.rs deleted file mode 100644 index 8b1378917..000000000 --- a/embassy-stm32/src/adc/g0.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 9955502a6..f292d0208 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -1,7 +1,7 @@ #![macro_use] #[cfg_attr(adc_v3, path = "v3.rs")] -#[cfg_attr(adc_g0, path = "g0.rs")] +#[cfg_attr(adc_g0, path = "v3.rs")] mod _version; #[allow(unused)] @@ -72,6 +72,9 @@ macro_rules! impl_pin { } crate::pac::peripheral_pins!( + ($inst:ident, adc, ADC, $pin:ident, IN0) => { + impl_pin!($inst, $pin, 0); + }; ($inst:ident, adc, ADC, $pin:ident, IN1) => { impl_pin!($inst, $pin, 1); }; diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 2781fc4dc..ddf06deae 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -6,6 +6,17 @@ use embedded_hal::blocking::delay::DelayUs; pub const VDDA_CALIB_MV: u32 = 3000; +/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock +/// configuration. +unsafe fn enable() { + #[cfg(rcc_h7)] + crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); + #[cfg(rcc_g0)] + crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true)); + #[cfg(rcc_l4)] + crate::pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); +} + pub enum Resolution { TwelveBit, TenBit, @@ -43,7 +54,11 @@ pub struct Vref; impl AdcPin for Vref {} impl super::sealed::AdcPin for Vref { fn channel(&self) -> u8 { - 0 + #[cfg(not(rcc_g0))] + let val = 0; + #[cfg(rcc_g0)] + let val = 13; + val } } @@ -51,7 +66,11 @@ pub struct Temperature; impl AdcPin for Temperature {} impl super::sealed::AdcPin for Temperature { fn channel(&self) -> u8 { - 17 + #[cfg(not(rcc_g0))] + let val = 17; + #[cfg(rcc_g0)] + let val = 12; + val } } @@ -59,61 +78,124 @@ pub struct Vbat; impl AdcPin for Vbat {} impl super::sealed::AdcPin for Vbat { fn channel(&self) -> u8 { - 18 + #[cfg(not(rcc_g0))] + let val = 18; + #[cfg(rcc_g0)] + let val = 14; + val } } -/// ADC sample time -/// -/// The default setting is 2.5 ADC clock cycles. -#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] -pub enum SampleTime { - /// 2.5 ADC clock cycles - Cycles2_5 = 0b000, +#[cfg(not(adc_g0))] +mod sample_time { + /// ADC sample time + /// + /// The default setting is 2.5 ADC clock cycles. + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] + pub enum SampleTime { + /// 2.5 ADC clock cycles + Cycles2_5 = 0b000, - /// 6.5 ADC clock cycles - Cycles6_5 = 0b001, + /// 6.5 ADC clock cycles + Cycles6_5 = 0b001, - /// 12.5 ADC clock cycles - Cycles12_5 = 0b010, + /// 12.5 ADC clock cycles + Cycles12_5 = 0b010, - /// 24.5 ADC clock cycles - Cycles24_5 = 0b011, + /// 24.5 ADC clock cycles + Cycles24_5 = 0b011, - /// 47.5 ADC clock cycles - Cycles47_5 = 0b100, + /// 47.5 ADC clock cycles + Cycles47_5 = 0b100, - /// 92.5 ADC clock cycles - Cycles92_5 = 0b101, + /// 92.5 ADC clock cycles + Cycles92_5 = 0b101, - /// 247.5 ADC clock cycles - Cycles247_5 = 0b110, + /// 247.5 ADC clock cycles + Cycles247_5 = 0b110, - /// 640.5 ADC clock cycles - Cycles640_5 = 0b111, -} + /// 640.5 ADC clock cycles + Cycles640_5 = 0b111, + } -impl SampleTime { - fn sample_time(&self) -> crate::pac::adc::vals::SampleTime { - match self { - SampleTime::Cycles2_5 => crate::pac::adc::vals::SampleTime::CYCLES2_5, - SampleTime::Cycles6_5 => crate::pac::adc::vals::SampleTime::CYCLES6_5, - SampleTime::Cycles12_5 => crate::pac::adc::vals::SampleTime::CYCLES12_5, - SampleTime::Cycles24_5 => crate::pac::adc::vals::SampleTime::CYCLES24_5, - SampleTime::Cycles47_5 => crate::pac::adc::vals::SampleTime::CYCLES47_5, - SampleTime::Cycles92_5 => crate::pac::adc::vals::SampleTime::CYCLES92_5, - SampleTime::Cycles247_5 => crate::pac::adc::vals::SampleTime::CYCLES247_5, - SampleTime::Cycles640_5 => crate::pac::adc::vals::SampleTime::CYCLES640_5, + impl SampleTime { + pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::SampleTime { + match self { + SampleTime::Cycles2_5 => crate::pac::adc::vals::SampleTime::CYCLES2_5, + SampleTime::Cycles6_5 => crate::pac::adc::vals::SampleTime::CYCLES6_5, + SampleTime::Cycles12_5 => crate::pac::adc::vals::SampleTime::CYCLES12_5, + SampleTime::Cycles24_5 => crate::pac::adc::vals::SampleTime::CYCLES24_5, + SampleTime::Cycles47_5 => crate::pac::adc::vals::SampleTime::CYCLES47_5, + SampleTime::Cycles92_5 => crate::pac::adc::vals::SampleTime::CYCLES92_5, + SampleTime::Cycles247_5 => crate::pac::adc::vals::SampleTime::CYCLES247_5, + SampleTime::Cycles640_5 => crate::pac::adc::vals::SampleTime::CYCLES640_5, + } + } + } + + impl Default for SampleTime { + fn default() -> Self { + Self::Cycles2_5 } } } -impl Default for SampleTime { - fn default() -> Self { - Self::Cycles2_5 +#[cfg(adc_g0)] +mod sample_time { + /// ADC sample time + /// + /// The default setting is 1.5 ADC clock cycles. + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] + pub enum SampleTime { + /// 1.5 ADC clock cycles + Cycles1_5 = 0b000, + + /// 3.5 ADC clock cycles + Cycles3_5 = 0b001, + + /// 7.5 ADC clock cycles + Cycles7_5 = 0b010, + + /// 12.5 ADC clock cycles + Cycles12_5 = 0b011, + + /// 19.5 ADC clock cycles + Cycles19_5 = 0b100, + + /// 39.5 ADC clock cycles + Cycles39_5 = 0b101, + + /// 79.5 ADC clock cycles + Cycles79_5 = 0b110, + + /// 160.5 ADC clock cycles + Cycles160_5 = 0b111, + } + + impl SampleTime { + pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::SampleTime { + match self { + SampleTime::Cycles1_5 => crate::pac::adc::vals::SampleTime::CYCLES1_5, + SampleTime::Cycles3_5 => crate::pac::adc::vals::SampleTime::CYCLES3_5, + SampleTime::Cycles7_5 => crate::pac::adc::vals::SampleTime::CYCLES7_5, + SampleTime::Cycles12_5 => crate::pac::adc::vals::SampleTime::CYCLES12_5, + SampleTime::Cycles19_5 => crate::pac::adc::vals::SampleTime::CYCLES19_5, + SampleTime::Cycles39_5 => crate::pac::adc::vals::SampleTime::CYCLES39_5, + SampleTime::Cycles79_5 => crate::pac::adc::vals::SampleTime::CYCLES79_5, + SampleTime::Cycles160_5 => crate::pac::adc::vals::SampleTime::CYCLES160_5, + } + } + } + + impl Default for SampleTime { + fn default() -> Self { + Self::Cycles1_5 + } } } +pub use sample_time::SampleTime; + pub struct Adc<'d, T: Instance> { sample_time: SampleTime, calibrated_vdda: u32, @@ -125,15 +207,26 @@ impl<'d, T: Instance> Adc<'d, T> { pub fn new(_peri: impl Unborrow + 'd, delay: &mut impl DelayUs) -> Self { unborrow!(_peri); unsafe { + enable(); T::regs().cr().modify(|reg| { + #[cfg(not(adc_g0))] reg.set_deeppwd(false); reg.set_advregen(true); }); + + #[cfg(adc_g0)] + T::regs().cfgr1().modify(|reg| { + reg.set_chselrmod(true); + }); } delay.delay_us(20); unsafe { + T::regs().cr().modify(|reg| { + reg.set_adcal(true); + }); + while T::regs().cr().read().adcal() { // spin } @@ -229,6 +322,27 @@ impl<'d, T: Instance> Adc<'d, T> { } */ + /// Perform a single conversion. + fn convert(&mut self) -> u16 { + unsafe { + T::regs().isr().modify(|reg| { + reg.set_eos(true); + reg.set_eoc(true); + }); + + // Start conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + + while !T::regs().isr().read().eos() { + // spin + } + + T::regs().dr().read().0 as u16 + } + } + pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { unsafe { // Make sure bits are off @@ -249,48 +363,36 @@ impl<'d, T: Instance> Adc<'d, T> { } // Configure ADC + #[cfg(not(rcc_g0))] T::regs() .cfgr() .modify(|reg| reg.set_res(self.resolution.res())); + #[cfg(rcc_g0)] + T::regs() + .cfgr1() + .modify(|reg| reg.set_res(self.resolution.res())); // Configure channel Self::set_channel_sample_time(pin.channel(), self.sample_time); // Select channel + #[cfg(not(rcc_g0))] T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); + #[cfg(rcc_g0)] + T::regs() + .chselr() + .write(|reg| reg.set_chsel(pin.channel() as u32)); - // Start conversion - T::regs().isr().modify(|reg| { - reg.set_eos(true); - reg.set_eoc(true); - }); - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); + // Some models are affected by an erratum: + // If we perform conversions slower than 1 kHz, the first read ADC value can be + // corrupted, so we discard it and measure again. + // + // STM32L471xx: Section 2.7.3 + // STM32G4: Section 2.7.3 + #[cfg(any(rcc_l4, rcc_g4))] + let _ = self.convert(); - while !T::regs().isr().read().eos() { - // spin - } - - // Read ADC value first time and discard it, as per errata sheet. - // The errata states that if we do conversions slower than 1 kHz, the - // first read ADC value can be corrupted, so we discard it and measure again. - - let _ = T::regs().dr().read(); - - T::regs().isr().modify(|reg| { - reg.set_eos(true); - reg.set_eoc(true); - }); - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); - - while !T::regs().isr().read().eos() { - // spin - } - - let val = T::regs().dr().read().0 as u16; + let val = self.convert(); T::regs().cr().modify(|reg| reg.set_addis(true)); @@ -298,6 +400,14 @@ impl<'d, T: Instance> Adc<'d, T> { } } + #[cfg(rcc_g0)] + unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { + T::regs() + .smpr() + .modify(|reg| reg.set_smp1(sample_time.sample_time())); + } + + #[cfg(not(rcc_g0))] unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { if ch <= 9 { T::regs() diff --git a/embassy-stm32/src/dac/v2.rs b/embassy-stm32/src/dac/v2.rs index f46145b8d..55a881d89 100644 --- a/embassy-stm32/src/dac/v2.rs +++ b/embassy-stm32/src/dac/v2.rs @@ -5,6 +5,17 @@ use core::marker::PhantomData; use embassy::util::Unborrow; use embassy_hal_common::unborrow; +/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent DAC clock +/// configuration. +unsafe fn enable() { + #[cfg(rcc_h7)] + crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); + #[cfg(rcc_g0)] + crate::pac::RCC.apbenr1().modify(|w| w.set_dac1en(true)); + #[cfg(rcc_l4)] + crate::pac::RCC.apb1enr1().modify(|w| w.set_dac1en(true)); +} + #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { @@ -91,6 +102,10 @@ impl<'d, T: Instance> Dac<'d, T> { ) -> Self { unborrow!(ch1, ch2); + unsafe { + enable(); + } + let ch1 = ch1.degrade_optional(); if ch1.is_some() { unsafe { diff --git a/embassy-stm32/src/rcc/g0/mod.rs b/embassy-stm32/src/rcc/g0/mod.rs index 863db709d..c0b5b14e3 100644 --- a/embassy-stm32/src/rcc/g0/mod.rs +++ b/embassy-stm32/src/rcc/g0/mod.rs @@ -18,10 +18,37 @@ pub const LSI_FREQ: u32 = 32_000; #[derive(Clone, Copy)] pub enum ClockSrc { HSE(Hertz), - HSI16, + HSI16(HSI16Prescaler), LSI, } +#[derive(Clone, Copy)] +pub enum HSI16Prescaler { + NotDivided, + Div2, + Div4, + Div8, + Div16, + Div32, + Div64, + Div128, +} + +impl Into for HSI16Prescaler { + fn into(self) -> u8 { + match self { + HSI16Prescaler::NotDivided => 0x00, + HSI16Prescaler::Div2 => 0x01, + HSI16Prescaler::Div4 => 0x02, + HSI16Prescaler::Div8 => 0x03, + HSI16Prescaler::Div16 => 0x04, + HSI16Prescaler::Div32 => 0x05, + HSI16Prescaler::Div64 => 0x06, + HSI16Prescaler::Div128 => 0x07, + } + } +} + impl Into for APBPrescaler { fn into(self) -> u8 { match self { @@ -55,15 +82,17 @@ pub struct Config { mux: ClockSrc, ahb_pre: AHBPrescaler, apb_pre: APBPrescaler, + low_power_run: bool, } impl Default for Config { #[inline] fn default() -> Config { Config { - mux: ClockSrc::HSI16, + mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided), ahb_pre: AHBPrescaler::NotDivided, apb_pre: APBPrescaler::NotDivided, + low_power_run: false, } } } @@ -86,6 +115,12 @@ impl Config { self.apb_pre = pre; self } + + #[inline] + pub fn low_power_run(mut self, on: bool) -> Self { + self.low_power_run = on; + self + } } /// RCC peripheral @@ -119,14 +154,18 @@ impl RccExt for RCC { fn freeze(self, cfgr: Config) -> Clocks { let rcc = pac::RCC; let (sys_clk, sw) = match cfgr.mux { - ClockSrc::HSI16 => { + ClockSrc::HSI16(div) => { // Enable HSI16 + let div: u8 = div.into(); unsafe { - rcc.cr().write(|w| w.set_hsion(true)); + rcc.cr().write(|w| { + w.set_hsidiv(div); + w.set_hsion(true) + }); while !rcc.cr().read().hsirdy() {} } - (HSI_FREQ, 0x00) + (HSI_FREQ >> div, 0x00) } ClockSrc::HSE(freq) => { // Enable HSE @@ -174,6 +213,14 @@ impl RccExt for RCC { } }; + let pwr = pac::PWR; + if cfgr.low_power_run { + assert!(sys_clk.hz() <= 2_000_000.hz()); + unsafe { + pwr.cr1().modify(|w| w.set_lpr(true)); + } + } + Clocks { sys: sys_clk.hz(), ahb: ahb_freq.hz(),