diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index e577ec28..147349de 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -60,7 +60,7 @@ impl<'d, T: Instance> Adc<'d, T> { } fn freq() -> Hertz { - unsafe { get_freqs() }.adc + unsafe { get_freqs() }.adc.unwrap() } pub fn sample_time_for_us(&self, us: u32) -> SampleTime { diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 31c48814..c47b0c09 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -8,6 +8,8 @@ pub use traits::Instance; #[allow(unused_imports)] use crate::gpio::sealed::{AFType, Pin}; use crate::gpio::AnyPin; +#[cfg(stm32f334)] +use crate::rcc::get_freqs; use crate::time::Hertz; use crate::Peripheral; @@ -158,17 +160,29 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> { T::enable(); ::reset(); - // // Enable and and stabilize the DLL - // T::regs().dllcr().modify(|w| { - // // w.set_calen(true); - // // w.set_calrte(11); - // w.set_cal(true); - // }); - // - // debug!("wait for dll calibration"); - // while !T::regs().isr().read().dllrdy() {} - // - // debug!("dll calibration complete"); + #[cfg(stm32f334)] + if unsafe { get_freqs() }.hrtim.is_some() { + // Enable and and stabilize the DLL + T::regs().dllcr().modify(|w| { + w.set_cal(true); + }); + + trace!("hrtim: wait for dll calibration"); + while !T::regs().isr().read().dllrdy() {} + + trace!("hrtim: dll calibration complete"); + + // Enable periodic calibration + // Cal must be disabled before we can enable it + T::regs().dllcr().modify(|w| { + w.set_cal(false); + }); + + T::regs().dllcr().modify(|w| { + w.set_calen(true); + w.set_calrte(11); + }); + } Self { _inner: tim, diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index 09510959..37cfb9b9 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs @@ -104,7 +104,13 @@ foreach_interrupt! { use crate::rcc::sealed::RccPeripheral; let f = frequency.0; + #[cfg(not(stm32f334))] let timer_f = Self::frequency().0; + #[cfg(stm32f334)] + let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or( + Self::frequency() + ).0; + let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); let psc = if Self::regs().isr().read().dllrdy() { Prescaler::compute_min_high_res(psc_min) @@ -125,7 +131,13 @@ foreach_interrupt! { use crate::rcc::sealed::RccPeripheral; let f = frequency.0; + #[cfg(not(stm32f334))] let timer_f = Self::frequency().0; + #[cfg(stm32f334)] + let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or( + Self::frequency() + ).0; + let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); let psc = if Self::regs().isr().read().dllrdy() { Prescaler::compute_min_high_res(psc_min) diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs index b6200231..304d8f50 100644 --- a/embassy-stm32/src/rcc/f1.rs +++ b/embassy-stm32/src/rcc/f1.rs @@ -184,6 +184,6 @@ pub(crate) unsafe fn init(config: Config) { apb1_tim: Hertz(pclk1 * timer_mul1), apb2_tim: Hertz(pclk2 * timer_mul2), ahb1: Hertz(hclk), - adc: Hertz(adcclk), + adc: Some(Hertz(adcclk)), }); } diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index f8726c24..cbbe4f98 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -1,3 +1,5 @@ +#[cfg(rcc_f3)] +use crate::pac::adccommon::vals::Ckmode; use crate::pac::flash::vals::Latency; use crate::pac::rcc::vals::{Adcpres, Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; use crate::pac::{FLASH, RCC}; @@ -10,44 +12,80 @@ pub const HSI_FREQ: Hertz = Hertz(8_000_000); /// LSI speed pub const LSI_FREQ: Hertz = Hertz(40_000); -#[repr(u16)] -#[derive(Clone, Copy)] -pub enum ADCPrescaler { - Div1 = 1, - Div2 = 2, - Div4 = 4, - Div6 = 6, - Div8 = 8, - Div12 = 12, - Div16 = 16, - Div32 = 32, - Div64 = 64, - Div128 = 128, - Div256 = 256, +impl From for Adcpres { + fn from(value: AdcClockSource) -> Self { + match value { + AdcClockSource::PllDiv1 => Adcpres::DIV1, + AdcClockSource::PllDiv2 => Adcpres::DIV2, + AdcClockSource::PllDiv4 => Adcpres::DIV4, + AdcClockSource::PllDiv6 => Adcpres::DIV6, + AdcClockSource::PllDiv8 => Adcpres::DIV8, + AdcClockSource::PllDiv12 => Adcpres::DIV12, + AdcClockSource::PllDiv16 => Adcpres::DIV16, + AdcClockSource::PllDiv32 => Adcpres::DIV32, + AdcClockSource::PllDiv64 => Adcpres::DIV64, + AdcClockSource::PllDiv128 => Adcpres::DIV128, + AdcClockSource::PllDiv256 => Adcpres::DIV256, + _ => unreachable!(), + } + } } -impl From for Adcpres { - fn from(value: ADCPrescaler) -> Self { +#[cfg(rcc_f3)] +impl From for Ckmode { + fn from(value: AdcClockSource) -> Self { match value { - ADCPrescaler::Div1 => Adcpres::DIV1, - ADCPrescaler::Div2 => Adcpres::DIV2, - ADCPrescaler::Div4 => Adcpres::DIV4, - ADCPrescaler::Div6 => Adcpres::DIV6, - ADCPrescaler::Div8 => Adcpres::DIV8, - ADCPrescaler::Div12 => Adcpres::DIV12, - ADCPrescaler::Div16 => Adcpres::DIV16, - ADCPrescaler::Div32 => Adcpres::DIV32, - ADCPrescaler::Div64 => Adcpres::DIV64, - ADCPrescaler::Div128 => Adcpres::DIV128, - ADCPrescaler::Div256 => Adcpres::DIV256, + AdcClockSource::BusDiv1 => Ckmode::SYNCDIV1, + AdcClockSource::BusDiv2 => Ckmode::SYNCDIV2, + AdcClockSource::BusDiv4 => Ckmode::SYNCDIV4, + _ => unreachable!(), } } } #[derive(Clone, Copy)] -pub enum ADCClock { - AHB(ADCPrescaler), - PLL(ADCPrescaler), +pub enum AdcClockSource { + PllDiv1 = 1, + PllDiv2 = 2, + PllDiv4 = 4, + PllDiv6 = 6, + PllDiv8 = 8, + PllDiv12 = 12, + PllDiv16 = 16, + PllDiv32 = 32, + PllDiv64 = 64, + PllDiv128 = 128, + PllDiv256 = 256, + BusDiv1, + BusDiv2, + BusDiv4, +} + +impl AdcClockSource { + pub fn is_bus(&self) -> bool { + match self { + Self::BusDiv1 => true, + Self::BusDiv2 => true, + Self::BusDiv4 => true, + _ => false, + } + } + + pub fn bus_div(&self) -> u32 { + match self { + Self::BusDiv1 => 1, + Self::BusDiv2 => 2, + Self::BusDiv4 => 4, + _ => unreachable!(), + } + } +} + +#[derive(Default)] +pub enum HrtimClockSource { + #[default] + BusClk, + PllClk, } /// Clocks configutation @@ -79,11 +117,13 @@ pub struct Config { #[cfg(rcc_f3)] /// ADC clock setup /// - For AHB, a psc of 4 or less must be used - pub adc: Option, + pub adc: Option, #[cfg(rcc_f3)] /// ADC clock setup /// - For AHB, a psc of 4 or less must be used - pub adc34: Option, + pub adc34: Option, + #[cfg(stm32f334)] + pub hrtim: HrtimClockSource, } // Information required to setup the PLL clock @@ -197,44 +237,6 @@ pub(crate) unsafe fn init(config: Config) { }); } - #[cfg(rcc_f3)] - let adc = config.adc.map(|adc| match adc { - ADCClock::PLL(psc) => RCC.cfgr2().modify(|w| { - // Make sure that we're using the PLL - pll_config.unwrap(); - w.set_adc12pres(psc.into()); - - Hertz(sysclk / psc as u32) - }), - ADCClock::AHB(psc) => { - assert!(psc as u16 <= 4); - assert!(!(psc as u16 == 1 && hpre_bits != Hpre::DIV1)); - - // To select this scheme, bits CKMODE[1:0] of the ADCx_CCR register must be - // different from “00”. - todo!(); - } - }); - - #[cfg(rcc_f3)] - let adc34 = config.adc34.map(|adc| match adc { - ADCClock::PLL(psc) => RCC.cfgr2().modify(|w| { - // Make sure that we're using the PLL - pll_config.unwrap(); - w.set_adc34pres(psc.into()); - - Hertz(sysclk / psc as u32) - }), - ADCClock::AHB(psc) => { - assert!(psc as u16 <= 4); - assert!(!(psc as u16 == 1 && hpre_bits != Hpre::DIV1)); - - // To select this scheme, bits CKMODE[1:0] of the ADCx_CCR register must be - // different from “00”. - todo!(); - } - }); - // Set prescalers // CFGR has been written before (PLL, PLL48) don't overwrite these settings RCC.cfgr().modify(|w| { @@ -257,6 +259,61 @@ pub(crate) unsafe fn init(config: Config) { }) }); + #[cfg(rcc_f3)] + let adc = config.adc.map(|adc| { + if !adc.is_bus() { + RCC.cfgr2().modify(|w| { + // Make sure that we're using the PLL + pll_config.unwrap(); + w.set_adc12pres(adc.into()); + + Hertz(sysclk / adc as u32) + }) + } else { + crate::pac::ADC_COMMON.ccr().modify(|w| { + assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1)); + + w.set_ckmode(adc.into()); + + Hertz(sysclk / adc.bus_div() as u32) + }) + } + }); + + #[cfg(rcc_f3)] + let adc34 = config.adc.map(|adc| { + if !adc.is_bus() { + RCC.cfgr2().modify(|w| { + // Make sure that we're using the PLL + pll_config.unwrap(); + w.set_adc12pres(adc.into()); + + Hertz(sysclk / adc as u32) + }) + } else { + // TODO: need to use only if adc32_common is present + + todo!() + } + }); + + #[cfg(stm32f334)] + let hrtim = match config.hrtim { + // Must be configured after the bus is ready, otherwise it won't work + HrtimClockSource::BusClk => None, + HrtimClockSource::PllClk => { + use crate::pac::rcc::vals::Timsw; + + // Make sure that we're using the PLL + pll_config.unwrap(); + assert!((pclk2 == sysclk) || (pclk2 * 2 == sysclk)); + + RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL)); + + Some(Hertz(sysclk * 2)) + } + }; + set_freqs(Clocks { sys: Hertz(sysclk), apb1: Hertz(pclk1), @@ -268,6 +325,8 @@ pub(crate) unsafe fn init(config: Config) { adc: adc, #[cfg(rcc_f3)] adc34: adc34, + #[cfg(stm32f334)] + hrtim: hrtim, }); } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 535ab6ad..4f0b7fd0 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -71,15 +71,15 @@ pub struct Clocks { #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] pub pllsai: Option, - #[cfg(stm32f1)] - pub adc: Hertz, - - #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3, rcc_g4))] + #[cfg(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3, rcc_g4))] pub adc: Option, #[cfg(any(rcc_f3, rcc_g4))] pub adc34: Option, + #[cfg(stm32f334)] + pub hrtim: Option, + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] /// Set only if the lsi or lse is configured, indicates stop is supported pub rtc: Option, diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index 6dffd673..e8b2cd8a 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs @@ -4,9 +4,9 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_stm32::adc::{Adc, VREF_INT}; -use embassy_stm32::rcc::{ADCClock, ADCPrescaler}; -use embassy_stm32::time::Hertz; +use embassy_stm32::adc::{Adc, SampleTime, VREF_INT}; +use embassy_stm32::rcc::AdcClockSource; +use embassy_stm32::time::mhz; use embassy_stm32::Config; use embassy_time::{Delay, Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -14,9 +14,11 @@ use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { let mut config = Config::default(); - config.rcc.hse = Some(Hertz(8_000_000)); - config.rcc.sysclk = Some(Hertz(16_000_000)); - config.rcc.adc = Some(ADCClock::PLL(ADCPrescaler::Div1)); + config.rcc.sysclk = Some(mhz(64)); + config.rcc.hclk = Some(mhz(64)); + config.rcc.pclk1 = Some(mhz(32)); + config.rcc.pclk2 = Some(mhz(64)); + config.rcc.adc = Some(AdcClockSource::PllDiv1); let mut p = embassy_stm32::init(config); @@ -24,6 +26,8 @@ async fn main(_spawner: Spawner) -> ! { let mut adc = Adc::new(p.ADC1, &mut Delay); + adc.set_sample_time(SampleTime::Cycles601_5); + info!("enable vrefint..."); let mut vrefint = adc.enable_vref(&mut Delay); diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index 2660b10c..aebc421b 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -5,6 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::hrtim::*; +use embassy_stm32::rcc::HrtimClockSource; use embassy_stm32::time::{khz, mhz}; use embassy_stm32::Config; use embassy_time::{Duration, Timer}; @@ -17,6 +18,7 @@ async fn main(_spawner: Spawner) { config.rcc.hclk = Some(mhz(64)); config.rcc.pclk1 = Some(mhz(32)); config.rcc.pclk2 = Some(mhz(64)); + config.rcc.hrtim = HrtimClockSource::PllClk; let p = embassy_stm32::init(config); info!("Hello World!");