From cda404731093015f84bad96675fdbfc712bc0215 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 24 Aug 2023 19:29:11 -0500 Subject: stm32: flesh out lp executor --- embassy-stm32/src/lib.rs | 5 +++ embassy-stm32/src/low_power.rs | 45 +++++++++++++++++------- embassy-stm32/src/rcc/mod.rs | 2 ++ embassy-stm32/src/rtc/v2.rs | 25 +++++++++---- embassy-stm32/src/time_driver.rs | 76 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 20 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 8c87ea7d5..ec8648ee4 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -197,6 +197,11 @@ pub fn init(config: Config) -> Peripherals { // must be after rcc init #[cfg(feature = "_time-driver")] time_driver::init(); + + #[cfg(feature = "low-power")] + while !crate::rcc::low_power_ready() { + crate::rcc::clock_refcount_sub(); + } } p diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 7814fa384..0d9506aaa 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -9,6 +9,7 @@ use crate::interrupt; use crate::interrupt::typelevel::Interrupt; use crate::pac::EXTI; use crate::rcc::low_power_ready; +use crate::time_driver::{pause_time, resume_time, time_until_next_alarm}; const THREAD_PENDER: usize = usize::MAX; const THRESHOLD: Duration = Duration::from_millis(500); @@ -16,6 +17,9 @@ const THRESHOLD: Duration = Duration::from_millis(500); use crate::rtc::{Rtc, RtcInstant}; static mut RTC: Option<&'static Rtc> = None; +static mut STOP_TIME: embassy_time::Duration = Duration::from_ticks(0); +static mut NEXT_ALARM: embassy_time::Duration = Duration::from_ticks(u64::MAX); +static mut RTC_INSTANT: Option = None; foreach_interrupt! { (RTC, rtc, $block:ident, WKUP, $irq:ident) => { @@ -69,13 +73,25 @@ impl Executor { } unsafe fn on_wakeup_irq() { - info!("on wakeup irq"); + trace!("on wakeup irq"); - cortex_m::asm::bkpt(); - } + let elapsed = RTC_INSTANT.take().unwrap() - stop_wakeup_alarm(); + + STOP_TIME += elapsed; + // let to_next = NEXT_ALARM - STOP_TIME; + let to_next = Duration::from_secs(3); - fn time_until_next_alarm(&self) -> Duration { - Duration::from_secs(3) + trace!("on wakeup irq: to next: {}", to_next); + if to_next > THRESHOLD { + trace!("start wakeup alarm"); + RTC_INSTANT.replace(start_wakeup_alarm(to_next)); + + trace!("set sleeponexit"); + Self::get_scb().set_sleeponexit(); + } else { + Self::get_scb().clear_sleeponexit(); + Self::get_scb().clear_sleepdeep(); + } } fn get_scb() -> SCB { @@ -86,25 +102,28 @@ impl Executor { trace!("configure_pwr"); if !low_power_ready() { + trace!("configure_pwr: low power not ready"); return; } - let time_until_next_alarm = self.time_until_next_alarm(); + let time_until_next_alarm = time_until_next_alarm(); if time_until_next_alarm < THRESHOLD { + trace!("configure_pwr: not enough time until next alarm"); return; } - trace!("low power stop required"); + unsafe { + NEXT_ALARM = time_until_next_alarm; + RTC_INSTANT = Some(start_wakeup_alarm(time_until_next_alarm)) + }; - critical_section::with(|_| { - trace!("executor: set wakeup alarm..."); + // return; - start_wakeup_alarm(time_until_next_alarm); + pause_time(); - trace!("low power wait for rtc ready..."); + trace!("enter stop..."); - Self::get_scb().set_sleepdeep(); - }); + Self::get_scb().set_sleepdeep(); } /// Run the executor. diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 3c75923e5..45a4d880d 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -86,6 +86,8 @@ static CLOCK_REFCOUNT: AtomicU32 = AtomicU32::new(0); #[cfg(feature = "low-power")] pub fn low_power_ready() -> bool { + trace!("clock refcount: {}", CLOCK_REFCOUNT.load(Ordering::SeqCst)); + CLOCK_REFCOUNT.load(Ordering::SeqCst) == 0 } diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index bcb127ecb..197c3b8f9 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -30,9 +30,6 @@ impl RtcInstant { let _ = RTC::regs().dr().read(); - trace!("ssr: {}", ssr); - trace!("st: {}", st); - Self { ssr, st } } } @@ -52,7 +49,12 @@ impl core::ops::Sub for RtcInstant { let other_ticks = rhs.st as u32 * 256 + (255 - rhs.ssr as u32); let rtc_ticks = self_ticks - other_ticks; - trace!("self, other, rtc ticks: {}, {}, {}", self_ticks, other_ticks, rtc_ticks); + trace!( + "rtc: instant sub: self, other, rtc ticks: {}, {}, {}", + self_ticks, + other_ticks, + rtc_ticks + ); Duration::from_ticks( ((((st as u32 * 256 + (255u32 - self.ssr as u32)) - (rhs.st as u32 * 256 + (255u32 - rhs.ssr as u32))) @@ -174,10 +176,10 @@ impl super::Rtc { rtc_ticks as u64 * TICK_HZ * (>::into(prescaler) as u64) / rtc_hz, ); - trace!("set wakeup timer for {} ms", duration.as_millis()); + trace!("rtc: set wakeup timer for {} ms", duration.as_millis()); self.write(false, |regs| { - regs.cr().modify(|w| w.set_wutie(true)); + // regs.cr().modify(|w| w.set_wutie(true)); regs.cr().modify(|w| w.set_wute(false)); regs.isr().modify(|w| w.set_wutf(false)); @@ -187,6 +189,15 @@ impl super::Rtc { regs.cr().modify(|w| w.set_wute(true)); }); + self.write(false, |regs| { + regs.cr().modify(|w| w.set_wutie(false)); + + regs.isr().modify(|w| w.set_wutf(false)); + crate::pac::PWR.cr1().modify(|w| w.set_cwuf(false)); + + regs.cr().modify(|w| w.set_wutie(true)); + }); + RtcInstant::now() } @@ -197,7 +208,7 @@ impl super::Rtc { /// note: this api is exposed for testing purposes until low power is implemented. /// it is not intended to be public pub(crate) fn stop_wakeup_alarm(&self) -> RtcInstant { - trace!("disable wakeup timer..."); + trace!("rtc: stop wakeup alarm..."); self.write(false, |regs| { regs.cr().modify(|w| w.set_wute(false)); diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 2622442f4..8e05346ad 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -259,6 +259,64 @@ impl RtcDriver { let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) }; f(alarm.ctx.get()); } + + #[cfg(feature = "low-power")] + /// Compute the approximate amount of time until the next alarm + pub(crate) fn time_until_next_alarm(&self) -> embassy_time::Duration { + critical_section::with(|cs| { + let now = self.now() + 32; + + embassy_time::Duration::from_ticks( + self.alarms + .borrow(cs) + .iter() + .map(|alarm: &AlarmState| alarm.timestamp.get().saturating_sub(now)) + .min() + .unwrap_or(u64::MAX), + ) + }) + } + + #[cfg(feature = "low-power")] + /// Pause the timer + pub(crate) fn pause_time(&self) { + T::regs_gp16().cr1().modify(|w| w.set_cen(false)); + } + + #[cfg(feature = "low-power")] + /// Resume the timer with the given offset + pub(crate) fn resume_time(&self, offset: embassy_time::Duration) { + let offset = offset.as_ticks(); + let cnt = T::regs_gp16().cnt().read().cnt() as u32; + let period = self.period.load(Ordering::SeqCst); + + // Correct the race, if it exists + let period = if period & 1 == 1 && cnt < u16::MAX as u32 / 2 { + period + 1 + } else { + period + }; + + // Normalize to the full overflow + let period = (period / 2) * 2; + + // Add the offset + let period = period + 2 * (offset / u16::MAX as u64) as u32; + let cnt = cnt + (offset % u16::MAX as u64) as u32; + + let (cnt, period) = if cnt > u16::MAX as u32 { + (cnt - u16::MAX as u32, period + 2) + } else { + (cnt, period) + }; + + let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period }; + + self.period.store(period, Ordering::SeqCst); + T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); + + T::regs_gp16().cr1().modify(|w| w.set_cen(true)); + } } impl Driver for RtcDriver { @@ -329,6 +387,24 @@ impl Driver for RtcDriver { } } +#[cfg(feature = "low-power")] +/// Compute the approximate amount of time until the next alarm +pub(crate) fn time_until_next_alarm() -> embassy_time::Duration { + DRIVER.time_until_next_alarm() +} + +#[cfg(feature = "low-power")] +/// Pause the timer +pub(crate) fn pause_time() { + DRIVER.pause_time(); +} + +#[cfg(feature = "low-power")] +/// Resume the timer with the given offset +pub(crate) fn resume_time(offset: embassy_time::Duration) { + DRIVER.resume_time(offset); +} + pub(crate) fn init() { DRIVER.init() } -- cgit From 3023e70ccf14157c6a9c1315b987951cb6138e0d Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 25 Aug 2023 18:41:51 -0500 Subject: stm32: clenaup lp executor --- embassy-stm32/src/low_power.rs | 154 ++++++++++++++++++++++++----------------- 1 file changed, 91 insertions(+), 63 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 0d9506aaa..cf12a1ea5 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -16,36 +16,30 @@ const THRESHOLD: Duration = Duration::from_millis(500); use crate::rtc::{Rtc, RtcInstant}; -static mut RTC: Option<&'static Rtc> = None; -static mut STOP_TIME: embassy_time::Duration = Duration::from_ticks(0); -static mut NEXT_ALARM: embassy_time::Duration = Duration::from_ticks(u64::MAX); -static mut RTC_INSTANT: Option = None; +static mut EXECUTOR: Option = None; foreach_interrupt! { (RTC, rtc, $block:ident, WKUP, $irq:ident) => { #[interrupt] unsafe fn $irq() { - Executor::on_wakeup_irq(); + unsafe { EXECUTOR.as_mut().unwrap() }.on_wakeup_irq(); } }; } pub fn stop_with_rtc(rtc: &'static Rtc) { - crate::interrupt::typelevel::RTC_WKUP::unpend(); - unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; - - EXTI.rtsr(0).modify(|w| w.set_line(22, true)); - EXTI.imr(0).modify(|w| w.set_line(22, true)); - - unsafe { RTC = Some(rtc) }; + unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) } pub fn start_wakeup_alarm(requested_duration: embassy_time::Duration) -> RtcInstant { - unsafe { RTC }.unwrap().start_wakeup_alarm(requested_duration) + unsafe { EXECUTOR.as_mut().unwrap() } + .rtc + .unwrap() + .start_wakeup_alarm(requested_duration) } pub fn stop_wakeup_alarm() -> RtcInstant { - unsafe { RTC }.unwrap().stop_wakeup_alarm() + unsafe { EXECUTOR.as_mut().unwrap() }.rtc.unwrap().stop_wakeup_alarm() } /// Thread mode executor, using WFE/SEV. @@ -61,69 +55,103 @@ pub fn stop_wakeup_alarm() -> RtcInstant { pub struct Executor { inner: raw::Executor, not_send: PhantomData<*mut ()>, + scb: SCB, + pub(self) rtc: Option<&'static Rtc>, + stop_time: embassy_time::Duration, + next_alarm: embassy_time::Duration, + last_stop: Option, } impl Executor { /// Create a new Executor. - pub fn new() -> Self { - Self { - inner: raw::Executor::new(THREAD_PENDER as *mut ()), - not_send: PhantomData, + pub fn new() -> &'static mut Self { + unsafe { + assert!(EXECUTOR.is_none()); + + EXECUTOR = Some(Self { + inner: raw::Executor::new(THREAD_PENDER as *mut ()), + not_send: PhantomData, + scb: cortex_m::Peripherals::steal().SCB, + rtc: None, + stop_time: Duration::from_ticks(0), + next_alarm: Duration::from_ticks(u64::MAX), + last_stop: None, + }); + + EXECUTOR.as_mut().unwrap() } } - unsafe fn on_wakeup_irq() { - trace!("on wakeup irq"); + unsafe fn on_wakeup_irq(&mut self) { + trace!("low power: one wakekup irq"); + + self.rtc.unwrap().clear_wakeup_alarm(); + // Self::get_scb().set_sleeponexit(); + // + // return; + // + // let elapsed = RTC_INSTANT.take().unwrap() - stop_wakeup_alarm(); + // + // STOP_TIME += elapsed; + // // let to_next = NEXT_ALARM - STOP_TIME; + // let to_next = Duration::from_secs(3); + // + // trace!("on wakeup irq: to next: {}", to_next); + // if to_next > THRESHOLD { + // trace!("start wakeup alarm"); + // RTC_INSTANT.replace(start_wakeup_alarm(to_next)); + // + // trace!("set sleeponexit"); + // Self::get_scb().set_sleeponexit(); + // } else { + // Self::get_scb().clear_sleeponexit(); + // Self::get_scb().clear_sleepdeep(); + // } + } - let elapsed = RTC_INSTANT.take().unwrap() - stop_wakeup_alarm(); + pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { + assert!(self.rtc.is_none()); - STOP_TIME += elapsed; - // let to_next = NEXT_ALARM - STOP_TIME; - let to_next = Duration::from_secs(3); + crate::interrupt::typelevel::RTC_WKUP::unpend(); + unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; - trace!("on wakeup irq: to next: {}", to_next); - if to_next > THRESHOLD { - trace!("start wakeup alarm"); - RTC_INSTANT.replace(start_wakeup_alarm(to_next)); + EXTI.rtsr(0).modify(|w| w.set_line(22, true)); + EXTI.imr(0).modify(|w| w.set_line(22, true)); - trace!("set sleeponexit"); - Self::get_scb().set_sleeponexit(); - } else { - Self::get_scb().clear_sleeponexit(); - Self::get_scb().clear_sleepdeep(); - } - } - - fn get_scb() -> SCB { - unsafe { cortex_m::Peripherals::steal() }.SCB + self.rtc = Some(rtc); } fn configure_pwr(&self) { - trace!("configure_pwr"); - - if !low_power_ready() { - trace!("configure_pwr: low power not ready"); - return; - } - - let time_until_next_alarm = time_until_next_alarm(); - if time_until_next_alarm < THRESHOLD { - trace!("configure_pwr: not enough time until next alarm"); - return; - } - - unsafe { - NEXT_ALARM = time_until_next_alarm; - RTC_INSTANT = Some(start_wakeup_alarm(time_until_next_alarm)) - }; - - // return; - - pause_time(); - - trace!("enter stop..."); - - Self::get_scb().set_sleepdeep(); + // defeat the borrow checker + let s = unsafe { EXECUTOR.as_mut().unwrap() }; + + // trace!("configure_pwr"); + // + // if !low_power_ready() { + // trace!("configure_pwr: low power not ready"); + // return; + // } + // + // let time_until_next_alarm = time_until_next_alarm(); + // if time_until_next_alarm < THRESHOLD { + // trace!("configure_pwr: not enough time until next alarm"); + // return; + // } + // + // unsafe { + // NEXT_ALARM = time_until_next_alarm; + // if RTC_INSTANT.is_none() { + // RTC_INSTANT = Some(start_wakeup_alarm(time_until_next_alarm)) + // } + // }; + // + // // return; + // + // pause_time(); + // + // trace!("enter stop..."); + // + // Self::get_scb().set_sleepdeep(); } /// Run the executor. -- cgit From 2897670f2438525bc128cf016ee8f8a948edfbb7 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 26 Aug 2023 19:23:25 -0500 Subject: stm32: get the basic lp working --- embassy-stm32/src/low_power.rs | 126 ++++++++++++++++++++++----------------- embassy-stm32/src/rtc/v2.rs | 55 +++++++++++++---- embassy-stm32/src/time_driver.rs | 107 +++++++++++++++++++++++++-------- 3 files changed, 196 insertions(+), 92 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index cf12a1ea5..964819abb 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -9,12 +9,11 @@ use crate::interrupt; use crate::interrupt::typelevel::Interrupt; use crate::pac::EXTI; use crate::rcc::low_power_ready; -use crate::time_driver::{pause_time, resume_time, time_until_next_alarm}; +use crate::time_driver::{get_driver, RtcDriver}; const THREAD_PENDER: usize = usize::MAX; -const THRESHOLD: Duration = Duration::from_millis(500); -use crate::rtc::{Rtc, RtcInstant}; +use crate::rtc::Rtc; static mut EXECUTOR: Option = None; @@ -27,20 +26,30 @@ foreach_interrupt! { }; } +// pub fn timer_driver_pause_time() { +// pause_time(); +// } + pub fn stop_with_rtc(rtc: &'static Rtc) { unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) } -pub fn start_wakeup_alarm(requested_duration: embassy_time::Duration) -> RtcInstant { - unsafe { EXECUTOR.as_mut().unwrap() } - .rtc - .unwrap() - .start_wakeup_alarm(requested_duration) -} - -pub fn stop_wakeup_alarm() -> RtcInstant { - unsafe { EXECUTOR.as_mut().unwrap() }.rtc.unwrap().stop_wakeup_alarm() -} +// pub fn start_wakeup_alarm(requested_duration: embassy_time::Duration) { +// let rtc_instant = unsafe { EXECUTOR.as_mut().unwrap() } +// .rtc +// .unwrap() +// .start_wakeup_alarm(requested_duration); +// +// unsafe { EXECUTOR.as_mut().unwrap() }.last_stop = Some(rtc_instant); +// } +// +// pub fn set_sleepdeep() { +// unsafe { EXECUTOR.as_mut().unwrap() }.scb.set_sleepdeep(); +// } +// +// pub fn stop_wakeup_alarm() -> RtcInstant { +// unsafe { EXECUTOR.as_mut().unwrap() }.rtc.unwrap().stop_wakeup_alarm() +// } /// Thread mode executor, using WFE/SEV. /// @@ -56,15 +65,15 @@ pub struct Executor { inner: raw::Executor, not_send: PhantomData<*mut ()>, scb: SCB, - pub(self) rtc: Option<&'static Rtc>, + time_driver: &'static RtcDriver, stop_time: embassy_time::Duration, next_alarm: embassy_time::Duration, - last_stop: Option, + wfe: u8, } impl Executor { /// Create a new Executor. - pub fn new() -> &'static mut Self { + pub fn take() -> &'static mut Self { unsafe { assert!(EXECUTOR.is_none()); @@ -72,10 +81,10 @@ impl Executor { inner: raw::Executor::new(THREAD_PENDER as *mut ()), not_send: PhantomData, scb: cortex_m::Peripherals::steal().SCB, - rtc: None, + time_driver: get_driver(), stop_time: Duration::from_ticks(0), next_alarm: Duration::from_ticks(u64::MAX), - last_stop: None, + wfe: 0, }); EXECUTOR.as_mut().unwrap() @@ -83,9 +92,31 @@ impl Executor { } unsafe fn on_wakeup_irq(&mut self) { - trace!("low power: one wakekup irq"); + trace!("low power: on wakeup irq"); + + if crate::pac::RTC.isr().read().wutf() { + trace!("low power: wutf set"); + } else { + trace!("low power: wutf not set"); + } + + self.time_driver.resume_time(); + trace!("low power: resume time"); - self.rtc.unwrap().clear_wakeup_alarm(); + crate::interrupt::typelevel::RTC_WKUP::disable(); + + // cortex_m::asm::bkpt(); + + // let time_elasped = self.rtc.unwrap().stop_wakeup_alarm() - self.last_stop.take().unwrap(); + // + // trace!("low power: {} ms elapsed", time_elasped.as_millis()); + // + // resume_time(time_elasped); + // trace!("low power: resume time"); + // + // self.scb.clear_sleepdeep(); + + // cortex_m::asm::bkpt(); // Self::get_scb().set_sleeponexit(); // // return; @@ -110,48 +141,33 @@ impl Executor { } pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { - assert!(self.rtc.is_none()); + trace!("low power: stop with rtc configured"); + + self.time_driver.set_rtc(rtc); crate::interrupt::typelevel::RTC_WKUP::unpend(); unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; EXTI.rtsr(0).modify(|w| w.set_line(22, true)); EXTI.imr(0).modify(|w| w.set_line(22, true)); - - self.rtc = Some(rtc); } - fn configure_pwr(&self) { - // defeat the borrow checker - let s = unsafe { EXECUTOR.as_mut().unwrap() }; + fn configure_pwr(&mut self) { + trace!("low power: configure_pwr"); - // trace!("configure_pwr"); - // - // if !low_power_ready() { - // trace!("configure_pwr: low power not ready"); - // return; - // } - // - // let time_until_next_alarm = time_until_next_alarm(); - // if time_until_next_alarm < THRESHOLD { - // trace!("configure_pwr: not enough time until next alarm"); - // return; - // } - // - // unsafe { - // NEXT_ALARM = time_until_next_alarm; - // if RTC_INSTANT.is_none() { - // RTC_INSTANT = Some(start_wakeup_alarm(time_until_next_alarm)) - // } - // }; - // - // // return; - // - // pause_time(); - // - // trace!("enter stop..."); - // - // Self::get_scb().set_sleepdeep(); + self.scb.clear_sleepdeep(); + if !low_power_ready() { + trace!("low power: configure_pwr: low power not ready"); + return; + } + + if self.time_driver.pause_time().is_err() { + trace!("low power: configure_pwr: time driver failed to pause"); + return; + } + + trace!("low power: enter stop..."); + self.scb.set_sleepdeep(); } /// Run the executor. @@ -173,11 +189,11 @@ impl Executor { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { - init(self.inner.spawner()); + init(unsafe { EXECUTOR.as_mut().unwrap() }.inner.spawner()); loop { unsafe { - self.inner.poll(); + EXECUTOR.as_mut().unwrap().inner.poll(); self.configure_pwr(); asm!("wfe"); }; diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 197c3b8f9..525dc45a2 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -30,6 +30,8 @@ impl RtcInstant { let _ = RTC::regs().dr().read(); + trace!("rtc: instant now: st, ssr: {}, {}", st, ssr); + Self { ssr, st } } } @@ -146,6 +148,21 @@ impl super::Rtc { } } + // pub(crate) fn clear_wakeup_alarm(&self) { + // use crate::interrupt::typelevel::Interrupt; + // + // self.write(false, |regs| { + // regs.cr().modify(|w| w.set_wutie(false)); + // + // regs.isr().modify(|w| w.set_wutf(false)); + // crate::pac::PWR.cr1().modify(|w| w.set_cwuf(false)); + // crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, false)); + // crate::interrupt::typelevel::RTC_WKUP::unpend(); + // + // regs.cr().modify(|w| w.set_wutie(true)); + // }); + // } + #[allow(dead_code)] #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] /// start the wakeup alarm and return the actual duration of the alarm @@ -157,6 +174,7 @@ impl super::Rtc { pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) -> RtcInstant { use embassy_time::{Duration, TICK_HZ}; + use crate::interrupt::typelevel::Interrupt; use crate::rcc::get_freqs; let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64; @@ -176,28 +194,40 @@ impl super::Rtc { rtc_ticks as u64 * TICK_HZ * (>::into(prescaler) as u64) / rtc_hz, ); - trace!("rtc: set wakeup timer for {} ms", duration.as_millis()); - self.write(false, |regs| { - // regs.cr().modify(|w| w.set_wutie(true)); - regs.cr().modify(|w| w.set_wute(false)); regs.isr().modify(|w| w.set_wutf(false)); while !regs.isr().read().wutwf() {} regs.cr().modify(|w| w.set_wucksel(prescaler.into())); regs.cr().modify(|w| w.set_wute(true)); - }); - - self.write(false, |regs| { - regs.cr().modify(|w| w.set_wutie(false)); - - regs.isr().modify(|w| w.set_wutf(false)); - crate::pac::PWR.cr1().modify(|w| w.set_cwuf(false)); - regs.cr().modify(|w| w.set_wutie(true)); }); + trace!("rtc: start wakeup alarm for {} ms", duration.as_millis()); + + // self.write(false, |regs| { + // regs.cr().modify(|w| w.set_wutie(false)); + // + // regs.isr().modify(|w| w.set_wutf(false)); + // + // regs.cr().modify(|w| w.set_wutie(true)); + // }); + // + // trace!("rtc: clear wuf..."); + // crate::pac::PWR.cr1().modify(|w| w.set_cwuf(true)); + // while crate::pac::PWR.csr1().read().wuf() {} + // trace!("rtc: clear wuf...done"); + // + // crate::pac::PWR + // .cr1() + // .modify(|w| w.set_pdds(crate::pac::pwr::vals::Pdds::STANDBY_MODE)); + // + // // crate::pac::PWR.cr1().modify(|w| w.set_lpds(true)); + // + // // crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, true)); + // crate::interrupt::typelevel::RTC_WKUP::unpend(); + RtcInstant::now() } @@ -211,6 +241,7 @@ impl super::Rtc { trace!("rtc: stop wakeup alarm..."); self.write(false, |regs| { + regs.cr().modify(|w| w.set_wutie(false)); regs.cr().modify(|w| w.set_wute(false)); regs.isr().modify(|w| w.set_wutf(false)); }); diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 8e05346ad..56f42aa96 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -14,6 +14,8 @@ use stm32_metapac::timer::regs; use crate::interrupt::typelevel::Interrupt; use crate::pac::timer::vals; use crate::rcc::sealed::RccPeripheral; +#[cfg(feature = "low-power")] +use crate::rtc::{Rtc, RtcInstant}; use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; use crate::{interrupt, peripherals}; @@ -130,12 +132,16 @@ impl AlarmState { } } -struct RtcDriver { +pub(crate) struct RtcDriver { /// Number of 2^15 periods elapsed since boot. period: AtomicU32, alarm_count: AtomicU8, /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. alarms: Mutex, + #[cfg(feature = "low-power")] + rtc: Mutex>>, + #[cfg(feature = "low-power")] + stop_time: Mutex>>, } const ALARM_STATE_NEW: AlarmState = AlarmState::new(); @@ -144,6 +150,10 @@ embassy_time::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { period: AtomicU32::new(0), alarm_count: AtomicU8::new(0), alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]), + #[cfg(feature = "low-power")] + rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), + #[cfg(feature = "low-power")] + stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), }); impl RtcDriver { @@ -260,9 +270,15 @@ impl RtcDriver { f(alarm.ctx.get()); } + #[cfg(feature = "low-power")] + /// Set the rtc but panic if it's already been set + pub(crate) fn set_rtc(&self, rtc: &'static Rtc) { + critical_section::with(|cs| assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none())); + } + #[cfg(feature = "low-power")] /// Compute the approximate amount of time until the next alarm - pub(crate) fn time_until_next_alarm(&self) -> embassy_time::Duration { + fn time_until_next_alarm(&self) -> embassy_time::Duration { critical_section::with(|cs| { let now = self.now() + 32; @@ -278,14 +294,8 @@ impl RtcDriver { } #[cfg(feature = "low-power")] - /// Pause the timer - pub(crate) fn pause_time(&self) { - T::regs_gp16().cr1().modify(|w| w.set_cen(false)); - } - - #[cfg(feature = "low-power")] - /// Resume the timer with the given offset - pub(crate) fn resume_time(&self, offset: embassy_time::Duration) { + /// Add the given offset to the current time + fn add_time(&self, offset: embassy_time::Duration) { let offset = offset.as_ticks(); let cnt = T::regs_gp16().cnt().read().cnt() as u32; let period = self.period.load(Ordering::SeqCst); @@ -315,6 +325,66 @@ impl RtcDriver { self.period.store(period, Ordering::SeqCst); T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); + // Now, recompute all alarms + critical_section::with(|cs| { + for i in 0..ALARM_COUNT { + let alarm_handle = unsafe { AlarmHandle::new(i as u8) }; + let alarm = self.get_alarm(cs, alarm_handle); + + self.set_alarm(alarm_handle, alarm.timestamp.get()); + } + }) + } + + #[cfg(feature = "low-power")] + /// Stop the wakeup alarm, if enabled, and add the appropriate offset + fn stop_wakeup_alarm(&self) { + critical_section::with(|cs| { + if let Some(stop_time) = self.stop_time.borrow(cs).take() { + let current_time = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(); + self.add_time(current_time - stop_time); + } + }); + } + + #[cfg(feature = "low-power")] + /// Pause the timer if ready; return err if not + pub(crate) fn pause_time(&self) -> Result<(), ()> { + /* + If the wakeup timer is currently running, then we need to stop it and + add the elapsed time to the current time + */ + self.stop_wakeup_alarm(); + + let time_until_next_alarm = self.time_until_next_alarm(); + if time_until_next_alarm < embassy_time::Duration::from_millis(250) { + Err(()) + } else { + critical_section::with(|cs| { + assert!(self + .stop_time + .borrow(cs) + .replace(Some( + self.rtc + .borrow(cs) + .get() + .unwrap() + .start_wakeup_alarm(time_until_next_alarm) + )) + .is_none()); + }); + + T::regs_gp16().cr1().modify(|w| w.set_cen(false)); + + Ok(()) + } + } + + #[cfg(feature = "low-power")] + /// Resume the timer with the given offset + pub(crate) fn resume_time(&self) { + self.stop_wakeup_alarm(); + T::regs_gp16().cr1().modify(|w| w.set_cen(true)); } } @@ -388,21 +458,8 @@ impl Driver for RtcDriver { } #[cfg(feature = "low-power")] -/// Compute the approximate amount of time until the next alarm -pub(crate) fn time_until_next_alarm() -> embassy_time::Duration { - DRIVER.time_until_next_alarm() -} - -#[cfg(feature = "low-power")] -/// Pause the timer -pub(crate) fn pause_time() { - DRIVER.pause_time(); -} - -#[cfg(feature = "low-power")] -/// Resume the timer with the given offset -pub(crate) fn resume_time(offset: embassy_time::Duration) { - DRIVER.resume_time(offset); +pub(crate) fn get_driver() -> &'static RtcDriver { + &DRIVER } pub(crate) fn init() { -- cgit From 1e430f74133acaeb31cb689ded3da77cb7b1c0ca Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 26 Aug 2023 20:31:12 -0500 Subject: stm32: complete stop impl. --- embassy-stm32/src/low_power.rs | 48 ---------------- embassy-stm32/src/rtc/mod.rs | 79 ++++++++++++++++++++++++++ embassy-stm32/src/rtc/v2.rs | 119 +++++++-------------------------------- embassy-stm32/src/time_driver.rs | 25 +++----- 4 files changed, 107 insertions(+), 164 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 964819abb..425362162 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -66,9 +66,6 @@ pub struct Executor { not_send: PhantomData<*mut ()>, scb: SCB, time_driver: &'static RtcDriver, - stop_time: embassy_time::Duration, - next_alarm: embassy_time::Duration, - wfe: u8, } impl Executor { @@ -82,9 +79,6 @@ impl Executor { not_send: PhantomData, scb: cortex_m::Peripherals::steal().SCB, time_driver: get_driver(), - stop_time: Duration::from_ticks(0), - next_alarm: Duration::from_ticks(u64::MAX), - wfe: 0, }); EXECUTOR.as_mut().unwrap() @@ -94,50 +88,8 @@ impl Executor { unsafe fn on_wakeup_irq(&mut self) { trace!("low power: on wakeup irq"); - if crate::pac::RTC.isr().read().wutf() { - trace!("low power: wutf set"); - } else { - trace!("low power: wutf not set"); - } - self.time_driver.resume_time(); trace!("low power: resume time"); - - crate::interrupt::typelevel::RTC_WKUP::disable(); - - // cortex_m::asm::bkpt(); - - // let time_elasped = self.rtc.unwrap().stop_wakeup_alarm() - self.last_stop.take().unwrap(); - // - // trace!("low power: {} ms elapsed", time_elasped.as_millis()); - // - // resume_time(time_elasped); - // trace!("low power: resume time"); - // - // self.scb.clear_sleepdeep(); - - // cortex_m::asm::bkpt(); - // Self::get_scb().set_sleeponexit(); - // - // return; - // - // let elapsed = RTC_INSTANT.take().unwrap() - stop_wakeup_alarm(); - // - // STOP_TIME += elapsed; - // // let to_next = NEXT_ALARM - STOP_TIME; - // let to_next = Duration::from_secs(3); - // - // trace!("on wakeup irq: to next: {}", to_next); - // if to_next > THRESHOLD { - // trace!("start wakeup alarm"); - // RTC_INSTANT.replace(start_wakeup_alarm(to_next)); - // - // trace!("set sleeponexit"); - // Self::get_scb().set_sleeponexit(); - // } else { - // Self::get_scb().clear_sleeponexit(); - // Self::get_scb().clear_sleepdeep(); - // } } pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index a6102077a..1f1abb78d 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -1,6 +1,14 @@ //! RTC peripheral abstraction mod datetime; +#[cfg(feature = "low-power")] +use core::cell::Cell; + +#[cfg(feature = "low-power")] +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +#[cfg(feature = "low-power")] +use embassy_sync::blocking_mutex::Mutex; + pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; /// refer to AN4759 to compare features of RTC2 and RTC3 @@ -30,9 +38,73 @@ pub enum RtcError { NotRunning, } +#[cfg(feature = "low-power")] +/// Represents an instant in time that can be substracted to compute a duration +struct RtcInstant { + second: u8, + subsecond: u16, +} + +#[cfg(feature = "low-power")] +impl RtcInstant { + pub fn now() -> Self { + let tr = RTC::regs().tr().read(); + let tr2 = RTC::regs().tr().read(); + let ssr = RTC::regs().ssr().read().ss(); + let ssr2 = RTC::regs().ssr().read().ss(); + + let st = bcd2_to_byte((tr.st(), tr.su())); + let st2 = bcd2_to_byte((tr2.st(), tr2.su())); + + assert!(st == st2); + assert!(ssr == ssr2); + + let _ = RTC::regs().dr().read(); + + let subsecond = ssr; + let second = st; + + // trace!("rtc: instant now: st, ssr: {}, {}", st, ssr); + + Self { second, subsecond } + } +} + +#[cfg(feature = "low-power")] +impl core::ops::Sub for RtcInstant { + type Output = embassy_time::Duration; + + fn sub(self, rhs: Self) -> Self::Output { + use embassy_time::{Duration, TICK_HZ}; + + let second = if self.second < rhs.second { + self.second + 60 + } else { + self.second + }; + + // TODO: read prescaler + + let self_ticks = second as u32 * 256 + (255 - self.subsecond as u32); + let other_ticks = rhs.second as u32 * 256 + (255 - rhs.subsecond as u32); + let rtc_ticks = self_ticks - other_ticks; + + // trace!( + // "rtc: instant sub: self, other, rtc ticks: {}, {}, {}", + // self_ticks, + // other_ticks, + // rtc_ticks + // ); + + Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / 256u32) as u64) + } +} + /// RTC Abstraction pub struct Rtc { rtc_config: RtcConfig, + #[cfg(feature = "low-power")] + stop_time: Mutex>>, } #[derive(Copy, Clone, Debug, PartialEq)] @@ -108,8 +180,15 @@ impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { RTC::enable_peripheral_clk(); + #[cfg(not(feature = "low-power"))] let mut rtc_struct = Self { rtc_config }; + #[cfg(feature = "low-power")] + let mut rtc_struct = Self { + rtc_config, + stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), + }; + Self::enable(); rtc_struct.configure(rtc_config); diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 525dc45a2..d73e7083c 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -1,71 +1,12 @@ use stm32_metapac::rtc::vals::{Init, Osel, Pol}; +#[cfg(feature = "low-power")] +use super::RtcInstant; use super::{sealed, RtcClockSource, RtcConfig}; use crate::pac::rtc::Rtc; use crate::peripherals::RTC; use crate::rtc::sealed::Instance; -#[cfg(all(feature = "time", any(stm32wb, stm32f4)))] -pub struct RtcInstant { - ssr: u16, - st: u8, -} - -#[cfg(all(feature = "time", any(stm32wb, stm32f4)))] -impl RtcInstant { - pub fn now() -> Self { - // TODO: read value twice - use crate::rtc::bcd2_to_byte; - - let tr = RTC::regs().tr().read(); - let tr2 = RTC::regs().tr().read(); - let ssr = RTC::regs().ssr().read().ss(); - let ssr2 = RTC::regs().ssr().read().ss(); - - let st = bcd2_to_byte((tr.st(), tr.su())); - let st2 = bcd2_to_byte((tr2.st(), tr2.su())); - - assert!(st == st2); - assert!(ssr == ssr2); - - let _ = RTC::regs().dr().read(); - - trace!("rtc: instant now: st, ssr: {}, {}", st, ssr); - - Self { ssr, st } - } -} - -#[cfg(all(feature = "time", any(stm32wb, stm32f4)))] -impl core::ops::Sub for RtcInstant { - type Output = embassy_time::Duration; - - fn sub(self, rhs: Self) -> Self::Output { - use embassy_time::{Duration, TICK_HZ}; - - let st = if self.st < rhs.st { self.st + 60 } else { self.st }; - - // TODO: read prescaler - - let self_ticks = st as u32 * 256 + (255 - self.ssr as u32); - let other_ticks = rhs.st as u32 * 256 + (255 - rhs.ssr as u32); - let rtc_ticks = self_ticks - other_ticks; - - trace!( - "rtc: instant sub: self, other, rtc ticks: {}, {}, {}", - self_ticks, - other_ticks, - rtc_ticks - ); - - Duration::from_ticks( - ((((st as u32 * 256 + (255u32 - self.ssr as u32)) - (rhs.st as u32 * 256 + (255u32 - rhs.ssr as u32))) - * TICK_HZ as u32) as u32 - / 256u32) as u64, - ) - } -} - #[allow(dead_code)] #[derive(Clone, Copy, Debug)] pub(crate) enum WakeupPrescaler { @@ -165,16 +106,11 @@ impl super::Rtc { #[allow(dead_code)] #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] - /// start the wakeup alarm and return the actual duration of the alarm - /// the actual duration will be the closest value possible that is less - /// than the requested duration. - /// - /// note: this api is exposed for testing purposes until low power is implemented. - /// it is not intended to be public - pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) -> RtcInstant { + /// start the wakeup alarm and wtih a duration that is as close to but less than + /// the requested duration, and record the instant the wakeup alarm was started + pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { use embassy_time::{Duration, TICK_HZ}; - use crate::interrupt::typelevel::Interrupt; use crate::rcc::get_freqs; let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64; @@ -206,47 +142,34 @@ impl super::Rtc { trace!("rtc: start wakeup alarm for {} ms", duration.as_millis()); - // self.write(false, |regs| { - // regs.cr().modify(|w| w.set_wutie(false)); - // - // regs.isr().modify(|w| w.set_wutf(false)); - // - // regs.cr().modify(|w| w.set_wutie(true)); - // }); - // - // trace!("rtc: clear wuf..."); - // crate::pac::PWR.cr1().modify(|w| w.set_cwuf(true)); - // while crate::pac::PWR.csr1().read().wuf() {} - // trace!("rtc: clear wuf...done"); - // - // crate::pac::PWR - // .cr1() - // .modify(|w| w.set_pdds(crate::pac::pwr::vals::Pdds::STANDBY_MODE)); - // - // // crate::pac::PWR.cr1().modify(|w| w.set_lpds(true)); - // - // // crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, true)); - // crate::interrupt::typelevel::RTC_WKUP::unpend(); - - RtcInstant::now() + critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(RtcInstant::now())).is_none())) } #[allow(dead_code)] #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] - /// stop the wakeup alarm and return the time remaining - /// - /// note: this api is exposed for testing purposes until low power is implemented. - /// it is not intended to be public - pub(crate) fn stop_wakeup_alarm(&self) -> RtcInstant { + /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` + /// was called, otherwise none + pub(crate) fn stop_wakeup_alarm(&self) -> Option { + use crate::interrupt::typelevel::Interrupt; + trace!("rtc: stop wakeup alarm..."); self.write(false, |regs| { regs.cr().modify(|w| w.set_wutie(false)); regs.cr().modify(|w| w.set_wute(false)); regs.isr().modify(|w| w.set_wutf(false)); + + crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, true)); + crate::interrupt::typelevel::RTC_WKUP::unpend(); }); - RtcInstant::now() + critical_section::with(|cs| { + if let Some(stop_time) = self.stop_time.borrow(cs).take() { + Some(RtcInstant::now() - stop_time) + } else { + None + } + }) } #[allow(dead_code)] diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 56f42aa96..99d423d08 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -15,7 +15,7 @@ use crate::interrupt::typelevel::Interrupt; use crate::pac::timer::vals; use crate::rcc::sealed::RccPeripheral; #[cfg(feature = "low-power")] -use crate::rtc::{Rtc, RtcInstant}; +use crate::rtc::Rtc; use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance}; use crate::{interrupt, peripherals}; @@ -140,8 +140,6 @@ pub(crate) struct RtcDriver { alarms: Mutex, #[cfg(feature = "low-power")] rtc: Mutex>>, - #[cfg(feature = "low-power")] - stop_time: Mutex>>, } const ALARM_STATE_NEW: AlarmState = AlarmState::new(); @@ -152,8 +150,6 @@ embassy_time::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]), #[cfg(feature = "low-power")] rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), - #[cfg(feature = "low-power")] - stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), }); impl RtcDriver { @@ -340,9 +336,8 @@ impl RtcDriver { /// Stop the wakeup alarm, if enabled, and add the appropriate offset fn stop_wakeup_alarm(&self) { critical_section::with(|cs| { - if let Some(stop_time) = self.stop_time.borrow(cs).take() { - let current_time = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(); - self.add_time(current_time - stop_time); + if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm() { + self.add_time(offset); } }); } @@ -361,17 +356,11 @@ impl RtcDriver { Err(()) } else { critical_section::with(|cs| { - assert!(self - .stop_time + self.rtc .borrow(cs) - .replace(Some( - self.rtc - .borrow(cs) - .get() - .unwrap() - .start_wakeup_alarm(time_until_next_alarm) - )) - .is_none()); + .get() + .unwrap() + .start_wakeup_alarm(time_until_next_alarm); }); T::regs_gp16().cr1().modify(|w| w.set_cen(false)); -- cgit From db71887817e665c5c226e8775ad2d5814babac6e Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 26 Aug 2023 20:37:01 -0500 Subject: tests/stm32: add stop and cleanpu --- embassy-stm32/src/low_power.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 425362162..65b93f8a4 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -3,7 +3,6 @@ use core::marker::PhantomData; use cortex_m::peripheral::SCB; use embassy_executor::*; -use embassy_time::Duration; use crate::interrupt; use crate::interrupt::typelevel::Interrupt; -- cgit From 94de1a53530d58cf6db38dffcf434ba19a576d40 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 26 Aug 2023 20:40:21 -0500 Subject: stm32: feature-gate wakeup alarm --- embassy-stm32/src/rtc/v2.rs | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index d73e7083c..bf926f986 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -89,23 +89,7 @@ impl super::Rtc { } } - // pub(crate) fn clear_wakeup_alarm(&self) { - // use crate::interrupt::typelevel::Interrupt; - // - // self.write(false, |regs| { - // regs.cr().modify(|w| w.set_wutie(false)); - // - // regs.isr().modify(|w| w.set_wutf(false)); - // crate::pac::PWR.cr1().modify(|w| w.set_cwuf(false)); - // crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, false)); - // crate::interrupt::typelevel::RTC_WKUP::unpend(); - // - // regs.cr().modify(|w| w.set_wutie(true)); - // }); - // } - - #[allow(dead_code)] - #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] + #[cfg(feature = "low-power")] /// start the wakeup alarm and wtih a duration that is as close to but less than /// the requested duration, and record the instant the wakeup alarm was started pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { @@ -145,8 +129,7 @@ impl super::Rtc { critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(RtcInstant::now())).is_none())) } - #[allow(dead_code)] - #[cfg(all(feature = "time", any(stm32wb, stm32f4)))] + #[cfg(feature = "low-power")] /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` /// was called, otherwise none pub(crate) fn stop_wakeup_alarm(&self) -> Option { -- cgit From 59a5e84df584faed5676de027601d09772be55f7 Mon Sep 17 00:00:00 2001 From: aidant <15520814+aidant@users.noreply.github.com> Date: Sun, 27 Aug 2023 18:36:35 +1000 Subject: fix day of the week conversion --- embassy-stm32/src/rtc/datetime.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs index a9c48d88d..3efe9be5d 100644 --- a/embassy-stm32/src/rtc/datetime.rs +++ b/embassy-stm32/src/rtc/datetime.rs @@ -89,7 +89,7 @@ pub enum DayOfWeek { #[cfg(feature = "chrono")] impl From for DayOfWeek { fn from(weekday: Weekday) -> Self { - day_of_week_from_u8(weekday.number_from_monday() as u8).unwrap() + day_of_week_from_u8(weekday.num_days_from_monday() as u8).unwrap() } } -- cgit From 48085939e70f31832d8b130094e34633da4f3745 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 08:35:13 -0500 Subject: stm32/rcc: rename common to bus --- embassy-stm32/src/rcc/bus.rs | 174 ++++++++++++++++++++++++++++++++++++++++ embassy-stm32/src/rcc/c0.rs | 2 +- embassy-stm32/src/rcc/common.rs | 174 ---------------------------------------- embassy-stm32/src/rcc/f2.rs | 4 +- embassy-stm32/src/rcc/f3.rs | 6 +- embassy-stm32/src/rcc/g0.rs | 2 +- embassy-stm32/src/rcc/g4.rs | 2 +- embassy-stm32/src/rcc/h5.rs | 2 +- embassy-stm32/src/rcc/h7.rs | 2 +- embassy-stm32/src/rcc/l0.rs | 2 +- embassy-stm32/src/rcc/l1.rs | 2 +- embassy-stm32/src/rcc/l4.rs | 2 +- embassy-stm32/src/rcc/l5.rs | 2 +- embassy-stm32/src/rcc/mod.rs | 2 +- embassy-stm32/src/rcc/u5.rs | 4 +- embassy-stm32/src/rcc/wb.rs | 2 +- embassy-stm32/src/rcc/wl.rs | 2 +- 17 files changed, 193 insertions(+), 193 deletions(-) create mode 100644 embassy-stm32/src/rcc/bus.rs delete mode 100644 embassy-stm32/src/rcc/common.rs (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bus.rs b/embassy-stm32/src/rcc/bus.rs new file mode 100644 index 000000000..62736a43a --- /dev/null +++ b/embassy-stm32/src/rcc/bus.rs @@ -0,0 +1,174 @@ +use core::ops::Div; + +#[allow(unused_imports)] +use crate::pac::rcc; +use crate::time::Hertz; + +/// Voltage Scale +/// +/// Represents the voltage range feeding the CPU core. The maximum core +/// clock frequency depends on this value. +/// +/// Scale0 represents the highest voltage range +#[derive(Copy, Clone, PartialEq)] +pub enum VoltageScale { + Scale0, + Scale1, + #[cfg(not(any(rcc_wl5, rcc_wle)))] + Scale2, + #[cfg(not(any(rcc_wl5, rcc_wle)))] + Scale3, +} + +/// AHB prescaler +#[derive(Clone, Copy, PartialEq)] +pub enum AHBPrescaler { + NotDivided, + Div2, + #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] + Div3, + Div4, + #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] + Div5, + #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] + Div6, + Div8, + #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] + Div10, + Div16, + #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] + Div32, + Div64, + Div128, + Div256, + Div512, +} + +impl Div for Hertz { + type Output = Hertz; + + fn div(self, rhs: AHBPrescaler) -> Self::Output { + let divisor = match rhs { + AHBPrescaler::NotDivided => 1, + AHBPrescaler::Div2 => 2, + #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] + AHBPrescaler::Div3 => 3, + AHBPrescaler::Div4 => 4, + #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] + AHBPrescaler::Div5 => 5, + #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] + AHBPrescaler::Div6 => 6, + AHBPrescaler::Div8 => 8, + #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] + AHBPrescaler::Div10 => 10, + AHBPrescaler::Div16 => 16, + #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] + AHBPrescaler::Div32 => 32, + AHBPrescaler::Div64 => 64, + AHBPrescaler::Div128 => 128, + AHBPrescaler::Div256 => 256, + AHBPrescaler::Div512 => 512, + }; + Hertz(self.0 / divisor) + } +} + +#[cfg(not(any(rcc_g4, rcc_wb, rcc_wl5, rcc_wle)))] +impl From for rcc::vals::Hpre { + fn from(val: AHBPrescaler) -> rcc::vals::Hpre { + use rcc::vals::Hpre; + + match val { + #[cfg(not(rcc_u5))] + AHBPrescaler::NotDivided => Hpre::DIV1, + #[cfg(rcc_u5)] + AHBPrescaler::NotDivided => Hpre::NONE, + AHBPrescaler::Div2 => Hpre::DIV2, + AHBPrescaler::Div4 => Hpre::DIV4, + AHBPrescaler::Div8 => Hpre::DIV8, + AHBPrescaler::Div16 => Hpre::DIV16, + AHBPrescaler::Div64 => Hpre::DIV64, + AHBPrescaler::Div128 => Hpre::DIV128, + AHBPrescaler::Div256 => Hpre::DIV256, + AHBPrescaler::Div512 => Hpre::DIV512, + } + } +} + +#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] +impl From for u8 { + fn from(val: AHBPrescaler) -> u8 { + match val { + AHBPrescaler::NotDivided => 0x0, + AHBPrescaler::Div2 => 0x08, + AHBPrescaler::Div3 => 0x01, + AHBPrescaler::Div4 => 0x09, + AHBPrescaler::Div5 => 0x02, + AHBPrescaler::Div6 => 0x05, + AHBPrescaler::Div8 => 0x0a, + AHBPrescaler::Div10 => 0x06, + AHBPrescaler::Div16 => 0x0b, + AHBPrescaler::Div32 => 0x07, + AHBPrescaler::Div64 => 0x0c, + AHBPrescaler::Div128 => 0x0d, + AHBPrescaler::Div256 => 0x0e, + AHBPrescaler::Div512 => 0x0f, + } + } +} + +/// APB prescaler +#[derive(Clone, Copy)] +pub enum APBPrescaler { + NotDivided, + Div2, + Div4, + Div8, + Div16, +} + +impl Div for Hertz { + type Output = Hertz; + + fn div(self, rhs: APBPrescaler) -> Self::Output { + let divisor = match rhs { + APBPrescaler::NotDivided => 1, + APBPrescaler::Div2 => 2, + APBPrescaler::Div4 => 4, + APBPrescaler::Div8 => 8, + APBPrescaler::Div16 => 16, + }; + Hertz(self.0 / divisor) + } +} + +#[cfg(not(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_g4, rcc_h7, rcc_h7ab, rcc_wb, rcc_wl5, rcc_wle)))] +impl From for rcc::vals::Ppre { + fn from(val: APBPrescaler) -> rcc::vals::Ppre { + use rcc::vals::Ppre; + + match val { + #[cfg(not(rcc_u5))] + APBPrescaler::NotDivided => Ppre::DIV1, + #[cfg(rcc_u5)] + APBPrescaler::NotDivided => Ppre::NONE, + APBPrescaler::Div2 => Ppre::DIV2, + APBPrescaler::Div4 => Ppre::DIV4, + APBPrescaler::Div8 => Ppre::DIV8, + APBPrescaler::Div16 => Ppre::DIV16, + } + } +} + +#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] +impl From for u8 { + fn from(val: APBPrescaler) -> u8 { + match val { + APBPrescaler::NotDivided => 1, + APBPrescaler::Div2 => 0x04, + APBPrescaler::Div4 => 0x05, + APBPrescaler::Div8 => 0x06, + APBPrescaler::Div16 => 0x07, + } + } +} diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 6a9326347..d85790797 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -1,4 +1,4 @@ -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::flash::vals::Latency; use crate::pac::rcc::vals::{Hsidiv, Ppre, Sw}; use crate::pac::{FLASH, RCC}; diff --git a/embassy-stm32/src/rcc/common.rs b/embassy-stm32/src/rcc/common.rs deleted file mode 100644 index 62736a43a..000000000 --- a/embassy-stm32/src/rcc/common.rs +++ /dev/null @@ -1,174 +0,0 @@ -use core::ops::Div; - -#[allow(unused_imports)] -use crate::pac::rcc; -use crate::time::Hertz; - -/// Voltage Scale -/// -/// Represents the voltage range feeding the CPU core. The maximum core -/// clock frequency depends on this value. -/// -/// Scale0 represents the highest voltage range -#[derive(Copy, Clone, PartialEq)] -pub enum VoltageScale { - Scale0, - Scale1, - #[cfg(not(any(rcc_wl5, rcc_wle)))] - Scale2, - #[cfg(not(any(rcc_wl5, rcc_wle)))] - Scale3, -} - -/// AHB prescaler -#[derive(Clone, Copy, PartialEq)] -pub enum AHBPrescaler { - NotDivided, - Div2, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - Div3, - Div4, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - Div5, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - Div6, - Div8, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - Div10, - Div16, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - Div32, - Div64, - Div128, - Div256, - Div512, -} - -impl Div for Hertz { - type Output = Hertz; - - fn div(self, rhs: AHBPrescaler) -> Self::Output { - let divisor = match rhs { - AHBPrescaler::NotDivided => 1, - AHBPrescaler::Div2 => 2, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - AHBPrescaler::Div3 => 3, - AHBPrescaler::Div4 => 4, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - AHBPrescaler::Div5 => 5, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - AHBPrescaler::Div6 => 6, - AHBPrescaler::Div8 => 8, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - AHBPrescaler::Div10 => 10, - AHBPrescaler::Div16 => 16, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - AHBPrescaler::Div32 => 32, - AHBPrescaler::Div64 => 64, - AHBPrescaler::Div128 => 128, - AHBPrescaler::Div256 => 256, - AHBPrescaler::Div512 => 512, - }; - Hertz(self.0 / divisor) - } -} - -#[cfg(not(any(rcc_g4, rcc_wb, rcc_wl5, rcc_wle)))] -impl From for rcc::vals::Hpre { - fn from(val: AHBPrescaler) -> rcc::vals::Hpre { - use rcc::vals::Hpre; - - match val { - #[cfg(not(rcc_u5))] - AHBPrescaler::NotDivided => Hpre::DIV1, - #[cfg(rcc_u5)] - AHBPrescaler::NotDivided => Hpre::NONE, - AHBPrescaler::Div2 => Hpre::DIV2, - AHBPrescaler::Div4 => Hpre::DIV4, - AHBPrescaler::Div8 => Hpre::DIV8, - AHBPrescaler::Div16 => Hpre::DIV16, - AHBPrescaler::Div64 => Hpre::DIV64, - AHBPrescaler::Div128 => Hpre::DIV128, - AHBPrescaler::Div256 => Hpre::DIV256, - AHBPrescaler::Div512 => Hpre::DIV512, - } - } -} - -#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] -impl From for u8 { - fn from(val: AHBPrescaler) -> u8 { - match val { - AHBPrescaler::NotDivided => 0x0, - AHBPrescaler::Div2 => 0x08, - AHBPrescaler::Div3 => 0x01, - AHBPrescaler::Div4 => 0x09, - AHBPrescaler::Div5 => 0x02, - AHBPrescaler::Div6 => 0x05, - AHBPrescaler::Div8 => 0x0a, - AHBPrescaler::Div10 => 0x06, - AHBPrescaler::Div16 => 0x0b, - AHBPrescaler::Div32 => 0x07, - AHBPrescaler::Div64 => 0x0c, - AHBPrescaler::Div128 => 0x0d, - AHBPrescaler::Div256 => 0x0e, - AHBPrescaler::Div512 => 0x0f, - } - } -} - -/// APB prescaler -#[derive(Clone, Copy)] -pub enum APBPrescaler { - NotDivided, - Div2, - Div4, - Div8, - Div16, -} - -impl Div for Hertz { - type Output = Hertz; - - fn div(self, rhs: APBPrescaler) -> Self::Output { - let divisor = match rhs { - APBPrescaler::NotDivided => 1, - APBPrescaler::Div2 => 2, - APBPrescaler::Div4 => 4, - APBPrescaler::Div8 => 8, - APBPrescaler::Div16 => 16, - }; - Hertz(self.0 / divisor) - } -} - -#[cfg(not(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_g4, rcc_h7, rcc_h7ab, rcc_wb, rcc_wl5, rcc_wle)))] -impl From for rcc::vals::Ppre { - fn from(val: APBPrescaler) -> rcc::vals::Ppre { - use rcc::vals::Ppre; - - match val { - #[cfg(not(rcc_u5))] - APBPrescaler::NotDivided => Ppre::DIV1, - #[cfg(rcc_u5)] - APBPrescaler::NotDivided => Ppre::NONE, - APBPrescaler::Div2 => Ppre::DIV2, - APBPrescaler::Div4 => Ppre::DIV4, - APBPrescaler::Div8 => Ppre::DIV8, - APBPrescaler::Div16 => Ppre::DIV16, - } - } -} - -#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] -impl From for u8 { - fn from(val: APBPrescaler) -> u8 { - match val { - APBPrescaler::NotDivided => 1, - APBPrescaler::Div2 => 0x04, - APBPrescaler::Div4 => 0x05, - APBPrescaler::Div8 => 0x06, - APBPrescaler::Div16 => 0x07, - } - } -} diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index ec4ed99b8..9d9bc59fd 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -1,7 +1,7 @@ use core::convert::TryFrom; use core::ops::{Div, Mul}; -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::flash::vals::Latency; use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw}; use crate::pac::{FLASH, RCC}; @@ -201,7 +201,7 @@ pub struct PLLClocks { pub pll48_freq: Hertz, } -pub use super::common::VoltageScale; +pub use super::bus::VoltageScale; impl VoltageScale { const fn wait_states(&self, ahb_freq: Hertz) -> Option { diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index 321270a70..7480c0393 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -201,9 +201,9 @@ fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) { // Calculates the Multiplier and the Divisor to arrive at // the required System clock from PLL source frequency let get_mul_div = |sysclk, pllsrcclk| { - let common_div = gcd(sysclk, pllsrcclk); - let mut multiplier = sysclk / common_div; - let mut divisor = pllsrcclk / common_div; + let bus_div = gcd(sysclk, pllsrcclk); + let mut multiplier = sysclk / bus_div; + let mut divisor = pllsrcclk / bus_div; // Minimum PLL multiplier is two if multiplier == 1 { multiplier *= 2; diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index bf2d5199e..7fdbcb00c 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -1,4 +1,4 @@ -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::flash::vals::Latency; use crate::pac::rcc::vals::{self, Hsidiv, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index dff04023e..3b044cd11 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -2,7 +2,7 @@ use stm32_metapac::flash::vals::Latency; use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw}; use stm32_metapac::FLASH; -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::{PWR, RCC}; use crate::rcc::sealed::RccPeripheral; use crate::rcc::{set_freqs, Clocks}; diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs index 2e72b1931..5741cdf92 100644 --- a/embassy-stm32/src/rcc/h5.rs +++ b/embassy-stm32/src/rcc/h5.rs @@ -26,7 +26,7 @@ const VCO_MAX: u32 = 420_000_000; const VCO_WIDE_MIN: u32 = 128_000_000; const VCO_WIDE_MAX: u32 = 560_000_000; -pub use super::common::{AHBPrescaler, APBPrescaler, VoltageScale}; +pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; pub enum HseMode { /// crystal/ceramic oscillator (HSEBYP=0) diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs index 7fb4fb95b..a6e694618 100644 --- a/embassy-stm32/src/rcc/h7.rs +++ b/embassy-stm32/src/rcc/h7.rs @@ -24,7 +24,7 @@ pub const HSI48_FREQ: Hertz = Hertz(48_000_000); /// LSI speed pub const LSI_FREQ: Hertz = Hertz(32_000); -pub use super::common::VoltageScale; +pub use super::bus::VoltageScale; #[derive(Clone, Copy)] pub enum AdcClockSource { diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index 46b58ca7c..7f9ab01f1 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -1,4 +1,4 @@ -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; use crate::pac::RCC; #[cfg(crs)] diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs index bdfc5b87a..ed949ea6f 100644 --- a/embassy-stm32/src/rcc/l1.rs +++ b/embassy-stm32/src/rcc/l1.rs @@ -1,4 +1,4 @@ -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index b34b8caab..4c4b4bfd6 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -4,7 +4,7 @@ use embassy_hal_internal::into_ref; use stm32_metapac::rcc::regs::Cfgr; use stm32_metapac::rcc::vals::{Lsedrv, Mcopre, Mcosel}; -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::gpio::sealed::AFType; use crate::gpio::Speed; use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs index a85e14889..9e4e0fc75 100644 --- a/embassy-stm32/src/rcc/l5.rs +++ b/embassy-stm32/src/rcc/l5.rs @@ -1,6 +1,6 @@ use stm32_metapac::PWR; -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 45a4d880d..f9ac88d97 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -1,6 +1,6 @@ #![macro_use] -pub mod common; +pub mod bus; use core::mem::MaybeUninit; diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index b5feeb0c4..4aca9cd3d 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -1,6 +1,6 @@ use stm32_metapac::rcc::vals::{Msirange, Msirgsel, Pllm, Pllsrc, Sw}; -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -11,7 +11,7 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000); /// LSI speed pub const LSI_FREQ: Hertz = Hertz(32_000); -pub use super::common::VoltageScale; +pub use super::bus::VoltageScale; #[derive(Copy, Clone)] pub enum ClockSrc { diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index ae708b37f..653d4d59d 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -1,4 +1,4 @@ -pub use super::common::{AHBPrescaler, APBPrescaler}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::rcc::Clocks; use crate::rtc::{Rtc, RtcClockSource}; use crate::time::{khz, mhz, Hertz}; diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index f1dd2bd7e..29f50dc66 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,4 +1,4 @@ -pub use super::common::{AHBPrescaler, APBPrescaler, VoltageScale}; +pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; use crate::pac::pwr::vals::Dbp; use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::{set_freqs, Clocks}; -- cgit From 4caa8497fcac5099d9e885683542aca6b4f0911e Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 09:07:34 -0500 Subject: stm32: extract backupdomain into mod --- embassy-stm32/src/rcc/bd.rs | 168 +++++++++++++++++++++++++++++++++++++++++++ embassy-stm32/src/rcc/f4.rs | 4 +- embassy-stm32/src/rcc/l4.rs | 6 +- embassy-stm32/src/rcc/mod.rs | 1 + embassy-stm32/src/rcc/wb.rs | 6 +- embassy-stm32/src/rcc/wl.rs | 6 +- embassy-stm32/src/rtc/mod.rs | 16 +---- embassy-stm32/src/rtc/v2.rs | 81 +-------------------- embassy-stm32/src/rtc/v3.rs | 65 +---------------- 9 files changed, 185 insertions(+), 168 deletions(-) create mode 100644 embassy-stm32/src/rcc/bd.rs (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs new file mode 100644 index 000000000..e09737690 --- /dev/null +++ b/embassy-stm32/src/rcc/bd.rs @@ -0,0 +1,168 @@ +#[derive(Copy, Clone, Debug, PartialEq)] +#[repr(u8)] +pub enum RtcClockSource { + /// 00: No clock + NoClock = 0b00, + /// 01: LSE oscillator clock used as RTC clock + LSE = 0b01, + /// 10: LSI oscillator clock used as RTC clock + LSI = 0b10, + /// 11: HSE oscillator clock divided by 32 used as RTC clock + HSE = 0b11, +} + +pub struct BackupDomain {} + +impl BackupDomain { + #[cfg(any( + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb + ))] + fn unlock_registers() { + #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] + let cr = crate::pac::PWR.cr(); + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] + let cr = crate::pac::PWR.cr1(); + + // TODO: Missing from PAC for l0 and f0? + #[cfg(not(any(rtc_v2f0, rtc_v2l0)))] + { + if !cr.read().dbp() { + cr.modify(|w| w.set_dbp(true)); + while !cr.read().dbp() {} + } + } + } + + #[cfg(any(rtc_v3, rtc_v3u5))] + fn unlock_registers() { + // Unlock the backup domain + #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] + { + if !crate::pac::PWR.cr1().read().dbp() { + crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); + while !crate::pac::PWR.cr1().read().dbp() {} + } + } + #[cfg(any(rcc_wl5, rcc_wle))] + { + use crate::pac::pwr::vals::Dbp; + + if crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED { + crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); + while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {} + } + } + } + + #[cfg(any( + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb + ))] + pub fn set_rtc_clock_source(clock_source: RtcClockSource) { + #[cfg(not(rtc_v2wb))] + use stm32_metapac::rcc::vals::Rtcsel; + + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + let cr = crate::pac::RCC.bdcr(); + #[cfg(any(rtc_v2l0, rtc_v2l1))] + let cr = crate::pac::RCC.csr(); + + Self::unlock_registers(); + + cr.modify(|w| { + // Select RTC source + #[cfg(not(rtc_v2wb))] + w.set_rtcsel(Rtcsel::from_bits(clock_source as u8)); + #[cfg(rtc_v2wb)] + w.set_rtcsel(clock_source as u8); + }); + } + + #[cfg(any(rtc_v3, rtc_v3u5))] + pub fn set_rtc_clock_source(clock_source: RtcClockSource) { + let clock_source = clock_source as u8; + #[cfg(not(any(rcc_wl5, rcc_wle)))] + let clock_source = crate::pac::rcc::vals::Rtcsel::from_bits(clock_source); + + Self::unlock_registers(); + + crate::pac::RCC.bdcr().modify(|w| { + // Select RTC source + w.set_rtcsel(clock_source); + }); + } + + #[cfg(any( + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb + ))] + pub fn enable_rtc() { + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + let reg = crate::pac::RCC.bdcr().read(); + #[cfg(any(rtc_v2l0, rtc_v2l1))] + let reg = crate::pac::RCC.csr().read(); + + #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] + assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); + + if !reg.rtcen() { + Self::unlock_registers(); + + #[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))] + crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + let cr = crate::pac::RCC.bdcr(); + #[cfg(any(rtc_v2l0, rtc_v2l1))] + let cr = crate::pac::RCC.csr(); + + cr.modify(|w| { + // Reset + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + w.set_bdrst(false); + + w.set_rtcen(true); + w.set_rtcsel(reg.rtcsel()); + + // Restore bcdr + #[cfg(any(rtc_v2l4, rtc_v2wb))] + w.set_lscosel(reg.lscosel()); + #[cfg(any(rtc_v2l4, rtc_v2wb))] + w.set_lscoen(reg.lscoen()); + + w.set_lseon(reg.lseon()); + + #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] + w.set_lsedrv(reg.lsedrv()); + w.set_lsebyp(reg.lsebyp()); + }); + } + } + + #[cfg(any(rtc_v3, rtc_v3u5))] + pub fn enable_rtc() { + let bdcr = crate::pac::RCC.bdcr(); + + let reg = bdcr.read(); + assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); + + if !reg.rtcen() { + Self::unlock_registers(); + + bdcr.modify(|w| w.set_bdrst(true)); + + bdcr.modify(|w| { + // Reset + w.set_bdrst(false); + + w.set_rtcen(true); + w.set_rtcsel(reg.rtcsel()); + + // Restore bcdr + w.set_lscosel(reg.lscosel()); + w.set_lscoen(reg.lscoen()); + + w.set_lseon(reg.lseon()); + w.set_lsedrv(reg.lsedrv()); + w.set_lsebyp(reg.lsebyp()); + }); + } + } +} diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index ee9cb2897..10d3322aa 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -8,8 +8,8 @@ use crate::gpio::sealed::AFType; use crate::gpio::Speed; use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; -use crate::rtc::{Rtc, RtcClockSource}; use crate::time::Hertz; use crate::{peripherals, Peripheral}; @@ -470,7 +470,7 @@ pub(crate) unsafe fn init(config: Config) { } config.rtc.map(|clock_source| { - Rtc::set_clock_source(clock_source); + BackupDomain::set_rtc_clock_source(clock_source); }); let rtc = match config.rtc { diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 4c4b4bfd6..1f02254b1 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -9,8 +9,8 @@ use crate::gpio::sealed::AFType; use crate::gpio::Speed; use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::bd::{BackupDomain, RtcClockSource as RCS}; use crate::rcc::{set_freqs, Clocks}; -use crate::rtc::{Rtc, RtcClockSource as RCS}; use crate::time::Hertz; use crate::{peripherals, Peripheral}; @@ -429,7 +429,7 @@ pub(crate) unsafe fn init(config: Config) { // Wait until LSE is running while !RCC.bdcr().read().lserdy() {} - Rtc::set_clock_source(RCS::LSE); + BackupDomain::set_rtc_clock_source(RCS::LSE); } RtcClockSource::LSI32 => { // Turn on the internal 32 kHz LSI oscillator @@ -438,7 +438,7 @@ pub(crate) unsafe fn init(config: Config) { // Wait until LSI is running while !RCC.csr().read().lsirdy() {} - Rtc::set_clock_source(RCS::LSI); + BackupDomain::set_rtc_clock_source(RCS::LSI); } } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index f9ac88d97..7b68495b3 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -1,5 +1,6 @@ #![macro_use] +pub(crate) mod bd; pub mod bus; use core::mem::MaybeUninit; diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index 653d4d59d..6a3eab707 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -1,6 +1,6 @@ pub use super::bus::{AHBPrescaler, APBPrescaler}; +use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::Clocks; -use crate::rtc::{Rtc, RtcClockSource}; use crate::time::{khz, mhz, Hertz}; /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, @@ -375,5 +375,7 @@ pub(crate) fn configure_clocks(config: &Config) { w.set_shdhpre(config.ahb3_pre.into()); }); - config.rtc.map(|clock_source| Rtc::set_clock_source(clock_source)); + config + .rtc + .map(|clock_source| BackupDomain::set_rtc_clock_source(clock_source)); } diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 29f50dc66..8a9b24c91 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,8 +1,8 @@ pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; use crate::pac::pwr::vals::Dbp; use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::bd::{BackupDomain, RtcClockSource as RCS}; use crate::rcc::{set_freqs, Clocks}; -use crate::rtc::{Rtc, RtcClockSource as RCS}; use crate::time::Hertz; /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, @@ -231,7 +231,7 @@ pub(crate) unsafe fn init(config: Config) { // Wait until LSE is running while !RCC.bdcr().read().lserdy() {} - Rtc::set_clock_source(RCS::LSE); + BackupDomain::set_rtc_clock_source(RCS::LSE); } RtcClockSource::LSI32 => { // Turn on the internal 32 kHz LSI oscillator @@ -240,7 +240,7 @@ pub(crate) unsafe fn init(config: Config) { // Wait until LSI is running while !RCC.csr().read().lsirdy() {} - Rtc::set_clock_source(RCS::LSI); + BackupDomain::set_rtc_clock_source(RCS::LSI); } } diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 1f1abb78d..0f9159512 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -10,6 +10,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; +use crate::rcc::bd::BackupDomain; /// refer to AN4759 to compare features of RTC2 and RTC3 #[cfg_attr(any(rtc_v1), path = "v1.rs")] @@ -107,19 +108,6 @@ pub struct Rtc { stop_time: Mutex>>, } -#[derive(Copy, Clone, Debug, PartialEq)] -#[repr(u8)] -pub enum RtcClockSource { - /// 00: No clock - NoClock = 0b00, - /// 01: LSE oscillator clock used as RTC clock - LSE = 0b01, - /// 10: LSI oscillator clock used as RTC clock - LSI = 0b10, - /// 11: HSE oscillator clock divided by 32 used as RTC clock - HSE = 0b11, -} - #[derive(Copy, Clone, PartialEq)] pub struct RtcConfig { /// Asynchronous prescaler factor @@ -189,7 +177,7 @@ impl Rtc { stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), }; - Self::enable(); + BackupDomain::enable_rtc(); rtc_struct.configure(rtc_config); rtc_struct.rtc_config = rtc_config; diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index bf926f986..1e0ca9b48 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -2,7 +2,7 @@ use stm32_metapac::rtc::vals::{Init, Osel, Pol}; #[cfg(feature = "low-power")] use super::RtcInstant; -use super::{sealed, RtcClockSource, RtcConfig}; +use super::{sealed, RtcConfig}; use crate::pac::rtc::Rtc; use crate::peripherals::RTC; use crate::rtc::sealed::Instance; @@ -73,22 +73,6 @@ impl WakeupPrescaler { } impl super::Rtc { - fn unlock_registers() { - #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] - let cr = crate::pac::PWR.cr(); - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] - let cr = crate::pac::PWR.cr1(); - - // TODO: Missing from PAC for l0 and f0? - #[cfg(not(any(rtc_v2f0, rtc_v2l0)))] - { - if !cr.read().dbp() { - cr.modify(|w| w.set_dbp(true)); - while !cr.read().dbp() {} - } - } - } - #[cfg(feature = "low-power")] /// start the wakeup alarm and wtih a duration that is as close to but less than /// the requested duration, and record the instant the wakeup alarm was started @@ -155,69 +139,6 @@ impl super::Rtc { }) } - #[allow(dead_code)] - pub(crate) fn set_clock_source(clock_source: RtcClockSource) { - #[cfg(not(rtc_v2wb))] - use stm32_metapac::rcc::vals::Rtcsel; - - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] - let cr = crate::pac::RCC.bdcr(); - #[cfg(any(rtc_v2l0, rtc_v2l1))] - let cr = crate::pac::RCC.csr(); - - Self::unlock_registers(); - - cr.modify(|w| { - // Select RTC source - #[cfg(not(rtc_v2wb))] - w.set_rtcsel(Rtcsel::from_bits(clock_source as u8)); - #[cfg(rtc_v2wb)] - w.set_rtcsel(clock_source as u8); - }); - } - - pub(super) fn enable() { - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] - let reg = crate::pac::RCC.bdcr().read(); - #[cfg(any(rtc_v2l0, rtc_v2l1))] - let reg = crate::pac::RCC.csr().read(); - - #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] - assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); - - if !reg.rtcen() { - Self::unlock_registers(); - - #[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))] - crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] - let cr = crate::pac::RCC.bdcr(); - #[cfg(any(rtc_v2l0, rtc_v2l1))] - let cr = crate::pac::RCC.csr(); - - cr.modify(|w| { - // Reset - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] - w.set_bdrst(false); - - w.set_rtcen(true); - w.set_rtcsel(reg.rtcsel()); - - // Restore bcdr - #[cfg(any(rtc_v2l4, rtc_v2wb))] - w.set_lscosel(reg.lscosel()); - #[cfg(any(rtc_v2l4, rtc_v2wb))] - w.set_lscoen(reg.lscoen()); - - w.set_lseon(reg.lseon()); - - #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); - }); - } - } - /// Applies the RTC config /// It this changes the RTC clock source the time will be reset pub(super) fn configure(&mut self, rtc_config: RtcConfig) { diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 3297303ee..12952b15a 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -1,74 +1,11 @@ use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Init, Key, Osel, Pol, TampalrmPu, TampalrmType}; -use super::{sealed, RtcCalibrationCyclePeriod, RtcClockSource, RtcConfig}; +use super::{sealed, RtcCalibrationCyclePeriod, RtcConfig}; use crate::pac::rtc::Rtc; use crate::peripherals::RTC; use crate::rtc::sealed::Instance; impl super::Rtc { - fn unlock_registers() { - // Unlock the backup domain - #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] - { - if !crate::pac::PWR.cr1().read().dbp() { - crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); - while !crate::pac::PWR.cr1().read().dbp() {} - } - } - #[cfg(any(rcc_wl5, rcc_wle))] - { - use crate::pac::pwr::vals::Dbp; - - if crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED { - crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); - while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {} - } - } - } - - #[allow(dead_code)] - pub(crate) fn set_clock_source(clock_source: RtcClockSource) { - let clock_source = clock_source as u8; - #[cfg(not(any(rcc_wl5, rcc_wle)))] - let clock_source = crate::pac::rcc::vals::Rtcsel::from_bits(clock_source); - - Self::unlock_registers(); - - crate::pac::RCC.bdcr().modify(|w| { - // Select RTC source - w.set_rtcsel(clock_source); - }); - } - - pub(super) fn enable() { - let bdcr = crate::pac::RCC.bdcr(); - - let reg = bdcr.read(); - assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); - - if !reg.rtcen() { - Self::unlock_registers(); - - bdcr.modify(|w| w.set_bdrst(true)); - - bdcr.modify(|w| { - // Reset - w.set_bdrst(false); - - w.set_rtcen(true); - w.set_rtcsel(reg.rtcsel()); - - // Restore bcdr - w.set_lscosel(reg.lscosel()); - w.set_lscoen(reg.lscoen()); - - w.set_lseon(reg.lseon()); - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); - }); - } - } - /// Applies the RTC config /// It this changes the RTC clock source the time will be reset pub(super) fn configure(&mut self, rtc_config: RtcConfig) { -- cgit From 10ea06802761a7aa6feb0241ebdbbe9bbaf37a7f Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 09:12:04 -0500 Subject: stm32/bd: allow dead code --- embassy-stm32/src/rcc/bd.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index e09737690..fd1b8d451 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -1,5 +1,6 @@ #[derive(Copy, Clone, Debug, PartialEq)] #[repr(u8)] +#[allow(dead_code)] pub enum RtcClockSource { /// 00: No clock NoClock = 0b00, @@ -11,12 +12,14 @@ pub enum RtcClockSource { HSE = 0b11, } +#[allow(dead_code)] pub struct BackupDomain {} impl BackupDomain { #[cfg(any( rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb ))] + #[allow(dead_code)] fn unlock_registers() { #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] let cr = crate::pac::PWR.cr(); @@ -34,6 +37,7 @@ impl BackupDomain { } #[cfg(any(rtc_v3, rtc_v3u5))] + #[allow(dead_code)] fn unlock_registers() { // Unlock the backup domain #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] @@ -57,6 +61,7 @@ impl BackupDomain { #[cfg(any( rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb ))] + #[allow(dead_code)] pub fn set_rtc_clock_source(clock_source: RtcClockSource) { #[cfg(not(rtc_v2wb))] use stm32_metapac::rcc::vals::Rtcsel; @@ -78,6 +83,7 @@ impl BackupDomain { } #[cfg(any(rtc_v3, rtc_v3u5))] + #[allow(dead_code)] pub fn set_rtc_clock_source(clock_source: RtcClockSource) { let clock_source = clock_source as u8; #[cfg(not(any(rcc_wl5, rcc_wle)))] @@ -94,6 +100,7 @@ impl BackupDomain { #[cfg(any( rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb ))] + #[allow(dead_code)] pub fn enable_rtc() { #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] let reg = crate::pac::RCC.bdcr().read(); @@ -137,6 +144,7 @@ impl BackupDomain { } #[cfg(any(rtc_v3, rtc_v3u5))] + #[allow(dead_code)] pub fn enable_rtc() { let bdcr = crate::pac::RCC.bdcr(); -- cgit From fb942e6675097540b6ca3f5fa37e0696337c2fc0 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 09:25:14 -0500 Subject: stm32: re-export rtcclocksource --- embassy-stm32/src/rcc/mod.rs | 2 +- embassy-stm32/src/rtc/mod.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 7b68495b3..9f1b3b663 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -2,9 +2,9 @@ pub(crate) mod bd; pub mod bus; - use core::mem::MaybeUninit; +pub use crate::rcc::bd::RtcClockSource; use crate::time::Hertz; #[cfg_attr(rcc_f0, path = "f0.rs")] diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 0f9159512..c408b2d61 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -11,6 +11,7 @@ use embassy_sync::blocking_mutex::Mutex; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; use crate::rcc::bd::BackupDomain; +pub use crate::rcc::RtcClockSource; /// refer to AN4759 to compare features of RTC2 and RTC3 #[cfg_attr(any(rtc_v1), path = "v1.rs")] -- cgit From 3bf6081eb5985d853ffee1bf8064304daa1fdfd8 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 09:41:31 -0500 Subject: stm32: fix wl re-export --- embassy-stm32/src/rcc/wl.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 8a9b24c91..5b1909659 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,7 +1,7 @@ pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; use crate::pac::pwr::vals::Dbp; use crate::pac::{FLASH, PWR, RCC}; -use crate::rcc::bd::{BackupDomain, RtcClockSource as RCS}; +use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -130,16 +130,11 @@ impl Default for Config { apb2_pre: APBPrescaler::NotDivided, enable_lsi: false, enable_rtc_apb: false, - rtc_mux: RtcClockSource::LSI32, + rtc_mux: RtcClockSource::LSI, } } } -pub enum RtcClockSource { - LSE32, - LSI32, -} - #[repr(u8)] pub enum Lsedrv { Low = 0, @@ -215,7 +210,7 @@ pub(crate) unsafe fn init(config: Config) { while FLASH.acr().read().latency() != ws {} match config.rtc_mux { - RtcClockSource::LSE32 => { + RtcClockSource::LSE => { // 1. Unlock the backup domain PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); @@ -231,17 +226,18 @@ pub(crate) unsafe fn init(config: Config) { // Wait until LSE is running while !RCC.bdcr().read().lserdy() {} - BackupDomain::set_rtc_clock_source(RCS::LSE); + BackupDomain::set_rtc_clock_source(RtcClockSource::LSE); } - RtcClockSource::LSI32 => { + RtcClockSource::LSI => { // Turn on the internal 32 kHz LSI oscillator RCC.csr().modify(|w| w.set_lsion(true)); // Wait until LSI is running while !RCC.csr().read().lsirdy() {} - BackupDomain::set_rtc_clock_source(RCS::LSI); + BackupDomain::set_rtc_clock_source(RtcClockSource::LSI); } + _ => unreachable!(), } match config.mux { @@ -266,7 +262,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_msirange(range.into()); w.set_msion(true); - if let RtcClockSource::LSE32 = config.rtc_mux { + if let RtcClockSource::LSE = config.rtc_mux { // If LSE is enabled, enable calibration of MSI w.set_msipllen(true); } else { -- cgit From f28ab18d7bc05ade2130979d67b0af6ad4085d76 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 09:50:02 -0500 Subject: stm32: fix l4 re-export --- embassy-stm32/src/rcc/l4.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 1f02254b1..c6bccfd26 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -9,7 +9,7 @@ use crate::gpio::sealed::AFType; use crate::gpio::Speed; use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; -use crate::rcc::bd::{BackupDomain, RtcClockSource as RCS}; +use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; use crate::{peripherals, Peripheral}; @@ -254,16 +254,11 @@ impl Default for Config { pllsai1: None, #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] hsi48: false, - rtc_mux: RtcClockSource::LSI32, + rtc_mux: RtcClockSource::LSI, } } } -pub enum RtcClockSource { - LSE32, - LSI32, -} - pub enum McoClock { DIV1, DIV2, @@ -413,7 +408,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.apb1enr1().modify(|w| w.set_pwren(true)); match config.rtc_mux { - RtcClockSource::LSE32 => { + RtcClockSource::LSE => { // 1. Unlock the backup domain PWR.cr1().modify(|w| w.set_dbp(true)); @@ -429,17 +424,18 @@ pub(crate) unsafe fn init(config: Config) { // Wait until LSE is running while !RCC.bdcr().read().lserdy() {} - BackupDomain::set_rtc_clock_source(RCS::LSE); + BackupDomain::set_rtc_clock_source(RtcClockSource::LSE); } - RtcClockSource::LSI32 => { + RtcClockSource::LSI => { // Turn on the internal 32 kHz LSI oscillator RCC.csr().modify(|w| w.set_lsion(true)); // Wait until LSI is running while !RCC.csr().read().lsirdy() {} - BackupDomain::set_rtc_clock_source(RCS::LSI); + BackupDomain::set_rtc_clock_source(RtcClockSource::LSI); } + _ => unreachable!(), } let (sys_clk, sw) = match config.mux { @@ -451,7 +447,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_msirgsel(true); w.set_msion(true); - if let RtcClockSource::LSE32 = config.rtc_mux { + if let RtcClockSource::LSE = config.rtc_mux { // If LSE is enabled, enable calibration of MSI w.set_msipllen(true); } else { -- cgit From 531f51d0eb66af9b681b49c10e28ef25e88bbcc2 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 15:01:09 -0500 Subject: rcc/bd: consolidate mod --- embassy-stm32/src/rcc/bd.rs | 107 +++++++++++++++----------------------------- embassy-stm32/src/rcc/wl.rs | 3 +- 2 files changed, 38 insertions(+), 72 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index fd1b8d451..d56bc0330 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -12,86 +12,67 @@ pub enum RtcClockSource { HSE = 0b11, } +#[cfg(not(any(rtc_v2l0, rtc_v2l1)))] +type Bdcr = crate::pac::rcc::regs::Bdcr; + +#[cfg(any(rtc_v2l0, rtc_v2l1))] +type Bdcr = crate::pac::rcc::regs::Csr; + #[allow(dead_code)] pub struct BackupDomain {} impl BackupDomain { #[cfg(any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, + rtc_v3u5 ))] #[allow(dead_code)] - fn unlock_registers() { + fn modify(f: impl FnOnce(&mut Bdcr) -> R) -> R { #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] let cr = crate::pac::PWR.cr(); - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] let cr = crate::pac::PWR.cr1(); // TODO: Missing from PAC for l0 and f0? - #[cfg(not(any(rtc_v2f0, rtc_v2l0)))] + #[cfg(not(any(rtc_v2f0, rtc_v2l0, rtc_v3u5)))] { - if !cr.read().dbp() { - cr.modify(|w| w.set_dbp(true)); - while !cr.read().dbp() {} - } + cr.modify(|w| w.set_dbp(true)); + while !cr.read().dbp() {} } - } - #[cfg(any(rtc_v3, rtc_v3u5))] - #[allow(dead_code)] - fn unlock_registers() { - // Unlock the backup domain - #[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))] - { - if !crate::pac::PWR.cr1().read().dbp() { - crate::pac::PWR.cr1().modify(|w| w.set_dbp(true)); - while !crate::pac::PWR.cr1().read().dbp() {} - } - } - #[cfg(any(rcc_wl5, rcc_wle))] - { - use crate::pac::pwr::vals::Dbp; - - if crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED { - crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); - while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {} - } - } + crate::pac::RCC.bdcr().modify(|w| f(w)) } #[cfg(any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, + rtc_v3u5 ))] #[allow(dead_code)] - pub fn set_rtc_clock_source(clock_source: RtcClockSource) { - #[cfg(not(rtc_v2wb))] - use stm32_metapac::rcc::vals::Rtcsel; - - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] - let cr = crate::pac::RCC.bdcr(); + fn read() -> Bdcr { #[cfg(any(rtc_v2l0, rtc_v2l1))] - let cr = crate::pac::RCC.csr(); + let r = crate::pac::RCC.csr().read(); - Self::unlock_registers(); + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + let r = crate::pac::RCC.bdcr().read(); - cr.modify(|w| { - // Select RTC source - #[cfg(not(rtc_v2wb))] - w.set_rtcsel(Rtcsel::from_bits(clock_source as u8)); - #[cfg(rtc_v2wb)] - w.set_rtcsel(clock_source as u8); - }); + r } - #[cfg(any(rtc_v3, rtc_v3u5))] + #[cfg(any( + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, + rtc_v3u5 + ))] #[allow(dead_code)] pub fn set_rtc_clock_source(clock_source: RtcClockSource) { let clock_source = clock_source as u8; - #[cfg(not(any(rcc_wl5, rcc_wle)))] + #[cfg(any( + all(not(any(rtc_v3, rtc_v3u5)), not(rtc_v2wb)), + all(any(rtc_v3, rtc_v3u5), not(any(rcc_wl5, rcc_wle))) + ))] let clock_source = crate::pac::rcc::vals::Rtcsel::from_bits(clock_source); - Self::unlock_registers(); - - crate::pac::RCC.bdcr().modify(|w| { + #[cfg(not(rtc_v2wb))] + Self::modify(|w| { // Select RTC source w.set_rtcsel(clock_source); }); @@ -102,25 +83,16 @@ impl BackupDomain { ))] #[allow(dead_code)] pub fn enable_rtc() { - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] - let reg = crate::pac::RCC.bdcr().read(); - #[cfg(any(rtc_v2l0, rtc_v2l1))] - let reg = crate::pac::RCC.csr().read(); + let reg = Self::read(); #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); if !reg.rtcen() { - Self::unlock_registers(); - #[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))] - crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] - let cr = crate::pac::RCC.bdcr(); - #[cfg(any(rtc_v2l0, rtc_v2l1))] - let cr = crate::pac::RCC.csr(); + Self::modify(|w| w.set_bdrst(true)); - cr.modify(|w| { + Self::modify(|w| { // Reset #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] w.set_bdrst(false); @@ -146,18 +118,13 @@ impl BackupDomain { #[cfg(any(rtc_v3, rtc_v3u5))] #[allow(dead_code)] pub fn enable_rtc() { - let bdcr = crate::pac::RCC.bdcr(); - - let reg = bdcr.read(); + let reg = Self::read(); assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); if !reg.rtcen() { - Self::unlock_registers(); - - bdcr.modify(|w| w.set_bdrst(true)); + Self::modify(|w| w.set_bdrst(true)); - bdcr.modify(|w| { - // Reset + Self::modify(|w| { w.set_bdrst(false); w.set_rtcen(true); diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 5b1909659..e33690d10 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,5 +1,4 @@ pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; -use crate::pac::pwr::vals::Dbp; use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; @@ -212,7 +211,7 @@ pub(crate) unsafe fn init(config: Config) { match config.rtc_mux { RtcClockSource::LSE => { // 1. Unlock the backup domain - PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED)); + PWR.cr1().modify(|w| w.set_dbp(true)); // 2. Setup the LSE RCC.bdcr().modify(|w| { -- cgit From cbc92dce052060bb15b82921c0a05c3a81d6dcc9 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 15:18:34 -0500 Subject: stm32/bd: fix errors --- embassy-stm32/src/rcc/bd.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index d56bc0330..0fc116ed8 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -12,10 +12,12 @@ pub enum RtcClockSource { HSE = 0b11, } -#[cfg(not(any(rtc_v2l0, rtc_v2l1)))] +#[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] +#[allow(dead_code)] type Bdcr = crate::pac::rcc::regs::Bdcr; #[cfg(any(rtc_v2l0, rtc_v2l1))] +#[allow(dead_code)] type Bdcr = crate::pac::rcc::regs::Csr; #[allow(dead_code)] @@ -26,7 +28,7 @@ impl BackupDomain { rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5 ))] - #[allow(dead_code)] + #[allow(dead_code, unused_variables)] fn modify(f: impl FnOnce(&mut Bdcr) -> R) -> R { #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] let cr = crate::pac::PWR.cr(); @@ -40,7 +42,13 @@ impl BackupDomain { while !cr.read().dbp() {} } - crate::pac::RCC.bdcr().modify(|w| f(w)) + #[cfg(any(rtc_v2l0, rtc_v2l1))] + let cr = crate::pac::RCC.csr(); + + #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + let cr = crate::pac::RCC.bdcr(); + + cr.modify(|w| f(w)) } #[cfg(any( @@ -62,7 +70,7 @@ impl BackupDomain { rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5 ))] - #[allow(dead_code)] + #[allow(dead_code, unused_variables)] pub fn set_rtc_clock_source(clock_source: RtcClockSource) { let clock_source = clock_source as u8; #[cfg(any( -- cgit From 9f928010a86be9e0f8b5fa4257c3edd70261c0dc Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 16:06:33 -0500 Subject: stm32/rtc: use psc to compute instants --- embassy-stm32/src/rtc/mod.rs | 53 ++++++++++++++------------------------------ embassy-stm32/src/rtc/v2.rs | 4 ++-- 2 files changed, 19 insertions(+), 38 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index c408b2d61..8bda0926e 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -47,31 +47,6 @@ struct RtcInstant { subsecond: u16, } -#[cfg(feature = "low-power")] -impl RtcInstant { - pub fn now() -> Self { - let tr = RTC::regs().tr().read(); - let tr2 = RTC::regs().tr().read(); - let ssr = RTC::regs().ssr().read().ss(); - let ssr2 = RTC::regs().ssr().read().ss(); - - let st = bcd2_to_byte((tr.st(), tr.su())); - let st2 = bcd2_to_byte((tr2.st(), tr2.su())); - - assert!(st == st2); - assert!(ssr == ssr2); - - let _ = RTC::regs().dr().read(); - - let subsecond = ssr; - let second = st; - - // trace!("rtc: instant now: st, ssr: {}, {}", st, ssr); - - Self { second, subsecond } - } -} - #[cfg(feature = "low-power")] impl core::ops::Sub for RtcInstant { type Output = embassy_time::Duration; @@ -85,20 +60,13 @@ impl core::ops::Sub for RtcInstant { self.second }; - // TODO: read prescaler + let psc = RTC::regs().prer().read().prediv_s() as u32; - let self_ticks = second as u32 * 256 + (255 - self.subsecond as u32); - let other_ticks = rhs.second as u32 * 256 + (255 - rhs.subsecond as u32); + let self_ticks = second as u32 * (psc + 1) + (psc - self.subsecond as u32); + let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32); let rtc_ticks = self_ticks - other_ticks; - // trace!( - // "rtc: instant sub: self, other, rtc ticks: {}, {}, {}", - // self_ticks, - // other_ticks, - // rtc_ticks - // ); - - Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / 256u32) as u64) + Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / psc) as u64) } } @@ -198,6 +166,19 @@ impl Rtc { Ok(()) } + /// Return the current instant. + fn instant(&self) -> RtcInstant { + let r = RTC::regs(); + let tr = r.tr().read(); + let subsecond = r.ssr().read().ss(); + let second = bcd2_to_byte((tr.st(), tr.su())); + + // Unlock the registers + r.dr(); + + RtcInstant { second, subsecond } + } + /// Return the current datetime. /// /// # Errors diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 1e0ca9b48..62b398689 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -110,7 +110,7 @@ impl super::Rtc { trace!("rtc: start wakeup alarm for {} ms", duration.as_millis()); - critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(RtcInstant::now())).is_none())) + critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())) } #[cfg(feature = "low-power")] @@ -132,7 +132,7 @@ impl super::Rtc { critical_section::with(|cs| { if let Some(stop_time) = self.stop_time.borrow(cs).take() { - Some(RtcInstant::now() - stop_time) + Some(self.instant() - stop_time) } else { None } -- cgit From e981cd496827c01cba11fd6ba40b2b7ed482e49b Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 21:15:57 -0500 Subject: stm32: fix rtc wakeup timing and add dbg --- embassy-stm32/src/low_power.rs | 7 +++++++ embassy-stm32/src/rcc/f4.rs | 2 +- embassy-stm32/src/rtc/mod.rs | 14 ++++++++++++- embassy-stm32/src/rtc/v2.rs | 43 ++++++++++++++++++++++++++++++---------- embassy-stm32/src/time_driver.rs | 2 ++ 5 files changed, 56 insertions(+), 12 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 65b93f8a4..f9b5fde91 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -89,6 +89,9 @@ impl Executor { self.time_driver.resume_time(); trace!("low power: resume time"); + + #[cfg(feature = "rtc-debug")] + cortex_m::asm::bkpt(); } pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { @@ -118,6 +121,7 @@ impl Executor { } trace!("low power: enter stop..."); + #[cfg(not(feature = "rtc-debug"))] self.scb.set_sleepdeep(); } @@ -140,6 +144,9 @@ impl Executor { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + #[cfg(feature = "rtc-debug")] + trace!("low power: rtc debug enabled"); + init(unsafe { EXECUTOR.as_mut().unwrap() }.inner.spawner()); loop { diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index 10d3322aa..d8b689e41 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -17,7 +17,7 @@ use crate::{peripherals, Peripheral}; pub const HSI_FREQ: Hertz = Hertz(16_000_000); /// LSI speed -pub const LSI_FREQ: Hertz = Hertz(32_000); +pub const LSI_FREQ: Hertz = Hertz(32_768); /// Clocks configuration #[non_exhaustive] diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 8bda0926e..496ad5c1e 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -47,6 +47,18 @@ struct RtcInstant { subsecond: u16, } +#[cfg(all(feature = "low-power", feature = "defmt"))] +impl defmt::Format for RtcInstant { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!( + fmt, + "{}:{}", + self.second, + RTC::regs().prer().read().prediv_s() - self.subsecond, + ) + } +} + #[cfg(feature = "low-power")] impl core::ops::Sub for RtcInstant { type Output = embassy_time::Duration; @@ -174,7 +186,7 @@ impl Rtc { let second = bcd2_to_byte((tr.st(), tr.su())); // Unlock the registers - r.dr(); + r.dr().read(); RtcInstant { second, subsecond } } diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 62b398689..7eb8a96c4 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -1,7 +1,5 @@ use stm32_metapac::rtc::vals::{Init, Osel, Pol}; -#[cfg(feature = "low-power")] -use super::RtcInstant; use super::{sealed, RtcConfig}; use crate::pac::rtc::Rtc; use crate::peripherals::RTC; @@ -77,6 +75,21 @@ impl super::Rtc { /// start the wakeup alarm and wtih a duration that is as close to but less than /// the requested duration, and record the instant the wakeup alarm was started pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { + #[cfg(feature = "rtc-debug")] + if critical_section::with(|cs| { + if let Some(instant) = self.stop_time.borrow(cs).take() { + self.stop_time.borrow(cs).replace(Some(instant)); + + Some(()) + } else { + None + } + }) + .is_some() + { + return; + } + use embassy_time::{Duration, TICK_HZ}; use crate::rcc::get_freqs; @@ -86,17 +99,14 @@ impl super::Rtc { let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ; let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); - // adjust the rtc ticks to the prescaler + // adjust the rtc ticks to the prescaler and subtract one rtc tick let rtc_ticks = rtc_ticks / (>::into(prescaler) as u64); let rtc_ticks = if rtc_ticks >= u16::MAX as u64 { u16::MAX - 1 } else { rtc_ticks as u16 - }; - - let duration = Duration::from_ticks( - rtc_ticks as u64 * TICK_HZ * (>::into(prescaler) as u64) / rtc_hz, - ); + } + .saturating_sub(1); self.write(false, |regs| { regs.cr().modify(|w| w.set_wute(false)); @@ -104,11 +114,21 @@ impl super::Rtc { while !regs.isr().read().wutwf() {} regs.cr().modify(|w| w.set_wucksel(prescaler.into())); + regs.wutr().write(|w| w.set_wut(rtc_ticks)); regs.cr().modify(|w| w.set_wute(true)); regs.cr().modify(|w| w.set_wutie(true)); }); - trace!("rtc: start wakeup alarm for {} ms", duration.as_millis()); + trace!( + "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}", + Duration::from_ticks( + rtc_ticks as u64 * TICK_HZ * (>::into(prescaler) as u64) / rtc_hz, + ) + .as_millis(), + >::into(prescaler), + rtc_ticks, + self.instant(), + ); critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())) } @@ -119,7 +139,10 @@ impl super::Rtc { pub(crate) fn stop_wakeup_alarm(&self) -> Option { use crate::interrupt::typelevel::Interrupt; - trace!("rtc: stop wakeup alarm..."); + trace!("rtc: stop wakeup alarm at {}", self.instant()); + + #[cfg(feature = "rtc-debug")] + return None; self.write(false, |regs| { regs.cr().modify(|w| w.set_wutie(false)); diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 99d423d08..d4442c231 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -363,6 +363,7 @@ impl RtcDriver { .start_wakeup_alarm(time_until_next_alarm); }); + #[cfg(not(feature = "rtc-debug"))] T::regs_gp16().cr1().modify(|w| w.set_cen(false)); Ok(()) @@ -374,6 +375,7 @@ impl RtcDriver { pub(crate) fn resume_time(&self) { self.stop_wakeup_alarm(); + #[cfg(not(feature = "rtc-debug"))] T::regs_gp16().cr1().modify(|w| w.set_cen(true)); } } -- cgit From 538001a4bc4cdf647924d621347c851f13b6a95d Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 21:24:16 -0500 Subject: stm32/rtc: fix psc div --- embassy-stm32/src/rtc/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 496ad5c1e..ca3758550 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -78,7 +78,7 @@ impl core::ops::Sub for RtcInstant { let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32); let rtc_ticks = self_ticks - other_ticks; - Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / psc) as u64) + Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / (psc + 1)) as u64) } } -- cgit From 2c80784fe6e1a165cabae83baf7c842218a35046 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 27 Aug 2023 21:26:29 -0500 Subject: stm32/rtc: feature-gate instant --- embassy-stm32/src/rtc/mod.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index ca3758550..796fd7d96 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -178,6 +178,7 @@ impl Rtc { Ok(()) } + #[cfg(feature = "low-power")] /// Return the current instant. fn instant(&self) -> RtcInstant { let r = RTC::regs(); -- cgit From fd739250ea8b830f06f8a78a272874faa888d42c Mon Sep 17 00:00:00 2001 From: Olle Sandberg Date: Mon, 28 Aug 2023 11:27:56 +0200 Subject: stm32: fix wait for RNG data If no data was available to read then the loop would wait for an interrupt and skip to the next chunk without writing the current one. This could cause the given slice to only be partially filled with random data. Fixed by moving the wait to before actually writing data to the chunk. --- embassy-stm32/src/rng.rs | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 30816e436..0979dce8c 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -119,7 +119,31 @@ impl<'d, T: Instance> Rng<'d, T> { pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { for chunk in dest.chunks_mut(4) { - let bits = T::regs().sr().read(); + let mut bits = T::regs().sr().read(); + if !bits.seis() && !bits.ceis() && !bits.drdy() { + // wait for interrupt + poll_fn(|cx| { + // quick check to avoid registration if already done. + let bits = T::regs().sr().read(); + if bits.drdy() || bits.seis() || bits.ceis() { + return Poll::Ready(()); + } + RNG_WAKER.register(cx.waker()); + T::regs().cr().modify(|reg| reg.set_ie(true)); + // Need to check condition **after** `register` to avoid a race + // condition that would result in lost notifications. + let bits = T::regs().sr().read(); + if bits.drdy() || bits.seis() || bits.ceis() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + + // Re-read the status register after wait. + bits = T::regs().sr().read() + } if bits.seis() { // in case of noise-source or seed error we try to recover here // but we must not use the data in DR and we return an error @@ -143,26 +167,6 @@ impl<'d, T: Instance> Rng<'d, T> { for (dest, src) in chunk.iter_mut().zip(random_word.to_be_bytes().iter()) { *dest = *src } - } else { - // wait for interrupt - poll_fn(|cx| { - // quick check to avoid registration if already done. - let bits = T::regs().sr().read(); - if bits.drdy() || bits.seis() || bits.ceis() { - return Poll::Ready(()); - } - RNG_WAKER.register(cx.waker()); - T::regs().cr().modify(|reg| reg.set_ie(true)); - // Need to check condition **after** `register` to avoid a race - // condition that would result in lost notifications. - let bits = T::regs().sr().read(); - if bits.drdy() || bits.seis() || bits.ceis() { - Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await; } } -- cgit From b315c28d4eda4fe62747d7f626226862cbc92629 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 28 Aug 2023 15:30:29 -0500 Subject: stm32/rtc: remove rtc-debug and asbtract exti wakeup --- embassy-stm32/src/low_power.rs | 10 +--------- embassy-stm32/src/rtc/v2.rs | 26 ++++++++------------------ embassy-stm32/src/time_driver.rs | 2 -- 3 files changed, 9 insertions(+), 29 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index f9b5fde91..d0230ed72 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -89,9 +89,6 @@ impl Executor { self.time_driver.resume_time(); trace!("low power: resume time"); - - #[cfg(feature = "rtc-debug")] - cortex_m::asm::bkpt(); } pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { @@ -102,8 +99,7 @@ impl Executor { crate::interrupt::typelevel::RTC_WKUP::unpend(); unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; - EXTI.rtsr(0).modify(|w| w.set_line(22, true)); - EXTI.imr(0).modify(|w| w.set_line(22, true)); + rtc.enable_wakeup_line(); } fn configure_pwr(&mut self) { @@ -121,7 +117,6 @@ impl Executor { } trace!("low power: enter stop..."); - #[cfg(not(feature = "rtc-debug"))] self.scb.set_sleepdeep(); } @@ -144,9 +139,6 @@ impl Executor { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { - #[cfg(feature = "rtc-debug")] - trace!("low power: rtc debug enabled"); - init(unsafe { EXECUTOR.as_mut().unwrap() }.inner.spawner()); loop { diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 7eb8a96c4..49f66e957 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -75,21 +75,6 @@ impl super::Rtc { /// start the wakeup alarm and wtih a duration that is as close to but less than /// the requested duration, and record the instant the wakeup alarm was started pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { - #[cfg(feature = "rtc-debug")] - if critical_section::with(|cs| { - if let Some(instant) = self.stop_time.borrow(cs).take() { - self.stop_time.borrow(cs).replace(Some(instant)); - - Some(()) - } else { - None - } - }) - .is_some() - { - return; - } - use embassy_time::{Duration, TICK_HZ}; use crate::rcc::get_freqs; @@ -133,6 +118,14 @@ impl super::Rtc { critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())) } + #[cfg(feature = "low-power")] + pub(crate) fn enable_wakeup_line(&self) { + use crate::pac::EXTI; + + EXTI.rtsr(0).modify(|w| w.set_line(22, true)); + EXTI.imr(0).modify(|w| w.set_line(22, true)); + } + #[cfg(feature = "low-power")] /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` /// was called, otherwise none @@ -141,9 +134,6 @@ impl super::Rtc { trace!("rtc: stop wakeup alarm at {}", self.instant()); - #[cfg(feature = "rtc-debug")] - return None; - self.write(false, |regs| { regs.cr().modify(|w| w.set_wutie(false)); regs.cr().modify(|w| w.set_wute(false)); diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index d4442c231..99d423d08 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -363,7 +363,6 @@ impl RtcDriver { .start_wakeup_alarm(time_until_next_alarm); }); - #[cfg(not(feature = "rtc-debug"))] T::regs_gp16().cr1().modify(|w| w.set_cen(false)); Ok(()) @@ -375,7 +374,6 @@ impl RtcDriver { pub(crate) fn resume_time(&self) { self.stop_wakeup_alarm(); - #[cfg(not(feature = "rtc-debug"))] T::regs_gp16().cr1().modify(|w| w.set_cen(true)); } } -- cgit From 70a5221b2e0d40a43794bf65fc4d84e0af8ab079 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 28 Aug 2023 15:34:08 -0500 Subject: stm32/bd: consolidate enable_rtc --- embassy-stm32/src/rcc/bd.rs | 39 +++++++-------------------------------- 1 file changed, 7 insertions(+), 32 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 0fc116ed8..4d8ed82aa 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -87,13 +87,14 @@ impl BackupDomain { } #[cfg(any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, + rtc_v3u5 ))] #[allow(dead_code)] pub fn enable_rtc() { let reg = Self::read(); - #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))] + #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); if !reg.rtcen() { @@ -102,47 +103,21 @@ impl BackupDomain { Self::modify(|w| { // Reset - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] + #[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))] w.set_bdrst(false); w.set_rtcen(true); w.set_rtcsel(reg.rtcsel()); // Restore bcdr - #[cfg(any(rtc_v2l4, rtc_v2wb))] + #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] w.set_lscosel(reg.lscosel()); - #[cfg(any(rtc_v2l4, rtc_v2wb))] + #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] w.set_lscoen(reg.lscoen()); w.set_lseon(reg.lseon()); - #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))] - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); - }); - } - } - - #[cfg(any(rtc_v3, rtc_v3u5))] - #[allow(dead_code)] - pub fn enable_rtc() { - let reg = Self::read(); - assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); - - if !reg.rtcen() { - Self::modify(|w| w.set_bdrst(true)); - - Self::modify(|w| { - w.set_bdrst(false); - - w.set_rtcen(true); - w.set_rtcsel(reg.rtcsel()); - - // Restore bcdr - w.set_lscosel(reg.lscosel()); - w.set_lscoen(reg.lscoen()); - - w.set_lseon(reg.lseon()); + #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] w.set_lsedrv(reg.lsedrv()); w.set_lsebyp(reg.lsebyp()); }); -- cgit From e07f9435624ea739282665d09fe0f996c71ef54c Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 28 Aug 2023 15:52:13 -0500 Subject: rustfmt --- embassy-stm32/src/low_power.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index d0230ed72..7e678d323 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -6,7 +6,6 @@ use embassy_executor::*; use crate::interrupt; use crate::interrupt::typelevel::Interrupt; -use crate::pac::EXTI; use crate::rcc::low_power_ready; use crate::time_driver::{get_driver, RtcDriver}; -- cgit From 6b8b145266faaa06f6483ccb8d227c8060c9a46d Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 28 Aug 2023 16:17:42 -0500 Subject: stm32: revert changes to rcc f4 --- embassy-stm32/src/rcc/f4.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index d8b689e41..10d3322aa 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -17,7 +17,7 @@ use crate::{peripherals, Peripheral}; pub const HSI_FREQ: Hertz = Hertz(16_000_000); /// LSI speed -pub const LSI_FREQ: Hertz = Hertz(32_768); +pub const LSI_FREQ: Hertz = Hertz(32_000); /// Clocks configuration #[non_exhaustive] -- cgit From 5e613d9abbb945e7fc7d4c895d645bfad6a3d2c8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 30 Aug 2023 01:37:18 +0200 Subject: Sync all fmt.rs files. --- embassy-stm32/src/fmt.rs | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/fmt.rs b/embassy-stm32/src/fmt.rs index 066970813..78e583c1c 100644 --- a/embassy-stm32/src/fmt.rs +++ b/embassy-stm32/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} -- cgit From 989c98f316df3cde4512066e3682debb47d48161 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 29 Aug 2023 19:41:03 -0500 Subject: stm32/rtc: autocompute prescalers --- embassy-stm32/src/rcc/f4.rs | 1 + embassy-stm32/src/rcc/mod.rs | 6 +++- embassy-stm32/src/rtc/mod.rs | 72 ++++++++++++++++++-------------------------- embassy-stm32/src/rtc/v2.rs | 6 ++-- embassy-stm32/src/rtc/v3.rs | 6 ++-- 5 files changed, 41 insertions(+), 50 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index 10d3322aa..c2c78a45e 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -499,6 +499,7 @@ pub(crate) unsafe fn init(config: Config) { pllsai: None, rtc: rtc, + rtc_hse: None, }); } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 9f1b3b663..1ead60b18 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -78,8 +78,12 @@ pub struct Clocks { pub adc: Option, #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] - /// Set only if the lsi or lse is configured + /// Set only if the lsi or lse is configured, indicates stop is supported pub rtc: Option, + + #[cfg(any(rcc_f4, rcc_f410))] + /// Set if the hse is configured, indicates stop is not supported + pub rtc_hse: Option, } #[cfg(feature = "low-power")] diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 796fd7d96..3704e4464 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -12,6 +12,7 @@ use embassy_sync::blocking_mutex::Mutex; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; use crate::rcc::bd::BackupDomain; pub use crate::rcc::RtcClockSource; +use crate::time::Hertz; /// refer to AN4759 to compare features of RTC2 and RTC3 #[cfg_attr(any(rtc_v1), path = "v1.rs")] @@ -84,47 +85,23 @@ impl core::ops::Sub for RtcInstant { /// RTC Abstraction pub struct Rtc { - rtc_config: RtcConfig, #[cfg(feature = "low-power")] stop_time: Mutex>>, } #[derive(Copy, Clone, PartialEq)] pub struct RtcConfig { - /// Asynchronous prescaler factor - /// This is the asynchronous division factor: - /// ck_apre frequency = RTCCLK frequency/(PREDIV_A+1) - /// ck_apre drives the subsecond register - async_prescaler: u8, - /// Synchronous prescaler factor - /// This is the synchronous division factor: - /// ck_spre frequency = ck_apre frequency/(PREDIV_S+1) - /// ck_spre must be 1Hz - sync_prescaler: u16, + /// The subsecond counter frequency; default is 256 + /// + /// A high counter frequency may impact stop power consumption + pub frequency: Hertz, } impl Default for RtcConfig { /// LSI with prescalers assuming 32.768 kHz. /// Raw sub-seconds in 1/256. fn default() -> Self { - RtcConfig { - async_prescaler: 127, - sync_prescaler: 255, - } - } -} - -impl RtcConfig { - /// Set the asynchronous prescaler of RTC config - pub fn async_prescaler(mut self, prescaler: u8) -> Self { - self.async_prescaler = prescaler; - self - } - - /// Set the synchronous prescaler of RTC config - pub fn sync_prescaler(mut self, prescaler: u16) -> Self { - self.sync_prescaler = prescaler; - self + RtcConfig { frequency: Hertz(256) } } } @@ -147,23 +124,36 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { - RTC::enable_peripheral_clk(); + use crate::rcc::get_freqs; - #[cfg(not(feature = "low-power"))] - let mut rtc_struct = Self { rtc_config }; + RTC::enable_peripheral_clk(); + BackupDomain::enable_rtc(); - #[cfg(feature = "low-power")] - let mut rtc_struct = Self { - rtc_config, + let mut this = Self { + #[cfg(feature = "low-power")] stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), }; - BackupDomain::enable_rtc(); + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] + let freqs = unsafe { get_freqs() }; + + // Load the clock frequency from the rcc mod, if supported + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] + let frequency = match freqs.rtc { + Some(hertz) => hertz, + None => freqs.rtc_hse.unwrap(), + }; - rtc_struct.configure(rtc_config); - rtc_struct.rtc_config = rtc_config; + // Assume the default value, if not supported + #[cfg(not(any(rcc_wb, rcc_f4, rcc_f410)))] + let frequency = Hertz(32_768); - rtc_struct + let async_psc = ((frequency.0 / rtc_config.frequency.0) - 1) as u8; + let sync_psc = (rtc_config.frequency.0 - 1) as u16; + + this.configure(async_psc, sync_psc); + + this } /// Set the datetime to a new value. @@ -228,10 +218,6 @@ impl Rtc { }) } - pub fn get_config(&self) -> RtcConfig { - self.rtc_config - } - pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT; /// Read content of the backup register. diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 49f66e957..63d9f09e7 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -154,7 +154,7 @@ impl super::Rtc { /// Applies the RTC config /// It this changes the RTC clock source the time will be reset - pub(super) fn configure(&mut self, rtc_config: RtcConfig) { + pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { self.write(true, |rtc| { rtc.cr().modify(|w| { #[cfg(rtc_v2f2)] @@ -166,8 +166,8 @@ impl super::Rtc { }); rtc.prer().modify(|w| { - w.set_prediv_s(rtc_config.sync_prescaler); - w.set_prediv_a(rtc_config.async_prescaler); + w.set_prediv_s(sync_psc); + w.set_prediv_a(async_psc); }); }); } diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 12952b15a..c03b1071d 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -8,7 +8,7 @@ use crate::rtc::sealed::Instance; impl super::Rtc { /// Applies the RTC config /// It this changes the RTC clock source the time will be reset - pub(super) fn configure(&mut self, rtc_config: RtcConfig) { + pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { self.write(true, |rtc| { rtc.cr().modify(|w| { w.set_fmt(Fmt::TWENTYFOURHOUR); @@ -17,8 +17,8 @@ impl super::Rtc { }); rtc.prer().modify(|w| { - w.set_prediv_s(rtc_config.sync_prescaler); - w.set_prediv_a(rtc_config.async_prescaler); + w.set_prediv_s(sync_psc); + w.set_prediv_a(async_psc); }); // TODO: configuration for output pins -- cgit From 21681d8b4ee392ce3b4f68be76b6096abe104ad3 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 29 Aug 2023 19:44:43 -0500 Subject: rustfmt --- embassy-stm32/src/rtc/mod.rs | 1 + embassy-stm32/src/rtc/v2.rs | 2 +- embassy-stm32/src/rtc/v3.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 3704e4464..9db4f69c5 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -124,6 +124,7 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] use crate::rcc::get_freqs; RTC::enable_peripheral_clk(); diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 63d9f09e7..482b6e75d 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -1,6 +1,6 @@ use stm32_metapac::rtc::vals::{Init, Osel, Pol}; -use super::{sealed, RtcConfig}; +use super::sealed; use crate::pac::rtc::Rtc; use crate::peripherals::RTC; use crate::rtc::sealed::Instance; diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index c03b1071d..a6b2655d8 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -1,6 +1,6 @@ use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Init, Key, Osel, Pol, TampalrmPu, TampalrmType}; -use super::{sealed, RtcCalibrationCyclePeriod, RtcConfig}; +use super::{sealed, RtcCalibrationCyclePeriod}; use crate::pac::rtc::Rtc; use crate::peripherals::RTC; use crate::rtc::sealed::Instance; -- cgit From 27dfced285f7f997d6a7679373052efb7ae84e01 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 29 Aug 2023 19:51:21 -0500 Subject: stm32: fix rcc wb --- embassy-stm32/src/rcc/mod.rs | 2 +- embassy-stm32/src/rcc/wb.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 1ead60b18..0430e4a74 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -81,7 +81,7 @@ pub struct Clocks { /// Set only if the lsi or lse is configured, indicates stop is supported pub rtc: Option, - #[cfg(any(rcc_f4, rcc_f410))] + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] /// Set if the hse is configured, indicates stop is not supported pub rtc_hse: Option, } diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index 6a3eab707..6496b41e1 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -271,6 +271,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { apb1_tim: apb1_tim_clk, apb2_tim: apb2_tim_clk, rtc: rtc_clk, + rtc_hse: None, } } -- cgit From 416ecc73d8211e348bf51a5cfe84075673b18963 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 29 Aug 2023 20:06:53 -0500 Subject: add qei draft --- embassy-stm32/src/timer/qei.rs | 142 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 embassy-stm32/src/timer/qei.rs (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs new file mode 100644 index 000000000..fa8814722 --- /dev/null +++ b/embassy-stm32/src/timer/qei.rs @@ -0,0 +1,142 @@ +//! # Quadrature Encoder Interface +use crate::{ + gpio::PushPull, + pac, rcc, + timer::{CPin, General}, +}; + +pub trait QeiExt: Sized + Instance { + fn qei( + self, + pins: ( + impl Into<>::Ch>, + impl Into<>::Ch>, + ), + ) -> Qei; +} + +impl QeiExt for TIM { + fn qei( + self, + pins: ( + impl Into<>::Ch>, + impl Into<>::Ch>, + ), + ) -> Qei { + Qei::new(self, pins) + } +} + +/// Hardware quadrature encoder interface peripheral +pub struct Qei { + tim: TIM, + pins: ( + >::Ch, + >::Ch, + ), +} + +impl Qei { + /// Configures a TIM peripheral as a quadrature encoder interface input + pub fn new( + mut tim: TIM, + pins: ( + impl Into<>::Ch>, + impl Into<>::Ch>, + ), + ) -> Self { + // Enable and reset clock. + unsafe { + TIM::enable_unchecked(); + TIM::reset_unchecked(); + } + + let pins = (pins.0.into(), pins.1.into()); + tim.setup_qei(); + + Qei { tim, pins } + } + + /// Releases the TIM peripheral and QEI pins + #[allow(clippy::type_complexity)] + pub fn release( + self, + ) -> ( + TIM, + ( + >::Ch, + >::Ch, + ), + ) { + (self.tim, self.pins) + } + + /// Set current count number + pub fn set_count(&mut self, value: TIM::Width) -> &mut Self { + self.tim.write_count(value); + self + } +} + +impl embedded_hal::Qei for Qei { + type Count = TIM::Width; + + fn count(&self) -> Self::Count { + self.tim.read_count() + } + + fn direction(&self) -> embedded_hal::Direction { + if self.tim.read_direction() { + embedded_hal::Direction::Upcounting + } else { + embedded_hal::Direction::Downcounting + } + } +} + +pub trait Instance: crate::Sealed + rcc::Enable + rcc::Reset + General + CPin<0> + CPin<1> { + fn setup_qei(&mut self); + + fn read_direction(&self) -> bool; +} + +macro_rules! hal { + ($TIM:ty) => { + impl Instance for $TIM { + fn setup_qei(&mut self) { + // Configure TxC1 and TxC2 as captures + #[cfg(not(feature = "gpio-f410"))] + self.ccmr1_input().write(|w| w.cc1s().ti1().cc2s().ti2()); + #[cfg(feature = "gpio-f410")] + self.ccmr1_input() + .write(|w| unsafe { w.cc1s().bits(0b01).cc2s().bits(0b01) }); + // enable and configure to capture on rising edge + self.ccer.write(|w| { + w.cc1e().set_bit().cc1p().clear_bit(); + w.cc2e().set_bit().cc2p().clear_bit() + }); + self.smcr.write(|w| w.sms().encoder_mode_3()); + self.set_auto_reload(<$TIM as General>::Width::MAX as u32) + .unwrap(); + self.cr1.write(|w| w.cen().set_bit()); + } + + fn read_direction(&self) -> bool { + self.cr1.read().dir().bit_is_clear() + } + } + }; +} + +#[cfg(feature = "tim1")] +hal! { pac::TIM1 } +#[cfg(feature = "tim2")] +hal! { pac::TIM2 } +#[cfg(feature = "tim3")] +hal! { pac::TIM3 } +#[cfg(feature = "tim4")] +hal! { pac::TIM4 } +#[cfg(feature = "tim5")] +hal! { pac::TIM5 } +#[cfg(feature = "tim8")] +hal! { pac::TIM8 } -- cgit From 36ec9bcc1d4ed9beff2e866bcb5ea388538320bb Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Wed, 30 Aug 2023 19:35:15 +0200 Subject: Stm32 timer prevent hardfault --- embassy-stm32/src/timer/mod.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 4ffb2a289..b5ced45fe 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -211,6 +211,7 @@ macro_rules! impl_basic_16bit_timer { use core::convert::TryInto; let f = frequency.0; let timer_f = Self::frequency().0; + assert!(f > 0); let pclk_ticks_per_timer_period = timer_f / f; let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into()); let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into()); @@ -255,6 +256,7 @@ macro_rules! impl_32bit_timer { fn set_frequency(&mut self, frequency: Hertz) { use core::convert::TryInto; let f = frequency.0; + assert!(f > 0); let timer_f = Self::frequency().0; let pclk_ticks_per_timer_period = (timer_f / f) as u64; let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into()); -- cgit From c10fb7c1c4ca40749494f4873c2144906c2f1a17 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 30 Aug 2023 18:10:26 -0500 Subject: stm32: implement qei --- embassy-stm32/src/timer/mod.rs | 1 + embassy-stm32/src/timer/qei.rs | 198 ++++++++++++++++------------------------- 2 files changed, 77 insertions(+), 122 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 4ffb2a289..6036a4561 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -1,4 +1,5 @@ pub mod complementary_pwm; +pub mod qei; pub mod simple_pwm; use stm32_metapac::timer::vals; diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index fa8814722..c0f9288a5 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -1,142 +1,96 @@ -//! # Quadrature Encoder Interface -use crate::{ - gpio::PushPull, - pac, rcc, - timer::{CPin, General}, -}; - -pub trait QeiExt: Sized + Instance { - fn qei( - self, - pins: ( - impl Into<>::Ch>, - impl Into<>::Ch>, - ), - ) -> Qei; -} +use core::marker::PhantomData; -impl QeiExt for TIM { - fn qei( - self, - pins: ( - impl Into<>::Ch>, - impl Into<>::Ch>, - ), - ) -> Qei { - Qei::new(self, pins) - } +use embassy_hal_internal::{into_ref, PeripheralRef}; + +use super::*; +use crate::gpio::sealed::AFType; +use crate::gpio::AnyPin; +use crate::Peripheral; + +pub enum Direction { + Upcounting, + Downcounting, } -/// Hardware quadrature encoder interface peripheral -pub struct Qei { - tim: TIM, - pins: ( - >::Ch, - >::Ch, - ), +pub struct Ch1; +pub struct Ch2; + +pub struct QeiPin<'d, Perip, Channel> { + _pin: PeripheralRef<'d, AnyPin>, + phantom: PhantomData<(Perip, Channel)>, } -impl Qei { - /// Configures a TIM peripheral as a quadrature encoder interface input - pub fn new( - mut tim: TIM, - pins: ( - impl Into<>::Ch>, - impl Into<>::Ch>, - ), - ) -> Self { - // Enable and reset clock. - unsafe { - TIM::enable_unchecked(); - TIM::reset_unchecked(); +macro_rules! channel_impl { + ($new_chx:ident, $channel:ident, $pin_trait:ident) => { + impl<'d, Perip: CaptureCompare16bitInstance> QeiPin<'d, Perip, $channel> { + pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { + into_ref!(pin); + critical_section::with(|_| { + pin.set_low(); + pin.set_as_af(pin.af_num(), AFType::Input); + #[cfg(gpio_v2)] + pin.set_speed(crate::gpio::Speed::VeryHigh); + }); + QeiPin { + _pin: pin.map_into(), + phantom: PhantomData, + } + } } + }; +} - let pins = (pins.0.into(), pins.1.into()); - tim.setup_qei(); +channel_impl!(new_ch1, Ch1, Channel1Pin); +channel_impl!(new_ch2, Ch2, Channel2Pin); - Qei { tim, pins } - } +pub struct SimplePwm<'d, T> { + _inner: PeripheralRef<'d, T>, +} - /// Releases the TIM peripheral and QEI pins - #[allow(clippy::type_complexity)] - pub fn release( - self, - ) -> ( - TIM, - ( - >::Ch, - >::Ch, - ), - ) { - (self.tim, self.pins) +impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { + pub fn new(tim: impl Peripheral

+ 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { + Self::new_inner(tim) } - /// Set current count number - pub fn set_count(&mut self, value: TIM::Width) -> &mut Self { - self.tim.write_count(value); - self - } -} + fn new_inner(tim: impl Peripheral

+ 'd) -> Self { + into_ref!(tim); -impl embedded_hal::Qei for Qei { - type Count = TIM::Width; + T::enable(); + ::reset(); - fn count(&self) -> Self::Count { - self.tim.read_count() - } + // Configure TxC1 and TxC2 as captures + T::regs_gp16().ccmr_input(0).modify(|w| { + w.set_ccs(0, vals::CcmrInputCcs::TI4); + w.set_ccs(1, vals::CcmrInputCcs::TI4); + }); - fn direction(&self) -> embedded_hal::Direction { - if self.tim.read_direction() { - embedded_hal::Direction::Upcounting - } else { - embedded_hal::Direction::Downcounting - } - } -} + // enable and configure to capture on rising edge + T::regs_gp16().ccer().modify(|w| { + w.set_cce(0, true); + w.set_cce(1, true); -pub trait Instance: crate::Sealed + rcc::Enable + rcc::Reset + General + CPin<0> + CPin<1> { - fn setup_qei(&mut self); + w.set_ccp(0, false); + w.set_ccp(1, false); + }); - fn read_direction(&self) -> bool; -} + T::regs_gp16().smcr().modify(|w| { + w.set_sms(vals::Sms::ENCODER_MODE_3); + }); -macro_rules! hal { - ($TIM:ty) => { - impl Instance for $TIM { - fn setup_qei(&mut self) { - // Configure TxC1 and TxC2 as captures - #[cfg(not(feature = "gpio-f410"))] - self.ccmr1_input().write(|w| w.cc1s().ti1().cc2s().ti2()); - #[cfg(feature = "gpio-f410")] - self.ccmr1_input() - .write(|w| unsafe { w.cc1s().bits(0b01).cc2s().bits(0b01) }); - // enable and configure to capture on rising edge - self.ccer.write(|w| { - w.cc1e().set_bit().cc1p().clear_bit(); - w.cc2e().set_bit().cc2p().clear_bit() - }); - self.smcr.write(|w| w.sms().encoder_mode_3()); - self.set_auto_reload(<$TIM as General>::Width::MAX as u32) - .unwrap(); - self.cr1.write(|w| w.cen().set_bit()); - } + T::regs_gp16().arr().modify(|w| w.set_arr(u16::MAX)); + T::regs_gp16().cr1().modify(|w| w.set_cen(true)); - fn read_direction(&self) -> bool { - self.cr1.read().dir().bit_is_clear() - } + Self { _inner: tim } + } + + pub fn read_direction(&self) -> Direction { + match T::regs_gp16().cr1().read().dir() { + vals::Dir::DOWN => Direction::Downcounting, + vals::Dir::UP => Direction::Upcounting, } - }; -} + } -#[cfg(feature = "tim1")] -hal! { pac::TIM1 } -#[cfg(feature = "tim2")] -hal! { pac::TIM2 } -#[cfg(feature = "tim3")] -hal! { pac::TIM3 } -#[cfg(feature = "tim4")] -hal! { pac::TIM4 } -#[cfg(feature = "tim5")] -hal! { pac::TIM5 } -#[cfg(feature = "tim8")] -hal! { pac::TIM8 } + pub fn count(&self) -> u16 { + T::regs_gp16().cnt().read().cnt() + } +} -- cgit From 1d87ec9cc36442542814d6dca7ae8e71068820e1 Mon Sep 17 00:00:00 2001 From: xoviat <49173759+xoviat@users.noreply.github.com> Date: Fri, 1 Sep 2023 17:30:27 -0500 Subject: stm32/qei: fix struct naming (#1852) Co-authored-by: xoviat --- embassy-stm32/src/timer/qei.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index c0f9288a5..15f2c3a79 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -43,11 +43,11 @@ macro_rules! channel_impl { channel_impl!(new_ch1, Ch1, Channel1Pin); channel_impl!(new_ch2, Ch2, Channel2Pin); -pub struct SimplePwm<'d, T> { +pub struct Qei<'d, T> { _inner: PeripheralRef<'d, T>, } -impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { +impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { pub fn new(tim: impl Peripheral

+ 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { Self::new_inner(tim) } -- cgit From 2e6f4237f2410aa18c9866a5a1a5ed1f3bec8a4e Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 3 Sep 2023 11:40:34 -0500 Subject: stm32: cleanup psc design --- embassy-stm32/src/hrtim/traits.rs | 49 ++++++++++++--------------------------- embassy-stm32/src/rtc/v2.rs | 31 +++++++------------------ 2 files changed, 24 insertions(+), 56 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index 158a68862..095109598 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs @@ -1,31 +1,17 @@ use crate::rcc::sealed::RccPeripheral; use crate::time::Hertz; +#[repr(u8)] #[derive(Clone, Copy)] pub(crate) enum Prescaler { - Div1, - Div2, - Div4, - Div8, - Div16, - Div32, - Div64, - Div128, -} - -impl From for u32 { - fn from(val: Prescaler) -> Self { - match val { - Prescaler::Div1 => 1, - Prescaler::Div2 => 2, - Prescaler::Div4 => 4, - Prescaler::Div8 => 8, - Prescaler::Div16 => 16, - Prescaler::Div32 => 32, - Prescaler::Div64 => 64, - Prescaler::Div128 => 128, - } - } + Div1 = 1, + Div2 = 2, + Div4 = 4, + Div8 = 8, + Div16 = 16, + Div32 = 32, + Div64 = 64, + Div128 = 128, } impl From for u8 { @@ -72,7 +58,7 @@ impl Prescaler { Prescaler::Div128, ] .iter() - .skip_while(|psc| >::into(**psc) <= val) + .skip_while(|psc| **psc as u32 <= val) .next() .unwrap() } @@ -80,7 +66,7 @@ impl Prescaler { pub fn compute_min_low_res(val: u32) -> Self { *[Prescaler::Div32, Prescaler::Div64, Prescaler::Div128] .iter() - .skip_while(|psc| >::into(**psc) <= val) + .skip_while(|psc| **psc as u32 <= val) .next() .unwrap() } @@ -126,8 +112,7 @@ foreach_interrupt! { Prescaler::compute_min_low_res(psc_min) }; - let psc_val: u32 = psc.into(); - let timer_f = 32 * (timer_f / psc_val); + let timer_f = 32 * (timer_f / psc as u32); let per: u16 = (timer_f / f) as u16; let regs = Self::regs(); @@ -148,8 +133,7 @@ foreach_interrupt! { Prescaler::compute_min_low_res(psc_min) }; - let psc_val: u32 = psc.into(); - let timer_f = 32 * (timer_f / psc_val); + let timer_f = 32 * (timer_f / psc as u32); let per: u16 = (timer_f / f) as u16; let regs = Self::regs(); @@ -163,20 +147,17 @@ foreach_interrupt! { let regs = Self::regs(); let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into(); - let psc_val: u32 = channel_psc.into(); - // The dead-time base clock runs 4 times slower than the hrtim base clock // u9::MAX = 511 - let psc_min = (psc_val * dead_time as u32) / (4 * 511); + let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511); let psc = if Self::regs().isr().read().dllrdy() { Prescaler::compute_min_high_res(psc_min) } else { Prescaler::compute_min_low_res(psc_min) }; - let dt_psc_val: u32 = psc.into(); - let dt_val = (dt_psc_val * dead_time as u32) / (4 * psc_val); + let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32); regs.tim(channel).dt().modify(|w| { w.set_dtprsc(psc.into()); diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 482b6e75d..62d8d4f9c 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -6,12 +6,13 @@ use crate::peripherals::RTC; use crate::rtc::sealed::Instance; #[allow(dead_code)] +#[repr(u8)] #[derive(Clone, Copy, Debug)] pub(crate) enum WakeupPrescaler { - Div2, - Div4, - Div8, - Div16, + Div2 = 2, + Div4 = 4, + Div8 = 8, + Div16 = 16, } #[cfg(any(stm32wb, stm32f4))] @@ -43,17 +44,6 @@ impl From for WakeupPrescaler { } } -impl From for u32 { - fn from(val: WakeupPrescaler) -> Self { - match val { - WakeupPrescaler::Div2 => 2, - WakeupPrescaler::Div4 => 4, - WakeupPrescaler::Div8 => 8, - WakeupPrescaler::Div16 => 16, - } - } -} - #[allow(dead_code)] impl WakeupPrescaler { pub fn compute_min(val: u32) -> Self { @@ -64,7 +54,7 @@ impl WakeupPrescaler { WakeupPrescaler::Div16, ] .iter() - .skip_while(|psc| >::into(**psc) <= val) + .skip_while(|psc| **psc as u32 <= val) .next() .unwrap_or(&WakeupPrescaler::Div16) } @@ -85,7 +75,7 @@ impl super::Rtc { let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); // adjust the rtc ticks to the prescaler and subtract one rtc tick - let rtc_ticks = rtc_ticks / (>::into(prescaler) as u64); + let rtc_ticks = rtc_ticks / prescaler as u64; let rtc_ticks = if rtc_ticks >= u16::MAX as u64 { u16::MAX - 1 } else { @@ -106,11 +96,8 @@ impl super::Rtc { trace!( "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}", - Duration::from_ticks( - rtc_ticks as u64 * TICK_HZ * (>::into(prescaler) as u64) / rtc_hz, - ) - .as_millis(), - >::into(prescaler), + Duration::from_ticks(rtc_ticks as u64 * TICK_HZ * prescaler as u64 / rtc_hz).as_millis(), + prescaler as u32, rtc_ticks, self.instant(), ); -- cgit From 274f63a879353923feac87f399aae9c5cadd4aa3 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 4 Sep 2023 15:47:33 -0500 Subject: stm32: fix refcounts for usart, spi, and i2c --- embassy-stm32/src/i2c/v1.rs | 6 ++++++ embassy-stm32/src/i2c/v2.rs | 6 ++++++ embassy-stm32/src/spi/mod.rs | 2 ++ embassy-stm32/src/usart/buffered.rs | 10 ++++++++++ embassy-stm32/src/usart/mod.rs | 18 ++++++++++++++++++ embassy-stm32/src/usart/ringbuffered.rs | 17 ++++++++++++----- 6 files changed, 54 insertions(+), 5 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 618d85af2..f32dd0f0c 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -339,6 +339,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } +impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { + fn drop(&mut self) { + T::disable(); + } +} + impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { type Error = Error; diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 4327899bb..36f70e32e 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -838,6 +838,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } +impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { + fn drop(&mut self) { + T::disable(); + } +} + mod eh02 { use super::*; diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index e2bc8d7f2..853de98f9 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -646,6 +646,8 @@ impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { 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(); } } diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 596d40bf9..989c88205 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -124,6 +124,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { rx_buffer: &'d mut [u8], config: Config, ) -> BufferedUart<'d, T> { + // UartRx and UartTx have one refcount ea. + T::enable(); T::enable(); T::reset(); @@ -143,6 +145,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { ) -> BufferedUart<'d, T> { into_ref!(cts, rts); + // UartRx and UartTx have one refcount ea. + T::enable(); T::enable(); T::reset(); @@ -169,6 +173,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { ) -> BufferedUart<'d, T> { into_ref!(de); + // UartRx and UartTx have one refcount ea. + T::enable(); T::enable(); T::reset(); @@ -382,6 +388,8 @@ impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> { T::Interrupt::disable(); } } + + T::disable(); } } @@ -397,6 +405,8 @@ impl<'d, T: BasicInstance> Drop for BufferedUartTx<'d, T> { T::Interrupt::disable(); } } + + T::disable(); } } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 255ddfd4b..bfb056718 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -618,6 +618,18 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { } } +impl<'d, T: BasicInstance, TxDma> Drop for UartTx<'d, T, TxDma> { + fn drop(&mut self) { + T::disable(); + } +} + +impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> { + fn drop(&mut self) { + T::disable(); + } +} + impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { pub fn new( peri: impl Peripheral

+ 'd, @@ -628,6 +640,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { rx_dma: impl Peripheral

+ 'd, config: Config, ) -> Self { + // UartRx and UartTx have one refcount ea. + T::enable(); T::enable(); T::reset(); @@ -647,6 +661,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { ) -> Self { into_ref!(cts, rts); + // UartRx and UartTx have one refcount ea. + T::enable(); T::enable(); T::reset(); @@ -672,6 +688,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { ) -> Self { into_ref!(de); + // UartRx and UartTx have one refcount ea. + T::enable(); T::enable(); T::reset(); diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index b3f570624..e990eaca8 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -1,4 +1,5 @@ use core::future::poll_fn; +use core::mem; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; @@ -24,12 +25,16 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> UartRx<'d, T, RxDma> { let request = self.rx_dma.request(); let opts = Default::default(); - let ring_buf = unsafe { ReadableRingBuffer::new_read(self.rx_dma, request, rdr(T::regs()), dma_buf, opts) }; + // Safety: we forget the struct before this function returns. + let rx_dma = unsafe { self.rx_dma.clone_unchecked() }; + let _peri = unsafe { self._peri.clone_unchecked() }; - RingBufferedUartRx { - _peri: self._peri, - ring_buf, - } + let ring_buf = unsafe { ReadableRingBuffer::new_read(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; + + // Don't disable the clock + mem::forget(self); + + RingBufferedUartRx { _peri, ring_buf } } } @@ -186,6 +191,8 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> RingBufferedUartRx<'d, T, RxD impl> Drop for RingBufferedUartRx<'_, T, RxDma> { fn drop(&mut self) { self.teardown_uart(); + + T::disable(); } } /// Return an error result if the Sr register has errors -- cgit From 49ba9c3da2b6929c5ec1fb17d8c43c271a70eb34 Mon Sep 17 00:00:00 2001 From: Daehyeok Mun Date: Sun, 20 Aug 2023 19:31:47 -0700 Subject: initial support for STM32G4 ADC --- embassy-stm32/src/adc/v4.rs | 193 +++++++++++++++++++------------------------ embassy-stm32/src/rcc/g4.rs | 54 +++++++++++- embassy-stm32/src/rcc/mod.rs | 6 ++ 3 files changed, 146 insertions(+), 107 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 64d0f0c75..d03f2550d 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -1,8 +1,10 @@ use core::sync::atomic::{AtomicU8, Ordering}; use embedded_hal_02::blocking::delay::DelayUs; +#[allow(unused)] use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; use pac::adccommon::vals::Presc; +use paste::paste; use super::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; use crate::time::Hertz; @@ -13,12 +15,31 @@ pub const VREF_DEFAULT_MV: u32 = 3300; /// VREF voltage used for factory calibration of VREFINTCAL register. pub const VREF_CALIB_MV: u32 = 3300; -// NOTE: Vrefint/Temperature/Vbat are only available on ADC3 on H7, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs +/// Max single ADC operation clock frequency +#[cfg(stm32g4)] +const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); +#[cfg(stm32h7)] +const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); + +#[cfg(stm32g4)] +const VREF_CHANNEL: u8 = 18; +#[cfg(stm32g4)] +const TEMP_CHANNEL: u8 = 16; + +#[cfg(stm32h7)] +const VREF_CHANNEL: u8 = 19; +#[cfg(stm32h7)] +const TEMP_CHANNEL: u8 = 18; + +// TODO this should be 14 for H7a/b/35 +const VBAT_CHANNEL: u8 = 17; + +// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs pub struct VrefInt; impl InternalChannel for VrefInt {} impl super::sealed::InternalChannel for VrefInt { fn channel(&self) -> u8 { - 19 + VREF_CHANNEL } } @@ -26,7 +47,7 @@ pub struct Temperature; impl InternalChannel for Temperature {} impl super::sealed::InternalChannel for Temperature { fn channel(&self) -> u8 { - 18 + TEMP_CHANNEL } } @@ -34,59 +55,20 @@ pub struct Vbat; impl InternalChannel for Vbat {} impl super::sealed::InternalChannel for Vbat { fn channel(&self) -> u8 { - // TODO this should be 14 for H7a/b/35 - 17 + VBAT_CHANNEL } } static ADC12_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0); +#[cfg(any(stm32g4x3, stm32g4x4))] +static ADC345_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0); -#[cfg(stm32h7)] -foreach_peripheral!( - (adc, ADC1) => { - impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 { - fn frequency() -> crate::time::Hertz { - critical_section::with(|_| { - match unsafe { crate::rcc::get_freqs() }.adc { - Some(ck) => ck, - None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") - } - }) - } - - fn enable() { - critical_section::with(|_| { - crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) - }); - ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); - } - - fn disable() { - if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { - critical_section::with(|_| { - crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); - }) - } - ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst); - } - - fn reset() { - if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { - critical_section::with(|_| { - crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); - crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); - }); - } - } - } - - impl crate::rcc::RccPeripheral for crate::peripherals::ADC1 {} - }; - (adc, ADC2) => { - impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 { +macro_rules! rcc_peripheral { + ($adc_name:ident, $freqs:ident, $ahb:ident, $reg:ident $(, $counter:ident )? ) => { + impl crate::rcc::sealed::RccPeripheral for crate::peripherals::$adc_name { fn frequency() -> crate::time::Hertz { critical_section::with(|_| { - match unsafe { crate::rcc::get_freqs() }.adc { + match unsafe { crate::rcc::get_freqs() }.$freqs { Some(ck) => ck, None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") } @@ -95,65 +77,57 @@ foreach_peripheral!( fn enable() { critical_section::with(|_| { - crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true)) + paste!{crate::pac::RCC.[< $ahb enr >]().modify(|w| w.[< set_ $reg en >](true))} }); - ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst); + $ ( $counter.fetch_add(1, Ordering::SeqCst); )? } fn disable() { - if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { + $ ( if $counter.load(Ordering::SeqCst) == 1 )? { critical_section::with(|_| { - crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false)); + paste!{crate::pac::RCC.[< $ahb enr >]().modify(|w| w.[< set_ $reg en >](false))} }) - } - ADC12_ENABLE_COUNTER.fetch_sub(1, Ordering::SeqCst); + } + $ ( $counter.fetch_sub(1, Ordering::SeqCst); )? } fn reset() { - if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 { + $ ( if $counter.load(Ordering::SeqCst) == 1 )? { critical_section::with(|_| { - crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true)); - crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false)); + paste!{crate::pac::RCC.[< $ahb rstr >]().modify(|w| w.[< set_ $reg rst >](true))} + paste!{crate::pac::RCC.[< $ahb rstr >]().modify(|w| w.[< set_ $reg rst >](false))} }); - } + } } } - impl crate::rcc::RccPeripheral for crate::peripherals::ADC2 {} + impl crate::rcc::RccPeripheral for crate::peripherals::$adc_name {} }; - (adc, ADC3) => { - impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 { - fn frequency() -> crate::time::Hertz { - critical_section::with(|_| { - match unsafe { crate::rcc::get_freqs() }.adc { - Some(ck) => ck, - None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") - } - }) - } +} - fn enable() { - critical_section::with(|_| { - crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true)) - }); - } +#[cfg(stm32g4)] +foreach_peripheral!( + (adc, ADC1) => { rcc_peripheral!(ADC1, adc12, ahb2, adc12, ADC12_ENABLE_COUNTER); }; + (adc, ADC2) => { rcc_peripheral!(ADC2, adc12, ahb2, adc12, ADC12_ENABLE_COUNTER); }; +); - fn disable() { - critical_section::with(|_| { - crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false)); - }) - } +#[cfg(stm32g4x1)] +foreach_peripheral!( + (adc, ADC3) => { rcc_peripheral!(ADC3, adc345, ahb2, adc345); }; +); - fn reset() { - critical_section::with(|_| { - crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true)); - crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false)); - }); - } - } +#[cfg(any(stm32g4x3, stm32g4x4))] +foreach_peripheral!( + (adc, ADC3) => { rcc_peripheral!(ADC3, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); }; + (adc, ADC4) => { rcc_peripheral!(ADC4, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); }; + (adc, ADC5) => { rcc_peripheral!(ADC5, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); }; +); - impl crate::rcc::RccPeripheral for crate::peripherals::ADC3 {} - }; +#[cfg(stm32h7)] +foreach_peripheral!( + (adc, ADC1) => { rcc_peripheral!(ADC1, adc, ahb1, adc12, ADC12_ENABLE_COUNTER); }; + (adc, ADC2) => { rcc_peripheral!(ADC2, adc, ahb1, adc12, ADC12_ENABLE_COUNTER); }; + (adc, ADC3) => { rcc_peripheral!(ADC3, adc, ahb4, adc3); }; ); // NOTE (unused): The prescaler enum closely copies the hardware capabilities, @@ -176,7 +150,7 @@ enum Prescaler { impl Prescaler { fn from_ker_ck(frequency: Hertz) -> Self { - let raw_prescaler = frequency.0 / 50_000_000; + let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; match raw_prescaler { 0 => Self::NotDivided, 1 => Self::DividedBy2, @@ -237,20 +211,23 @@ impl<'d, T: Instance> Adc<'d, T> { let frequency = Hertz(T::frequency().0 / prescaler.divisor()); info!("ADC frequency set to {} Hz", frequency.0); - if frequency > Hertz::mhz(50) { - panic!("Maximal allowed frequency for the ADC is 50 MHz and it varies with different packages, refer to ST docs for more information."); + if frequency > MAX_ADC_CLK_FREQ { + panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); } - let boost = if frequency < Hertz::khz(6_250) { - Boost::LT6_25 - } else if frequency < Hertz::khz(12_500) { - Boost::LT12_5 - } else if frequency < Hertz::mhz(25) { - Boost::LT25 - } else { - Boost::LT50 - }; - T::regs().cr().modify(|w| w.set_boost(boost)); + #[cfg(stm32h7)] + { + let boost = if frequency < Hertz::khz(6_250) { + Boost::LT6_25 + } else if frequency < Hertz::khz(12_500) { + Boost::LT12_5 + } else if frequency < Hertz::mhz(25) { + Boost::LT25 + } else { + Boost::LT50 + }; + T::regs().cr().modify(|w| w.set_boost(boost)); + } let mut s = Self { adc, sample_time: Default::default(), @@ -379,10 +356,14 @@ impl<'d, T: Instance> Adc<'d, T> { // Configure channel Self::set_channel_sample_time(channel, self.sample_time); - T::regs().cfgr2().modify(|w| w.set_lshift(0)); - T::regs() - .pcsel() - .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); + #[cfg(stm32h7)] + { + T::regs().cfgr2().modify(|w| w.set_lshift(0)); + T::regs() + .pcsel() + .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); + } + T::regs().sqr1().write(|reg| { reg.set_sq(0, channel); reg.set_l(0); diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 3b044cd11..4c95bb154 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -1,5 +1,5 @@ use stm32_metapac::flash::vals::Latency; -use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw}; +use stm32_metapac::rcc::vals::{Adcsel, Hpre, Pllsrc, Ppre, Sw}; use stm32_metapac::FLASH; pub use super::bus::{AHBPrescaler, APBPrescaler}; @@ -14,6 +14,29 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000); /// LSI speed pub const LSI_FREQ: Hertz = Hertz(32_000); +#[derive(Clone, Copy)] +pub enum AdcClockSource { + NoClk, + SysClk, + PllP, +} + +impl AdcClockSource { + pub fn adcsel(&self) -> Adcsel { + match self { + AdcClockSource::NoClk => Adcsel::NOCLK, + AdcClockSource::SysClk => Adcsel::SYSCLK, + AdcClockSource::PllP => Adcsel::PLLP, + } + } +} + +impl Default for AdcClockSource { + fn default() -> Self { + Self::NoClk + } +} + /// System clock mux source #[derive(Clone, Copy)] pub enum ClockSrc { @@ -327,6 +350,8 @@ pub struct Config { pub pll: Option, /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals. pub clock_48mhz_src: Option, + pub adc12_clock_source: AdcClockSource, + pub adc345_clock_source: AdcClockSource, } /// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator. @@ -346,6 +371,8 @@ impl Default for Config { low_power_run: false, pll: None, clock_48mhz_src: None, + adc12_clock_source: Default::default(), + adc345_clock_source: Default::default(), } } } @@ -549,6 +576,29 @@ pub(crate) unsafe fn init(config: Config) { RCC.ccipr().modify(|w| w.set_clk48sel(source)); } + RCC.ccipr() + .modify(|w| w.set_adc12sel(config.adc12_clock_source.adcsel())); + RCC.ccipr() + .modify(|w| w.set_adc345sel(config.adc345_clock_source.adcsel())); + + let adc12_ck = match config.adc12_clock_source { + AdcClockSource::NoClk => None, + AdcClockSource::PllP => match &pll_freq { + Some(pll) => pll.pll_p, + None => None, + }, + AdcClockSource::SysClk => Some(Hertz(sys_clk)), + }; + + let adc345_ck = match config.adc345_clock_source { + AdcClockSource::NoClk => None, + AdcClockSource::PllP => match &pll_freq { + Some(pll) => pll.pll_p, + None => None, + }, + AdcClockSource::SysClk => Some(Hertz(sys_clk)), + }; + if config.low_power_run { assert!(sys_clk <= 2_000_000); PWR.cr1().modify(|w| w.set_lpr(true)); @@ -562,5 +612,7 @@ pub(crate) unsafe fn init(config: Config) { apb1_tim: Hertz(apb1_tim_freq), apb2: Hertz(apb2_freq), apb2_tim: Hertz(apb2_tim_freq), + adc12: adc12_ck, + adc345: adc345_ck, }); } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 0430e4a74..ecabe23ae 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -77,6 +77,12 @@ pub struct Clocks { #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))] pub adc: Option, + #[cfg(any(rcc_g4))] + pub adc12: Option, + + #[cfg(any(rcc_g4))] + pub adc345: 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, -- cgit From f5022719401ef15b02bfefadcf7e10719e48f06e Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 5 Sep 2023 16:46:57 -0500 Subject: stm32: add initial adc f3 impl --- embassy-stm32/src/adc/f3.rs | 126 +++++++++++++++++++++++++++++++++++ embassy-stm32/src/adc/mod.rs | 59 ++++++++++++---- embassy-stm32/src/adc/resolution.rs | 8 +-- embassy-stm32/src/adc/sample_time.rs | 18 ++++- embassy-stm32/src/rcc/f3.rs | 93 +++++++++++++++++++++++++- embassy-stm32/src/rcc/mod.rs | 5 +- 6 files changed, 290 insertions(+), 19 deletions(-) create mode 100644 embassy-stm32/src/adc/f3.rs (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs new file mode 100644 index 000000000..458573c05 --- /dev/null +++ b/embassy-stm32/src/adc/f3.rs @@ -0,0 +1,126 @@ +use embassy_hal_internal::into_ref; +use embedded_hal_02::blocking::delay::DelayUs; + +use crate::adc::{Adc, AdcPin, Instance, SampleTime}; +use crate::time::Hertz; +use crate::Peripheral; + +pub const VDDA_CALIB_MV: u32 = 3300; +pub const ADC_MAX: u32 = (1 << 12) - 1; +// No calibration data for F103, voltage should be 1.2v +pub const VREF_INT: u32 = 1200; + +pub struct Vref; +impl AdcPin for Vref {} +impl super::sealed::AdcPin for Vref { + fn channel(&self) -> u8 { + 18 + } +} + +pub struct Temperature; +impl AdcPin for Temperature {} +impl super::sealed::AdcPin for Temperature { + fn channel(&self) -> u8 { + 16 + } +} + +impl<'d, T: Instance> Adc<'d, T> { + pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { + use crate::pac::adc::vals; + + into_ref!(adc); + + T::enable(); + T::reset(); + + // Enable the adc regulator + T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE)); + T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::ENABLED)); + + // Wait for the regulator to stabilize + delay.delay_us(10); + + assert!(!T::regs().cr().read().aden()); + + // Begin calibration + T::regs().cr().modify(|w| w.set_adcaldif(false)); + T::regs().cr().modify(|w| w.set_adcal(true)); + + while T::regs().cr().read().adcal() {} + + // Enable the adc + T::regs().cr().modify(|w| w.set_aden(true)); + + // Wait until the adc is ready + while !T::regs().isr().read().adrdy() {} + + Self { + adc, + sample_time: Default::default(), + } + } + + fn freq() -> Hertz { + ::frequency() + } + + pub fn sample_time_for_us(&self, us: u32) -> SampleTime { + match us * Self::freq().0 / 1_000_000 { + 0..=1 => SampleTime::Cycles1_5, + 2..=4 => SampleTime::Cycles4_5, + 5..=7 => SampleTime::Cycles7_5, + 8..=19 => SampleTime::Cycles19_5, + 20..=61 => SampleTime::Cycles61_5, + 62..=181 => SampleTime::Cycles181_5, + _ => SampleTime::Cycles601_5, + } + } + + pub fn enable_vref(&self, _delay: &mut impl DelayUs) -> Vref { + T::common_regs().ccr().modify(|w| w.set_vrefen(true)); + + Vref {} + } + + pub fn enable_temperature(&self) -> Temperature { + T::common_regs().ccr().modify(|w| w.set_tsen(true)); + + Temperature {} + } + + pub fn set_sample_time(&mut self, sample_time: SampleTime) { + self.sample_time = sample_time; + } + + /// Perform a single conversion. + fn convert(&mut self) -> u16 { + T::regs().isr().write(|_| {}); + T::regs().cr().modify(|w| w.set_adstart(true)); + + while !T::regs().isr().read().eoc() && !T::regs().isr().read().eos() {} + T::regs().isr().write(|_| {}); + + T::regs().dr().read().0 as u16 + } + + pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { + // pin.set_as_analog(); + + Self::set_channel_sample_time(pin.channel(), self.sample_time); + + // Configure the channel to sample + T::regs().sqr3().write(|w| w.set_sq(0, pin.channel())); + self.convert() + } + + fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { + let sample_time = sample_time.into(); + if ch <= 9 { + T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); + } else { + T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); + } + } +} diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index e57889aa6..a127445d8 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -1,23 +1,24 @@ #![macro_use] -#[cfg(not(any(adc_f3, adc_f3_v2)))] +#[cfg(not(adc_f3_v2))] #[cfg_attr(adc_f1, path = "f1.rs")] +#[cfg_attr(adc_f3, path = "f3.rs")] #[cfg_attr(adc_v1, path = "v1.rs")] #[cfg_attr(adc_v2, path = "v2.rs")] #[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")] #[cfg_attr(adc_v4, path = "v4.rs")] mod _version; -#[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))] +#[cfg(not(any(adc_f1, adc_f3_v2)))] mod resolution; mod sample_time; -#[cfg(not(any(adc_f3, adc_f3_v2)))] #[allow(unused)] +#[cfg(not(adc_f3_v2))] pub use _version::*; #[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))] pub use resolution::Resolution; -#[cfg(not(any(adc_f3, adc_f3_v2)))] +#[cfg(not(adc_f3_v2))] pub use sample_time::SampleTime; use crate::peripherals; @@ -25,15 +26,17 @@ use crate::peripherals; pub struct Adc<'d, T: Instance> { #[allow(unused)] adc: crate::PeripheralRef<'d, T>, - #[cfg(not(any(adc_f3, adc_f3_v2)))] + #[cfg(not(adc_f3_v2))] sample_time: SampleTime, } pub(crate) mod sealed { pub trait Instance { fn regs() -> crate::pac::adc::Adc; - #[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))] + #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2)))] fn common_regs() -> crate::pac::adccommon::AdcCommon; + #[cfg(adc_f3)] + fn frequency() -> crate::time::Hertz; } pub trait AdcPin { @@ -45,22 +48,22 @@ pub(crate) mod sealed { } } -#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4)))] +#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3)))] pub trait Instance: sealed::Instance + crate::Peripheral

{} -#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4))] +#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3))] pub trait Instance: sealed::Instance + crate::Peripheral

+ crate::rcc::RccPeripheral {} pub trait AdcPin: sealed::AdcPin {} pub trait InternalChannel: sealed::InternalChannel {} -#[cfg(not(stm32h7))] +#[cfg(not(any(stm32h7, adc_f3)))] foreach_peripheral!( (adc, $inst:ident) => { impl crate::adc::sealed::Instance for peripherals::$inst { fn regs() -> crate::pac::adc::Adc { crate::pac::$inst } - #[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))] + #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2)))] fn common_regs() -> crate::pac::adccommon::AdcCommon { foreach_peripheral!{ (adccommon, $common_inst:ident) => { @@ -74,7 +77,7 @@ foreach_peripheral!( }; ); -#[cfg(stm32h7)] +#[cfg(any(stm32h7, adc_f3))] foreach_peripheral!( (adc, ADC3) => { impl crate::adc::sealed::Instance for peripherals::ADC3 { @@ -89,16 +92,43 @@ foreach_peripheral!( }; } } + + #[cfg(adc_f3)] + fn frequency() -> crate::time::Hertz { + unsafe { crate::rcc::get_freqs() }.adc34.unwrap() + } } impl crate::adc::Instance for peripherals::ADC3 {} }; + (adc, ADC4) => { + impl crate::adc::sealed::Instance for peripherals::ADC4 { + fn regs() -> crate::pac::adc::Adc { + crate::pac::ADC4 + } + #[cfg(not(any(adc_f1, adc_v1)))] + fn common_regs() -> crate::pac::adccommon::AdcCommon { + foreach_peripheral!{ + (adccommon, ADC3_COMMON) => { + return crate::pac::ADC3_COMMON + }; + } + } + + #[cfg(adc_f3)] + fn frequency() -> crate::time::Hertz { + unsafe { crate::rcc::get_freqs() }.adc34.unwrap() + } + } + + impl crate::adc::Instance for peripherals::ADC4 {} + }; (adc, $inst:ident) => { impl crate::adc::sealed::Instance for peripherals::$inst { fn regs() -> crate::pac::adc::Adc { crate::pac::$inst } - #[cfg(all(not(adc_f1), not(adc_v1)))] + #[cfg(not(any(adc_f1, adc_v1)))] fn common_regs() -> crate::pac::adccommon::AdcCommon { foreach_peripheral!{ (adccommon, ADC_COMMON) => { @@ -106,6 +136,11 @@ foreach_peripheral!( }; } } + + #[cfg(adc_f3)] + fn frequency() -> crate::time::Hertz { + unsafe { crate::rcc::get_freqs() }.adc.unwrap() + } } impl crate::adc::Instance for peripherals::$inst {} diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs index 67fb9b8c0..5668137b5 100644 --- a/embassy-stm32/src/adc/resolution.rs +++ b/embassy-stm32/src/adc/resolution.rs @@ -1,4 +1,4 @@ -#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] +#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Resolution { TwelveBit, @@ -19,7 +19,7 @@ pub enum Resolution { impl Default for Resolution { fn default() -> Self { - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] { Self::TwelveBit } @@ -40,7 +40,7 @@ impl From for crate::pac::adc::vals::Res { Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT, Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT, Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT, - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT, } } @@ -56,7 +56,7 @@ impl Resolution { Resolution::TwelveBit => (1 << 12) - 1, Resolution::TenBit => (1 << 10) - 1, Resolution::EightBit => (1 << 8) - 1, - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3))] Resolution::SixBit => (1 << 6) - 1, } } diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs index 5480e7a77..6a6619299 100644 --- a/embassy-stm32/src/adc/sample_time.rs +++ b/embassy-stm32/src/adc/sample_time.rs @@ -1,4 +1,4 @@ -#[cfg(not(any(adc_f3, adc_f3_v2)))] +#[cfg(not(adc_f3_v2))] macro_rules! impl_sample_time { ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => { #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")] @@ -105,3 +105,19 @@ impl_sample_time!( ("810.5", Cycles810_5, CYCLES810_5) ) ); + +#[cfg(adc_f3)] +impl_sample_time!( + "1.5", + Cycles1_5, + ( + ("1.5", Cycles1_5, CYCLES1_5), + ("2.5", Cycles2_5, CYCLES2_5), + ("4.5", Cycles4_5, CYCLES4_5), + ("7.5", Cycles7_5, CYCLES7_5), + ("19.5", Cycles19_5, CYCLES19_5), + ("61.5", Cycles61_5, CYCLES61_5), + ("181.5", Cycles181_5, CYCLES181_5), + ("601.5", Cycles601_5, CYCLES601_5) + ) +); diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index 7480c0393..f8726c24a 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -1,5 +1,5 @@ use crate::pac::flash::vals::Latency; -use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; +use crate::pac::rcc::vals::{Adcpres, Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -10,6 +10,46 @@ 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: ADCPrescaler) -> 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, + } + } +} + +#[derive(Clone, Copy)] +pub enum ADCClock { + AHB(ADCPrescaler), + PLL(ADCPrescaler), +} + /// Clocks configutation #[non_exhaustive] #[derive(Default)] @@ -36,9 +76,18 @@ pub struct Config { /// - The System clock frequency is either 48MHz or 72MHz /// - APB1 clock has a minimum frequency of 10MHz pub pll48: bool, + #[cfg(rcc_f3)] + /// ADC clock setup + /// - For AHB, a psc of 4 or less must be used + pub adc: Option, + #[cfg(rcc_f3)] + /// ADC clock setup + /// - For AHB, a psc of 4 or less must be used + pub adc34: Option, } // Information required to setup the PLL clock +#[derive(Clone, Copy)] struct PllConfig { pll_src: Pllsrc, pll_mul: Pllmul, @@ -148,6 +197,44 @@ 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| { @@ -177,6 +264,10 @@ pub(crate) unsafe fn init(config: Config) { apb1_tim: Hertz(pclk1 * timer_mul1), apb2_tim: Hertz(pclk2 * timer_mul2), ahb1: Hertz(hclk), + #[cfg(rcc_f3)] + adc: adc, + #[cfg(rcc_f3)] + adc34: adc34, }); } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 0430e4a74..2e1f60358 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -74,9 +74,12 @@ pub struct Clocks { #[cfg(stm32f1)] pub adc: Hertz, - #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))] + #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3))] pub adc: Option, + #[cfg(rcc_f3)] + pub adc34: 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, -- cgit From 7622d2eb61c030972756a962fee65e3ab66cfa10 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 5 Sep 2023 17:10:15 -0500 Subject: stm32: fix merge issues --- embassy-stm32/src/adc/v4.rs | 12 ++++++------ embassy-stm32/src/rcc/g4.rs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index d03f2550d..2ff5c8f9e 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -107,20 +107,20 @@ macro_rules! rcc_peripheral { #[cfg(stm32g4)] foreach_peripheral!( - (adc, ADC1) => { rcc_peripheral!(ADC1, adc12, ahb2, adc12, ADC12_ENABLE_COUNTER); }; - (adc, ADC2) => { rcc_peripheral!(ADC2, adc12, ahb2, adc12, ADC12_ENABLE_COUNTER); }; + (adc, ADC1) => { rcc_peripheral!(ADC1, adc, ahb2, adc12, ADC12_ENABLE_COUNTER); }; + (adc, ADC2) => { rcc_peripheral!(ADC2, adc, ahb2, adc12, ADC12_ENABLE_COUNTER); }; ); #[cfg(stm32g4x1)] foreach_peripheral!( - (adc, ADC3) => { rcc_peripheral!(ADC3, adc345, ahb2, adc345); }; + (adc, ADC3) => { rcc_peripheral!(ADC3, adc34, ahb2, adc345); }; ); #[cfg(any(stm32g4x3, stm32g4x4))] foreach_peripheral!( - (adc, ADC3) => { rcc_peripheral!(ADC3, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); }; - (adc, ADC4) => { rcc_peripheral!(ADC4, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); }; - (adc, ADC5) => { rcc_peripheral!(ADC5, adc345, ahb2, adc345, ADC345_ENABLE_COUNTER); }; + (adc, ADC3) => { rcc_peripheral!(ADC3, adc34, ahb2, adc345, ADC345_ENABLE_COUNTER); }; + (adc, ADC4) => { rcc_peripheral!(ADC4, adc34, ahb2, adc345, ADC345_ENABLE_COUNTER); }; + (adc, ADC5) => { rcc_peripheral!(ADC5, adc34, ahb2, adc345, ADC345_ENABLE_COUNTER); }; ); #[cfg(stm32h7)] diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 4c95bb154..2359f39c1 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -612,7 +612,7 @@ pub(crate) unsafe fn init(config: Config) { apb1_tim: Hertz(apb1_tim_freq), apb2: Hertz(apb2_freq), apb2_tim: Hertz(apb2_tim_freq), - adc12: adc12_ck, - adc345: adc345_ck, + adc: adc12_ck, + adc34: adc345_ck, }); } -- cgit From fd22f4fac5da01c8c171f2f3ed92f701bb0421d7 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 5 Sep 2023 17:45:52 -0500 Subject: stm32: remove paste and use refcount statics --- embassy-stm32/src/adc/mod.rs | 6 ++-- embassy-stm32/src/adc/v4.rs | 74 -------------------------------------------- 2 files changed, 4 insertions(+), 76 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index a127445d8..023a94f2f 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -56,7 +56,7 @@ pub trait Instance: sealed::Instance + crate::Peripheral

+ crate::rcc: pub trait AdcPin: sealed::AdcPin {} pub trait InternalChannel: sealed::InternalChannel {} -#[cfg(not(any(stm32h7, adc_f3)))] +#[cfg(not(any(stm32h7, adc_f3, adc_v4)))] foreach_peripheral!( (adc, $inst:ident) => { impl crate::adc::sealed::Instance for peripherals::$inst { @@ -77,9 +77,10 @@ foreach_peripheral!( }; ); -#[cfg(any(stm32h7, adc_f3))] +#[cfg(any(stm32h7, adc_f3, adc_v4))] foreach_peripheral!( (adc, ADC3) => { + #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::sealed::Instance for peripherals::ADC3 { fn regs() -> crate::pac::adc::Adc { crate::pac::ADC3 @@ -99,6 +100,7 @@ foreach_peripheral!( } } + #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::Instance for peripherals::ADC3 {} }; (adc, ADC4) => { diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 2ff5c8f9e..655c0cb6a 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -1,10 +1,7 @@ -use core::sync::atomic::{AtomicU8, Ordering}; - use embedded_hal_02::blocking::delay::DelayUs; #[allow(unused)] use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; use pac::adccommon::vals::Presc; -use paste::paste; use super::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; use crate::time::Hertz; @@ -59,77 +56,6 @@ impl super::sealed::InternalChannel for Vbat { } } -static ADC12_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0); -#[cfg(any(stm32g4x3, stm32g4x4))] -static ADC345_ENABLE_COUNTER: AtomicU8 = AtomicU8::new(0); - -macro_rules! rcc_peripheral { - ($adc_name:ident, $freqs:ident, $ahb:ident, $reg:ident $(, $counter:ident )? ) => { - impl crate::rcc::sealed::RccPeripheral for crate::peripherals::$adc_name { - fn frequency() -> crate::time::Hertz { - critical_section::with(|_| { - match unsafe { crate::rcc::get_freqs() }.$freqs { - Some(ck) => ck, - None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.") - } - }) - } - - fn enable() { - critical_section::with(|_| { - paste!{crate::pac::RCC.[< $ahb enr >]().modify(|w| w.[< set_ $reg en >](true))} - }); - $ ( $counter.fetch_add(1, Ordering::SeqCst); )? - } - - fn disable() { - $ ( if $counter.load(Ordering::SeqCst) == 1 )? { - critical_section::with(|_| { - paste!{crate::pac::RCC.[< $ahb enr >]().modify(|w| w.[< set_ $reg en >](false))} - }) - } - $ ( $counter.fetch_sub(1, Ordering::SeqCst); )? - } - - fn reset() { - $ ( if $counter.load(Ordering::SeqCst) == 1 )? { - critical_section::with(|_| { - paste!{crate::pac::RCC.[< $ahb rstr >]().modify(|w| w.[< set_ $reg rst >](true))} - paste!{crate::pac::RCC.[< $ahb rstr >]().modify(|w| w.[< set_ $reg rst >](false))} - }); - } - } - } - - impl crate::rcc::RccPeripheral for crate::peripherals::$adc_name {} - }; -} - -#[cfg(stm32g4)] -foreach_peripheral!( - (adc, ADC1) => { rcc_peripheral!(ADC1, adc, ahb2, adc12, ADC12_ENABLE_COUNTER); }; - (adc, ADC2) => { rcc_peripheral!(ADC2, adc, ahb2, adc12, ADC12_ENABLE_COUNTER); }; -); - -#[cfg(stm32g4x1)] -foreach_peripheral!( - (adc, ADC3) => { rcc_peripheral!(ADC3, adc34, ahb2, adc345); }; -); - -#[cfg(any(stm32g4x3, stm32g4x4))] -foreach_peripheral!( - (adc, ADC3) => { rcc_peripheral!(ADC3, adc34, ahb2, adc345, ADC345_ENABLE_COUNTER); }; - (adc, ADC4) => { rcc_peripheral!(ADC4, adc34, ahb2, adc345, ADC345_ENABLE_COUNTER); }; - (adc, ADC5) => { rcc_peripheral!(ADC5, adc34, ahb2, adc345, ADC345_ENABLE_COUNTER); }; -); - -#[cfg(stm32h7)] -foreach_peripheral!( - (adc, ADC1) => { rcc_peripheral!(ADC1, adc, ahb1, adc12, ADC12_ENABLE_COUNTER); }; - (adc, ADC2) => { rcc_peripheral!(ADC2, adc, ahb1, adc12, ADC12_ENABLE_COUNTER); }; - (adc, ADC3) => { rcc_peripheral!(ADC3, adc, ahb4, adc3); }; -); - // NOTE (unused): The prescaler enum closely copies the hardware capabilities, // but high prescaling doesn't make a lot of sense in the current implementation and is ommited. #[allow(unused)] -- cgit From f4601af2a4bbedc32a3c270696a8de2ed743b6d6 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 5 Sep 2023 17:48:20 -0500 Subject: stm32: don't generate adc4 for g4 --- embassy-stm32/src/adc/mod.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 023a94f2f..bdb1ab8ac 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -104,6 +104,7 @@ foreach_peripheral!( impl crate::adc::Instance for peripherals::ADC3 {} }; (adc, ADC4) => { + #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::sealed::Instance for peripherals::ADC4 { fn regs() -> crate::pac::adc::Adc { crate::pac::ADC4 @@ -123,6 +124,7 @@ foreach_peripheral!( } } + #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::Instance for peripherals::ADC4 {} }; (adc, $inst:ident) => { -- cgit From 73070987804023f50fcc4a264de8371fbba723d2 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 5 Sep 2023 17:50:45 -0500 Subject: stm32: don't generate adc5 --- embassy-stm32/src/adc/mod.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index bdb1ab8ac..0eeadfa93 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -126,6 +126,9 @@ foreach_peripheral!( #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::Instance for peripherals::ADC4 {} + }; + (adc, ADC5) => { + }; (adc, $inst:ident) => { impl crate::adc::sealed::Instance for peripherals::$inst { -- cgit From 6770d8e8a690ca42a695105303784f4fc9796f6a Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Wed, 6 Sep 2023 00:04:09 +0100 Subject: Allow the RTC clock source to be configured with the new RTC mechanism --- embassy-stm32/src/rcc/f2.rs | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index 9d9bc59fd..8b6556249 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -4,8 +4,10 @@ use core::ops::{Div, Mul}; pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::flash::vals::Latency; use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw}; -use crate::pac::{FLASH, RCC}; +use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::bd::BackupDomain; use crate::rcc::{set_freqs, Clocks}; +use crate::rtc::RtcClockSource; use crate::time::Hertz; /// HSI speed @@ -288,6 +290,7 @@ pub struct Config { pub pll_mux: PLLSrc, pub pll: PLLConfig, pub mux: ClockSrc, + pub rtc: Option, pub voltage: VoltageScale, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, @@ -304,6 +307,7 @@ impl Default for Config { pll: PLLConfig::default(), voltage: VoltageScale::Scale3, mux: ClockSrc::HSI, + rtc: None, ahb_pre: AHBPrescaler::NotDivided, apb1_pre: APBPrescaler::NotDivided, apb2_pre: APBPrescaler::NotDivided, @@ -414,6 +418,37 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().modify(|w| w.set_hsion(false)); } + RCC.apb1enr().modify(|w| w.set_pwren(true)); + PWR.cr().read(); + + match config.rtc { + Some(RtcClockSource::LSE) => { + // 1. Unlock the backup domain + PWR.cr().modify(|w| w.set_dbp(true)); + + // 2. Setup the LSE + RCC.bdcr().modify(|w| { + // Enable LSE + w.set_lseon(true); + }); + + // Wait until LSE is running + while !RCC.bdcr().read().lserdy() {} + + BackupDomain::set_rtc_clock_source(RtcClockSource::LSE); + } + Some(RtcClockSource::LSI) => { + // Turn on the internal 32 kHz LSI oscillator + RCC.csr().modify(|w| w.set_lsion(true)); + + // Wait until LSI is running + while !RCC.csr().read().lsirdy() {} + + BackupDomain::set_rtc_clock_source(RtcClockSource::LSI); + } + _ => todo!(), + } + set_freqs(Clocks { sys: sys_clk, ahb1: ahb_freq, -- cgit From bb2d6c854273ea57eb7d898c0f67dd9f8020f3e7 Mon Sep 17 00:00:00 2001 From: Olle Sandberg Date: Tue, 5 Sep 2023 12:10:31 +0200 Subject: adc_v3: replace cfg(stm32g0) + friends with cfg(adc_g0) Since any MCU (not just STM32G0) using adc_g0 should probably be handled the same way. --- embassy-stm32/src/adc/mod.rs | 4 ++-- embassy-stm32/src/adc/v3.rs | 39 +++++++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 14 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 0eeadfa93..013debca8 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -33,7 +33,7 @@ pub struct Adc<'d, T: Instance> { pub(crate) mod sealed { pub trait Instance { fn regs() -> crate::pac::adc::Adc; - #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2)))] + #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] fn common_regs() -> crate::pac::adccommon::AdcCommon; #[cfg(adc_f3)] fn frequency() -> crate::time::Hertz; @@ -63,7 +63,7 @@ foreach_peripheral!( fn regs() -> crate::pac::adc::Adc { crate::pac::$inst } - #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2)))] + #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] fn common_regs() -> crate::pac::adccommon::AdcCommon { foreach_peripheral!{ (adccommon, $common_inst:ident) => { diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 821cc7f6a..7d63b0cee 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -26,9 +26,9 @@ pub struct VrefInt; impl AdcPin for VrefInt {} impl super::sealed::AdcPin for VrefInt { fn channel(&self) -> u8 { - #[cfg(not(stm32g0))] + #[cfg(not(adc_g0))] let val = 0; - #[cfg(stm32g0)] + #[cfg(adc_g0)] let val = 13; val } @@ -38,9 +38,9 @@ pub struct Temperature; impl AdcPin for Temperature {} impl super::sealed::AdcPin for Temperature { fn channel(&self) -> u8 { - #[cfg(not(stm32g0))] + #[cfg(not(adc_g0))] let val = 17; - #[cfg(stm32g0)] + #[cfg(adc_g0)] let val = 12; val } @@ -50,9 +50,9 @@ pub struct Vbat; impl AdcPin for Vbat {} impl super::sealed::AdcPin for Vbat { fn channel(&self) -> u8 { - #[cfg(not(stm32g0))] + #[cfg(not(adc_g0))] let val = 18; - #[cfg(stm32g0)] + #[cfg(adc_g0)] let val = 14; val } @@ -92,9 +92,14 @@ impl<'d, T: Instance> Adc<'d, T> { } pub fn enable_vrefint(&self, delay: &mut impl DelayUs) -> VrefInt { + #[cfg(not(adc_g0))] T::common_regs().ccr().modify(|reg| { reg.set_vrefen(true); }); + #[cfg(adc_g0)] + T::regs().ccr().modify(|reg| { + reg.set_vrefen(true); + }); // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us // to stabilize the internal voltage reference, we wait a little more. @@ -106,17 +111,27 @@ impl<'d, T: Instance> Adc<'d, T> { } pub fn enable_temperature(&self) -> Temperature { + #[cfg(not(adc_g0))] T::common_regs().ccr().modify(|reg| { reg.set_ch17sel(true); }); + #[cfg(adc_g0)] + T::regs().ccr().modify(|reg| { + reg.set_tsen(true); + }); Temperature {} } pub fn enable_vbat(&self) -> Vbat { + #[cfg(not(adc_g0))] T::common_regs().ccr().modify(|reg| { reg.set_ch18sel(true); }); + #[cfg(adc_g0)] + T::regs().ccr().modify(|reg| { + reg.set_vbaten(true); + }); Vbat {} } @@ -126,9 +141,9 @@ impl<'d, T: Instance> Adc<'d, T> { } pub fn set_resolution(&mut self, resolution: Resolution) { - #[cfg(not(stm32g0))] + #[cfg(not(adc_g0))] T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); - #[cfg(stm32g0)] + #[cfg(adc_g0)] T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); } @@ -182,9 +197,9 @@ impl<'d, T: Instance> Adc<'d, T> { Self::set_channel_sample_time(pin.channel(), self.sample_time); // Select channel - #[cfg(not(stm32g0))] + #[cfg(not(adc_g0))] T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); - #[cfg(stm32g0)] + #[cfg(adc_g0)] T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); // Some models are affected by an erratum: @@ -203,12 +218,12 @@ impl<'d, T: Instance> Adc<'d, T> { val } - #[cfg(stm32g0)] + #[cfg(adc_g0)] fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); } - #[cfg(not(stm32g0))] + #[cfg(not(adc_g0))] fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { let sample_time = sample_time.into(); T::regs() -- cgit From 0d3ff34d80c98f62a1f6e8b4df1226f6c36337a0 Mon Sep 17 00:00:00 2001 From: Olle Sandberg Date: Tue, 5 Sep 2023 12:14:04 +0200 Subject: adc: enable ADC and clock selection for STM32WLx --- embassy-stm32/src/adc/v3.rs | 2 +- embassy-stm32/src/rcc/wl.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 7d63b0cee..011ecc281 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -13,7 +13,7 @@ pub const VREF_CALIB_MV: u32 = 3000; /// configuration. fn enable() { critical_section::with(|_| { - #[cfg(stm32h7)] + #[cfg(any(stm32h7, stm32wl))] crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); #[cfg(stm32g0)] crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true)); diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index e33690d10..47be00ad8 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,4 +1,5 @@ pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; +use crate::pac::rcc::vals::Adcsel; use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; @@ -106,6 +107,29 @@ impl Into for MSIRange { } } +#[derive(Clone, Copy)] +pub enum AdcClockSource { + HSI16, + PLLPCLK, + SYSCLK, +} + +impl AdcClockSource { + pub fn adcsel(&self) -> Adcsel { + match self { + AdcClockSource::HSI16 => Adcsel::HSI16, + AdcClockSource::PLLPCLK => Adcsel::PLLPCLK, + AdcClockSource::SYSCLK => Adcsel::SYSCLK, + } + } +} + +impl Default for AdcClockSource { + fn default() -> Self { + Self::HSI16 + } +} + /// Clocks configutation pub struct Config { pub mux: ClockSrc, @@ -116,6 +140,7 @@ pub struct Config { pub enable_lsi: bool, pub enable_rtc_apb: bool, pub rtc_mux: RtcClockSource, + pub adc_clock_source: AdcClockSource, } impl Default for Config { @@ -130,6 +155,7 @@ impl Default for Config { enable_lsi: false, enable_rtc_apb: false, rtc_mux: RtcClockSource::LSI, + adc_clock_source: AdcClockSource::default(), } } } @@ -299,6 +325,9 @@ pub(crate) unsafe fn init(config: Config) { w.set_ppre2(config.apb2_pre.into()); }); + // ADC clock MUX + RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel())); + // TODO: switch voltage range if config.enable_lsi { -- cgit From d097c99719f31aa68afdedde09149d6de1d0b600 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 6 Sep 2023 17:33:56 -0500 Subject: stm32/rcc: add lsi and lse bd abstraction --- embassy-stm32/src/rcc/bd.rs | 76 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 4d8ed82aa..b4d21c35f 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -1,6 +1,34 @@ +#[allow(dead_code)] +#[derive(Default)] +pub enum LseDrive { + #[cfg(any(rtc_v2f7, rtc_v2l4))] + Low = 0, + MediumLow = 0x01, + #[default] + MediumHigh = 0x02, + #[cfg(any(rtc_v2f7, rtc_v2l4))] + High = 0x03, +} + +#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] +impl From for crate::pac::rcc::vals::Lsedrv { + fn from(value: LseDrive) -> Self { + use crate::pac::rcc::vals::Lsedrv; + + match value { + #[cfg(any(rtc_v2f7, rtc_v2l4))] + LseDrive::Low => Lsedrv::LOW, + LseDrive::MediumLow => Lsedrv::MEDIUMLOW, + LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH, + #[cfg(any(rtc_v2f7, rtc_v2l4))] + LseDrive::High => Lsedrv::HIGH, + } + } +} + +#[allow(dead_code)] #[derive(Copy, Clone, Debug, PartialEq)] #[repr(u8)] -#[allow(dead_code)] pub enum RtcClockSource { /// 00: No clock NoClock = 0b00, @@ -66,6 +94,38 @@ impl BackupDomain { r } + #[allow(dead_code, unused_variables)] + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb))] + pub fn enable_lse(lse_drive: LseDrive) { + Self::modify(|w| { + #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] + w.set_lsedrv(lse_drive.into()); + w.set_lseon(true); + }); + + while !Self::read().lserdy() {} + } + + #[allow(dead_code)] + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb))] + pub fn enable_lsi() { + let csr = crate::pac::RCC.csr(); + + Self::modify(|_| { + #[cfg(not(rtc_v2wb))] + csr.modify(|w| w.set_lsion(true)); + + #[cfg(rtc_v2wb)] + csr.modify(|w| w.set_lsi1on(true)); + }); + + #[cfg(not(rtc_v2wb))] + while !csr.read().lsirdy() {} + + #[cfg(rtc_v2wb)] + while !csr.read().lsi1rdy() {} + } + #[cfg(any( rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5 @@ -74,7 +134,7 @@ impl BackupDomain { pub fn set_rtc_clock_source(clock_source: RtcClockSource) { let clock_source = clock_source as u8; #[cfg(any( - all(not(any(rtc_v3, rtc_v3u5)), not(rtc_v2wb)), + not(any(rtc_v3, rtc_v3u5, rtc_v2wb)), all(any(rtc_v3, rtc_v3u5), not(any(rcc_wl5, rcc_wle))) ))] let clock_source = crate::pac::rcc::vals::Rtcsel::from_bits(clock_source); @@ -86,6 +146,18 @@ impl BackupDomain { }); } + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb))] + #[allow(dead_code, unused_variables)] + pub fn configure_rtc(clock_source: RtcClockSource, lse_drive: Option) { + match clock_source { + RtcClockSource::LSI => Self::enable_lsi(), + RtcClockSource::LSE => Self::enable_lse(lse_drive.unwrap_or_default()), + _ => {} + }; + + Self::set_rtc_clock_source(clock_source); + } + #[cfg(any( rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5 -- cgit From c21ad04c2ed2e5bd0c0e53ded4be8d1c4c4a1bc3 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 6 Sep 2023 17:48:12 -0500 Subject: stm32: extract lse/lsi into bd mod --- embassy-stm32/src/rcc/bd.rs | 6 +++--- embassy-stm32/src/rcc/l4.rs | 35 +++-------------------------------- embassy-stm32/src/rcc/wb.rs | 14 +------------- embassy-stm32/src/rcc/wl.rs | 33 ++------------------------------- 4 files changed, 9 insertions(+), 79 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index b4d21c35f..34b88458f 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -95,7 +95,7 @@ impl BackupDomain { } #[allow(dead_code, unused_variables)] - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb))] + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3))] pub fn enable_lse(lse_drive: LseDrive) { Self::modify(|w| { #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] @@ -107,7 +107,7 @@ impl BackupDomain { } #[allow(dead_code)] - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb))] + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3))] pub fn enable_lsi() { let csr = crate::pac::RCC.csr(); @@ -146,7 +146,7 @@ impl BackupDomain { }); } - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb))] + #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3))] #[allow(dead_code, unused_variables)] pub fn configure_rtc(clock_source: RtcClockSource, lse_drive: Option) { match clock_source { diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index c6bccfd26..0083ae5bb 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -2,13 +2,13 @@ use core::marker::PhantomData; use embassy_hal_internal::into_ref; use stm32_metapac::rcc::regs::Cfgr; -use stm32_metapac::rcc::vals::{Lsedrv, Mcopre, Mcosel}; +use stm32_metapac::rcc::vals::{Mcopre, Mcosel}; pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::gpio::sealed::AFType; use crate::gpio::Speed; use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; -use crate::pac::{FLASH, PWR, RCC}; +use crate::pac::{FLASH, RCC}; use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -407,36 +407,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.apb1enr1().modify(|w| w.set_pwren(true)); - match config.rtc_mux { - RtcClockSource::LSE => { - // 1. Unlock the backup domain - PWR.cr1().modify(|w| w.set_dbp(true)); - - // 2. Setup the LSE - RCC.bdcr().modify(|w| { - // Enable LSE - w.set_lseon(true); - // Max drive strength - // TODO: should probably be settable - w.set_lsedrv(Lsedrv::HIGH); - }); - - // Wait until LSE is running - while !RCC.bdcr().read().lserdy() {} - - BackupDomain::set_rtc_clock_source(RtcClockSource::LSE); - } - RtcClockSource::LSI => { - // Turn on the internal 32 kHz LSI oscillator - RCC.csr().modify(|w| w.set_lsion(true)); - - // Wait until LSI is running - while !RCC.csr().read().lsirdy() {} - - BackupDomain::set_rtc_clock_source(RtcClockSource::LSI); - } - _ => unreachable!(), - } + BackupDomain::configure_rtc(config.rtc_mux, None); let (sys_clk, sw) = match config.mux { ClockSrc::MSI(range) => { diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index 6496b41e1..efd964642 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -293,18 +293,6 @@ pub(crate) fn configure_clocks(config: &Config) { while !rcc.cr().read().hsirdy() {} } - let needs_lsi = if let Some(rtc_mux) = &config.rtc { - *rtc_mux == RtcClockSource::LSI - } else { - false - }; - - if needs_lsi { - rcc.csr().modify(|w| w.set_lsi1on(true)); - - while !rcc.csr().read().lsi1rdy() {} - } - match &config.lse { Some(_) => { rcc.cfgr().modify(|w| w.set_stopwuck(true)); @@ -378,5 +366,5 @@ pub(crate) fn configure_clocks(config: &Config) { config .rtc - .map(|clock_source| BackupDomain::set_rtc_clock_source(clock_source)); + .map(|clock_source| BackupDomain::configure_rtc(clock_source, None)); } diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index e33690d10..b3ddbae64 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,5 +1,5 @@ pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; -use crate::pac::{FLASH, PWR, RCC}; +use crate::pac::{FLASH, RCC}; use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -208,36 +208,7 @@ pub(crate) unsafe fn init(config: Config) { while FLASH.acr().read().latency() != ws {} - match config.rtc_mux { - RtcClockSource::LSE => { - // 1. Unlock the backup domain - PWR.cr1().modify(|w| w.set_dbp(true)); - - // 2. Setup the LSE - RCC.bdcr().modify(|w| { - // Enable LSE - w.set_lseon(true); - // Max drive strength - // TODO: should probably be settable - w.set_lsedrv(Lsedrv::High as u8); //---// PAM - should not be commented - }); - - // Wait until LSE is running - while !RCC.bdcr().read().lserdy() {} - - BackupDomain::set_rtc_clock_source(RtcClockSource::LSE); - } - RtcClockSource::LSI => { - // Turn on the internal 32 kHz LSI oscillator - RCC.csr().modify(|w| w.set_lsion(true)); - - // Wait until LSI is running - while !RCC.csr().read().lsirdy() {} - - BackupDomain::set_rtc_clock_source(RtcClockSource::LSI); - } - _ => unreachable!(), - } + BackupDomain::configure_rtc(config.rtc_mux, None); match config.mux { ClockSrc::HSI16 => { -- cgit From 08410432b5112536ff53b5012601649f27ca9eb1 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 6 Sep 2023 17:51:40 -0500 Subject: stm32: fix rcc merge --- embassy-stm32/src/rcc/wl.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 92bb07967..cd91c8a77 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,5 +1,6 @@ pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; use crate::pac::rcc::vals::Adcsel; +use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; -- cgit From 4550452f43648533ea6e3a5a92a5e643d59bd617 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 6 Sep 2023 17:53:02 -0500 Subject: rustfmt --- embassy-stm32/src/rcc/wl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index cd91c8a77..7a03d9060 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,6 +1,6 @@ pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; use crate::pac::rcc::vals::Adcsel; -use crate::pac::{FLASH, PWR, RCC}; +use crate::pac::{FLASH, RCC}; use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; -- cgit From 11a78fb1e4885604b6819253f97c20762fc0a23b Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 8 Sep 2023 18:20:58 -0500 Subject: rcc: more cleanup --- embassy-stm32/src/rcc/bd.rs | 83 ++++++++++++++++++++++---------------------- embassy-stm32/src/rcc/f2.rs | 30 ++-------------- embassy-stm32/src/rcc/f4.rs | 14 ++------ embassy-stm32/src/rcc/l4.rs | 2 +- embassy-stm32/src/rcc/wb.rs | 19 +++------- embassy-stm32/src/rcc/wl.rs | 23 ++---------- embassy-stm32/src/rtc/mod.rs | 2 +- embassy-stm32/src/rtc/v2.rs | 9 +++++ embassy-stm32/src/rtc/v3.rs | 17 +++++++++ 9 files changed, 82 insertions(+), 117 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 34b88458f..76d0f3a36 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -94,36 +94,49 @@ impl BackupDomain { r } + #[cfg(any( + rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, + rtc_v3u5 + ))] #[allow(dead_code, unused_variables)] - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3))] - pub fn enable_lse(lse_drive: LseDrive) { - Self::modify(|w| { - #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] - w.set_lsedrv(lse_drive.into()); - w.set_lseon(true); - }); - - while !Self::read().lserdy() {} - } - - #[allow(dead_code)] - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3))] - pub fn enable_lsi() { - let csr = crate::pac::RCC.csr(); - - Self::modify(|_| { - #[cfg(not(rtc_v2wb))] - csr.modify(|w| w.set_lsion(true)); - - #[cfg(rtc_v2wb)] - csr.modify(|w| w.set_lsi1on(true)); - }); - - #[cfg(not(rtc_v2wb))] - while !csr.read().lsirdy() {} + pub fn configure_ls(clock_source: RtcClockSource, lse_drive: Option) { + match clock_source { + RtcClockSource::LSI => { + #[cfg(rtc_v3u5)] + let csr = crate::pac::RCC.bdcr(); + + #[cfg(not(rtc_v3u5))] + let csr = crate::pac::RCC.csr(); + + Self::modify(|_| { + #[cfg(not(rtc_v2wb))] + csr.modify(|w| w.set_lsion(true)); + + #[cfg(rtc_v2wb)] + csr.modify(|w| w.set_lsi1on(true)); + }); + + #[cfg(not(rtc_v2wb))] + while !csr.read().lsirdy() {} + + #[cfg(rtc_v2wb)] + while !csr.read().lsi1rdy() {} + } + RtcClockSource::LSE => { + let lse_drive = lse_drive.unwrap_or_default(); + + Self::modify(|w| { + #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] + w.set_lsedrv(lse_drive.into()); + w.set_lseon(true); + }); + + while !Self::read().lserdy() {} + } + _ => {} + }; - #[cfg(rtc_v2wb)] - while !csr.read().lsi1rdy() {} + Self::configure_rtc(clock_source); } #[cfg(any( @@ -131,7 +144,7 @@ impl BackupDomain { rtc_v3u5 ))] #[allow(dead_code, unused_variables)] - pub fn set_rtc_clock_source(clock_source: RtcClockSource) { + pub fn configure_rtc(clock_source: RtcClockSource) { let clock_source = clock_source as u8; #[cfg(any( not(any(rtc_v3, rtc_v3u5, rtc_v2wb)), @@ -146,18 +159,6 @@ impl BackupDomain { }); } - #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3))] - #[allow(dead_code, unused_variables)] - pub fn configure_rtc(clock_source: RtcClockSource, lse_drive: Option) { - match clock_source { - RtcClockSource::LSI => Self::enable_lsi(), - RtcClockSource::LSE => Self::enable_lse(lse_drive.unwrap_or_default()), - _ => {} - }; - - Self::set_rtc_clock_source(clock_source); - } - #[cfg(any( rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5 diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index 8b6556249..b821f9585 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -421,33 +421,9 @@ pub(crate) unsafe fn init(config: Config) { RCC.apb1enr().modify(|w| w.set_pwren(true)); PWR.cr().read(); - match config.rtc { - Some(RtcClockSource::LSE) => { - // 1. Unlock the backup domain - PWR.cr().modify(|w| w.set_dbp(true)); - - // 2. Setup the LSE - RCC.bdcr().modify(|w| { - // Enable LSE - w.set_lseon(true); - }); - - // Wait until LSE is running - while !RCC.bdcr().read().lserdy() {} - - BackupDomain::set_rtc_clock_source(RtcClockSource::LSE); - } - Some(RtcClockSource::LSI) => { - // Turn on the internal 32 kHz LSI oscillator - RCC.csr().modify(|w| w.set_lsion(true)); - - // Wait until LSI is running - while !RCC.csr().read().lsirdy() {} - - BackupDomain::set_rtc_clock_source(RtcClockSource::LSI); - } - _ => todo!(), - } + config + .rtc + .map(|clock_source| BackupDomain::configure_ls(clock_source, None)); set_freqs(Clocks { sys: sys_clk, diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index c2c78a45e..f7bc0d99a 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -461,17 +461,9 @@ pub(crate) unsafe fn init(config: Config) { }) }); - match config.rtc { - Some(RtcClockSource::LSI) => { - RCC.csr().modify(|w| w.set_lsion(true)); - while !RCC.csr().read().lsirdy() {} - } - _ => {} - } - - config.rtc.map(|clock_source| { - BackupDomain::set_rtc_clock_source(clock_source); - }); + config + .rtc + .map(|clock_source| BackupDomain::configure_ls(clock_source, None)); let rtc = match config.rtc { Some(RtcClockSource::LSI) => Some(LSI_FREQ), diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 0083ae5bb..41dbff01e 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -407,7 +407,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.apb1enr1().modify(|w| w.set_pwren(true)); - BackupDomain::configure_rtc(config.rtc_mux, None); + BackupDomain::configure_ls(config.rtc_mux, None); let (sys_clk, sw) = match config.mux { ClockSrc::MSI(range) => { diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index efd964642..d90a50cf4 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -276,7 +276,6 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { } pub(crate) fn configure_clocks(config: &Config) { - let pwr = crate::pac::PWR; let rcc = crate::pac::RCC; let needs_hsi = if let Some(pll_mux) = &config.mux { @@ -293,17 +292,11 @@ pub(crate) fn configure_clocks(config: &Config) { while !rcc.cr().read().hsirdy() {} } - match &config.lse { - Some(_) => { - rcc.cfgr().modify(|w| w.set_stopwuck(true)); + rcc.cfgr().modify(|w| w.set_stopwuck(true)); - pwr.cr1().modify(|w| w.set_dbp(true)); - pwr.cr1().modify(|w| w.set_dbp(true)); - - rcc.bdcr().modify(|w| w.set_lseon(true)); - } - _ => {} - } + config + .rtc + .map(|clock_source| BackupDomain::configure_ls(clock_source, None)); match &config.hse { Some(hse) => { @@ -363,8 +356,4 @@ pub(crate) fn configure_clocks(config: &Config) { w.set_c2hpre(config.ahb2_pre.into()); w.set_shdhpre(config.ahb3_pre.into()); }); - - config - .rtc - .map(|clock_source| BackupDomain::configure_rtc(clock_source, None)); } diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 7a03d9060..6035f50b0 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -137,8 +137,6 @@ pub struct Config { pub shd_ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, - pub enable_lsi: bool, - pub enable_rtc_apb: bool, pub rtc_mux: RtcClockSource, pub adc_clock_source: AdcClockSource, } @@ -152,8 +150,6 @@ impl Default for Config { shd_ahb_pre: AHBPrescaler::NotDivided, apb1_pre: APBPrescaler::NotDivided, apb2_pre: APBPrescaler::NotDivided, - enable_lsi: false, - enable_rtc_apb: false, rtc_mux: RtcClockSource::LSI, adc_clock_source: AdcClockSource::default(), } @@ -234,7 +230,8 @@ pub(crate) unsafe fn init(config: Config) { while FLASH.acr().read().latency() != ws {} - BackupDomain::configure_rtc(config.rtc_mux, None); + // Enables the LSI if configured + BackupDomain::configure_ls(config.rtc_mux, None); match config.mux { ClockSrc::HSI16 => { @@ -269,14 +266,6 @@ pub(crate) unsafe fn init(config: Config) { } } - if config.enable_rtc_apb { - // enable peripheral clock for communication - crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true)); - - // read to allow the pwr clock to enable - crate::pac::PWR.cr1().read(); - } - RCC.extcfgr().modify(|w| { if config.shd_ahb_pre == AHBPrescaler::NotDivided { w.set_shdhpre(0); @@ -301,14 +290,6 @@ pub(crate) unsafe fn init(config: Config) { // TODO: switch voltage range - if config.enable_lsi { - let csr = RCC.csr().read(); - if !csr.lsion() { - RCC.csr().modify(|w| w.set_lsion(true)); - while !RCC.csr().read().lsirdy() {} - } - } - set_freqs(Clocks { sys: Hertz(sys_clk), ahb1: Hertz(ahb_freq), diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 9db4f69c5..a1133a80b 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -268,7 +268,7 @@ pub(crate) mod sealed { crate::pac::RTC } - fn enable_peripheral_clk() {} + fn enable_peripheral_clk(); /// Read content of the backup register. /// diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 62d8d4f9c..9037389ec 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -270,9 +270,18 @@ impl sealed::Instance for crate::peripherals::RTC { } #[cfg(any(rtc_v2f2))] { + // enable peripheral clock for communication crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true)); + + // read to allow the pwr clock to enable crate::pac::PWR.cr().read(); } + + #[cfg(any(rtc_v2f0))] + { + // enable peripheral clock for communication + crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true)); + } } fn read_backup_register(rtc: &Rtc, register: usize) -> Option { diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index a6b2655d8..9ac9f9f85 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -128,6 +128,23 @@ impl super::Rtc { impl sealed::Instance for crate::peripherals::RTC { const BACKUP_REGISTER_COUNT: usize = 32; + fn enable_peripheral_clk() { + #[cfg(any(rcc_wle, rcc_wl5, rcc_g4))] + { + // enable peripheral clock for communication + crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true)); + } + + #[cfg(rcc_g0)] + { + // enable peripheral clock for communication + crate::pac::RCC.apbenr1().modify(|w| w.set_rtcapben(true)); + } + + // read to allow the pwr clock to enable + crate::pac::PWR.cr1().read(); + } + fn read_backup_register(_rtc: &Rtc, register: usize) -> Option { #[allow(clippy::if_same_then_else)] if register < Self::BACKUP_REGISTER_COUNT { -- cgit From 70a4a193c51876b994cbeea547747b6cfcaf2e9a Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 9 Sep 2023 22:01:51 -0500 Subject: stm32: fix adc f3 and example --- embassy-stm32/src/adc/f3.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 458573c05..8f16c6abf 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -7,8 +7,7 @@ use crate::Peripheral; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; -// No calibration data for F103, voltage should be 1.2v -pub const VREF_INT: u32 = 1200; +pub const VREF_INT: u32 = 1230; pub struct Vref; impl AdcPin for Vref {} @@ -102,16 +101,14 @@ impl<'d, T: Instance> Adc<'d, T> { while !T::regs().isr().read().eoc() && !T::regs().isr().read().eos() {} T::regs().isr().write(|_| {}); - T::regs().dr().read().0 as u16 + T::regs().dr().read().rdata() } pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { - // pin.set_as_analog(); - Self::set_channel_sample_time(pin.channel(), self.sample_time); // Configure the channel to sample - T::regs().sqr3().write(|w| w.set_sq(0, pin.channel())); + T::regs().sqr1().write(|w| w.set_sq(0, pin.channel())); self.convert() } -- cgit From 08415e001e93a35579a8fc8e41147df96d80da84 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 10 Sep 2023 13:33:17 -0500 Subject: stm32/f3: add high res for hrtim and misc. --- embassy-stm32/src/adc/f1.rs | 2 +- embassy-stm32/src/hrtim/mod.rs | 36 ++++--- embassy-stm32/src/hrtim/traits.rs | 12 +++ embassy-stm32/src/rcc/f1.rs | 2 +- embassy-stm32/src/rcc/f3.rs | 199 ++++++++++++++++++++++++-------------- embassy-stm32/src/rcc/mod.rs | 8 +- 6 files changed, 172 insertions(+), 87 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index e577ec289..147349de6 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 31c488144..c47b0c092 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 095109598..37cfb9b90 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 b6200231e..304d8f504 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 f8726c24a..cbbe4f98b 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 535ab6ad4..4f0b7fd09 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, -- cgit From 268da2fcde429887a7df879deb90d2383d9d754e Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sun, 10 Sep 2023 14:51:59 +0100 Subject: Handle stbiterr in 4bit wide mode for sdmmc_v1 --- embassy-stm32/src/sdmmc/mod.rs | 56 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 10 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 6b532363c..9fb380fd6 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -33,6 +33,8 @@ impl InterruptHandler { w.set_dtimeoutie(enable); w.set_dataendie(enable); + #[cfg(sdmmc_v1)] + w.set_stbiterre(enable); #[cfg(sdmmc_v2)] w.set_dabortie(enable); }); @@ -102,6 +104,8 @@ pub enum Error { BadClock, SignalingSwitchFailed, PeripheralBusy, + #[cfg(sdmmc_v1)] + StBitErr, } /// A SD command @@ -707,9 +711,15 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); - } else if status.dtimeout() { + } + if status.dtimeout() { return Poll::Ready(Err(Error::Timeout)); - } else if status.dataend() { + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { return Poll::Ready(Ok(())); } Poll::Pending @@ -782,9 +792,15 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); - } else if status.dtimeout() { + } + if status.dtimeout() { return Poll::Ready(Err(Error::Timeout)); - } else if status.dataend() { + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { return Poll::Ready(Ok(())); } Poll::Pending @@ -836,6 +852,8 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { w.set_dataendc(true); w.set_dbckendc(true); w.set_sdioitc(true); + #[cfg(sdmmc_v1)] + w.set_stbiterrc(true); #[cfg(sdmmc_v2)] { @@ -873,9 +891,15 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); - } else if status.dtimeout() { + } + if status.dtimeout() { return Poll::Ready(Err(Error::Timeout)); - } else if status.dataend() { + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { return Poll::Ready(Ok(())); } Poll::Pending @@ -1156,9 +1180,15 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); - } else if status.dtimeout() { + } + if status.dtimeout() { return Poll::Ready(Err(Error::Timeout)); - } else if status.dataend() { + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { return Poll::Ready(Ok(())); } Poll::Pending @@ -1207,9 +1237,15 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); - } else if status.dtimeout() { + } + if status.dtimeout() { return Poll::Ready(Err(Error::Timeout)); - } else if status.dataend() { + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { return Poll::Ready(Ok(())); } Poll::Pending -- cgit From b9889ad3b568b54b029422a039b7e9bf73b60a39 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 11 Sep 2023 17:12:54 -0500 Subject: stm32: add g4 adc345 and misc. --- embassy-stm32/src/adc/mod.rs | 38 ++++++++++++++++++++++++++++++++++---- embassy-stm32/src/adc/v2.rs | 2 +- 2 files changed, 35 insertions(+), 5 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 013debca8..d1cfd8fbd 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -80,17 +80,21 @@ foreach_peripheral!( #[cfg(any(stm32h7, adc_f3, adc_v4))] foreach_peripheral!( (adc, ADC3) => { - #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::sealed::Instance for peripherals::ADC3 { fn regs() -> crate::pac::adc::Adc { crate::pac::ADC3 } #[cfg(all(not(adc_f1), not(adc_v1)))] + #[allow(unreachable_code)] fn common_regs() -> crate::pac::adccommon::AdcCommon { foreach_peripheral!{ (adccommon, ADC3_COMMON) => { return crate::pac::ADC3_COMMON }; + // Fall back to ADC_COMMON if ADC3_COMMON does not exist + (adccommon, ADC_COMMON) => { + return crate::pac::ADC_COMMON + }; } } @@ -100,21 +104,24 @@ foreach_peripheral!( } } - #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::Instance for peripherals::ADC3 {} }; (adc, ADC4) => { - #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::sealed::Instance for peripherals::ADC4 { fn regs() -> crate::pac::adc::Adc { crate::pac::ADC4 } #[cfg(not(any(adc_f1, adc_v1)))] + #[allow(unreachable_code)] fn common_regs() -> crate::pac::adccommon::AdcCommon { foreach_peripheral!{ (adccommon, ADC3_COMMON) => { return crate::pac::ADC3_COMMON }; + // Fall back to ADC_COMMON if ADC3_COMMON does not exist + (adccommon, ADC_COMMON) => { + return crate::pac::ADC_COMMON + }; } } @@ -124,11 +131,34 @@ foreach_peripheral!( } } - #[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))] impl crate::adc::Instance for peripherals::ADC4 {} }; (adc, ADC5) => { + impl crate::adc::sealed::Instance for peripherals::ADC5 { + fn regs() -> crate::pac::adc::Adc { + crate::pac::ADC5 + } + #[cfg(not(any(adc_f1, adc_v1)))] + #[allow(unreachable_code)] + fn common_regs() -> crate::pac::adccommon::AdcCommon { + foreach_peripheral!{ + (adccommon, ADC3_COMMON) => { + return crate::pac::ADC3_COMMON + }; + // Fall back to ADC_COMMON if ADC3_COMMON does not exist + (adccommon, ADC_COMMON) => { + return crate::pac::ADC_COMMON + }; + } + } + + #[cfg(adc_f3)] + fn frequency() -> crate::time::Hertz { + unsafe { crate::rcc::get_freqs() }.adc34.unwrap() + } + } + impl crate::adc::Instance for peripherals::ADC5 {} }; (adc, $inst:ident) => { impl crate::adc::sealed::Instance for peripherals::$inst { diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 9a7acea53..4fbd1cfa2 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -102,7 +102,7 @@ where let presc = Prescaler::from_pclk2(T::frequency()); T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); T::regs().cr2().modify(|reg| { - reg.set_adon(crate::pac::adc::vals::Adon::ENABLED); + reg.set_adon(true); }); delay.delay_us(ADC_POWERUP_TIME_US); -- cgit From 44a5c32ea460a7fb1c125b0f487bc1d705f077e1 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 11 Sep 2023 17:27:47 -0500 Subject: adc/f3: fix startup bug --- embassy-stm32/src/adc/f3.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 8f16c6abf..c7b876fe1 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -49,6 +49,9 @@ impl<'d, T: Instance> Adc<'d, T> { while T::regs().cr().read().adcal() {} + // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223) + delay.delay_us(6 * Self::freq().0 / 1_000_000); + // Enable the adc T::regs().cr().modify(|w| w.set_aden(true)); -- cgit From d36e7abb71bb95907e69bd32359b21b44fe2150b Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 11 Sep 2023 18:52:52 -0500 Subject: adc/f3: fix delay calculation --- embassy-stm32/src/adc/f3.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index c7b876fe1..2971ad527 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -50,7 +50,7 @@ impl<'d, T: Instance> Adc<'d, T> { while T::regs().cr().read().adcal() {} // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223) - delay.delay_us(6 * Self::freq().0 / 1_000_000); + delay.delay_us(6 * 1_000_000 / Self::freq().0); // Enable the adc T::regs().cr().modify(|w| w.set_aden(true)); -- cgit From 582ef9099405947ae621e923ba40bd6fd3789285 Mon Sep 17 00:00:00 2001 From: cumthugo Date: Wed, 13 Sep 2023 00:18:18 +0800 Subject: stm32/usart: fix usart not wake up issue --- embassy-stm32/src/usart/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index bfb056718..2d7443221 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -545,6 +545,13 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { unsafe { rdr(r).read_volatile() }; clear_interrupt_flags(r, sr); + if enable_idle_line_detection { + // enable idle interrupt + r.cr1().modify(|w| { + w.set_idleie(true); + }); + } + compiler_fence(Ordering::SeqCst); let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore(); -- cgit From 49847ff4320daaae16a7e46c43bfb70f9ea3e3d6 Mon Sep 17 00:00:00 2001 From: Mathias Date: Thu, 14 Sep 2023 10:09:09 +0200 Subject: Implement blocking embedded-io::Write for Uart & UartTx --- embassy-stm32/src/usart/buffered.rs | 6 ---- embassy-stm32/src/usart/mod.rs | 70 +++++++++++++++++++++++++++---------- 2 files changed, 52 insertions(+), 24 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 989c88205..b88eebc79 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -410,12 +410,6 @@ impl<'d, T: BasicInstance> Drop for BufferedUartTx<'d, T> { } } -impl embedded_io_async::Error for Error { - fn kind(&self) -> embedded_io_async::ErrorKind { - embedded_io_async::ErrorKind::Other - } -} - impl<'d, T: BasicInstance> embedded_io_async::ErrorType for BufferedUart<'d, T> { type Error = Error; } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 2d7443221..c6d6cc59c 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1037,20 +1037,61 @@ mod eh1 { } } -#[cfg(all(feature = "unstable-traits", feature = "nightly"))] -mod eio { - use embedded_io_async::{ErrorType, Write}; +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other + } +} - use super::*; +impl embedded_io::ErrorType for Uart<'_, T, TxDma, RxDma> +where + T: BasicInstance, +{ + type Error = Error; +} - impl ErrorType for Uart<'_, T, TxDma, RxDma> - where - T: BasicInstance, - { - type Error = Error; +impl embedded_io::ErrorType for UartTx<'_, T, TxDma> +where + T: BasicInstance, +{ + type Error = Error; +} + +impl embedded_io::Write for Uart<'_, T, TxDma, RxDma> +where + T: BasicInstance, + TxDma: crate::usart::TxDma, +{ + fn write(&mut self, buf: &[u8]) -> Result { + self.blocking_write(buf)?; + Ok(buf.len()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.blocking_flush() + } +} + +impl embedded_io::Write for UartTx<'_, T, TxDma> +where + T: BasicInstance, + TxDma: crate::usart::TxDma, +{ + fn write(&mut self, buf: &[u8]) -> Result { + self.blocking_write(buf)?; + Ok(buf.len()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.blocking_flush() } +} - impl Write for Uart<'_, T, TxDma, RxDma> +#[cfg(all(feature = "unstable-traits", feature = "nightly"))] +mod eio { + use super::*; + + impl embedded_io_async::Write for Uart<'_, T, TxDma, RxDma> where T: BasicInstance, TxDma: super::TxDma, @@ -1065,14 +1106,7 @@ mod eio { } } - impl ErrorType for UartTx<'_, T, TxDma> - where - T: BasicInstance, - { - type Error = Error; - } - - impl Write for UartTx<'_, T, TxDma> + impl embedded_io_async::Write for UartTx<'_, T, TxDma> where T: BasicInstance, TxDma: super::TxDma, -- cgit From 309c3d6b472aa07bdf8b96f57eef5c0b5a686844 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 14 Sep 2023 18:36:03 -0500 Subject: update metapac --- embassy-stm32/src/adc/v2.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 4fbd1cfa2..f583c08a9 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -125,7 +125,7 @@ where /// [Adc::read_internal()] to perform conversion. pub fn enable_vrefint(&self) -> VrefInt { T::common_regs().ccr().modify(|reg| { - reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); + reg.set_tsvrefe(true); }); VrefInt {} @@ -138,7 +138,7 @@ where /// temperature sensor will return vbat value. pub fn enable_temperature(&self) -> Temperature { T::common_regs().ccr().modify(|reg| { - reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED); + reg.set_tsvrefe(true); }); Temperature {} @@ -148,7 +148,7 @@ where /// [Adc::read_internal()] to perform conversion. pub fn enable_vbat(&self) -> Vbat { T::common_regs().ccr().modify(|reg| { - reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED); + reg.set_vbate(true); }); Vbat {} -- cgit From 9fb14379c3d24f68a1f0715d61a54e31b7b53d2a Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 14 Sep 2023 18:53:27 -0500 Subject: stm32: add lp to l0 --- embassy-stm32/src/low_power.rs | 15 ++++++++++++++- embassy-stm32/src/rcc/bd.rs | 4 ++-- embassy-stm32/src/rcc/l0.rs | 8 ++++++++ embassy-stm32/src/rtc/v2.rs | 25 +++++++++++++++++++++++-- 4 files changed, 47 insertions(+), 5 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 7e678d323..b42b674e1 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -95,8 +95,21 @@ impl Executor { self.time_driver.set_rtc(rtc); + #[cfg(not(stm32l0))] crate::interrupt::typelevel::RTC_WKUP::unpend(); - unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() }; + + #[cfg(not(stm32l0))] + unsafe { + crate::interrupt::typelevel::RTC_WKUP::enable() + }; + + #[cfg(stm32l0)] + crate::interrupt::typelevel::RTC::unpend(); + + #[cfg(stm32l0)] + unsafe { + crate::interrupt::typelevel::RTC::enable() + }; rtc.enable_wakeup_line(); } diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 76d0f3a36..059a32116 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -58,13 +58,13 @@ impl BackupDomain { ))] #[allow(dead_code, unused_variables)] fn modify(f: impl FnOnce(&mut Bdcr) -> R) -> R { - #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))] + #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1, rtc_v2l0))] let cr = crate::pac::PWR.cr(); #[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] let cr = crate::pac::PWR.cr1(); // TODO: Missing from PAC for l0 and f0? - #[cfg(not(any(rtc_v2f0, rtc_v2l0, rtc_v3u5)))] + #[cfg(not(any(rtc_v2f0, rtc_v3u5)))] { cr.modify(|w| w.set_dbp(true)); while !cr.read().dbp() {} diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index 7f9ab01f1..3c8511ffd 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -1,4 +1,6 @@ +use super::bd::BackupDomain; pub use super::bus::{AHBPrescaler, APBPrescaler}; +use super::RtcClockSource; use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; use crate::pac::RCC; #[cfg(crs)] @@ -135,6 +137,7 @@ pub struct Config { pub apb2_pre: APBPrescaler, #[cfg(crs)] pub enable_hsi48: bool, + pub rtc: Option, } impl Default for Config { @@ -147,6 +150,7 @@ impl Default for Config { apb2_pre: APBPrescaler::NotDivided, #[cfg(crs)] enable_hsi48: false, + rtc: None, } } } @@ -231,6 +235,10 @@ pub(crate) unsafe fn init(config: Config) { } }; + config.rtc.map(|rtc| { + BackupDomain::configure_ls(rtc, None); + }); + RCC.cfgr().modify(|w| { w.set_sw(sw); w.set_hpre(config.ahb_pre.into()); diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 9037389ec..1fa9f2fe3 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -15,7 +15,7 @@ pub(crate) enum WakeupPrescaler { Div16 = 16, } -#[cfg(any(stm32wb, stm32f4))] +#[cfg(any(stm32wb, stm32f4, stm32l0))] impl From for crate::pac::rtc::vals::Wucksel { fn from(val: WakeupPrescaler) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -29,7 +29,7 @@ impl From for crate::pac::rtc::vals::Wucksel { } } -#[cfg(any(stm32wb, stm32f4))] +#[cfg(any(stm32wb, stm32f4, stm32l0))] impl From for WakeupPrescaler { fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -67,10 +67,15 @@ impl super::Rtc { pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { use embassy_time::{Duration, TICK_HZ}; + #[cfg(not(stm32l0))] use crate::rcc::get_freqs; + #[cfg(not(stm32l0))] let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64; + #[cfg(stm32l0)] + let rtc_hz = 32_768u64; + let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ; let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); @@ -109,7 +114,14 @@ impl super::Rtc { pub(crate) fn enable_wakeup_line(&self) { use crate::pac::EXTI; + #[cfg(stm32l0)] + EXTI.rtsr(0).modify(|w| w.set_line(20, true)); + #[cfg(stm32l0)] + EXTI.imr(0).modify(|w| w.set_line(20, true)); + + #[cfg(not(stm32l0))] EXTI.rtsr(0).modify(|w| w.set_line(22, true)); + #[cfg(not(stm32l0))] EXTI.imr(0).modify(|w| w.set_line(22, true)); } @@ -126,8 +138,17 @@ impl super::Rtc { regs.cr().modify(|w| w.set_wute(false)); regs.isr().modify(|w| w.set_wutf(false)); + #[cfg(not(stm32l0))] crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, true)); + + #[cfg(stm32l0)] + crate::pac::EXTI.pr(0).modify(|w| w.set_line(20, true)); + + #[cfg(not(stm32l0))] crate::interrupt::typelevel::RTC_WKUP::unpend(); + + #[cfg(stm32l0)] + crate::interrupt::typelevel::RTC::unpend(); }); critical_section::with(|cs| { -- cgit From 45e9e51bdc5c3657c44a0951932e5f5a87d5f175 Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Fri, 15 Sep 2023 15:13:52 +0200 Subject: Fix low-power feature for STM32L0 --- embassy-stm32/src/rtc/v2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 1fa9f2fe3..726886f10 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -298,7 +298,7 @@ impl sealed::Instance for crate::peripherals::RTC { crate::pac::PWR.cr().read(); } - #[cfg(any(rtc_v2f0))] + #[cfg(any(rtc_v2f0, rtc_v2l0))] { // enable peripheral clock for communication crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true)); -- cgit From c28a6bdd0b6cde56c5b1b40a4c57d9b31e05d531 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 15 Sep 2023 17:35:53 -0500 Subject: stm32: generate adc_common --- embassy-stm32/src/adc/mod.rs | 116 ++----------------------------------------- embassy-stm32/src/rcc/f3.rs | 14 ++++-- 2 files changed, 15 insertions(+), 115 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index d1cfd8fbd..9334deac4 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -56,127 +56,21 @@ pub trait Instance: sealed::Instance + crate::Peripheral

+ crate::rcc: pub trait AdcPin: sealed::AdcPin {} pub trait InternalChannel: sealed::InternalChannel {} -#[cfg(not(any(stm32h7, adc_f3, adc_v4)))] -foreach_peripheral!( - (adc, $inst:ident) => { +foreach_adc!( + ($inst:ident, $common_inst:ident, $clock:ident) => { impl crate::adc::sealed::Instance for peripherals::$inst { fn regs() -> crate::pac::adc::Adc { crate::pac::$inst } - #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] - fn common_regs() -> crate::pac::adccommon::AdcCommon { - foreach_peripheral!{ - (adccommon, $common_inst:ident) => { - return crate::pac::$common_inst - }; - } - } - } - - impl crate::adc::Instance for peripherals::$inst {} - }; -); - -#[cfg(any(stm32h7, adc_f3, adc_v4))] -foreach_peripheral!( - (adc, ADC3) => { - impl crate::adc::sealed::Instance for peripherals::ADC3 { - fn regs() -> crate::pac::adc::Adc { - crate::pac::ADC3 - } - #[cfg(all(not(adc_f1), not(adc_v1)))] - #[allow(unreachable_code)] - fn common_regs() -> crate::pac::adccommon::AdcCommon { - foreach_peripheral!{ - (adccommon, ADC3_COMMON) => { - return crate::pac::ADC3_COMMON - }; - // Fall back to ADC_COMMON if ADC3_COMMON does not exist - (adccommon, ADC_COMMON) => { - return crate::pac::ADC_COMMON - }; - } - } - - #[cfg(adc_f3)] - fn frequency() -> crate::time::Hertz { - unsafe { crate::rcc::get_freqs() }.adc34.unwrap() - } - } - - impl crate::adc::Instance for peripherals::ADC3 {} - }; - (adc, ADC4) => { - impl crate::adc::sealed::Instance for peripherals::ADC4 { - fn regs() -> crate::pac::adc::Adc { - crate::pac::ADC4 - } - #[cfg(not(any(adc_f1, adc_v1)))] - #[allow(unreachable_code)] - fn common_regs() -> crate::pac::adccommon::AdcCommon { - foreach_peripheral!{ - (adccommon, ADC3_COMMON) => { - return crate::pac::ADC3_COMMON - }; - // Fall back to ADC_COMMON if ADC3_COMMON does not exist - (adccommon, ADC_COMMON) => { - return crate::pac::ADC_COMMON - }; - } - } - - #[cfg(adc_f3)] - fn frequency() -> crate::time::Hertz { - unsafe { crate::rcc::get_freqs() }.adc34.unwrap() - } - } - - impl crate::adc::Instance for peripherals::ADC4 {} - }; - (adc, ADC5) => { - impl crate::adc::sealed::Instance for peripherals::ADC5 { - fn regs() -> crate::pac::adc::Adc { - crate::pac::ADC5 - } - #[cfg(not(any(adc_f1, adc_v1)))] - #[allow(unreachable_code)] - fn common_regs() -> crate::pac::adccommon::AdcCommon { - foreach_peripheral!{ - (adccommon, ADC3_COMMON) => { - return crate::pac::ADC3_COMMON - }; - // Fall back to ADC_COMMON if ADC3_COMMON does not exist - (adccommon, ADC_COMMON) => { - return crate::pac::ADC_COMMON - }; - } - } - #[cfg(adc_f3)] - fn frequency() -> crate::time::Hertz { - unsafe { crate::rcc::get_freqs() }.adc34.unwrap() - } - } - - impl crate::adc::Instance for peripherals::ADC5 {} - }; - (adc, $inst:ident) => { - impl crate::adc::sealed::Instance for peripherals::$inst { - fn regs() -> crate::pac::adc::Adc { - crate::pac::$inst - } - #[cfg(not(any(adc_f1, adc_v1)))] + #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] fn common_regs() -> crate::pac::adccommon::AdcCommon { - foreach_peripheral!{ - (adccommon, ADC_COMMON) => { - return crate::pac::ADC_COMMON - }; - } + return crate::pac::$common_inst } #[cfg(adc_f3)] fn frequency() -> crate::time::Hertz { - unsafe { crate::rcc::get_freqs() }.adc.unwrap() + unsafe { crate::rcc::get_freqs() }.$clock.unwrap() } } diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index cbbe4f98b..630dbd4fe 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -280,7 +280,7 @@ pub(crate) unsafe fn init(config: Config) { } }); - #[cfg(rcc_f3)] + #[cfg(all(rcc_f3, adc3_common))] let adc34 = config.adc.map(|adc| { if !adc.is_bus() { RCC.cfgr2().modify(|w| { @@ -291,9 +291,13 @@ pub(crate) unsafe fn init(config: Config) { Hertz(sysclk / adc as u32) }) } else { - // TODO: need to use only if adc32_common is present + crate::pac::ADC3_COMMON.ccr().modify(|w| { + assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1)); + + w.set_ckmode(adc.into()); - todo!() + Hertz(sysclk / adc.bus_div() as u32) + }) } }); @@ -323,8 +327,10 @@ pub(crate) unsafe fn init(config: Config) { ahb1: Hertz(hclk), #[cfg(rcc_f3)] adc: adc, - #[cfg(rcc_f3)] + #[cfg(all(rcc_f3, adc3_common))] adc34: adc34, + #[cfg(all(rcc_f3, not(adc3_common)))] + adc34: None, #[cfg(stm32f334)] hrtim: hrtim, }); -- cgit From aa2fa29b89c120ec23d64252d3f1b036c1369b00 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 15 Sep 2023 17:36:21 -0500 Subject: stm32: fix adc f3 startup time closes #1888. --- embassy-stm32/src/adc/f3.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 2971ad527..b39d6ac8e 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -50,7 +50,7 @@ impl<'d, T: Instance> Adc<'d, T> { while T::regs().cr().read().adcal() {} // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223) - delay.delay_us(6 * 1_000_000 / Self::freq().0); + delay.delay_us(1 + (6 * 1_000_000 / Self::freq().0)); // Enable the adc T::regs().cr().modify(|w| w.set_aden(true)); -- cgit From 6da75ea285482bd950b04ae00dde25303f160705 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 15 Sep 2023 18:41:33 -0500 Subject: stm32: rtc/low-power cleanup --- embassy-stm32/src/exti.rs | 3 +++ embassy-stm32/src/low_power.rs | 47 ++++++------------------------------- embassy-stm32/src/rtc/mod.rs | 34 ++++++++++++++++----------- embassy-stm32/src/rtc/v2.rs | 50 +++++++++++++++++++--------------------- embassy-stm32/src/time_driver.rs | 6 +++++ 5 files changed, 60 insertions(+), 80 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 925cf39be..bd4bab1f8 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -39,6 +39,9 @@ fn exticr_regs() -> pac::afio::Afio { } pub unsafe fn on_irq() { + #[cfg(feature = "low-power")] + crate::low_power::on_wakeup_irq(); + #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))] let bits = EXTI.pr(0).read().0; #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index b42b674e1..ce8afb578 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -5,7 +5,6 @@ use cortex_m::peripheral::SCB; use embassy_executor::*; use crate::interrupt; -use crate::interrupt::typelevel::Interrupt; use crate::rcc::low_power_ready; use crate::time_driver::{get_driver, RtcDriver}; @@ -19,36 +18,20 @@ foreach_interrupt! { (RTC, rtc, $block:ident, WKUP, $irq:ident) => { #[interrupt] unsafe fn $irq() { - unsafe { EXECUTOR.as_mut().unwrap() }.on_wakeup_irq(); + EXECUTOR.as_mut().unwrap().on_wakeup_irq(); } }; } -// pub fn timer_driver_pause_time() { -// pause_time(); -// } +#[allow(dead_code)] +pub(crate) unsafe fn on_wakeup_irq() { + EXECUTOR.as_mut().unwrap().on_wakeup_irq(); +} pub fn stop_with_rtc(rtc: &'static Rtc) { unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) } -// pub fn start_wakeup_alarm(requested_duration: embassy_time::Duration) { -// let rtc_instant = unsafe { EXECUTOR.as_mut().unwrap() } -// .rtc -// .unwrap() -// .start_wakeup_alarm(requested_duration); -// -// unsafe { EXECUTOR.as_mut().unwrap() }.last_stop = Some(rtc_instant); -// } -// -// pub fn set_sleepdeep() { -// unsafe { EXECUTOR.as_mut().unwrap() }.scb.set_sleepdeep(); -// } -// -// pub fn stop_wakeup_alarm() -> RtcInstant { -// unsafe { EXECUTOR.as_mut().unwrap() }.rtc.unwrap().stop_wakeup_alarm() -// } - /// Thread mode executor, using WFE/SEV. /// /// This is the simplest and most common kind of executor. It runs on @@ -91,27 +74,11 @@ impl Executor { } pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { - trace!("low power: stop with rtc configured"); - self.time_driver.set_rtc(rtc); - #[cfg(not(stm32l0))] - crate::interrupt::typelevel::RTC_WKUP::unpend(); - - #[cfg(not(stm32l0))] - unsafe { - crate::interrupt::typelevel::RTC_WKUP::enable() - }; - - #[cfg(stm32l0)] - crate::interrupt::typelevel::RTC::unpend(); - - #[cfg(stm32l0)] - unsafe { - crate::interrupt::typelevel::RTC::enable() - }; - rtc.enable_wakeup_line(); + + trace!("low power: stop with rtc configured"); } fn configure_pwr(&mut self) { diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index a1133a80b..32a5cc123 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -124,9 +124,6 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { - #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] - use crate::rcc::get_freqs; - RTC::enable_peripheral_clk(); BackupDomain::enable_rtc(); @@ -135,26 +132,29 @@ impl Rtc { stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), }; + let frequency = Self::frequency(); + let async_psc = ((frequency.0 / rtc_config.frequency.0) - 1) as u8; + let sync_psc = (rtc_config.frequency.0 - 1) as u16; + + this.configure(async_psc, sync_psc); + + this + } + + fn frequency() -> Hertz { #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] - let freqs = unsafe { get_freqs() }; + let freqs = unsafe { crate::rcc::get_freqs() }; // Load the clock frequency from the rcc mod, if supported #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] - let frequency = match freqs.rtc { + match freqs.rtc { Some(hertz) => hertz, None => freqs.rtc_hse.unwrap(), - }; + } // Assume the default value, if not supported #[cfg(not(any(rcc_wb, rcc_f4, rcc_f410)))] - let frequency = Hertz(32_768); - - let async_psc = ((frequency.0 / rtc_config.frequency.0) - 1) as u8; - let sync_psc = (rtc_config.frequency.0 - 1) as u16; - - this.configure(async_psc, sync_psc); - - this + Hertz(32_768) } /// Set the datetime to a new value. @@ -264,6 +264,12 @@ pub(crate) mod sealed { pub trait Instance { const BACKUP_REGISTER_COUNT: usize; + #[cfg(feature = "low-power")] + const EXTI_WAKEUP_LINE: usize; + + #[cfg(feature = "low-power")] + type WakeupInterrupt: crate::interrupt::typelevel::Interrupt; + fn regs() -> Rtc { crate::pac::RTC } diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 726886f10..aa3c31ee1 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -67,15 +67,10 @@ impl super::Rtc { pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { use embassy_time::{Duration, TICK_HZ}; - #[cfg(not(stm32l0))] - use crate::rcc::get_freqs; - - #[cfg(not(stm32l0))] - let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64; - - #[cfg(stm32l0)] - let rtc_hz = 32_768u64; + #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] + unsafe { crate::rcc::get_freqs() }.rtc.unwrap(); + let rtc_hz = Self::frequency().0 as u64; let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ; let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); @@ -112,17 +107,14 @@ impl super::Rtc { #[cfg(feature = "low-power")] pub(crate) fn enable_wakeup_line(&self) { + use crate::interrupt::typelevel::Interrupt; use crate::pac::EXTI; - #[cfg(stm32l0)] - EXTI.rtsr(0).modify(|w| w.set_line(20, true)); - #[cfg(stm32l0)] - EXTI.imr(0).modify(|w| w.set_line(20, true)); + ::WakeupInterrupt::unpend(); + unsafe { ::WakeupInterrupt::enable() }; - #[cfg(not(stm32l0))] - EXTI.rtsr(0).modify(|w| w.set_line(22, true)); - #[cfg(not(stm32l0))] - EXTI.imr(0).modify(|w| w.set_line(22, true)); + EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); } #[cfg(feature = "low-power")] @@ -138,17 +130,11 @@ impl super::Rtc { regs.cr().modify(|w| w.set_wute(false)); regs.isr().modify(|w| w.set_wutf(false)); - #[cfg(not(stm32l0))] - crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, true)); - - #[cfg(stm32l0)] - crate::pac::EXTI.pr(0).modify(|w| w.set_line(20, true)); - - #[cfg(not(stm32l0))] - crate::interrupt::typelevel::RTC_WKUP::unpend(); + crate::pac::EXTI + .pr(0) + .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); - #[cfg(stm32l0)] - crate::interrupt::typelevel::RTC::unpend(); + ::WakeupInterrupt::unpend(); }); critical_section::with(|cs| { @@ -280,6 +266,18 @@ impl super::Rtc { impl sealed::Instance for crate::peripherals::RTC { const BACKUP_REGISTER_COUNT: usize = 20; + #[cfg(all(feature = "low-power", stm32f4))] + const EXTI_WAKEUP_LINE: usize = 22; + + #[cfg(all(feature = "low-power", stm32l0))] + const EXTI_WAKEUP_LINE: usize = 20; + + #[cfg(all(feature = "low-power", stm32f4))] + type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; + + #[cfg(all(feature = "low-power", stm32l0))] + type WakeupInterrupt = crate::interrupt::typelevel::RTC; + fn enable_peripheral_clk() { #[cfg(any(rtc_v2l4, rtc_v2wb))] { diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 99d423d08..887e54f65 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -372,6 +372,12 @@ impl RtcDriver { #[cfg(feature = "low-power")] /// Resume the timer with the given offset pub(crate) fn resume_time(&self) { + if T::regs_gp16().cr1().read().cen() { + // Time isn't currently stopped + + return; + } + self.stop_wakeup_alarm(); T::regs_gp16().cr1().modify(|w| w.set_cen(true)); -- cgit From 8315cf064eab133006e1397819b50f072fec6398 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 16 Sep 2023 03:44:01 +0200 Subject: stm32: add stm32wba support. --- embassy-stm32/src/lib.rs | 2 +- embassy-stm32/src/rcc/bd.rs | 110 ++++++++++---------------- embassy-stm32/src/rcc/bus.rs | 6 -- embassy-stm32/src/rcc/mod.rs | 8 +- embassy-stm32/src/rcc/u5.rs | 2 +- embassy-stm32/src/rcc/wba.rs | 184 +++++++++++++++++++++++++++++++++++++++++++ embassy-stm32/src/rtc/mod.rs | 2 - 7 files changed, 234 insertions(+), 80 deletions(-) create mode 100644 embassy-stm32/src/rcc/wba.rs (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index ec8648ee4..6a53f8762 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -154,7 +154,7 @@ pub fn init(config: Config) -> Peripherals { #[cfg(dbgmcu)] if config.enable_debug_during_sleep { crate::pac::DBGMCU.cr().modify(|cr| { - #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))] + #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))] { cr.set_dbg_stop(true); cr.set_dbg_standby(true); diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 059a32116..d774b993b 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -26,19 +26,7 @@ impl From for crate::pac::rcc::vals::Lsedrv { } } -#[allow(dead_code)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[repr(u8)] -pub enum RtcClockSource { - /// 00: No clock - NoClock = 0b00, - /// 01: LSE oscillator clock used as RTC clock - LSE = 0b01, - /// 10: LSI oscillator clock used as RTC clock - LSI = 0b10, - /// 11: HSE oscillator clock divided by 32 used as RTC clock - HSE = 0b11, -} +pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource; #[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] #[allow(dead_code)] @@ -109,17 +97,17 @@ impl BackupDomain { let csr = crate::pac::RCC.csr(); Self::modify(|_| { - #[cfg(not(rtc_v2wb))] + #[cfg(not(any(rcc_wb, rcc_wba)))] csr.modify(|w| w.set_lsion(true)); - #[cfg(rtc_v2wb)] + #[cfg(any(rcc_wb, rcc_wba))] csr.modify(|w| w.set_lsi1on(true)); }); - #[cfg(not(rtc_v2wb))] + #[cfg(not(any(rcc_wb, rcc_wba)))] while !csr.read().lsirdy() {} - #[cfg(rtc_v2wb)] + #[cfg(any(rcc_wb, rcc_wba))] while !csr.read().lsi1rdy() {} } RtcClockSource::LSE => { @@ -136,64 +124,50 @@ impl BackupDomain { _ => {} }; - Self::configure_rtc(clock_source); - } - - #[cfg(any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, - rtc_v3u5 - ))] - #[allow(dead_code, unused_variables)] - pub fn configure_rtc(clock_source: RtcClockSource) { - let clock_source = clock_source as u8; - #[cfg(any( - not(any(rtc_v3, rtc_v3u5, rtc_v2wb)), - all(any(rtc_v3, rtc_v3u5), not(any(rcc_wl5, rcc_wle))) - ))] - let clock_source = crate::pac::rcc::vals::Rtcsel::from_bits(clock_source); - - #[cfg(not(rtc_v2wb))] - Self::modify(|w| { - // Select RTC source - w.set_rtcsel(clock_source); - }); - } - - #[cfg(any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, - rtc_v3u5 - ))] - #[allow(dead_code)] - pub fn enable_rtc() { - let reg = Self::read(); + if clock_source == RtcClockSource::NOCLOCK { + // disable it + Self::modify(|w| { + #[cfg(not(rcc_wba))] + w.set_rtcen(false); + w.set_rtcsel(clock_source); + }); + } else { + // check if it's already enabled and in the source we want. + let reg = Self::read(); + let ok = reg.rtcsel() == clock_source; + #[cfg(not(rcc_wba))] + let ok = ok & reg.rtcen(); - #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); + // if not, configure it. + if !ok { + #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] + assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); - if !reg.rtcen() { - #[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))] - Self::modify(|w| w.set_bdrst(true)); + #[cfg(not(any(rcc_l0, rcc_l1)))] + Self::modify(|w| w.set_bdrst(true)); - Self::modify(|w| { - // Reset - #[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))] - w.set_bdrst(false); + Self::modify(|w| { + // Reset + #[cfg(not(any(rcc_l0, rcc_l1)))] + w.set_bdrst(false); - w.set_rtcen(true); - w.set_rtcsel(reg.rtcsel()); + #[cfg(not(rcc_wba))] + w.set_rtcen(true); + w.set_rtcsel(clock_source); - // Restore bcdr - #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - w.set_lscosel(reg.lscosel()); - #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - w.set_lscoen(reg.lscoen()); + // Restore bcdr + #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] + w.set_lscosel(reg.lscosel()); + #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] + w.set_lscoen(reg.lscoen()); - w.set_lseon(reg.lseon()); + w.set_lseon(reg.lseon()); - #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); - }); + #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] + w.set_lsedrv(reg.lsedrv()); + w.set_lsebyp(reg.lsebyp()); + }); + } } } } diff --git a/embassy-stm32/src/rcc/bus.rs b/embassy-stm32/src/rcc/bus.rs index 62736a43a..32e10b7ec 100644 --- a/embassy-stm32/src/rcc/bus.rs +++ b/embassy-stm32/src/rcc/bus.rs @@ -79,10 +79,7 @@ impl From for rcc::vals::Hpre { use rcc::vals::Hpre; match val { - #[cfg(not(rcc_u5))] AHBPrescaler::NotDivided => Hpre::DIV1, - #[cfg(rcc_u5)] - AHBPrescaler::NotDivided => Hpre::NONE, AHBPrescaler::Div2 => Hpre::DIV2, AHBPrescaler::Div4 => Hpre::DIV4, AHBPrescaler::Div8 => Hpre::DIV8, @@ -148,10 +145,7 @@ impl From for rcc::vals::Ppre { use rcc::vals::Ppre; match val { - #[cfg(not(rcc_u5))] APBPrescaler::NotDivided => Ppre::DIV1, - #[cfg(rcc_u5)] - APBPrescaler::NotDivided => Ppre::NONE, APBPrescaler::Div2 => Ppre::DIV2, APBPrescaler::Div4 => Ppre::DIV4, APBPrescaler::Div8 => Ppre::DIV8, diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 4f0b7fd09..b8c12b995 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -1,6 +1,7 @@ #![macro_use] pub(crate) mod bd; +#[cfg(not(rcc_wba))] pub mod bus; use core::mem::MaybeUninit; @@ -23,6 +24,7 @@ use crate::time::Hertz; #[cfg_attr(rcc_l5, path = "l5.rs")] #[cfg_attr(rcc_u5, path = "u5.rs")] #[cfg_attr(rcc_wb, path = "wb.rs")] +#[cfg_attr(rcc_wba, path = "wba.rs")] #[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")] #[cfg_attr(any(rcc_h5, rcc_h50), path = "h5.rs")] mod _version; @@ -46,12 +48,14 @@ pub struct Clocks { pub apb3: Hertz, #[cfg(any(rcc_h7, rcc_h7ab))] pub apb4: Hertz, + #[cfg(any(rcc_wba))] + pub apb7: Hertz, // AHB pub ahb1: Hertz, #[cfg(any( rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb, - rcc_wl5, rcc_wle + rcc_wba, rcc_wl5, rcc_wle ))] pub ahb2: Hertz, #[cfg(any( @@ -59,7 +63,7 @@ pub struct Clocks { rcc_wle ))] pub ahb3: Hertz, - #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))] + #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_wba))] pub ahb4: Hertz, #[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))] diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 4aca9cd3d..6540b1f5c 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -165,7 +165,7 @@ impl Into for ClockSrc { ClockSrc::MSI(..) => Sw::MSIS, ClockSrc::HSE(..) => Sw::HSE, ClockSrc::HSI16 => Sw::HSI16, - ClockSrc::PLL1R(..) => Sw::PLL1R, + ClockSrc::PLL1R(..) => Sw::PLL1_R, } } } diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs new file mode 100644 index 000000000..2a11c9a22 --- /dev/null +++ b/embassy-stm32/src/rcc/wba.rs @@ -0,0 +1,184 @@ +use stm32_metapac::rcc::vals::{Pllsrc, Sw}; + +use crate::pac::{FLASH, RCC}; +use crate::rcc::{set_freqs, Clocks}; +use crate::time::Hertz; + +/// HSI speed +pub const HSI_FREQ: Hertz = Hertz(16_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(32_000); + +pub use crate::pac::pwr::vals::Vos as VoltageScale; +pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; + +#[derive(Copy, Clone)] +pub enum ClockSrc { + HSE(Hertz), + HSI16, +} + +#[derive(Clone, Copy, Debug)] +pub enum PllSrc { + HSE(Hertz), + HSI16, +} + +impl Into for PllSrc { + fn into(self) -> Pllsrc { + match self { + PllSrc::HSE(..) => Pllsrc::HSE32, + PllSrc::HSI16 => Pllsrc::HSI16, + } + } +} + +impl Into for ClockSrc { + fn into(self) -> Sw { + match self { + ClockSrc::HSE(..) => Sw::HSE32, + ClockSrc::HSI16 => Sw::HSI16, + } + } +} + +trait Div { + fn div(&self) -> u8; +} + +impl Div for APBPrescaler { + fn div(&self) -> u8 { + match self { + Self::DIV1 => 1, + Self::DIV2 => 2, + Self::DIV4 => 4, + Self::DIV8 => 8, + Self::DIV16 => 16, + _ => unreachable!(), + } + } +} + +impl Div for AHBPrescaler { + fn div(&self) -> u8 { + match self { + Self::DIV1 => 1, + Self::DIV2 => 2, + Self::DIV4 => 4, + Self::DIV8 => 8, + Self::DIV16 => 16, + _ => unreachable!(), + } + } +} + +#[derive(Copy, Clone)] +pub struct Config { + pub mux: ClockSrc, + pub ahb_pre: AHBPrescaler, + pub apb1_pre: APBPrescaler, + pub apb2_pre: APBPrescaler, + pub apb7_pre: APBPrescaler, +} + +impl Default for Config { + fn default() -> Self { + Self { + mux: ClockSrc::HSI16, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, + apb7_pre: APBPrescaler::DIV1, + } + } +} + +pub(crate) unsafe fn init(config: Config) { + let sys_clk = match config.mux { + ClockSrc::HSE(freq) => { + RCC.cr().write(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + + freq.0 + } + ClockSrc::HSI16 => { + RCC.cr().write(|w| w.set_hsion(true)); + while !RCC.cr().read().hsirdy() {} + + HSI_FREQ.0 + } + }; + + // TODO make configurable + let power_vos = VoltageScale::RANGE1; + + // states and programming delay + let wait_states = match power_vos { + VoltageScale::RANGE1 => match sys_clk { + ..=32_000_000 => 0, + ..=64_000_000 => 1, + ..=96_000_000 => 2, + ..=100_000_000 => 3, + _ => 4, + }, + VoltageScale::RANGE2 => match sys_clk { + ..=8_000_000 => 0, + ..=16_000_000 => 1, + _ => 2, + }, + }; + + FLASH.acr().modify(|w| { + w.set_latency(wait_states); + }); + + RCC.cfgr1().modify(|w| { + w.set_sw(config.mux.into()); + }); + + RCC.cfgr2().modify(|w| { + w.set_hpre(config.ahb_pre.into()); + w.set_ppre1(config.apb1_pre.into()); + w.set_ppre2(config.apb2_pre.into()); + }); + + RCC.cfgr3().modify(|w| { + w.set_ppre7(config.apb7_pre.into()); + }); + + let ahb_freq: u32 = sys_clk / config.ahb_pre.div() as u32; + let (apb1_freq, apb1_tim_freq) = match config.apb1_pre.div() { + 1 => (ahb_freq, ahb_freq), + div => { + let freq = ahb_freq / div as u32; + (freq, freq * 2) + } + }; + let (apb2_freq, apb2_tim_freq) = match config.apb2_pre.div() { + 1 => (ahb_freq, ahb_freq), + div => { + let freq = ahb_freq / div as u32; + (freq, freq * 2) + } + }; + let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre.div() { + 1 => (ahb_freq, ahb_freq), + div => { + let freq = ahb_freq / div as u32; + (freq, freq * 2) + } + }; + + set_freqs(Clocks { + sys: Hertz(sys_clk), + ahb1: Hertz(ahb_freq), + ahb2: Hertz(ahb_freq), + ahb4: Hertz(ahb_freq), + apb1: Hertz(apb1_freq), + apb2: Hertz(apb2_freq), + apb7: Hertz(apb7_freq), + apb1_tim: Hertz(apb1_tim_freq), + apb2_tim: Hertz(apb2_tim_freq), + }); +} diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 32a5cc123..3ecf477db 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -10,7 +10,6 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; -use crate::rcc::bd::BackupDomain; pub use crate::rcc::RtcClockSource; use crate::time::Hertz; @@ -125,7 +124,6 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { RTC::enable_peripheral_clk(); - BackupDomain::enable_rtc(); let mut this = Self { #[cfg(feature = "low-power")] -- cgit From ad0a306ea52f7d842efa8ce40c89f462501ed018 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 16 Sep 2023 10:19:09 -0500 Subject: stm32: fix wpan_ble test --- embassy-stm32/src/rcc/wb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index d90a50cf4..f003f6d7d 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -135,7 +135,7 @@ pub const WPAN_DEFAULT: Config = Config { prediv: 2, }), pll48: None, - rtc: None, + rtc: Some(RtcClockSource::LSE), pll: Some(Pll { mul: 12, -- cgit From de2773afdd3f2d06cad0632ee075e1b88aa71515 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 16 Sep 2023 17:41:11 -0500 Subject: stm32/rcc: convert bus prescalers to pac enums --- embassy-stm32/src/rcc/bus.rs | 144 +++++++------------------------------------ embassy-stm32/src/rcc/c0.rs | 25 ++++---- embassy-stm32/src/rcc/f1.rs | 4 +- embassy-stm32/src/rcc/f2.rs | 10 +-- embassy-stm32/src/rcc/g0.rs | 6 +- embassy-stm32/src/rcc/g4.rs | 90 +++++++++------------------ embassy-stm32/src/rcc/h5.rs | 50 +++++++-------- embassy-stm32/src/rcc/h7.rs | 10 +-- embassy-stm32/src/rcc/l0.rs | 12 ++-- embassy-stm32/src/rcc/l1.rs | 12 ++-- embassy-stm32/src/rcc/l4.rs | 12 ++-- embassy-stm32/src/rcc/l5.rs | 12 ++-- embassy-stm32/src/rcc/u5.rs | 56 +++-------------- embassy-stm32/src/rcc/wb.rs | 30 ++++----- embassy-stm32/src/rcc/wl.rs | 24 +++----- 15 files changed, 162 insertions(+), 335 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bus.rs b/embassy-stm32/src/rcc/bus.rs index 32e10b7ec..fb6dcb01d 100644 --- a/embassy-stm32/src/rcc/bus.rs +++ b/embassy-stm32/src/rcc/bus.rs @@ -2,6 +2,7 @@ use core::ops::Div; #[allow(unused_imports)] use crate::pac::rcc; +pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; use crate::time::Hertz; /// Voltage Scale @@ -20,149 +21,48 @@ pub enum VoltageScale { Scale3, } -/// AHB prescaler -#[derive(Clone, Copy, PartialEq)] -pub enum AHBPrescaler { - NotDivided, - Div2, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - Div3, - Div4, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - Div5, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - Div6, - Div8, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - Div10, - Div16, - #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - Div32, - Div64, - Div128, - Div256, - Div512, -} - impl Div for Hertz { type Output = Hertz; fn div(self, rhs: AHBPrescaler) -> Self::Output { let divisor = match rhs { - AHBPrescaler::NotDivided => 1, - AHBPrescaler::Div2 => 2, + AHBPrescaler::DIV1 => 1, + AHBPrescaler::DIV2 => 2, #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - AHBPrescaler::Div3 => 3, - AHBPrescaler::Div4 => 4, + AHBPrescaler::DIV3 => 3, + AHBPrescaler::DIV4 => 4, #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - AHBPrescaler::Div5 => 5, + AHBPrescaler::DIV5 => 5, #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - AHBPrescaler::Div6 => 6, - AHBPrescaler::Div8 => 8, + AHBPrescaler::DIV6 => 6, + AHBPrescaler::DIV8 => 8, #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - AHBPrescaler::Div10 => 10, - AHBPrescaler::Div16 => 16, + AHBPrescaler::DIV10 => 10, + AHBPrescaler::DIV16 => 16, #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] - AHBPrescaler::Div32 => 32, - AHBPrescaler::Div64 => 64, - AHBPrescaler::Div128 => 128, - AHBPrescaler::Div256 => 256, - AHBPrescaler::Div512 => 512, + AHBPrescaler::DIV32 => 32, + AHBPrescaler::DIV64 => 64, + AHBPrescaler::DIV128 => 128, + AHBPrescaler::DIV256 => 256, + AHBPrescaler::DIV512 => 512, + _ => unreachable!(), }; Hertz(self.0 / divisor) } } -#[cfg(not(any(rcc_g4, rcc_wb, rcc_wl5, rcc_wle)))] -impl From for rcc::vals::Hpre { - fn from(val: AHBPrescaler) -> rcc::vals::Hpre { - use rcc::vals::Hpre; - - match val { - AHBPrescaler::NotDivided => Hpre::DIV1, - AHBPrescaler::Div2 => Hpre::DIV2, - AHBPrescaler::Div4 => Hpre::DIV4, - AHBPrescaler::Div8 => Hpre::DIV8, - AHBPrescaler::Div16 => Hpre::DIV16, - AHBPrescaler::Div64 => Hpre::DIV64, - AHBPrescaler::Div128 => Hpre::DIV128, - AHBPrescaler::Div256 => Hpre::DIV256, - AHBPrescaler::Div512 => Hpre::DIV512, - } - } -} - -#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] -impl From for u8 { - fn from(val: AHBPrescaler) -> u8 { - match val { - AHBPrescaler::NotDivided => 0x0, - AHBPrescaler::Div2 => 0x08, - AHBPrescaler::Div3 => 0x01, - AHBPrescaler::Div4 => 0x09, - AHBPrescaler::Div5 => 0x02, - AHBPrescaler::Div6 => 0x05, - AHBPrescaler::Div8 => 0x0a, - AHBPrescaler::Div10 => 0x06, - AHBPrescaler::Div16 => 0x0b, - AHBPrescaler::Div32 => 0x07, - AHBPrescaler::Div64 => 0x0c, - AHBPrescaler::Div128 => 0x0d, - AHBPrescaler::Div256 => 0x0e, - AHBPrescaler::Div512 => 0x0f, - } - } -} - -/// APB prescaler -#[derive(Clone, Copy)] -pub enum APBPrescaler { - NotDivided, - Div2, - Div4, - Div8, - Div16, -} - impl Div for Hertz { type Output = Hertz; fn div(self, rhs: APBPrescaler) -> Self::Output { let divisor = match rhs { - APBPrescaler::NotDivided => 1, - APBPrescaler::Div2 => 2, - APBPrescaler::Div4 => 4, - APBPrescaler::Div8 => 8, - APBPrescaler::Div16 => 16, + APBPrescaler::DIV1 => 1, + APBPrescaler::DIV2 => 2, + APBPrescaler::DIV4 => 4, + APBPrescaler::DIV8 => 8, + APBPrescaler::DIV16 => 16, + _ => unreachable!(), }; Hertz(self.0 / divisor) } } - -#[cfg(not(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_g4, rcc_h7, rcc_h7ab, rcc_wb, rcc_wl5, rcc_wle)))] -impl From for rcc::vals::Ppre { - fn from(val: APBPrescaler) -> rcc::vals::Ppre { - use rcc::vals::Ppre; - - match val { - APBPrescaler::NotDivided => Ppre::DIV1, - APBPrescaler::Div2 => Ppre::DIV2, - APBPrescaler::Div4 => Ppre::DIV4, - APBPrescaler::Div8 => Ppre::DIV8, - APBPrescaler::Div16 => Ppre::DIV16, - } - } -} - -#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] -impl From for u8 { - fn from(val: APBPrescaler) -> u8 { - match val { - APBPrescaler::NotDivided => 1, - APBPrescaler::Div2 => 0x04, - APBPrescaler::Div4 => 0x05, - APBPrescaler::Div8 => 0x06, - APBPrescaler::Div16 => 0x07, - } - } -} diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index d85790797..8f45e7c0f 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -58,8 +58,8 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::HSI(HSIPrescaler::NotDivided), - ahb_pre: AHBPrescaler::NotDivided, - apb_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb_pre: APBPrescaler::DIV1, } } } @@ -151,20 +151,21 @@ pub(crate) unsafe fn init(config: Config) { } let ahb_div = match config.ahb_pre { - AHBPrescaler::NotDivided => 1, - AHBPrescaler::Div2 => 2, - AHBPrescaler::Div4 => 4, - AHBPrescaler::Div8 => 8, - AHBPrescaler::Div16 => 16, - AHBPrescaler::Div64 => 64, - AHBPrescaler::Div128 => 128, - AHBPrescaler::Div256 => 256, - AHBPrescaler::Div512 => 512, + AHBPrescaler::DIV1 => 1, + AHBPrescaler::DIV2 => 2, + AHBPrescaler::DIV4 => 4, + AHBPrescaler::DIV8 => 8, + AHBPrescaler::DIV16 => 16, + AHBPrescaler::DIV64 => 64, + AHBPrescaler::DIV128 => 128, + AHBPrescaler::DIV256 => 256, + AHBPrescaler::DIV512 => 512, + _ => unreachable!(), }; let ahb_freq = sys_clk / ahb_div; let (apb_freq, apb_tim_freq) = match config.apb_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs index 304d8f504..081c0c767 100644 --- a/embassy-stm32/src/rcc/f1.rs +++ b/embassy-stm32/src/rcc/f1.rs @@ -163,8 +163,8 @@ pub(crate) unsafe fn init(config: Config) { // Only needed for stm32f103? RCC.cfgr().modify(|w| { w.set_adcpre(Adcpre::from_bits(apre_bits)); - w.set_ppre2(Ppre1::from_bits(ppre2_bits)); - w.set_ppre1(Ppre1::from_bits(ppre1_bits)); + w.set_ppre2(Ppre::from_bits(ppre2_bits)); + w.set_ppre1(Ppre::from_bits(ppre1_bits)); w.set_hpre(Hpre::from_bits(hpre_bits)); #[cfg(not(rcc_f100))] w.set_usbpre(Usbpre::from_bits(usbpre as u8)); diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index b821f9585..da88e44dc 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -308,9 +308,9 @@ impl Default for Config { voltage: VoltageScale::Scale3, mux: ClockSrc::HSI, rtc: None, - ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, } } } @@ -383,7 +383,7 @@ pub(crate) unsafe fn init(config: Config) { assert!(ahb_freq <= Hertz(120_000_000)); let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let freq = ahb_freq / pre; (freq, Hertz(freq.0 * 2)) @@ -393,7 +393,7 @@ pub(crate) unsafe fn init(config: Config) { assert!(apb1_freq <= Hertz(30_000_000)); let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let freq = ahb_freq / pre; (freq, Hertz(freq.0 * 2)) diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index 7fdbcb00c..7f0a2c7fb 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -186,8 +186,8 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided), - ahb_pre: AHBPrescaler::NotDivided, - apb_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb_pre: APBPrescaler::DIV1, low_power_run: false, } } @@ -377,7 +377,7 @@ pub(crate) unsafe fn init(config: Config) { let ahb_freq = Hertz(sys_clk) / config.ahb_pre; let (apb_freq, apb_tim_freq) = match config.apb_pre { - APBPrescaler::NotDivided => (ahb_freq.0, ahb_freq.0), + APBPrescaler::DIV1 => (ahb_freq.0, ahb_freq.0), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 2359f39c1..41bebc918 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -1,5 +1,5 @@ use stm32_metapac::flash::vals::Latency; -use stm32_metapac::rcc::vals::{Adcsel, Hpre, Pllsrc, Ppre, Sw}; +use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw}; use stm32_metapac::FLASH; pub use super::bus::{AHBPrescaler, APBPrescaler}; @@ -261,59 +261,29 @@ pub struct Pll { pub div_r: Option, } -impl AHBPrescaler { - const fn div(self) -> u32 { - match self { - AHBPrescaler::NotDivided => 1, - AHBPrescaler::Div2 => 2, - AHBPrescaler::Div4 => 4, - AHBPrescaler::Div8 => 8, - AHBPrescaler::Div16 => 16, - AHBPrescaler::Div64 => 64, - AHBPrescaler::Div128 => 128, - AHBPrescaler::Div256 => 256, - AHBPrescaler::Div512 => 512, - } - } -} - -impl APBPrescaler { - const fn div(self) -> u32 { - match self { - APBPrescaler::NotDivided => 1, - APBPrescaler::Div2 => 2, - APBPrescaler::Div4 => 4, - APBPrescaler::Div8 => 8, - APBPrescaler::Div16 => 16, - } +fn ahb_div(ahb: AHBPrescaler) -> u32 { + match ahb { + AHBPrescaler::DIV1 => 1, + AHBPrescaler::DIV2 => 2, + AHBPrescaler::DIV4 => 4, + AHBPrescaler::DIV8 => 8, + AHBPrescaler::DIV16 => 16, + AHBPrescaler::DIV64 => 64, + AHBPrescaler::DIV128 => 128, + AHBPrescaler::DIV256 => 256, + AHBPrescaler::DIV512 => 512, + _ => unreachable!(), } } -impl Into for APBPrescaler { - fn into(self) -> Ppre { - match self { - APBPrescaler::NotDivided => Ppre::DIV1, - APBPrescaler::Div2 => Ppre::DIV2, - APBPrescaler::Div4 => Ppre::DIV4, - APBPrescaler::Div8 => Ppre::DIV8, - APBPrescaler::Div16 => Ppre::DIV16, - } - } -} - -impl Into for AHBPrescaler { - fn into(self) -> Hpre { - match self { - AHBPrescaler::NotDivided => Hpre::DIV1, - AHBPrescaler::Div2 => Hpre::DIV2, - AHBPrescaler::Div4 => Hpre::DIV4, - AHBPrescaler::Div8 => Hpre::DIV8, - AHBPrescaler::Div16 => Hpre::DIV16, - AHBPrescaler::Div64 => Hpre::DIV64, - AHBPrescaler::Div128 => Hpre::DIV128, - AHBPrescaler::Div256 => Hpre::DIV256, - AHBPrescaler::Div512 => Hpre::DIV512, - } +fn apb_div(apb: APBPrescaler) -> u32 { + match apb { + APBPrescaler::DIV1 => 1, + APBPrescaler::DIV2 => 2, + APBPrescaler::DIV4 => 4, + APBPrescaler::DIV8 => 8, + APBPrescaler::DIV16 => 16, + _ => unreachable!(), } } @@ -365,9 +335,9 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::HSI16, - ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, low_power_run: false, pll: None, clock_48mhz_src: None, @@ -512,22 +482,22 @@ pub(crate) unsafe fn init(config: Config) { }); let ahb_freq: u32 = match config.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, - pre => sys_clk / pre.div(), + AHBPrescaler::DIV1 => sys_clk, + pre => sys_clk / ahb_div(pre), }; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { - let freq = ahb_freq / pre.div(); + let freq = ahb_freq / apb_div(pre); (freq, freq * 2) } }; let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { - let freq = ahb_freq / pre.div(); + let freq = ahb_freq / apb_div(pre); (freq, freq * 2) } }; diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs index 5741cdf92..ac45605f7 100644 --- a/embassy-stm32/src/rcc/h5.rs +++ b/embassy-stm32/src/rcc/h5.rs @@ -91,25 +91,25 @@ pub struct Pll { pub divr: Option, } -impl APBPrescaler { - fn div_tim(&self, clk: Hertz, tim: TimerPrescaler) -> Hertz { - match (tim, self) { - // The timers kernel clock is equal to rcc_hclk1 if PPRE1 or PPRE2 corresponds to a - // division by 1 or 2, else it is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 - (TimerPrescaler::DefaultX2, Self::NotDivided) => clk, - (TimerPrescaler::DefaultX2, Self::Div2) => clk, - (TimerPrescaler::DefaultX2, Self::Div4) => clk / 2u32, - (TimerPrescaler::DefaultX2, Self::Div8) => clk / 4u32, - (TimerPrescaler::DefaultX2, Self::Div16) => clk / 8u32, - // The timers kernel clock is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 if PPRE1 or PPRE2 - // corresponds to a division by 1, 2 or 4, else it is equal to 4 x Frcc_pclk1 or 4 x Frcc_pclk2 - // this makes NO SENSE and is different than in the H7. Mistake in the RM?? - (TimerPrescaler::DefaultX4, Self::NotDivided) => clk * 2u32, - (TimerPrescaler::DefaultX4, Self::Div2) => clk, - (TimerPrescaler::DefaultX4, Self::Div4) => clk / 2u32, - (TimerPrescaler::DefaultX4, Self::Div8) => clk / 2u32, - (TimerPrescaler::DefaultX4, Self::Div16) => clk / 4u32, - } +fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz { + match (tim, apb) { + // The timers kernel clock is equal to rcc_hclk1 if PPRE1 or PPRE2 corresponds to a + // division by 1 or 2, else it is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 + (TimerPrescaler::DefaultX2, APBPrescaler::DIV1) => clk, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV2) => clk, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV4) => clk / 2u32, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV8) => clk / 4u32, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV16) => clk / 8u32, + // The timers kernel clock is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 if PPRE1 or PPRE2 + // corresponds to a division by 1, 2 or 4, else it is equal to 4 x Frcc_pclk1 or 4 x Frcc_pclk2 + // this makes NO SENSE and is different than in the H7. Mistake in the RM?? + (TimerPrescaler::DefaultX4, APBPrescaler::DIV1) => clk * 2u32, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV2) => clk, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV4) => clk / 2u32, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV8) => clk / 2u32, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV16) => clk / 4u32, + + _ => unreachable!(), } } @@ -165,10 +165,10 @@ impl Default for Config { #[cfg(rcc_h5)] pll3: None, - ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, - apb3_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, + apb3_pre: APBPrescaler::DIV1, timer_prescaler: TimerPrescaler::DefaultX2, voltage_scale: VoltageScale::Scale3, @@ -317,9 +317,9 @@ pub(crate) unsafe fn init(config: Config) { let hclk = sys / config.ahb_pre; let apb1 = hclk / config.apb1_pre; - let apb1_tim = config.apb1_pre.div_tim(hclk, config.timer_prescaler); + let apb1_tim = apb_div_tim(&config.apb1_pre, hclk, config.timer_prescaler); let apb2 = hclk / config.apb2_pre; - let apb2_tim = config.apb2_pre.div_tim(hclk, config.timer_prescaler); + let apb2_tim = apb_div_tim(&config.apb2_pre, hclk, config.timer_prescaler); let apb3 = hclk / config.apb3_pre; flash_setup(hclk, config.voltage_scale); diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs index a6e694618..23e186943 100644 --- a/embassy-stm32/src/rcc/h7.rs +++ b/embassy-stm32/src/rcc/h7.rs @@ -6,7 +6,7 @@ use stm32_metapac::rcc::vals::{Mco1, Mco2}; use crate::gpio::sealed::AFType; use crate::gpio::Speed; -use crate::pac::rcc::vals::{Adcsel, Ckpersel, Dppre, Hpre, Hsidiv, Pllsrc, Sw, Timpre}; +use crate::pac::rcc::vals::{Adcsel, Ckpersel, Hpre, Hsidiv, Pllsrc, Ppre, Sw, Timpre}; use crate::pac::{PWR, RCC, SYSCFG}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -631,7 +631,7 @@ pub(crate) unsafe fn init(mut config: Config) { // Core Prescaler / AHB Prescaler / APB3 Prescaler RCC.d1cfgr().modify(|w| { w.set_d1cpre(Hpre::from_bits(d1cpre_bits)); - w.set_d1ppre(Dppre::from_bits(ppre3_bits)); + w.set_d1ppre(Ppre::from_bits(ppre3_bits)); w.set_hpre(hpre_bits) }); // Ensure core prescaler value is valid before future lower @@ -642,12 +642,12 @@ pub(crate) unsafe fn init(mut config: Config) { // APB1 / APB2 Prescaler RCC.d2cfgr().modify(|w| { - w.set_d2ppre1(Dppre::from_bits(ppre1_bits)); - w.set_d2ppre2(Dppre::from_bits(ppre2_bits)); + w.set_d2ppre1(Ppre::from_bits(ppre1_bits)); + w.set_d2ppre2(Ppre::from_bits(ppre2_bits)); }); // APB4 Prescaler - RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre::from_bits(ppre4_bits))); + RCC.d3cfgr().modify(|w| w.set_d3ppre(Ppre::from_bits(ppre4_bits))); // Peripheral Clock (per_ck) RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel)); diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index 3c8511ffd..2dfd0232c 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -145,9 +145,9 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::MSI(MSIRange::default()), - ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, #[cfg(crs)] enable_hsi48: false, rtc: None, @@ -247,7 +247,7 @@ pub(crate) unsafe fn init(config: Config) { }); let ahb_freq: u32 = match config.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: Hpre = pre.into(); let pre = 1 << (pre.to_bits() as u32 - 7); @@ -256,7 +256,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); @@ -266,7 +266,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs index ed949ea6f..90524fb37 100644 --- a/embassy-stm32/src/rcc/l1.rs +++ b/embassy-stm32/src/rcc/l1.rs @@ -138,9 +138,9 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::MSI(MSIRange::default()), - ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, } } } @@ -240,7 +240,7 @@ pub(crate) unsafe fn init(config: Config) { }); let ahb_freq: u32 = match config.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: Hpre = pre.into(); let pre = 1 << (pre.to_bits() as u32 - 7); @@ -249,7 +249,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); @@ -259,7 +259,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 41dbff01e..447a57b2c 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -248,9 +248,9 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::MSI(MSIRange::Range6), - ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, pllsai1: None, #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] hsi48: false, @@ -576,7 +576,7 @@ pub(crate) unsafe fn init(config: Config) { }); let ahb_freq: u32 = match config.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: Hpre = pre.into(); let pre = 1 << (pre.to_bits() as u32 - 7); @@ -585,7 +585,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); @@ -595,7 +595,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs index 9e4e0fc75..553b1619e 100644 --- a/embassy-stm32/src/rcc/l5.rs +++ b/embassy-stm32/src/rcc/l5.rs @@ -238,9 +238,9 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::MSI(MSIRange::Range6), - ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, pllsai1: None, hsi48: false, } @@ -407,7 +407,7 @@ pub(crate) unsafe fn init(config: Config) { }); let ahb_freq: u32 = match config.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: Hpre = pre.into(); let pre = 1 << (pre.to_bits() as u32 - 7); @@ -416,7 +416,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); @@ -426,7 +426,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); let pre: u8 = 1 << (pre.to_bits() - 3); diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 6540b1f5c..ff43c5eb7 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -119,46 +119,6 @@ impl Into for PllM { } } -impl Into for AHBPrescaler { - fn into(self) -> u8 { - match self { - AHBPrescaler::NotDivided => 1, - AHBPrescaler::Div2 => 0x08, - AHBPrescaler::Div4 => 0x09, - AHBPrescaler::Div8 => 0x0a, - AHBPrescaler::Div16 => 0x0b, - AHBPrescaler::Div64 => 0x0c, - AHBPrescaler::Div128 => 0x0d, - AHBPrescaler::Div256 => 0x0e, - AHBPrescaler::Div512 => 0x0f, - } - } -} - -impl Default for AHBPrescaler { - fn default() -> Self { - AHBPrescaler::NotDivided - } -} - -impl Default for APBPrescaler { - fn default() -> Self { - APBPrescaler::NotDivided - } -} - -impl Into for APBPrescaler { - fn into(self) -> u8 { - match self { - APBPrescaler::NotDivided => 1, - APBPrescaler::Div2 => 0x04, - APBPrescaler::Div4 => 0x05, - APBPrescaler::Div8 => 0x06, - APBPrescaler::Div16 => 0x07, - } - } -} - impl Into for ClockSrc { fn into(self) -> Sw { match self { @@ -239,10 +199,10 @@ impl Default for Config { fn default() -> Self { Self { mux: ClockSrc::MSI(MSIRange::default()), - ahb_pre: Default::default(), - apb1_pre: Default::default(), - apb2_pre: Default::default(), - apb3_pre: Default::default(), + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, + apb3_pre: APBPrescaler::DIV1, hsi48: false, } } @@ -395,7 +355,7 @@ pub(crate) unsafe fn init(config: Config) { }); let ahb_freq: u32 = match config.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: u8 = pre.into(); let pre = 1 << (pre as u32 - 7); @@ -404,7 +364,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: u8 = pre.into(); let pre: u8 = 1 << (pre - 3); @@ -414,7 +374,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: u8 = pre.into(); let pre: u8 = 1 << (pre - 3); @@ -424,7 +384,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: u8 = pre.into(); let pre: u8 = 1 << (pre - 3); diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index f003f6d7d..3f4c37429 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -145,11 +145,11 @@ pub const WPAN_DEFAULT: Config = Config { }), pllsai: None, - ahb1_pre: AHBPrescaler::NotDivided, - ahb2_pre: AHBPrescaler::Div2, - ahb3_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb1_pre: AHBPrescaler::DIV1, + ahb2_pre: AHBPrescaler::DIV2, + ahb3_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, }; impl Default for Config { @@ -165,11 +165,11 @@ impl Default for Config { pllsai: None, rtc: None, - ahb1_pre: AHBPrescaler::NotDivided, - ahb2_pre: AHBPrescaler::NotDivided, - ahb3_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb1_pre: AHBPrescaler::DIV1, + ahb2_pre: AHBPrescaler::DIV1, + ahb3_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, } } } @@ -209,7 +209,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { }; let ahb1_clk = match config.ahb1_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: u8 = pre.into(); let pre = 1u32 << (pre as u32 - 7); @@ -218,7 +218,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { }; let ahb2_clk = match config.ahb2_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: u8 = pre.into(); let pre = 1u32 << (pre as u32 - 7); @@ -227,7 +227,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { }; let ahb3_clk = match config.ahb3_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: u8 = pre.into(); let pre = 1u32 << (pre as u32 - 7); @@ -236,7 +236,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { }; let (apb1_clk, apb1_tim_clk) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk), + APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk), pre => { let pre: u8 = pre.into(); let pre: u8 = 1 << (pre - 3); @@ -246,7 +246,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { }; let (apb2_clk, apb2_tim_clk) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk), + APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk), pre => { let pre: u8 = pre.into(); let pre: u8 = 1 << (pre - 3); diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 6035f50b0..07856a28c 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -146,10 +146,10 @@ impl Default for Config { fn default() -> Config { Config { mux: ClockSrc::MSI(MSIRange::default()), - ahb_pre: AHBPrescaler::NotDivided, - shd_ahb_pre: AHBPrescaler::NotDivided, - apb1_pre: APBPrescaler::NotDivided, - apb2_pre: APBPrescaler::NotDivided, + ahb_pre: AHBPrescaler::DIV1, + shd_ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, rtc_mux: RtcClockSource::LSI, adc_clock_source: AdcClockSource::default(), } @@ -172,7 +172,7 @@ pub(crate) unsafe fn init(config: Config) { }; let ahb_freq: u32 = match config.ahb_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: u8 = pre.into(); let pre = 1 << (pre as u32 - 7); @@ -181,7 +181,7 @@ pub(crate) unsafe fn init(config: Config) { }; let shd_ahb_freq: u32 = match config.shd_ahb_pre { - AHBPrescaler::NotDivided => sys_clk, + AHBPrescaler::DIV1 => sys_clk, pre => { let pre: u8 = pre.into(); let pre = 1 << (pre as u32 - 7); @@ -190,7 +190,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: u8 = pre.into(); let pre: u8 = 1 << (pre - 3); @@ -200,7 +200,7 @@ pub(crate) unsafe fn init(config: Config) { }; let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { - APBPrescaler::NotDivided => (ahb_freq, ahb_freq), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { let pre: u8 = pre.into(); let pre: u8 = 1 << (pre - 3); @@ -267,7 +267,7 @@ pub(crate) unsafe fn init(config: Config) { } RCC.extcfgr().modify(|w| { - if config.shd_ahb_pre == AHBPrescaler::NotDivided { + if config.shd_ahb_pre == AHBPrescaler::DIV1 { w.set_shdhpre(0); } else { w.set_shdhpre(config.shd_ahb_pre.into()); @@ -276,11 +276,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.cfgr().modify(|w| { w.set_sw(sw.into()); - if config.ahb_pre == AHBPrescaler::NotDivided { - w.set_hpre(0); - } else { - w.set_hpre(config.ahb_pre.into()); - } + w.set_hpre(config.ahb_pre); w.set_ppre1(config.apb1_pre.into()); w.set_ppre2(config.apb2_pre.into()); }); -- cgit From bbe1d96045a0669a1658617c28c9cbb26ad6e76c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 17 Sep 2023 02:30:50 +0200 Subject: stm32/rcc: use AHBPrescaler div impls in stm32wba --- embassy-stm32/src/rcc/bus.rs | 4 ++ embassy-stm32/src/rcc/mod.rs | 1 - embassy-stm32/src/rcc/wba.rs | 88 +++++++++++++++----------------------------- 3 files changed, 33 insertions(+), 60 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bus.rs b/embassy-stm32/src/rcc/bus.rs index fb6dcb01d..9c9de5486 100644 --- a/embassy-stm32/src/rcc/bus.rs +++ b/embassy-stm32/src/rcc/bus.rs @@ -41,9 +41,13 @@ impl Div for Hertz { AHBPrescaler::DIV16 => 16, #[cfg(any(rcc_wb, rcc_wl5, rcc_wle))] AHBPrescaler::DIV32 => 32, + #[cfg(not(rcc_wba))] AHBPrescaler::DIV64 => 64, + #[cfg(not(rcc_wba))] AHBPrescaler::DIV128 => 128, + #[cfg(not(rcc_wba))] AHBPrescaler::DIV256 => 256, + #[cfg(not(rcc_wba))] AHBPrescaler::DIV512 => 512, _ => unreachable!(), }; diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index b8c12b995..892dcf937 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -1,7 +1,6 @@ #![macro_use] pub(crate) mod bd; -#[cfg(not(rcc_wba))] pub mod bus; use core::mem::MaybeUninit; diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index 2a11c9a22..c5d7ab62f 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -43,36 +43,6 @@ impl Into for ClockSrc { } } -trait Div { - fn div(&self) -> u8; -} - -impl Div for APBPrescaler { - fn div(&self) -> u8 { - match self { - Self::DIV1 => 1, - Self::DIV2 => 2, - Self::DIV4 => 4, - Self::DIV8 => 8, - Self::DIV16 => 16, - _ => unreachable!(), - } - } -} - -impl Div for AHBPrescaler { - fn div(&self) -> u8 { - match self { - Self::DIV1 => 1, - Self::DIV2 => 2, - Self::DIV4 => 4, - Self::DIV8 => 8, - Self::DIV16 => 16, - _ => unreachable!(), - } - } -} - #[derive(Copy, Clone)] pub struct Config { pub mux: ClockSrc, @@ -100,13 +70,13 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().write(|w| w.set_hseon(true)); while !RCC.cr().read().hserdy() {} - freq.0 + freq } ClockSrc::HSI16 => { RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - HSI_FREQ.0 + HSI_FREQ } }; @@ -115,14 +85,14 @@ pub(crate) unsafe fn init(config: Config) { // states and programming delay let wait_states = match power_vos { - VoltageScale::RANGE1 => match sys_clk { + VoltageScale::RANGE1 => match sys_clk.0 { ..=32_000_000 => 0, ..=64_000_000 => 1, ..=96_000_000 => 2, ..=100_000_000 => 3, _ => 4, }, - VoltageScale::RANGE2 => match sys_clk { + VoltageScale::RANGE2 => match sys_clk.0 { ..=8_000_000 => 0, ..=16_000_000 => 1, _ => 2, @@ -147,38 +117,38 @@ pub(crate) unsafe fn init(config: Config) { w.set_ppre7(config.apb7_pre.into()); }); - let ahb_freq: u32 = sys_clk / config.ahb_pre.div() as u32; - let (apb1_freq, apb1_tim_freq) = match config.apb1_pre.div() { - 1 => (ahb_freq, ahb_freq), - div => { - let freq = ahb_freq / div as u32; - (freq, freq * 2) + let ahb_freq = sys_clk / config.ahb_pre; + let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), + pre => { + let freq = ahb_freq / pre; + (freq, freq * 2u32) } }; - let (apb2_freq, apb2_tim_freq) = match config.apb2_pre.div() { - 1 => (ahb_freq, ahb_freq), - div => { - let freq = ahb_freq / div as u32; - (freq, freq * 2) + let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), + pre => { + let freq = ahb_freq / pre; + (freq, freq * 2u32) } }; - let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre.div() { - 1 => (ahb_freq, ahb_freq), - div => { - let freq = ahb_freq / div as u32; - (freq, freq * 2) + let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre { + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), + pre => { + let freq = ahb_freq / pre; + (freq, freq * 2u32) } }; set_freqs(Clocks { - sys: Hertz(sys_clk), - ahb1: Hertz(ahb_freq), - ahb2: Hertz(ahb_freq), - ahb4: Hertz(ahb_freq), - apb1: Hertz(apb1_freq), - apb2: Hertz(apb2_freq), - apb7: Hertz(apb7_freq), - apb1_tim: Hertz(apb1_tim_freq), - apb2_tim: Hertz(apb2_tim_freq), + sys: sys_clk, + ahb1: ahb_freq, + ahb2: ahb_freq, + ahb4: ahb_freq, + apb1: apb1_freq, + apb2: apb2_freq, + apb7: apb7_freq, + apb1_tim: apb1_tim_freq, + apb2_tim: apb2_tim_freq, }); } -- cgit From 087ef918bf9444b41d1260be5f2b475d3499f640 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sun, 17 Sep 2023 18:04:05 +0100 Subject: stm32: Add RtcTimeProvider struct to Rtc module This struct allows users to acquire the current time without putting `Rtc` in a mutex and passing that around. This is allowed because reading from the rtc registers is atomic. --- embassy-stm32/src/rtc/mod.rs | 51 +++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 15 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 3ecf477db..a588c8b18 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -82,12 +82,42 @@ impl core::ops::Sub for RtcInstant { } } +#[non_exhaustive] +pub struct RtcTimeProvider; + +impl RtcTimeProvider { + /// Return the current datetime. + /// + /// # Errors + /// + /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. + pub fn now(&self) -> Result { + let r = RTC::regs(); + let tr = r.tr().read(); + let second = bcd2_to_byte((tr.st(), tr.su())); + let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); + let hour = bcd2_to_byte((tr.ht(), tr.hu())); + // Reading either RTC_SSR or RTC_TR locks the values in the higher-order + // calendar shadow registers until RTC_DR is read. + let dr = r.dr().read(); + + let weekday = dr.wdu(); + let day = bcd2_to_byte((dr.dt(), dr.du())); + let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); + let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; + + self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) + } +} + +#[non_exhaustive] /// RTC Abstraction pub struct Rtc { #[cfg(feature = "low-power")] stop_time: Mutex>>, } +#[non_exhaustive] #[derive(Copy, Clone, PartialEq)] pub struct RtcConfig { /// The subsecond counter frequency; default is 256 @@ -155,6 +185,11 @@ impl Rtc { Hertz(32_768) } + /// Acquire a [`RtcTimeProvider`] instance. + pub fn time_provider(&self) -> RtcTimeProvider { + RtcTimeProvider + } + /// Set the datetime to a new value. /// /// # Errors @@ -187,21 +222,7 @@ impl Rtc { /// /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. pub fn now(&self) -> Result { - let r = RTC::regs(); - let tr = r.tr().read(); - let second = bcd2_to_byte((tr.st(), tr.su())); - let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); - let hour = bcd2_to_byte((tr.ht(), tr.hu())); - // Reading either RTC_SSR or RTC_TR locks the values in the higher-order - // calendar shadow registers until RTC_DR is read. - let dr = r.dr().read(); - - let weekday = dr.wdu(); - let day = bcd2_to_byte((dr.dt(), dr.du())); - let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); - let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; - - self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) + RtcTimeProvider.now() } /// Check if daylight savings time is active. -- cgit From 88eb5cca71a470cca93001943e962b63e15168af Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sat, 16 Sep 2023 22:32:14 +0100 Subject: stm32: Implement `set_config` for Uart structs --- embassy-stm32/src/spi/mod.rs | 4 +-- embassy-stm32/src/usart/buffered.rs | 36 ++++++++++++++++++++++++ embassy-stm32/src/usart/mod.rs | 49 +++++++++++++++++++++++++++++++++ embassy-stm32/src/usart/ringbuffered.rs | 16 ++++++++++- 4 files changed, 102 insertions(+), 3 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 853de98f9..f40bce784 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -323,7 +323,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { } /// Reconfigures it with the supplied config. - pub fn reconfigure(&mut self, config: Config) { + pub fn set_config(&mut self, config: Config) { let cpha = config.raw_phase(); let cpol = config.raw_polarity(); @@ -1062,6 +1062,6 @@ foreach_peripheral!( impl<'d, T: Instance, Tx, Rx> SetConfig for Spi<'d, T, Tx, Rx> { type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.reconfigure(*config); + self.set_config(*config); } } diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index b88eebc79..323d83818 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -114,6 +114,30 @@ pub struct BufferedUartRx<'d, T: BasicInstance> { phantom: PhantomData<&'d mut T>, } +impl<'d, T: BasicInstance> SetConfig for BufferedUart<'d, T> { + type Config = Config; + + fn set_config(&mut self, config: &Self::Config) { + self.set_config(config) + } +} + +impl<'d, T: BasicInstance> SetConfig for BufferedUartRx<'d, T> { + type Config = Config; + + fn set_config(&mut self, config: &Self::Config) { + self.set_config(config) + } +} + +impl<'d, T: BasicInstance> SetConfig for BufferedUartTx<'d, T> { + type Config = Config; + + fn set_config(&mut self, config: &Self::Config) { + self.set_config(config) + } +} + impl<'d, T: BasicInstance> BufferedUart<'d, T> { pub fn new( peri: impl Peripheral

+ 'd, @@ -228,6 +252,10 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { (self.tx, self.rx) } + + pub fn set_config(&mut self, config: &Config) { + reconfigure::(config) + } } impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { @@ -304,6 +332,10 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { T::Interrupt::pend(); } } + + pub fn set_config(&mut self, config: &Config) { + reconfigure::(config) + } } impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { @@ -374,6 +406,10 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { } } } + + pub fn set_config(&mut self, config: &Config) { + reconfigure::(config) + } } impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> { diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index c6d6cc59c..ff02d0a63 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -5,6 +5,7 @@ use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; +use embassy_embedded_hal::SetConfig; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; use futures::future::{select, Either}; @@ -168,11 +169,28 @@ pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { rx: UartRx<'d, T, RxDma>, } +impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> { + type Config = Config; + + fn set_config(&mut self, config: &Self::Config) { + self.tx.set_config(config); + self.rx.set_config(config); + } +} + pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { phantom: PhantomData<&'d mut T>, tx_dma: PeripheralRef<'d, TxDma>, } +impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> { + type Config = Config; + + fn set_config(&mut self, config: &Self::Config) { + self.set_config(config); + } +} + pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { _peri: PeripheralRef<'d, T>, rx_dma: PeripheralRef<'d, RxDma>, @@ -181,6 +199,14 @@ pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { buffered_sr: stm32_metapac::usart::regs::Sr, } +impl<'d, T: BasicInstance, RxDma> SetConfig for UartRx<'d, T, RxDma> { + type Config = Config; + + fn set_config(&mut self, config: &Self::Config) { + self.set_config(config); + } +} + impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power. pub fn new( @@ -237,6 +263,10 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { } } + pub fn set_config(&mut self, config: &Config) { + reconfigure::(config) + } + pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> where TxDma: crate::usart::TxDma, @@ -334,6 +364,10 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { } } + pub fn set_config(&mut self, config: &Config) { + reconfigure::(config) + } + #[cfg(any(usart_v1, usart_v2))] fn check_rx_flags(&mut self) -> Result { let r = T::regs(); @@ -759,6 +793,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { } } + pub fn set_config(&mut self, config: &Config) { + reconfigure::(config) + } + pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> where TxDma: crate::usart::TxDma, @@ -804,6 +842,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { } } +fn reconfigure(config: &Config) { + T::Interrupt::disable(); + let r = T::regs(); + + let cr = r.cr1().read(); + configure(r, config, T::frequency(), T::KIND, cr.re(), cr.te()); + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; +} + fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: bool, enable_tx: bool) { if !enable_rx && !enable_tx { panic!("USART: At least one of RX or TX should be enabled"); diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index e990eaca8..eed5ef5d6 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -3,10 +3,11 @@ use core::mem; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; +use embassy_embedded_hal::SetConfig; use embassy_hal_internal::PeripheralRef; use futures::future::{select, Either}; -use super::{clear_interrupt_flags, rdr, sr, BasicInstance, Error, UartRx}; +use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, Error, UartRx}; use crate::dma::ReadableRingBuffer; use crate::usart::{Regs, Sr}; @@ -15,6 +16,14 @@ pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma> { ring_buf: ReadableRingBuffer<'d, RxDma, u8>, } +impl<'d, T: BasicInstance, RxDma: super::RxDma> SetConfig for RingBufferedUartRx<'d, T, RxDma> { + type Config = Config; + + fn set_config(&mut self, config: &Self::Config) { + self.set_config(config); + } +} + impl<'d, T: BasicInstance, RxDma: super::RxDma> UartRx<'d, T, RxDma> { /// Turn the `UartRx` into a buffered uart which can continously receive in the background /// without the possibility of loosing bytes. The `dma_buf` is a buffer registered to the @@ -54,6 +63,11 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> RingBufferedUartRx<'d, T, RxD Err(err) } + pub fn set_config(&mut self, config: &Config) { + self.teardown_uart(); + reconfigure::(config) + } + /// Start uart background receive fn setup_uart(&mut self) { // fence before starting DMA. -- cgit From a6ef314be150fd2e8adbfefe5f2b38126f97551a Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 17 Sep 2023 18:41:45 -0500 Subject: stm32: update configure_ls as agreed --- embassy-stm32/src/rcc/bd.rs | 58 +++++++++++++++++++++++--------------------- embassy-stm32/src/rcc/f2.rs | 12 ++++++--- embassy-stm32/src/rcc/f4.rs | 11 ++++++--- embassy-stm32/src/rcc/l0.rs | 12 ++++++--- embassy-stm32/src/rcc/l4.rs | 6 ++++- embassy-stm32/src/rcc/mod.rs | 10 ++++++++ embassy-stm32/src/rcc/wb.rs | 11 ++++++--- embassy-stm32/src/rcc/wl.rs | 6 ++++- 8 files changed, 84 insertions(+), 42 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index d774b993b..762e84355 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -1,5 +1,5 @@ #[allow(dead_code)] -#[derive(Default)] +#[derive(Default, Clone, Copy)] pub enum LseDrive { #[cfg(any(rtc_v2f7, rtc_v2l4))] Low = 0, @@ -87,40 +87,42 @@ impl BackupDomain { rtc_v3u5 ))] #[allow(dead_code, unused_variables)] - pub fn configure_ls(clock_source: RtcClockSource, lse_drive: Option) { - match clock_source { - RtcClockSource::LSI => { - #[cfg(rtc_v3u5)] - let csr = crate::pac::RCC.bdcr(); - - #[cfg(not(rtc_v3u5))] - let csr = crate::pac::RCC.csr(); + pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option) { + if lsi { + #[cfg(rtc_v3u5)] + let csr = crate::pac::RCC.bdcr(); - Self::modify(|_| { - #[cfg(not(any(rcc_wb, rcc_wba)))] - csr.modify(|w| w.set_lsion(true)); - - #[cfg(any(rcc_wb, rcc_wba))] - csr.modify(|w| w.set_lsi1on(true)); - }); + #[cfg(not(rtc_v3u5))] + let csr = crate::pac::RCC.csr(); + Self::modify(|_| { #[cfg(not(any(rcc_wb, rcc_wba)))] - while !csr.read().lsirdy() {} + csr.modify(|w| w.set_lsion(true)); #[cfg(any(rcc_wb, rcc_wba))] - while !csr.read().lsi1rdy() {} - } - RtcClockSource::LSE => { - let lse_drive = lse_drive.unwrap_or_default(); + csr.modify(|w| w.set_lsi1on(true)); + }); - Self::modify(|w| { - #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] - w.set_lsedrv(lse_drive.into()); - w.set_lseon(true); - }); + #[cfg(not(any(rcc_wb, rcc_wba)))] + while !csr.read().lsirdy() {} - while !Self::read().lserdy() {} - } + #[cfg(any(rcc_wb, rcc_wba))] + while !csr.read().lsi1rdy() {} + } + + if let Some(lse_drive) = lse { + Self::modify(|w| { + #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] + w.set_lsedrv(lse_drive.into()); + w.set_lseon(true); + }); + + while !Self::read().lserdy() {} + } + + match clock_source { + RtcClockSource::LSI => assert!(lsi), + RtcClockSource::LSE => assert!(&lse.is_some()), _ => {} }; diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index da88e44dc..56ccdcbd8 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -291,6 +291,8 @@ pub struct Config { pub pll: PLLConfig, pub mux: ClockSrc, pub rtc: Option, + pub lsi: bool, + pub lse: Option, pub voltage: VoltageScale, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, @@ -308,6 +310,8 @@ impl Default for Config { voltage: VoltageScale::Scale3, mux: ClockSrc::HSI, rtc: None, + lsi: false, + lse: None, ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, @@ -421,9 +425,11 @@ pub(crate) unsafe fn init(config: Config) { RCC.apb1enr().modify(|w| w.set_pwren(true)); PWR.cr().read(); - config - .rtc - .map(|clock_source| BackupDomain::configure_ls(clock_source, None)); + BackupDomain::configure_ls( + config.rtc.unwrap_or(RtcClockSource::NOCLOCK), + config.lsi, + config.lse.map(|_| Default::default()), + ); set_freqs(Clocks { sys: sys_clk, diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index f7bc0d99a..d8d0312bc 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -35,6 +35,8 @@ pub struct Config { pub pll48: bool, pub rtc: Option, + pub lsi: bool, + pub lse: Option, } #[cfg(stm32f410)] @@ -461,12 +463,15 @@ pub(crate) unsafe fn init(config: Config) { }) }); - config - .rtc - .map(|clock_source| BackupDomain::configure_ls(clock_source, None)); + BackupDomain::configure_ls( + config.rtc.unwrap_or(RtcClockSource::NOCLOCK), + config.lsi, + config.lse.map(|_| Default::default()), + ); let rtc = match config.rtc { Some(RtcClockSource::LSI) => Some(LSI_FREQ), + Some(RtcClockSource::LSE) => Some(config.lse.unwrap()), _ => None, }; diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index 2dfd0232c..1c655592e 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -138,6 +138,8 @@ pub struct Config { #[cfg(crs)] pub enable_hsi48: bool, pub rtc: Option, + pub lse: Option, + pub lsi: bool, } impl Default for Config { @@ -151,6 +153,8 @@ impl Default for Config { #[cfg(crs)] enable_hsi48: false, rtc: None, + lse: None, + lsi: false, } } } @@ -235,9 +239,11 @@ pub(crate) unsafe fn init(config: Config) { } }; - config.rtc.map(|rtc| { - BackupDomain::configure_ls(rtc, None); - }); + BackupDomain::configure_ls( + config.rtc.unwrap_or(RtcClockSource::NOCLOCK), + config.lsi, + config.lse.map(|_| Default::default()), + ); RCC.cfgr().modify(|w| { w.set_sw(sw); diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 447a57b2c..f7b9354a6 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -241,6 +241,8 @@ pub struct Config { #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] pub hsi48: bool, pub rtc_mux: RtcClockSource, + pub lse: Option, + pub lsi: bool, } impl Default for Config { @@ -255,6 +257,8 @@ impl Default for Config { #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] hsi48: false, rtc_mux: RtcClockSource::LSI, + lsi: true, + lse: None, } } } @@ -407,7 +411,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.apb1enr1().modify(|w| w.set_pwren(true)); - BackupDomain::configure_ls(config.rtc_mux, None); + BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default())); let (sys_clk, sw) = match config.mux { ClockSrc::MSI(range) => { diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 892dcf937..ff9b9bac8 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -31,6 +31,16 @@ pub use _version::*; #[cfg(feature = "low-power")] use atomic_polyfill::{AtomicU32, Ordering}; +// Model Clock Configuration +// +// pub struct Clocks { +// hse: Option, +// hsi: bool, +// lse: Option, +// lsi: bool, +// rtc: RtcSource, +// } + #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Clocks { diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index 3f4c37429..ee45a342b 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -108,6 +108,7 @@ pub struct Pll { pub struct Config { pub hse: Option, pub lse: Option, + pub lsi: bool, pub sys: Sysclk, pub mux: Option, pub pll48: Option, @@ -136,6 +137,7 @@ pub const WPAN_DEFAULT: Config = Config { }), pll48: None, rtc: Some(RtcClockSource::LSE), + lsi: false, pll: Some(Pll { mul: 12, @@ -164,6 +166,7 @@ impl Default for Config { pll: None, pllsai: None, rtc: None, + lsi: false, ahb1_pre: AHBPrescaler::DIV1, ahb2_pre: AHBPrescaler::DIV1, @@ -294,9 +297,11 @@ pub(crate) fn configure_clocks(config: &Config) { rcc.cfgr().modify(|w| w.set_stopwuck(true)); - config - .rtc - .map(|clock_source| BackupDomain::configure_ls(clock_source, None)); + BackupDomain::configure_ls( + config.rtc.unwrap_or(RtcClockSource::NOCLOCK), + config.lsi, + config.lse.map(|_| Default::default()), + ); match &config.hse { Some(hse) => { diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 07856a28c..5db942fca 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -138,6 +138,8 @@ pub struct Config { pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, pub rtc_mux: RtcClockSource, + pub lse: Option, + pub lsi: bool, pub adc_clock_source: AdcClockSource, } @@ -151,6 +153,8 @@ impl Default for Config { apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, rtc_mux: RtcClockSource::LSI, + lsi: true, + lse: None, adc_clock_source: AdcClockSource::default(), } } @@ -231,7 +235,7 @@ pub(crate) unsafe fn init(config: Config) { while FLASH.acr().read().latency() != ws {} // Enables the LSI if configured - BackupDomain::configure_ls(config.rtc_mux, None); + BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default())); match config.mux { ClockSrc::HSI16 => { -- cgit From feaeee1e835bf3e2a6b36fc8d2d45d4cbc5c27a3 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 17 Sep 2023 18:47:22 -0500 Subject: stm32: misc. cleanup --- embassy-stm32/src/rtc/mod.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index a588c8b18..07b4fe1f0 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -82,8 +82,9 @@ impl core::ops::Sub for RtcInstant { } } -#[non_exhaustive] -pub struct RtcTimeProvider; +pub struct RtcTimeProvider { + _private: (), +} impl RtcTimeProvider { /// Return the current datetime. @@ -186,8 +187,8 @@ impl Rtc { } /// Acquire a [`RtcTimeProvider`] instance. - pub fn time_provider(&self) -> RtcTimeProvider { - RtcTimeProvider + pub const fn time_provider(&self) -> RtcTimeProvider { + RtcTimeProvider { _private: () } } /// Set the datetime to a new value. @@ -222,7 +223,7 @@ impl Rtc { /// /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. pub fn now(&self) -> Result { - RtcTimeProvider.now() + self.time_provider().now() } /// Check if daylight savings time is active. -- cgit From 4bfbcd6c72fadd97ef71403a1406ff437f4aa6e8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 18 Sep 2023 03:00:59 +0200 Subject: stm32: use PAC enums for VOS. --- embassy-stm32/src/rcc/bus.rs | 16 -------- embassy-stm32/src/rcc/f2.rs | 25 +++++++++--- embassy-stm32/src/rcc/h5.rs | 70 ++++++++++++++++---------------- embassy-stm32/src/rcc/h7.rs | 97 ++++++++++++++++++++++++++++++++++---------- embassy-stm32/src/rcc/u5.rs | 20 ++++----- embassy-stm32/src/rcc/wl.rs | 16 ++++---- 6 files changed, 148 insertions(+), 96 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bus.rs b/embassy-stm32/src/rcc/bus.rs index 9c9de5486..495cf7fe1 100644 --- a/embassy-stm32/src/rcc/bus.rs +++ b/embassy-stm32/src/rcc/bus.rs @@ -5,22 +5,6 @@ use crate::pac::rcc; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; use crate::time::Hertz; -/// Voltage Scale -/// -/// Represents the voltage range feeding the CPU core. The maximum core -/// clock frequency depends on this value. -/// -/// Scale0 represents the highest voltage range -#[derive(Copy, Clone, PartialEq)] -pub enum VoltageScale { - Scale0, - Scale1, - #[cfg(not(any(rcc_wl5, rcc_wle)))] - Scale2, - #[cfg(not(any(rcc_wl5, rcc_wle)))] - Scale3, -} - impl Div for Hertz { type Output = Hertz; diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index 56ccdcbd8..af90a9c3f 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -203,7 +203,20 @@ pub struct PLLClocks { pub pll48_freq: Hertz, } -pub use super::bus::VoltageScale; +/// Voltage range of the power supply used. +/// +/// Used to calculate flash waitstates. See +/// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency +pub enum VoltageScale { + /// 2.7v to 4.6v + Range0, + /// 2.4v to 2.7v + Range1, + /// 2.1v to 2.4v + Range2, + /// 1.8v to 2.1v + Range3, +} impl VoltageScale { const fn wait_states(&self, ahb_freq: Hertz) -> Option { @@ -211,7 +224,7 @@ impl VoltageScale { // Reference: RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock // frequency match self { - VoltageScale::Scale3 => { + VoltageScale::Range3 => { if ahb_freq <= 16_000_000 { Some(Latency::WS0) } else if ahb_freq <= 32_000_000 { @@ -232,7 +245,7 @@ impl VoltageScale { None } } - VoltageScale::Scale2 => { + VoltageScale::Range2 => { if ahb_freq <= 18_000_000 { Some(Latency::WS0) } else if ahb_freq <= 36_000_000 { @@ -251,7 +264,7 @@ impl VoltageScale { None } } - VoltageScale::Scale1 => { + VoltageScale::Range1 => { if ahb_freq <= 24_000_000 { Some(Latency::WS0) } else if ahb_freq <= 48_000_000 { @@ -266,7 +279,7 @@ impl VoltageScale { None } } - VoltageScale::Scale0 => { + VoltageScale::Range0 => { if ahb_freq <= 30_000_000 { Some(Latency::WS0) } else if ahb_freq <= 60_000_000 { @@ -307,7 +320,7 @@ impl Default for Config { hsi: true, pll_mux: PLLSrc::HSI, pll: PLLConfig::default(), - voltage: VoltageScale::Scale3, + voltage: VoltageScale::Range3, mux: ClockSrc::HSI, rtc: None, lsi: false, diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs index ac45605f7..15f28c5dc 100644 --- a/embassy-stm32/src/rcc/h5.rs +++ b/embassy-stm32/src/rcc/h5.rs @@ -2,7 +2,6 @@ use core::marker::PhantomData; use stm32_metapac::rcc::vals::Timpre; -use crate::pac::pwr::vals::Vos; use crate::pac::rcc::vals::{Hseext, Hsidiv, Mco1, Mco2, Pllrge, Pllsrc, Pllvcosel, Sw}; use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::{set_freqs, Clocks}; @@ -26,7 +25,8 @@ const VCO_MAX: u32 = 420_000_000; const VCO_WIDE_MIN: u32 = 128_000_000; const VCO_WIDE_MAX: u32 = 560_000_000; -pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; +pub use crate::pac::pwr::vals::Vos as VoltageScale; pub enum HseMode { /// crystal/ceramic oscillator (HSEBYP=0) @@ -171,7 +171,7 @@ impl Default for Config { apb3_pre: APBPrescaler::DIV1, timer_prescaler: TimerPrescaler::DefaultX2, - voltage_scale: VoltageScale::Scale3, + voltage_scale: VoltageScale::SCALE3, } } } @@ -222,15 +222,15 @@ impl<'d, T: McoInstance> Mco<'d, T> { } pub(crate) unsafe fn init(config: Config) { - let (vos, max_clk) = match config.voltage_scale { - VoltageScale::Scale0 => (Vos::SCALE0, Hertz(250_000_000)), - VoltageScale::Scale1 => (Vos::SCALE1, Hertz(200_000_000)), - VoltageScale::Scale2 => (Vos::SCALE2, Hertz(150_000_000)), - VoltageScale::Scale3 => (Vos::SCALE3, Hertz(100_000_000)), + let max_clk = match config.voltage_scale { + VoltageScale::SCALE0 => Hertz(250_000_000), + VoltageScale::SCALE1 => Hertz(200_000_000), + VoltageScale::SCALE2 => Hertz(150_000_000), + VoltageScale::SCALE3 => Hertz(100_000_000), }; // Configure voltage scale. - PWR.voscr().modify(|w| w.set_vos(vos)); + PWR.voscr().modify(|w| w.set_vos(config.voltage_scale)); while !PWR.vossr().read().vosrdy() {} // Configure HSI @@ -472,36 +472,36 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) { // See RM0433 Rev 7 Table 17. FLASH recommended number of wait // states and programming delay let (latency, wrhighfreq) = match (vos, clk.0) { - (VoltageScale::Scale0, ..=42_000_000) => (0, 0), - (VoltageScale::Scale0, ..=84_000_000) => (1, 0), - (VoltageScale::Scale0, ..=126_000_000) => (2, 1), - (VoltageScale::Scale0, ..=168_000_000) => (3, 1), - (VoltageScale::Scale0, ..=210_000_000) => (4, 2), - (VoltageScale::Scale0, ..=250_000_000) => (5, 2), - - (VoltageScale::Scale1, ..=34_000_000) => (0, 0), - (VoltageScale::Scale1, ..=68_000_000) => (1, 0), - (VoltageScale::Scale1, ..=102_000_000) => (2, 1), - (VoltageScale::Scale1, ..=136_000_000) => (3, 1), - (VoltageScale::Scale1, ..=170_000_000) => (4, 2), - (VoltageScale::Scale1, ..=200_000_000) => (5, 2), - - (VoltageScale::Scale2, ..=30_000_000) => (0, 0), - (VoltageScale::Scale2, ..=60_000_000) => (1, 0), - (VoltageScale::Scale2, ..=90_000_000) => (2, 1), - (VoltageScale::Scale2, ..=120_000_000) => (3, 1), - (VoltageScale::Scale2, ..=150_000_000) => (4, 2), - - (VoltageScale::Scale3, ..=20_000_000) => (0, 0), - (VoltageScale::Scale3, ..=40_000_000) => (1, 0), - (VoltageScale::Scale3, ..=60_000_000) => (2, 1), - (VoltageScale::Scale3, ..=80_000_000) => (3, 1), - (VoltageScale::Scale3, ..=100_000_000) => (4, 2), + (VoltageScale::SCALE0, ..=42_000_000) => (0, 0), + (VoltageScale::SCALE0, ..=84_000_000) => (1, 0), + (VoltageScale::SCALE0, ..=126_000_000) => (2, 1), + (VoltageScale::SCALE0, ..=168_000_000) => (3, 1), + (VoltageScale::SCALE0, ..=210_000_000) => (4, 2), + (VoltageScale::SCALE0, ..=250_000_000) => (5, 2), + + (VoltageScale::SCALE1, ..=34_000_000) => (0, 0), + (VoltageScale::SCALE1, ..=68_000_000) => (1, 0), + (VoltageScale::SCALE1, ..=102_000_000) => (2, 1), + (VoltageScale::SCALE1, ..=136_000_000) => (3, 1), + (VoltageScale::SCALE1, ..=170_000_000) => (4, 2), + (VoltageScale::SCALE1, ..=200_000_000) => (5, 2), + + (VoltageScale::SCALE2, ..=30_000_000) => (0, 0), + (VoltageScale::SCALE2, ..=60_000_000) => (1, 0), + (VoltageScale::SCALE2, ..=90_000_000) => (2, 1), + (VoltageScale::SCALE2, ..=120_000_000) => (3, 1), + (VoltageScale::SCALE2, ..=150_000_000) => (4, 2), + + (VoltageScale::SCALE3, ..=20_000_000) => (0, 0), + (VoltageScale::SCALE3, ..=40_000_000) => (1, 0), + (VoltageScale::SCALE3, ..=60_000_000) => (2, 1), + (VoltageScale::SCALE3, ..=80_000_000) => (3, 1), + (VoltageScale::SCALE3, ..=100_000_000) => (4, 2), _ => unreachable!(), }; - defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); + debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); FLASH.acr().write(|w| { w.set_wrhighfreq(wrhighfreq); diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs index 23e186943..585e1faac 100644 --- a/embassy-stm32/src/rcc/h7.rs +++ b/embassy-stm32/src/rcc/h7.rs @@ -1,9 +1,10 @@ use core::marker::PhantomData; use embassy_hal_internal::into_ref; -pub use pll::PllConfig; +use stm32_metapac::pwr::vals::Vos; use stm32_metapac::rcc::vals::{Mco1, Mco2}; +pub use self::pll::PllConfig; use crate::gpio::sealed::AFType; use crate::gpio::Speed; use crate::pac::rcc::vals::{Adcsel, Ckpersel, Hpre, Hsidiv, Pllsrc, Ppre, Sw, Timpre}; @@ -24,7 +25,13 @@ pub const HSI48_FREQ: Hertz = Hertz(48_000_000); /// LSI speed pub const LSI_FREQ: Hertz = Hertz(32_000); -pub use super::bus::VoltageScale; +#[derive(Clone, Copy)] +pub enum VoltageScale { + Scale0, + Scale1, + Scale2, + Scale3, +} #[derive(Clone, Copy)] pub enum AdcClockSource { @@ -85,7 +92,6 @@ pub struct CoreClocks { /// Configuration of the core clocks #[non_exhaustive] -#[derive(Default)] pub struct Config { pub hse: Option, pub bypass_hse: bool, @@ -100,6 +106,28 @@ pub struct Config { pub pll2: PllConfig, pub pll3: PllConfig, pub adc_clock_source: AdcClockSource, + pub voltage_scale: VoltageScale, +} + +impl Default for Config { + fn default() -> Self { + Self { + hse: None, + bypass_hse: false, + sys_ck: None, + per_ck: None, + hclk: None, + pclk1: None, + pclk2: None, + pclk3: None, + pclk4: None, + pll1: Default::default(), + pll2: Default::default(), + pll3: Default::default(), + adc_clock_source: Default::default(), + voltage_scale: VoltageScale::Scale1, + } + } } /// Setup traceclk @@ -431,9 +459,6 @@ impl<'d, T: McoInstance> Mco<'d, T> { } pub(crate) unsafe fn init(mut config: Config) { - // TODO make configurable? - let enable_overdrive = false; - // NB. The lower bytes of CR3 can only be written once after // POR, and must be written with a valid combination. Refer to // RM0433 Rev 7 6.8.4. This is partially enforced by dropping @@ -461,21 +486,49 @@ pub(crate) unsafe fn init(mut config: Config) { // 1.0V. while !PWR.csr1().read().actvosrdy() {} - // Go to Scale 1 - PWR.d3cr().modify(|w| w.set_vos(0b11)); - while !PWR.d3cr().read().vosrdy() {} - - let pwr_vos = if !enable_overdrive { - VoltageScale::Scale1 - } else { - critical_section::with(|_| { - RCC.apb4enr().modify(|w| w.set_syscfgen(true)); - - SYSCFG.pwrcr().modify(|w| w.set_oden(1)); + #[cfg(syscfg_h7)] + { + // in chips without the overdrive bit, we can go from any scale to any scale directly. + PWR.d3cr().modify(|w| { + w.set_vos(match config.voltage_scale { + VoltageScale::Scale0 => Vos::SCALE0, + VoltageScale::Scale1 => Vos::SCALE1, + VoltageScale::Scale2 => Vos::SCALE2, + VoltageScale::Scale3 => Vos::SCALE3, + }) }); while !PWR.d3cr().read().vosrdy() {} - VoltageScale::Scale0 - }; + } + + #[cfg(syscfg_h7od)] + { + match config.voltage_scale { + VoltageScale::Scale0 => { + // to go to scale0, we must go to Scale1 first... + PWR.d3cr().modify(|w| w.set_vos(Vos::SCALE1)); + while !PWR.d3cr().read().vosrdy() {} + + // Then enable overdrive. + critical_section::with(|_| { + RCC.apb4enr().modify(|w| w.set_syscfgen(true)); + SYSCFG.pwrcr().modify(|w| w.set_oden(1)); + }); + while !PWR.d3cr().read().vosrdy() {} + } + _ => { + // for all other scales, we can go directly. + PWR.d3cr().modify(|w| { + w.set_vos(match config.voltage_scale { + VoltageScale::Scale0 => unreachable!(), + VoltageScale::Scale1 => Vos::SCALE1, + VoltageScale::Scale2 => Vos::SCALE2, + VoltageScale::Scale3 => Vos::SCALE3, + }) + }); + while !PWR.d3cr().read().vosrdy() {} + } + } + } // Freeze the core clocks, returning a Core Clocks Distribution // and Reset (CCDR) structure. The actual frequency of the clocks @@ -538,11 +591,11 @@ pub(crate) unsafe fn init(mut config: Config) { // Refer to part datasheet "General operating conditions" // table for (rev V). We do not assert checks for earlier // revisions which may have lower limits. - let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr_vos { + let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match config.voltage_scale { VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000), VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000), VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000), - _ => (200_000_000, 100_000_000, 50_000_000), + VoltageScale::Scale3 => (200_000_000, 100_000_000, 50_000_000), }; assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max); @@ -638,7 +691,7 @@ pub(crate) unsafe fn init(mut config: Config) { // core voltage while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {} - flash_setup(rcc_aclk, pwr_vos); + flash_setup(rcc_aclk, config.voltage_scale); // APB1 / APB2 Prescaler RCC.d2cfgr().modify(|w| { diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index ff43c5eb7..d9a531285 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -11,7 +11,7 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000); /// LSI speed pub const LSI_FREQ: Hertz = Hertz(32_000); -pub use super::bus::VoltageScale; +pub use crate::pac::pwr::vals::Vos as VoltageScale; #[derive(Copy, Clone)] pub enum ClockSrc { @@ -286,12 +286,12 @@ pub(crate) unsafe fn init(config: Config) { } // TODO make configurable - let power_vos = VoltageScale::Scale3; + let power_vos = VoltageScale::RANGE3; // states and programming delay let wait_states = match power_vos { - // VOS 0 range VCORE 1.26V - 1.40V - VoltageScale::Scale0 => { + // VOS 1 range VCORE 1.26V - 1.40V + VoltageScale::RANGE1 => { if sys_clk < 32_000_000 { 0 } else if sys_clk < 64_000_000 { @@ -304,8 +304,8 @@ pub(crate) unsafe fn init(config: Config) { 4 } } - // VOS 1 range VCORE 1.15V - 1.26V - VoltageScale::Scale1 => { + // VOS 2 range VCORE 1.15V - 1.26V + VoltageScale::RANGE2 => { if sys_clk < 30_000_000 { 0 } else if sys_clk < 60_000_000 { @@ -316,8 +316,8 @@ pub(crate) unsafe fn init(config: Config) { 3 } } - // VOS 2 range VCORE 1.05V - 1.15V - VoltageScale::Scale2 => { + // VOS 3 range VCORE 1.05V - 1.15V + VoltageScale::RANGE3 => { if sys_clk < 24_000_000 { 0 } else if sys_clk < 48_000_000 { @@ -326,8 +326,8 @@ pub(crate) unsafe fn init(config: Config) { 2 } } - // VOS 3 range VCORE 0.95V - 1.05V - VoltageScale::Scale3 => { + // VOS 4 range VCORE 0.95V - 1.05V + VoltageScale::RANGE4 => { if sys_clk < 12_000_000 { 0 } else { diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 5db942fca..6643d278a 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,4 +1,5 @@ -pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale}; +pub use super::bus::{AHBPrescaler, APBPrescaler}; +pub use crate::pac::pwr::vals::Vos as VoltageScale; use crate::pac::rcc::vals::Adcsel; use crate::pac::{FLASH, RCC}; use crate::rcc::bd::{BackupDomain, RtcClockSource}; @@ -75,9 +76,9 @@ impl MSIRange { fn vos(&self) -> VoltageScale { if self > &MSIRange::Range8 { - VoltageScale::Scale0 + VoltageScale::RANGE1 } else { - VoltageScale::Scale1 + VoltageScale::RANGE2 } } } @@ -170,8 +171,8 @@ pub enum Lsedrv { pub(crate) unsafe fn init(config: Config) { let (sys_clk, sw, vos) = match config.mux { - ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::Scale1), - ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::Scale0), + ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::RANGE2), + ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::RANGE1), ClockSrc::MSI(range) => (range.freq(), 0x00, range.vos()), }; @@ -216,16 +217,17 @@ pub(crate) unsafe fn init(config: Config) { // Adjust flash latency let flash_clk_src_freq: u32 = shd_ahb_freq; let ws = match vos { - VoltageScale::Scale0 => match flash_clk_src_freq { + VoltageScale::RANGE1 => match flash_clk_src_freq { 0..=18_000_000 => 0b000, 18_000_001..=36_000_000 => 0b001, _ => 0b010, }, - VoltageScale::Scale1 => match flash_clk_src_freq { + VoltageScale::RANGE2 => match flash_clk_src_freq { 0..=6_000_000 => 0b000, 6_000_001..=12_000_000 => 0b001, _ => 0b010, }, + _ => unreachable!(), }; FLASH.acr().modify(|w| { -- cgit From e640933e2f0c8fb0b5a6df645002f69b55f51d8a Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 18 Sep 2023 16:31:20 -0500 Subject: stm32/adc: add async conversion --- embassy-stm32/src/adc/f3.rs | 65 ++++++++++++++++++++++++++++++++++++++------ embassy-stm32/src/adc/mod.rs | 39 +++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 9 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index b39d6ac8e..5d2ea1daa 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -1,14 +1,36 @@ +use core::future::poll_fn; +use core::marker::PhantomData; +use core::task::Poll; + use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; use crate::adc::{Adc, AdcPin, Instance, SampleTime}; +use crate::interrupt::typelevel::Interrupt; use crate::time::Hertz; -use crate::Peripheral; +use crate::{interrupt, Peripheral}; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; pub const VREF_INT: u32 = 1230; +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + if T::regs().isr().read().eoc() { + T::regs().ier().modify(|w| w.set_eocie(false)); + } else { + return; + } + + T::state().waker.wake(); + } +} + pub struct Vref; impl AdcPin for Vref {} impl super::sealed::AdcPin for Vref { @@ -17,6 +39,13 @@ impl super::sealed::AdcPin for Vref { } } +impl Vref { + /// The value that vref would be if vdda was at 3300mv + pub fn value(&self) -> u16 { + crate::pac::VREFINTCAL.data().read().value() + } +} + pub struct Temperature; impl AdcPin for Temperature {} impl super::sealed::AdcPin for Temperature { @@ -26,7 +55,11 @@ impl super::sealed::AdcPin for Temperature { } impl<'d, T: Instance> Adc<'d, T> { - pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { + pub fn new( + adc: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + delay: &mut impl DelayUs, + ) -> Self { use crate::pac::adc::vals; into_ref!(adc); @@ -58,6 +91,11 @@ impl<'d, T: Instance> Adc<'d, T> { // Wait until the adc is ready while !T::regs().isr().read().adrdy() {} + T::Interrupt::unpend(); + unsafe { + T::Interrupt::enable(); + } + Self { adc, sample_time: Default::default(), @@ -97,30 +135,41 @@ impl<'d, T: Instance> Adc<'d, T> { } /// Perform a single conversion. - fn convert(&mut self) -> u16 { + async fn convert(&mut self) -> u16 { T::regs().isr().write(|_| {}); + T::regs().ier().modify(|w| w.set_eocie(true)); T::regs().cr().modify(|w| w.set_adstart(true)); - while !T::regs().isr().read().eoc() && !T::regs().isr().read().eos() {} + poll_fn(|cx| { + T::state().waker.register(cx.waker()); + + if T::regs().isr().read().eoc() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + T::regs().isr().write(|_| {}); T::regs().dr().read().rdata() } - pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { + pub async fn read(&mut self, pin: &mut impl AdcPin) -> u16 { Self::set_channel_sample_time(pin.channel(), self.sample_time); // Configure the channel to sample T::regs().sqr1().write(|w| w.set_sq(0, pin.channel())); - self.convert() + self.convert().await } fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { let sample_time = sample_time.into(); if ch <= 9 { - T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); + T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time)); } else { - T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); + T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); } } } diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 9334deac4..e74913da8 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -31,12 +31,35 @@ pub struct Adc<'d, T: Instance> { } pub(crate) mod sealed { - pub trait Instance { + #[cfg(adc_f3)] + use embassy_sync::waitqueue::AtomicWaker; + + #[cfg(adc_f3)] + pub struct State { + pub waker: AtomicWaker, + } + + #[cfg(adc_f3)] + impl State { + pub const fn new() -> Self { + Self { + waker: AtomicWaker::new(), + } + } + } + + pub trait InterruptableInstance { + type Interrupt: crate::interrupt::typelevel::Interrupt; + } + + pub trait Instance: InterruptableInstance { fn regs() -> crate::pac::adc::Adc; #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] fn common_regs() -> crate::pac::adccommon::AdcCommon; #[cfg(adc_f3)] fn frequency() -> crate::time::Hertz; + #[cfg(adc_f3)] + fn state() -> &'static State; } pub trait AdcPin { @@ -72,8 +95,22 @@ foreach_adc!( fn frequency() -> crate::time::Hertz { unsafe { crate::rcc::get_freqs() }.$clock.unwrap() } + + #[cfg(adc_f3)] + fn state() -> &'static sealed::State { + static STATE: sealed::State = sealed::State::new(); + &STATE + } } + foreach_interrupt!( + ($inst,adc,ADC,GLOBAL,$irq:ident) => { + impl sealed::InterruptableInstance for peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$irq; + } + }; + ); + impl crate::adc::Instance for peripherals::$inst {} }; ); -- cgit From 561696dfadba90c2b24a1fddd5f8b4370ab9cc0b Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Tue, 19 Sep 2023 10:20:25 +0200 Subject: Fix typo in F2 RCC voltage ranges --- embassy-stm32/src/rcc/f2.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index af90a9c3f..1a34c2cbe 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -208,13 +208,13 @@ pub struct PLLClocks { /// Used to calculate flash waitstates. See /// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency pub enum VoltageScale { - /// 2.7v to 4.6v + /// 2.7 to 3.6 V Range0, - /// 2.4v to 2.7v + /// 2.4 to 2.7 V Range1, - /// 2.1v to 2.4v + /// 2.1 to 2.4 V Range2, - /// 1.8v to 2.1v + /// 1.8 to 2.1 V Range3, } -- cgit From 2405aff11f466d1c3fc07bca70c07d11fc96c3be Mon Sep 17 00:00:00 2001 From: Sebastian Goll Date: Tue, 19 Sep 2023 23:23:14 +0200 Subject: Add get_level() to ExtiInput --- embassy-stm32/src/exti.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index bd4bab1f8..efa51fb24 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -6,7 +6,7 @@ use core::task::{Context, Poll}; use embassy_hal_internal::impl_peripheral; use embassy_sync::waitqueue::AtomicWaker; -use crate::gpio::{AnyPin, Input, Pin as GpioPin}; +use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin}; use crate::pac::exti::regs::Lines; use crate::pac::EXTI; use crate::{interrupt, pac, peripherals, Peripheral}; @@ -101,6 +101,10 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> { self.pin.is_low() } + pub fn get_level(&self) -> Level { + self.pin.get_level() + } + pub async fn wait_for_high<'a>(&'a mut self) { let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false); if self.is_high() { -- cgit From d46920dce692859e0818a6171c930af270a7a02f Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 20 Sep 2023 16:07:35 -0500 Subject: stm32/adc: make v1 async and leave en --- embassy-stm32/src/adc/mod.rs | 10 ++-- embassy-stm32/src/adc/v1.rs | 137 +++++++++++++++++++++++++++---------------- 2 files changed, 91 insertions(+), 56 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index e74913da8..2f8f8f9e3 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -31,15 +31,15 @@ pub struct Adc<'d, T: Instance> { } pub(crate) mod sealed { - #[cfg(adc_f3)] + #[cfg(any(adc_f3, adc_v1))] use embassy_sync::waitqueue::AtomicWaker; - #[cfg(adc_f3)] + #[cfg(any(adc_f3, adc_v1))] pub struct State { pub waker: AtomicWaker, } - #[cfg(adc_f3)] + #[cfg(any(adc_f3, adc_v1))] impl State { pub const fn new() -> Self { Self { @@ -58,7 +58,7 @@ pub(crate) mod sealed { fn common_regs() -> crate::pac::adccommon::AdcCommon; #[cfg(adc_f3)] fn frequency() -> crate::time::Hertz; - #[cfg(adc_f3)] + #[cfg(any(adc_f3, adc_v1))] fn state() -> &'static State; } @@ -96,7 +96,7 @@ foreach_adc!( unsafe { crate::rcc::get_freqs() }.$clock.unwrap() } - #[cfg(adc_f3)] + #[cfg(any(adc_f3, adc_v1))] fn state() -> &'static sealed::State { static STATE: sealed::State = sealed::State::new(); &STATE diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index e8245884e..15b2dc593 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -1,13 +1,35 @@ +use core::future::poll_fn; +use core::marker::PhantomData; +use core::task::Poll; + use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; +use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC; -use crate::Peripheral; +use crate::{interrupt, Peripheral}; pub const VDDA_CALIB_MV: u32 = 3300; pub const VREF_INT: u32 = 1230; +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + if T::regs().isr().read().eoc() { + T::regs().ier().modify(|w| w.set_eocie(false)); + } else { + return; + } + + T::state().waker.wake(); + } +} + pub struct Vbat; impl InternalChannel for Vbat {} impl super::sealed::InternalChannel for Vbat { @@ -33,7 +55,11 @@ impl super::sealed::InternalChannel for Temperature { } impl<'d, T: Instance> Adc<'d, T> { - pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { + pub fn new( + adc: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + delay: &mut impl DelayUs, + ) -> Self { into_ref!(adc); T::enable(); T::reset(); @@ -44,12 +70,32 @@ impl<'d, T: Instance> Adc<'d, T> { // tstab = 14 * 1/fadc delay.delay_us(1); - let s = Self { + // A.7.1 ADC calibration code example + T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); + T::regs().cr().modify(|reg| reg.set_adcal(true)); + while T::regs().cr().read().adcal() {} + + // A.7.2 ADC enable sequence code example + if T::regs().isr().read().adrdy() { + T::regs().isr().modify(|reg| reg.set_adrdy(true)); + } + T::regs().cr().modify(|reg| reg.set_aden(true)); + while !T::regs().isr().read().adrdy() { + // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration + // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the + // ADEN bit until the ADRDY flag goes high. + T::regs().cr().modify(|reg| reg.set_aden(true)); + } + + T::Interrupt::unpend(); + unsafe { + T::Interrupt::enable(); + } + + Self { adc, sample_time: Default::default(), - }; - s.calibrate(); - s + } } pub fn enable_vbat(&self, _delay: &mut impl DelayUs) -> Vbat { @@ -80,21 +126,6 @@ impl<'d, T: Instance> Adc<'d, T> { Temperature } - fn calibrate(&self) { - // A.7.1 ADC calibration code example - if T::regs().cr().read().aden() { - T::regs().cr().modify(|reg| reg.set_addis(true)); - } - while T::regs().cr().read().aden() { - // spin - } - T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); - T::regs().cr().modify(|reg| reg.set_adcal(true)); - while T::regs().cr().read().adcal() { - // spin - } - } - pub fn set_sample_time(&mut self, sample_time: SampleTime) { self.sample_time = sample_time; } @@ -103,57 +134,61 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); } - pub fn read

(&mut self, pin: &mut P) -> u16 + pub async fn read

(&mut self, pin: &mut P) -> u16 where P: AdcPin + crate::gpio::sealed::Pin, { let channel = pin.channel(); pin.set_as_analog(); - self.read_channel(channel) + self.read_channel(channel).await } - pub fn read_internal(&mut self, channel: &mut impl InternalChannel) -> u16 { + pub async fn read_internal(&mut self, channel: &mut impl InternalChannel) -> u16 { let channel = channel.channel(); - self.read_channel(channel) + self.read_channel(channel).await } - fn read_channel(&mut self, channel: u8) -> u16 { - // A.7.2 ADC enable sequence code example - if T::regs().isr().read().adrdy() { - T::regs().isr().modify(|reg| reg.set_adrdy(true)); - } - T::regs().cr().modify(|reg| reg.set_aden(true)); - while !T::regs().isr().read().adrdy() { - // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration - // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the - // ADEN bit until the ADRDY flag goes high. - T::regs().cr().modify(|reg| reg.set_aden(true)); - } - + async fn convert(&mut self) -> u16 { T::regs().isr().modify(|reg| { reg.set_eoc(true); reg.set_eosmp(true); }); - // A.7.5 Single conversion sequence code example - Software trigger - T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true)); T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into())); + T::regs().ier().modify(|w| w.set_eocie(true)); T::regs().cr().modify(|reg| reg.set_adstart(true)); - while !T::regs().isr().read().eoc() { - // spin - } - let value = T::regs().dr().read().0 as u16; + poll_fn(|cx| { + T::state().waker.register(cx.waker()); + + if T::regs().isr().read().eoc() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + + T::regs().dr().read().data() + } + + async fn read_channel(&mut self, channel: u8) -> u16 { + // A.7.5 Single conversion sequence code example - Software trigger + T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true)); + + self.convert().await + } +} + +impl<'d, T: Instance> Drop for Adc<'d, T> { + fn drop(&mut self) { // A.7.3 ADC disable code example T::regs().cr().modify(|reg| reg.set_adstp(true)); - while T::regs().cr().read().adstp() { - // spin - } + while T::regs().cr().read().adstp() {} + T::regs().cr().modify(|reg| reg.set_addis(true)); - while T::regs().cr().read().aden() { - // spin - } + while T::regs().cr().read().aden() {} - value + T::disable(); } } -- cgit From 00b9f9acef129155e0c9d1fa7d021104103a897b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 21 Sep 2023 00:23:56 +0200 Subject: stm32/h7: fix bad PWR reg versions. --- embassy-stm32/src/rcc/h7.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs index 585e1faac..ea26c26c1 100644 --- a/embassy-stm32/src/rcc/h7.rs +++ b/embassy-stm32/src/rcc/h7.rs @@ -464,14 +464,14 @@ pub(crate) unsafe fn init(mut config: Config) { // RM0433 Rev 7 6.8.4. This is partially enforced by dropping // `self` at the end of this method, but of course we cannot // know what happened between the previous POR and here. - #[cfg(pwr_h7)] + #[cfg(pwr_h7rm0433)] PWR.cr3().modify(|w| { w.set_scuen(true); w.set_ldoen(true); w.set_bypass(false); }); - #[cfg(pwr_h7smps)] + #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] PWR.cr3().modify(|w| { // hardcode "Direct SPMS" for now, this is what works on nucleos with the // default solderbridge configuration. @@ -484,7 +484,9 @@ pub(crate) unsafe fn init(mut config: Config) { // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset // VOS = Scale 3, so check that the voltage on the VCAP pins = // 1.0V. + info!("a"); while !PWR.csr1().read().actvosrdy() {} + info!("b"); #[cfg(syscfg_h7)] { -- cgit From ad64d7b20b26e0854c4d1302f562df51e67a022b Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Thu, 21 Sep 2023 17:17:58 +0200 Subject: fix low-power: APB1 needed for LSE --- embassy-stm32/src/rcc/bd.rs | 5 +++++ embassy-stm32/src/rtc/mod.rs | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 762e84355..4915d5e2a 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -88,6 +88,11 @@ impl BackupDomain { ))] #[allow(dead_code, unused_variables)] pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option) { + if lsi || lse.is_some() { + use crate::rtc::sealed::Instance; + crate::peripherals::RTC::enable_peripheral_clk(); + } + if lsi { #[cfg(rtc_v3u5)] let csr = crate::pac::RCC.bdcr(); diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 07b4fe1f0..7eafedec4 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -154,8 +154,6 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { - RTC::enable_peripheral_clk(); - let mut this = Self { #[cfg(feature = "low-power")] stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), -- cgit From 83b4c0127337c55c6a445abee6ab5eac4c993f9c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 19 Sep 2023 04:22:57 +0200 Subject: stm32/rcc: unify h5 and h7. --- embassy-stm32/src/rcc/h.rs | 777 +++++++++++++++++++++++++++++++++++ embassy-stm32/src/rcc/h5.rs | 511 ----------------------- embassy-stm32/src/rcc/h7.rs | 934 ------------------------------------------- embassy-stm32/src/rcc/mco.rs | 71 ++++ embassy-stm32/src/rcc/mod.rs | 14 +- 5 files changed, 857 insertions(+), 1450 deletions(-) create mode 100644 embassy-stm32/src/rcc/h.rs delete mode 100644 embassy-stm32/src/rcc/h5.rs delete mode 100644 embassy-stm32/src/rcc/h7.rs create mode 100644 embassy-stm32/src/rcc/mco.rs (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs new file mode 100644 index 000000000..a4730ed49 --- /dev/null +++ b/embassy-stm32/src/rcc/h.rs @@ -0,0 +1,777 @@ +use core::ops::RangeInclusive; + +use crate::pac; +use crate::pac::pwr::vals::Vos; +#[cfg(stm32h5)] +pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource; +#[cfg(stm32h7)] +pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; +pub use crate::pac::rcc::vals::Ckpersel as PerClockSource; +use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre}; +use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::{set_freqs, Clocks}; +use crate::time::Hertz; + +/// HSI speed +pub const HSI_FREQ: Hertz = Hertz(64_000_000); + +/// CSI speed +pub const CSI_FREQ: Hertz = Hertz(4_000_000); + +/// HSI48 speed +pub const HSI48_FREQ: Hertz = Hertz(48_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(32_000); + +const VCO_RANGE: RangeInclusive = 150_000_000..=420_000_000; +#[cfg(any(stm32h5, pwr_h7rm0455))] +const VCO_WIDE_RANGE: RangeInclusive = 128_000_000..=560_000_000; +#[cfg(pwr_h7rm0468)] +const VCO_WIDE_RANGE: RangeInclusive = 192_000_000..=836_000_000; +#[cfg(any(pwr_h7rm0399, pwr_h7rm0433))] +const VCO_WIDE_RANGE: RangeInclusive = 192_000_000..=960_000_000; + +pub use super::bus::{AHBPrescaler, APBPrescaler}; + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum VoltageScale { + Scale0, + Scale1, + Scale2, + Scale3, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum HseMode { + /// crystal/ceramic oscillator (HSEBYP=0) + Oscillator, + /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) + Bypass, + /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1) + #[cfg(any(rcc_h5, rcc_h50))] + BypassDigital, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Hse { + /// HSE frequency. + pub freq: Hertz, + /// HSE mode. + pub mode: HseMode, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum Hsi { + /// 64Mhz + Mhz64, + /// 32Mhz (divided by 2) + Mhz32, + /// 16Mhz (divided by 4) + Mhz16, + /// 8Mhz (divided by 8) + Mhz8, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum Sysclk { + /// HSI selected as sysclk + HSI, + /// HSE selected as sysclk + HSE, + /// CSI selected as sysclk + CSI, + /// PLL1_P selected as sysclk + Pll1P, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum PllSource { + Hsi, + Csi, + Hse, +} + +#[derive(Clone, Copy)] +pub struct Pll { + /// Source clock selection. + #[cfg(stm32h5)] + pub source: PllSource, + + /// PLL pre-divider (DIVM). Must be between 1 and 63. + pub prediv: u8, + + /// PLL multiplication factor. Must be between 4 and 512. + pub mul: u16, + + /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128. + /// On PLL1, it must be even (in particular, it cannot be 1.) + pub divp: Option, + /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128. + pub divq: Option, + /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128. + pub divr: Option, +} + +fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz { + match (tim, apb) { + (TimerPrescaler::DefaultX2, APBPrescaler::DIV1) => clk, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV2) => clk, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV4) => clk / 2u32, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV8) => clk / 4u32, + (TimerPrescaler::DefaultX2, APBPrescaler::DIV16) => clk / 8u32, + + (TimerPrescaler::DefaultX4, APBPrescaler::DIV1) => clk, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV2) => clk, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV4) => clk, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV8) => clk / 2u32, + (TimerPrescaler::DefaultX4, APBPrescaler::DIV16) => clk / 4u32, + + _ => unreachable!(), + } +} + +/// Timer prescaler +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum TimerPrescaler { + /// The timers kernel clock is equal to hclk if PPREx corresponds to a + /// division by 1 or 2, else it is equal to 2*pclk + DefaultX2, + + /// The timers kernel clock is equal to hclk if PPREx corresponds to a + /// division by 1, 2 or 4, else it is equal to 4*pclk + DefaultX4, +} + +impl From for Timpre { + fn from(value: TimerPrescaler) -> Self { + match value { + TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2, + TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4, + } + } +} + +/// Configuration of the core clocks +#[non_exhaustive] +pub struct Config { + pub hsi: Option, + pub hse: Option, + pub csi: bool, + pub hsi48: bool, + pub sys: Sysclk, + + #[cfg(stm32h7)] + pub pll_src: PllSource, + + pub pll1: Option, + pub pll2: Option, + #[cfg(any(rcc_h5, stm32h7))] + pub pll3: Option, + + pub d1c_pre: AHBPrescaler, + pub ahb_pre: AHBPrescaler, + pub apb1_pre: APBPrescaler, + pub apb2_pre: APBPrescaler, + pub apb3_pre: APBPrescaler, + #[cfg(stm32h7)] + pub apb4_pre: APBPrescaler, + + pub per_clock_source: PerClockSource, + pub adc_clock_source: AdcClockSource, + pub timer_prescaler: TimerPrescaler, + pub voltage_scale: VoltageScale, +} + +impl Default for Config { + fn default() -> Self { + Self { + hsi: Some(Hsi::Mhz64), + hse: None, + csi: false, + hsi48: false, + sys: Sysclk::HSI, + #[cfg(stm32h7)] + pll_src: PllSource::Hsi, + pll1: None, + pll2: None, + #[cfg(any(rcc_h5, stm32h7))] + pll3: None, + + d1c_pre: AHBPrescaler::DIV1, + ahb_pre: AHBPrescaler::DIV1, + apb1_pre: APBPrescaler::DIV1, + apb2_pre: APBPrescaler::DIV1, + apb3_pre: APBPrescaler::DIV1, + #[cfg(stm32h7)] + apb4_pre: APBPrescaler::DIV1, + + per_clock_source: PerClockSource::HSI, + adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5 + timer_prescaler: TimerPrescaler::DefaultX2, + voltage_scale: VoltageScale::Scale0, + } + } +} + +pub(crate) unsafe fn init(config: Config) { + #[cfg(stm32h7)] + RCC.apb4enr().modify(|w| w.set_syscfgen(true)); + #[cfg(stm32h5)] + RCC.apb3enr().modify(|w| w.set_sbsen(true)); + + // NB. The lower bytes of CR3 can only be written once after + // POR, and must be written with a valid combination. Refer to + // RM0433 Rev 7 6.8.4. This is partially enforced by dropping + // `self` at the end of this method, but of course we cannot + // know what happened between the previous POR and here. + #[cfg(pwr_h7rm0433)] + PWR.cr3().modify(|w| { + w.set_scuen(true); + w.set_ldoen(true); + w.set_bypass(false); + }); + + #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] + PWR.cr3().modify(|w| { + // hardcode "Direct SPMS" for now, this is what works on nucleos with the + // default solderbridge configuration. + w.set_sden(true); + w.set_ldoen(false); + }); + + // Validate the supply configuration. If you are stuck here, it is + // because the voltages on your board do not match those specified + // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset + // VOS = Scale 3, so check that the voltage on the VCAP pins = + // 1.0V. + #[cfg(any(pwr_h7rm0433, pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] + while !PWR.csr1().read().actvosrdy() {} + + // Configure voltage scale. + #[cfg(any(pwr_h5, pwr_h50))] + { + PWR.voscr().modify(|w| { + w.set_vos(match config.voltage_scale { + VoltageScale::Scale0 => Vos::SCALE0, + VoltageScale::Scale1 => Vos::SCALE1, + VoltageScale::Scale2 => Vos::SCALE2, + VoltageScale::Scale3 => Vos::SCALE3, + }) + }); + while !PWR.vossr().read().vosrdy() {} + } + + #[cfg(syscfg_h7)] + { + // in chips without the overdrive bit, we can go from any scale to any scale directly. + PWR.d3cr().modify(|w| { + w.set_vos(match config.voltage_scale { + VoltageScale::Scale0 => Vos::SCALE0, + VoltageScale::Scale1 => Vos::SCALE1, + VoltageScale::Scale2 => Vos::SCALE2, + VoltageScale::Scale3 => Vos::SCALE3, + }) + }); + while !PWR.d3cr().read().vosrdy() {} + } + + #[cfg(syscfg_h7od)] + { + match config.voltage_scale { + VoltageScale::Scale0 => { + // to go to scale0, we must go to Scale1 first... + PWR.d3cr().modify(|w| w.set_vos(Vos::SCALE1)); + while !PWR.d3cr().read().vosrdy() {} + + // Then enable overdrive. + critical_section::with(|_| pac::SYSCFG.pwrcr().modify(|w| w.set_oden(1))); + while !PWR.d3cr().read().vosrdy() {} + } + _ => { + // for all other scales, we can go directly. + PWR.d3cr().modify(|w| { + w.set_vos(match config.voltage_scale { + VoltageScale::Scale0 => unreachable!(), + VoltageScale::Scale1 => Vos::SCALE1, + VoltageScale::Scale2 => Vos::SCALE2, + VoltageScale::Scale3 => Vos::SCALE3, + }) + }); + while !PWR.d3cr().read().vosrdy() {} + } + } + } + + // Configure HSI + let hsi = match config.hsi { + None => { + RCC.cr().modify(|w| w.set_hsion(false)); + None + } + Some(hsi) => { + let (freq, hsidiv) = match hsi { + Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1), + Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2), + Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4), + Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8), + }; + RCC.cr().modify(|w| { + w.set_hsidiv(hsidiv); + w.set_hsion(true); + }); + while !RCC.cr().read().hsirdy() {} + Some(freq) + } + }; + + // Configure HSE + let hse = match config.hse { + None => { + RCC.cr().modify(|w| w.set_hseon(false)); + None + } + Some(hse) => { + RCC.cr().modify(|w| { + w.set_hsebyp(hse.mode != HseMode::Oscillator); + #[cfg(any(rcc_h5, rcc_h50))] + w.set_hseext(match hse.mode { + HseMode::Oscillator | HseMode::Bypass => pac::rcc::vals::Hseext::ANALOG, + HseMode::BypassDigital => pac::rcc::vals::Hseext::DIGITAL, + }); + }); + RCC.cr().modify(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + Some(hse.freq) + } + }; + + // Configure HSI48. + RCC.cr().modify(|w| w.set_hsi48on(config.hsi48)); + let _hsi48 = match config.hsi48 { + false => None, + true => { + while !RCC.cr().read().hsi48rdy() {} + Some(CSI_FREQ) + } + }; + + // Configure CSI. + RCC.cr().modify(|w| w.set_csion(config.csi)); + let csi = match config.csi { + false => None, + true => { + while !RCC.cr().read().csirdy() {} + Some(CSI_FREQ) + } + }; + + // Configure PLLs. + let pll_input = PllInput { + csi, + hse, + hsi, + #[cfg(stm32h7)] + source: config.pll_src, + }; + let pll1 = init_pll(0, config.pll1, &pll_input); + let pll2 = init_pll(1, config.pll2, &pll_input); + #[cfg(any(rcc_h5, stm32h7))] + let _pll3 = init_pll(2, config.pll3, &pll_input); + + // Configure sysclk + let (sys, sw) = match config.sys { + Sysclk::HSI => (unwrap!(hsi), Sw::HSI), + Sysclk::HSE => (unwrap!(hse), Sw::HSE), + Sysclk::CSI => (unwrap!(csi), Sw::CSI), + Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1), + }; + + // Check limits. + #[cfg(stm32h5)] + let (hclk_max, pclk_max) = match config.voltage_scale { + VoltageScale::Scale0 => (Hertz(250_000_000), Hertz(250_000_000)), + VoltageScale::Scale1 => (Hertz(200_000_000), Hertz(200_000_000)), + VoltageScale::Scale2 => (Hertz(150_000_000), Hertz(150_000_000)), + VoltageScale::Scale3 => (Hertz(100_000_000), Hertz(100_000_000)), + }; + #[cfg(stm32h7)] + let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { + VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)), + VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), + VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)), + VoltageScale::Scale3 => (Hertz(200_000_000), Hertz(100_000_000), Hertz(50_000_000)), + }; + + #[cfg(stm32h7)] + let hclk = { + let d1cpre_clk = sys / config.d1c_pre; + assert!(d1cpre_clk <= d1cpre_clk_max); + sys / config.ahb_pre + }; + #[cfg(stm32h5)] + let hclk = sys / config.ahb_pre; + assert!(hclk <= hclk_max); + + let apb1 = hclk / config.apb1_pre; + let apb1_tim = apb_div_tim(&config.apb1_pre, hclk, config.timer_prescaler); + assert!(apb1 <= pclk_max); + let apb2 = hclk / config.apb2_pre; + let apb2_tim = apb_div_tim(&config.apb2_pre, hclk, config.timer_prescaler); + assert!(apb2 <= pclk_max); + let apb3 = hclk / config.apb3_pre; + assert!(apb3 <= pclk_max); + #[cfg(stm32h7)] + let apb4 = hclk / config.apb4_pre; + #[cfg(stm32h7)] + assert!(apb4 <= pclk_max); + + let _per_ck = match config.per_clock_source { + Ckpersel::HSI => hsi, + Ckpersel::CSI => csi, + Ckpersel::HSE => hse, + _ => unreachable!(), + }; + + #[cfg(stm32h7)] + let adc = match config.adc_clock_source { + AdcClockSource::PLL2_P => pll2.p, + AdcClockSource::PLL3_R => _pll3.r, + AdcClockSource::PER => _per_ck, + _ => unreachable!(), + }; + #[cfg(stm32h5)] + let adc = match config.adc_clock_source { + AdcClockSource::HCLK => Some(hclk), + AdcClockSource::SYSCLK => Some(sys), + AdcClockSource::PLL2_R => pll2.r, + AdcClockSource::HSE => hse, + AdcClockSource::HSI_KER => hsi, + AdcClockSource::CSI_KER => csi, + _ => unreachable!(), + }; + + flash_setup(hclk, config.voltage_scale); + + #[cfg(stm32h7)] + { + RCC.d1cfgr().modify(|w| { + w.set_d1cpre(config.d1c_pre); + w.set_d1ppre(config.apb3_pre); + w.set_hpre(config.ahb_pre); + }); + // Ensure core prescaler value is valid before future lower core voltage + while RCC.d1cfgr().read().d1cpre() != config.d1c_pre {} + + RCC.d2cfgr().modify(|w| { + w.set_d2ppre1(config.apb1_pre); + w.set_d2ppre2(config.apb2_pre); + }); + RCC.d3cfgr().modify(|w| { + w.set_d3ppre(config.apb4_pre); + }); + + RCC.d1ccipr().modify(|w| { + w.set_ckpersel(config.per_clock_source); + }); + RCC.d3ccipr().modify(|w| { + w.set_adcsel(config.adc_clock_source); + }); + } + #[cfg(stm32h5)] + { + // Set hpre + RCC.cfgr2().modify(|w| w.set_hpre(config.ahb_pre)); + while RCC.cfgr2().read().hpre() != config.ahb_pre {} + + // set ppre + RCC.cfgr2().modify(|w| { + w.set_ppre1(config.apb1_pre); + w.set_ppre2(config.apb2_pre); + w.set_ppre3(config.apb3_pre); + }); + + RCC.ccipr5().modify(|w| { + w.set_ckpersel(config.per_clock_source); + w.set_adcdacsel(config.adc_clock_source) + }); + } + + RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into())); + + RCC.cfgr().modify(|w| w.set_sw(sw)); + while RCC.cfgr().read().sws() != sw {} + + // IO compensation cell - Requires CSI clock and SYSCFG + #[cfg(stm32h7)] // TODO h5 + if csi.is_some() { + // Enable the compensation cell, using back-bias voltage code + // provide by the cell. + critical_section::with(|_| { + pac::SYSCFG.cccsr().modify(|w| { + w.set_en(true); + w.set_cs(false); + w.set_hslv(false); + }) + }); + while !pac::SYSCFG.cccsr().read().ready() {} + } + + set_freqs(Clocks { + sys, + ahb1: hclk, + ahb2: hclk, + ahb3: hclk, + ahb4: hclk, + apb1, + apb2, + apb3, + #[cfg(stm32h7)] + apb4, + apb1_tim, + apb2_tim, + adc: adc, + }); +} + +struct PllInput { + hsi: Option, + hse: Option, + csi: Option, + #[cfg(stm32h7)] + source: PllSource, +} + +struct PllOutput { + p: Option, + #[allow(dead_code)] + q: Option, + #[allow(dead_code)] + r: Option, +} + +fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { + let Some(config) = config else { + // Stop PLL + RCC.cr().modify(|w| w.set_pllon(num, false)); + while RCC.cr().read().pllrdy(num) {} + + // "To save power when PLL1 is not used, the value of PLL1M must be set to 0."" + #[cfg(stm32h7)] + RCC.pllckselr().write(|w| w.set_divm(num, 0)); + #[cfg(stm32h5)] + RCC.pllcfgr(num).write(|w| w.set_divm(0)); + + return PllOutput { + p: None, + q: None, + r: None, + }; + }; + + assert!(1 <= config.prediv && config.prediv <= 63); + assert!(4 <= config.mul && config.mul <= 512); + + #[cfg(stm32h5)] + let source = config.source; + #[cfg(stm32h7)] + let source = input.source; + + let (in_clk, src) = match source { + PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI), + PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE), + PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI), + }; + + let ref_clk = in_clk / config.prediv as u32; + + let ref_range = match ref_clk.0 { + ..=1_999_999 => Pllrge::RANGE1, + ..=3_999_999 => Pllrge::RANGE2, + ..=7_999_999 => Pllrge::RANGE4, + ..=16_000_000 => Pllrge::RANGE8, + x => panic!("pll ref_clk out of range: {} mhz", x), + }; + + // The smaller range (150 to 420 MHz) must + // be chosen when the reference clock frequency is lower than 2 MHz. + let wide_allowed = ref_range != Pllrge::RANGE1; + + let vco_clk = ref_clk * config.mul; + let vco_range = if VCO_RANGE.contains(&vco_clk.0) { + Pllvcosel::MEDIUMVCO + } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk.0) { + Pllvcosel::WIDEVCO + } else { + panic!("pll vco_clk out of range: {} mhz", vco_clk.0) + }; + + let p = config.divp.map(|div| { + assert!(1 <= div && div <= 128); + if num == 0 { + // on PLL1, DIVP must be even. + assert!(div % 2 == 0); + } + + vco_clk / div + }); + let q = config.divq.map(|div| { + assert!(1 <= div && div <= 128); + vco_clk / div + }); + let r = config.divr.map(|div| { + assert!(1 <= div && div <= 128); + vco_clk / div + }); + + #[cfg(stm32h5)] + RCC.pllcfgr(num).write(|w| { + w.set_pllsrc(src); + w.set_divm(config.prediv); + w.set_pllvcosel(vco_range); + w.set_pllrge(ref_range); + w.set_pllfracen(false); + w.set_pllpen(p.is_some()); + w.set_pllqen(q.is_some()); + w.set_pllren(r.is_some()); + }); + + #[cfg(stm32h7)] + { + RCC.pllckselr().modify(|w| { + w.set_divm(num, config.prediv); + w.set_pllsrc(src); + }); + RCC.pllcfgr().modify(|w| { + w.set_pllvcosel(num, vco_range); + w.set_pllrge(num, ref_range); + w.set_pllfracen(num, false); + w.set_divpen(num, p.is_some()); + w.set_divqen(num, q.is_some()); + w.set_divren(num, r.is_some()); + }); + } + + RCC.plldivr(num).write(|w| { + w.set_plln(config.mul - 1); + w.set_pllp((config.divp.unwrap_or(1) - 1) as u8); + w.set_pllq((config.divq.unwrap_or(1) - 1) as u8); + w.set_pllr((config.divr.unwrap_or(1) - 1) as u8); + }); + + RCC.cr().modify(|w| w.set_pllon(num, true)); + while !RCC.cr().read().pllrdy(num) {} + + PllOutput { p, q, r } +} + +fn flash_setup(clk: Hertz, vos: VoltageScale) { + // RM0481 Rev 1, table 37 + // LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0 + // 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz + // 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz + // 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz + // 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz + // 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz + // 5 2 170 to 200 MHz 210 to 250 MHz + #[cfg(stm32h5)] + let (latency, wrhighfreq) = match (vos, clk.0) { + (VoltageScale::Scale0, ..=42_000_000) => (0, 0), + (VoltageScale::Scale0, ..=84_000_000) => (1, 0), + (VoltageScale::Scale0, ..=126_000_000) => (2, 1), + (VoltageScale::Scale0, ..=168_000_000) => (3, 1), + (VoltageScale::Scale0, ..=210_000_000) => (4, 2), + (VoltageScale::Scale0, ..=250_000_000) => (5, 2), + + (VoltageScale::Scale1, ..=34_000_000) => (0, 0), + (VoltageScale::Scale1, ..=68_000_000) => (1, 0), + (VoltageScale::Scale1, ..=102_000_000) => (2, 1), + (VoltageScale::Scale1, ..=136_000_000) => (3, 1), + (VoltageScale::Scale1, ..=170_000_000) => (4, 2), + (VoltageScale::Scale1, ..=200_000_000) => (5, 2), + + (VoltageScale::Scale2, ..=30_000_000) => (0, 0), + (VoltageScale::Scale2, ..=60_000_000) => (1, 0), + (VoltageScale::Scale2, ..=90_000_000) => (2, 1), + (VoltageScale::Scale2, ..=120_000_000) => (3, 1), + (VoltageScale::Scale2, ..=150_000_000) => (4, 2), + + (VoltageScale::Scale3, ..=20_000_000) => (0, 0), + (VoltageScale::Scale3, ..=40_000_000) => (1, 0), + (VoltageScale::Scale3, ..=60_000_000) => (2, 1), + (VoltageScale::Scale3, ..=80_000_000) => (3, 1), + (VoltageScale::Scale3, ..=100_000_000) => (4, 2), + + _ => unreachable!(), + }; + + #[cfg(flash_h7)] + let (latency, wrhighfreq) = match (vos, clk.0) { + // VOS 0 range VCORE 1.26V - 1.40V + (VoltageScale::Scale0, ..=70_000_000) => (0, 0), + (VoltageScale::Scale0, ..=140_000_000) => (1, 1), + (VoltageScale::Scale0, ..=185_000_000) => (2, 1), + (VoltageScale::Scale0, ..=210_000_000) => (2, 2), + (VoltageScale::Scale0, ..=225_000_000) => (3, 2), + (VoltageScale::Scale0, ..=240_000_000) => (4, 2), + // VOS 1 range VCORE 1.15V - 1.26V + (VoltageScale::Scale1, ..=70_000_000) => (0, 0), + (VoltageScale::Scale1, ..=140_000_000) => (1, 1), + (VoltageScale::Scale1, ..=185_000_000) => (2, 1), + (VoltageScale::Scale1, ..=210_000_000) => (2, 2), + (VoltageScale::Scale1, ..=225_000_000) => (3, 2), + // VOS 2 range VCORE 1.05V - 1.15V + (VoltageScale::Scale2, ..=55_000_000) => (0, 0), + (VoltageScale::Scale2, ..=110_000_000) => (1, 1), + (VoltageScale::Scale2, ..=165_000_000) => (2, 1), + (VoltageScale::Scale2, ..=224_000_000) => (3, 2), + // VOS 3 range VCORE 0.95V - 1.05V + (VoltageScale::Scale3, ..=45_000_000) => (0, 0), + (VoltageScale::Scale3, ..=90_000_000) => (1, 1), + (VoltageScale::Scale3, ..=135_000_000) => (2, 1), + (VoltageScale::Scale3, ..=180_000_000) => (3, 2), + (VoltageScale::Scale3, ..=224_000_000) => (4, 2), + _ => unreachable!(), + }; + + // See RM0455 Rev 10 Table 16. FLASH recommended number of wait + // states and programming delay + #[cfg(flash_h7ab)] + let (latency, wrhighfreq) = match (vos, clk.0) { + // VOS 0 range VCORE 1.25V - 1.35V + (VoltageScale::Scale0, ..=42_000_000) => (0, 0), + (VoltageScale::Scale0, ..=84_000_000) => (1, 0), + (VoltageScale::Scale0, ..=126_000_000) => (2, 1), + (VoltageScale::Scale0, ..=168_000_000) => (3, 1), + (VoltageScale::Scale0, ..=210_000_000) => (4, 2), + (VoltageScale::Scale0, ..=252_000_000) => (5, 2), + (VoltageScale::Scale0, ..=280_000_000) => (6, 3), + // VOS 1 range VCORE 1.15V - 1.25V + (VoltageScale::Scale1, ..=38_000_000) => (0, 0), + (VoltageScale::Scale1, ..=76_000_000) => (1, 0), + (VoltageScale::Scale1, ..=114_000_000) => (2, 1), + (VoltageScale::Scale1, ..=152_000_000) => (3, 1), + (VoltageScale::Scale1, ..=190_000_000) => (4, 2), + (VoltageScale::Scale1, ..=225_000_000) => (5, 2), + // VOS 2 range VCORE 1.05V - 1.15V + (VoltageScale::Scale2, ..=34) => (0, 0), + (VoltageScale::Scale2, ..=68) => (1, 0), + (VoltageScale::Scale2, ..=102) => (2, 1), + (VoltageScale::Scale2, ..=136) => (3, 1), + (VoltageScale::Scale2, ..=160) => (4, 2), + // VOS 3 range VCORE 0.95V - 1.05V + (VoltageScale::Scale3, ..=22) => (0, 0), + (VoltageScale::Scale3, ..=44) => (1, 0), + (VoltageScale::Scale3, ..=66) => (2, 1), + (VoltageScale::Scale3, ..=88) => (3, 1), + _ => unreachable!(), + }; + + debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); + + FLASH.acr().write(|w| { + w.set_wrhighfreq(wrhighfreq); + w.set_latency(latency); + }); + while FLASH.acr().read().latency() != latency {} +} diff --git a/embassy-stm32/src/rcc/h5.rs b/embassy-stm32/src/rcc/h5.rs deleted file mode 100644 index 15f28c5dc..000000000 --- a/embassy-stm32/src/rcc/h5.rs +++ /dev/null @@ -1,511 +0,0 @@ -use core::marker::PhantomData; - -use stm32_metapac::rcc::vals::Timpre; - -use crate::pac::rcc::vals::{Hseext, Hsidiv, Mco1, Mco2, Pllrge, Pllsrc, Pllvcosel, Sw}; -use crate::pac::{FLASH, PWR, RCC}; -use crate::rcc::{set_freqs, Clocks}; -use crate::time::Hertz; -use crate::{peripherals, Peripheral}; - -/// HSI speed -pub const HSI_FREQ: Hertz = Hertz(64_000_000); - -/// CSI speed -pub const CSI_FREQ: Hertz = Hertz(4_000_000); - -/// HSI48 speed -pub const HSI48_FREQ: Hertz = Hertz(48_000_000); - -/// LSI speed -pub const LSI_FREQ: Hertz = Hertz(32_000); - -const VCO_MIN: u32 = 150_000_000; -const VCO_MAX: u32 = 420_000_000; -const VCO_WIDE_MIN: u32 = 128_000_000; -const VCO_WIDE_MAX: u32 = 560_000_000; - -pub use super::bus::{AHBPrescaler, APBPrescaler}; -pub use crate::pac::pwr::vals::Vos as VoltageScale; - -pub enum HseMode { - /// crystal/ceramic oscillator (HSEBYP=0) - Oscillator, - /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) - BypassAnalog, - /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1) - BypassDigital, -} - -pub struct Hse { - /// HSE frequency. - pub freq: Hertz, - /// HSE mode. - pub mode: HseMode, -} - -pub enum Hsi { - /// 64Mhz - Mhz64, - /// 32Mhz (divided by 2) - Mhz32, - /// 16Mhz (divided by 4) - Mhz16, - /// 8Mhz (divided by 8) - Mhz8, -} - -pub enum Sysclk { - /// HSI selected as sysclk - HSI, - /// HSE selected as sysclk - HSE, - /// CSI selected as sysclk - CSI, - /// PLL1_P selected as sysclk - Pll1P, -} - -pub enum PllSource { - Hsi, - Csi, - Hse, -} - -pub struct Pll { - /// Source clock selection. - pub source: PllSource, - - /// PLL pre-divider (DIVM). Must be between 1 and 63. - pub prediv: u8, - - /// PLL multiplication factor. Must be between 4 and 512. - pub mul: u16, - - /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128. - /// On PLL1, it must be even (in particular, it cannot be 1.) - pub divp: Option, - /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128. - pub divq: Option, - /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128. - pub divr: Option, -} - -fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz { - match (tim, apb) { - // The timers kernel clock is equal to rcc_hclk1 if PPRE1 or PPRE2 corresponds to a - // division by 1 or 2, else it is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 - (TimerPrescaler::DefaultX2, APBPrescaler::DIV1) => clk, - (TimerPrescaler::DefaultX2, APBPrescaler::DIV2) => clk, - (TimerPrescaler::DefaultX2, APBPrescaler::DIV4) => clk / 2u32, - (TimerPrescaler::DefaultX2, APBPrescaler::DIV8) => clk / 4u32, - (TimerPrescaler::DefaultX2, APBPrescaler::DIV16) => clk / 8u32, - // The timers kernel clock is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 if PPRE1 or PPRE2 - // corresponds to a division by 1, 2 or 4, else it is equal to 4 x Frcc_pclk1 or 4 x Frcc_pclk2 - // this makes NO SENSE and is different than in the H7. Mistake in the RM?? - (TimerPrescaler::DefaultX4, APBPrescaler::DIV1) => clk * 2u32, - (TimerPrescaler::DefaultX4, APBPrescaler::DIV2) => clk, - (TimerPrescaler::DefaultX4, APBPrescaler::DIV4) => clk / 2u32, - (TimerPrescaler::DefaultX4, APBPrescaler::DIV8) => clk / 2u32, - (TimerPrescaler::DefaultX4, APBPrescaler::DIV16) => clk / 4u32, - - _ => unreachable!(), - } -} - -/// APB prescaler -#[derive(Clone, Copy)] -pub enum TimerPrescaler { - DefaultX2, - DefaultX4, -} - -impl From for Timpre { - fn from(value: TimerPrescaler) -> Self { - match value { - TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2, - TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4, - } - } -} - -/// Configuration of the core clocks -#[non_exhaustive] -pub struct Config { - pub hsi: Option, - pub hse: Option, - pub csi: bool, - pub hsi48: bool, - pub sys: Sysclk, - - pub pll1: Option, - pub pll2: Option, - #[cfg(rcc_h5)] - pub pll3: Option, - - pub ahb_pre: AHBPrescaler, - pub apb1_pre: APBPrescaler, - pub apb2_pre: APBPrescaler, - pub apb3_pre: APBPrescaler, - pub timer_prescaler: TimerPrescaler, - - pub voltage_scale: VoltageScale, -} - -impl Default for Config { - fn default() -> Self { - Self { - hsi: Some(Hsi::Mhz64), - hse: None, - csi: false, - hsi48: false, - sys: Sysclk::HSI, - pll1: None, - pll2: None, - #[cfg(rcc_h5)] - pll3: None, - - ahb_pre: AHBPrescaler::DIV1, - apb1_pre: APBPrescaler::DIV1, - apb2_pre: APBPrescaler::DIV1, - apb3_pre: APBPrescaler::DIV1, - timer_prescaler: TimerPrescaler::DefaultX2, - - voltage_scale: VoltageScale::SCALE3, - } - } -} - -pub(crate) mod sealed { - pub trait McoInstance { - type Source; - unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8); - } -} - -pub trait McoInstance: sealed::McoInstance + 'static {} - -pin_trait!(McoPin, McoInstance); - -macro_rules! impl_peri { - ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => { - impl sealed::McoInstance for peripherals::$peri { - type Source = $source; - - unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) { - RCC.cfgr().modify(|w| { - w.$set_source(source); - w.$set_prescaler(prescaler); - }); - } - } - - impl McoInstance for peripherals::$peri {} - }; -} - -impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre); -impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre); - -pub struct Mco<'d, T: McoInstance> { - phantom: PhantomData<&'d mut T>, -} - -impl<'d, T: McoInstance> Mco<'d, T> { - pub fn new( - _peri: impl Peripheral

+ 'd, - _pin: impl Peripheral

> + 'd, - _source: T::Source, - ) -> Self { - todo!(); - } -} - -pub(crate) unsafe fn init(config: Config) { - let max_clk = match config.voltage_scale { - VoltageScale::SCALE0 => Hertz(250_000_000), - VoltageScale::SCALE1 => Hertz(200_000_000), - VoltageScale::SCALE2 => Hertz(150_000_000), - VoltageScale::SCALE3 => Hertz(100_000_000), - }; - - // Configure voltage scale. - PWR.voscr().modify(|w| w.set_vos(config.voltage_scale)); - while !PWR.vossr().read().vosrdy() {} - - // Configure HSI - let hsi = match config.hsi { - None => { - RCC.cr().modify(|w| w.set_hsion(false)); - None - } - Some(hsi) => { - let (freq, hsidiv) = match hsi { - Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1), - Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2), - Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4), - Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8), - }; - RCC.cr().modify(|w| { - w.set_hsidiv(hsidiv); - w.set_hsion(true); - }); - while !RCC.cr().read().hsirdy() {} - Some(freq) - } - }; - - // Configure HSE - let hse = match config.hse { - None => { - RCC.cr().modify(|w| w.set_hseon(false)); - None - } - Some(hse) => { - let (byp, ext) = match hse.mode { - HseMode::Oscillator => (false, Hseext::ANALOG), - HseMode::BypassAnalog => (true, Hseext::ANALOG), - HseMode::BypassDigital => (true, Hseext::DIGITAL), - }; - - RCC.cr().modify(|w| { - w.set_hsebyp(byp); - w.set_hseext(ext); - }); - RCC.cr().modify(|w| w.set_hseon(true)); - while !RCC.cr().read().hserdy() {} - Some(hse.freq) - } - }; - - // Configure HSI48. - RCC.cr().modify(|w| w.set_hsi48on(config.hsi48)); - let _hsi48 = match config.hsi48 { - false => None, - true => { - while !RCC.cr().read().hsi48rdy() {} - Some(CSI_FREQ) - } - }; - - // Configure CSI. - RCC.cr().modify(|w| w.set_csion(config.csi)); - let csi = match config.csi { - false => None, - true => { - while !RCC.cr().read().csirdy() {} - Some(CSI_FREQ) - } - }; - - // Configure PLLs. - let pll_input = PllInput { csi, hse, hsi }; - let pll1 = init_pll(0, config.pll1, &pll_input); - let _pll2 = init_pll(1, config.pll2, &pll_input); - #[cfg(rcc_h5)] - let _pll3 = init_pll(2, config.pll3, &pll_input); - - // Configure sysclk - let (sys, sw) = match config.sys { - Sysclk::HSI => (unwrap!(hsi), Sw::HSI), - Sysclk::HSE => (unwrap!(hse), Sw::HSE), - Sysclk::CSI => (unwrap!(csi), Sw::CSI), - Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1), - }; - assert!(sys <= max_clk); - - let hclk = sys / config.ahb_pre; - - let apb1 = hclk / config.apb1_pre; - let apb1_tim = apb_div_tim(&config.apb1_pre, hclk, config.timer_prescaler); - let apb2 = hclk / config.apb2_pre; - let apb2_tim = apb_div_tim(&config.apb2_pre, hclk, config.timer_prescaler); - let apb3 = hclk / config.apb3_pre; - - flash_setup(hclk, config.voltage_scale); - - // Set hpre - let hpre = config.ahb_pre.into(); - RCC.cfgr2().modify(|w| w.set_hpre(hpre)); - while RCC.cfgr2().read().hpre() != hpre {} - - // set ppre - RCC.cfgr2().modify(|w| { - w.set_ppre1(config.apb1_pre.into()); - w.set_ppre2(config.apb2_pre.into()); - w.set_ppre3(config.apb3_pre.into()); - }); - - RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into())); - - RCC.cfgr().modify(|w| w.set_sw(sw)); - while RCC.cfgr().read().sws() != sw {} - - set_freqs(Clocks { - sys, - ahb1: hclk, - ahb2: hclk, - ahb3: hclk, - ahb4: hclk, - apb1, - apb2, - apb3, - apb1_tim, - apb2_tim, - adc: None, - }); -} - -struct PllInput { - hsi: Option, - hse: Option, - csi: Option, -} - -struct PllOutput { - p: Option, - #[allow(dead_code)] - q: Option, - #[allow(dead_code)] - r: Option, -} - -fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { - let Some(config) = config else { - // Stop PLL - RCC.cr().modify(|w| w.set_pllon(num, false)); - while RCC.cr().read().pllrdy(num) {} - - // "To save power when PLL1 is not used, the value of PLL1M must be set to 0."" - RCC.pllcfgr(num).write(|w| { - w.set_divm(0); - }); - - return PllOutput { - p: None, - q: None, - r: None, - }; - }; - - assert!(1 <= config.prediv && config.prediv <= 63); - assert!(4 <= config.mul && config.mul <= 512); - - let (in_clk, src) = match config.source { - PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI), - PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE), - PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI), - }; - - let ref_clk = in_clk / config.prediv as u32; - - let ref_range = match ref_clk.0 { - ..=1_999_999 => Pllrge::RANGE1, - ..=3_999_999 => Pllrge::RANGE2, - ..=7_999_999 => Pllrge::RANGE4, - ..=16_000_000 => Pllrge::RANGE8, - x => panic!("pll ref_clk out of range: {} mhz", x), - }; - - // The smaller range (150 to 420 MHz) must - // be chosen when the reference clock frequency is lower than 2 MHz. - let wide_allowed = ref_range != Pllrge::RANGE1; - - let vco_clk = ref_clk * config.mul; - let vco_range = match vco_clk.0 { - VCO_MIN..=VCO_MAX => Pllvcosel::MEDIUMVCO, - VCO_WIDE_MIN..=VCO_WIDE_MAX if wide_allowed => Pllvcosel::WIDEVCO, - x => panic!("pll vco_clk out of range: {} mhz", x), - }; - - let p = config.divp.map(|div| { - assert!(1 <= div && div <= 128); - if num == 0 { - // on PLL1, DIVP must be even. - assert!(div % 2 == 0); - } - - vco_clk / div - }); - let q = config.divq.map(|div| { - assert!(1 <= div && div <= 128); - vco_clk / div - }); - let r = config.divr.map(|div| { - assert!(1 <= div && div <= 128); - vco_clk / div - }); - - RCC.pllcfgr(num).write(|w| { - w.set_pllsrc(src); - w.set_divm(config.prediv); - w.set_pllvcosel(vco_range); - w.set_pllrge(ref_range); - w.set_pllfracen(false); - w.set_pllpen(p.is_some()); - w.set_pllqen(q.is_some()); - w.set_pllren(r.is_some()); - }); - RCC.plldivr(num).write(|w| { - w.set_plln(config.mul - 1); - w.set_pllp((config.divp.unwrap_or(1) - 1) as u8); - w.set_pllq((config.divq.unwrap_or(1) - 1) as u8); - w.set_pllr((config.divr.unwrap_or(1) - 1) as u8); - }); - - RCC.cr().modify(|w| w.set_pllon(num, true)); - while !RCC.cr().read().pllrdy(num) {} - - PllOutput { p, q, r } -} - -fn flash_setup(clk: Hertz, vos: VoltageScale) { - // RM0481 Rev 1, table 37 - // LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0 - // 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz - // 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz - // 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz - // 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz - // 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz - // 5 2 170 to 200 MHz 210 to 250 MHz - - // See RM0433 Rev 7 Table 17. FLASH recommended number of wait - // states and programming delay - let (latency, wrhighfreq) = match (vos, clk.0) { - (VoltageScale::SCALE0, ..=42_000_000) => (0, 0), - (VoltageScale::SCALE0, ..=84_000_000) => (1, 0), - (VoltageScale::SCALE0, ..=126_000_000) => (2, 1), - (VoltageScale::SCALE0, ..=168_000_000) => (3, 1), - (VoltageScale::SCALE0, ..=210_000_000) => (4, 2), - (VoltageScale::SCALE0, ..=250_000_000) => (5, 2), - - (VoltageScale::SCALE1, ..=34_000_000) => (0, 0), - (VoltageScale::SCALE1, ..=68_000_000) => (1, 0), - (VoltageScale::SCALE1, ..=102_000_000) => (2, 1), - (VoltageScale::SCALE1, ..=136_000_000) => (3, 1), - (VoltageScale::SCALE1, ..=170_000_000) => (4, 2), - (VoltageScale::SCALE1, ..=200_000_000) => (5, 2), - - (VoltageScale::SCALE2, ..=30_000_000) => (0, 0), - (VoltageScale::SCALE2, ..=60_000_000) => (1, 0), - (VoltageScale::SCALE2, ..=90_000_000) => (2, 1), - (VoltageScale::SCALE2, ..=120_000_000) => (3, 1), - (VoltageScale::SCALE2, ..=150_000_000) => (4, 2), - - (VoltageScale::SCALE3, ..=20_000_000) => (0, 0), - (VoltageScale::SCALE3, ..=40_000_000) => (1, 0), - (VoltageScale::SCALE3, ..=60_000_000) => (2, 1), - (VoltageScale::SCALE3, ..=80_000_000) => (3, 1), - (VoltageScale::SCALE3, ..=100_000_000) => (4, 2), - - _ => unreachable!(), - }; - - debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq); - - FLASH.acr().write(|w| { - w.set_wrhighfreq(wrhighfreq); - w.set_latency(latency); - }); - while FLASH.acr().read().latency() != latency {} -} diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs deleted file mode 100644 index ea26c26c1..000000000 --- a/embassy-stm32/src/rcc/h7.rs +++ /dev/null @@ -1,934 +0,0 @@ -use core::marker::PhantomData; - -use embassy_hal_internal::into_ref; -use stm32_metapac::pwr::vals::Vos; -use stm32_metapac::rcc::vals::{Mco1, Mco2}; - -pub use self::pll::PllConfig; -use crate::gpio::sealed::AFType; -use crate::gpio::Speed; -use crate::pac::rcc::vals::{Adcsel, Ckpersel, Hpre, Hsidiv, Pllsrc, Ppre, Sw, Timpre}; -use crate::pac::{PWR, RCC, SYSCFG}; -use crate::rcc::{set_freqs, Clocks}; -use crate::time::Hertz; -use crate::{peripherals, Peripheral}; - -/// HSI speed -pub const HSI_FREQ: Hertz = Hertz(64_000_000); - -/// CSI speed -pub const CSI_FREQ: Hertz = Hertz(4_000_000); - -/// HSI48 speed -pub const HSI48_FREQ: Hertz = Hertz(48_000_000); - -/// LSI speed -pub const LSI_FREQ: Hertz = Hertz(32_000); - -#[derive(Clone, Copy)] -pub enum VoltageScale { - Scale0, - Scale1, - Scale2, - Scale3, -} - -#[derive(Clone, Copy)] -pub enum AdcClockSource { - Pll2PCk, - Pll3RCk, - PerCk, -} - -impl AdcClockSource { - pub fn adcsel(&self) -> Adcsel { - match self { - AdcClockSource::Pll2PCk => Adcsel::PLL2_P, - AdcClockSource::Pll3RCk => Adcsel::PLL3_R, - AdcClockSource::PerCk => Adcsel::PER, - } - } -} - -impl Default for AdcClockSource { - fn default() -> Self { - Self::Pll2PCk - } -} - -/// Core clock frequencies -#[derive(Clone, Copy)] -pub struct CoreClocks { - pub hclk: Hertz, - pub pclk1: Hertz, - pub pclk2: Hertz, - pub pclk3: Hertz, - pub pclk4: Hertz, - pub ppre1: u8, - pub ppre2: u8, - pub ppre3: u8, - pub ppre4: u8, - pub csi_ck: Option, - pub hsi_ck: Option, - pub hsi48_ck: Option, - pub lsi_ck: Option, - pub per_ck: Option, - pub hse_ck: Option, - pub pll1_p_ck: Option, - pub pll1_q_ck: Option, - pub pll1_r_ck: Option, - pub pll2_p_ck: Option, - pub pll2_q_ck: Option, - pub pll2_r_ck: Option, - pub pll3_p_ck: Option, - pub pll3_q_ck: Option, - pub pll3_r_ck: Option, - pub timx_ker_ck: Option, - pub timy_ker_ck: Option, - pub adc_ker_ck: Option, - pub sys_ck: Hertz, - pub c_ck: Hertz, -} - -/// Configuration of the core clocks -#[non_exhaustive] -pub struct Config { - pub hse: Option, - pub bypass_hse: bool, - pub sys_ck: Option, - pub per_ck: Option, - pub hclk: Option, - pub pclk1: Option, - pub pclk2: Option, - pub pclk3: Option, - pub pclk4: Option, - pub pll1: PllConfig, - pub pll2: PllConfig, - pub pll3: PllConfig, - pub adc_clock_source: AdcClockSource, - pub voltage_scale: VoltageScale, -} - -impl Default for Config { - fn default() -> Self { - Self { - hse: None, - bypass_hse: false, - sys_ck: None, - per_ck: None, - hclk: None, - pclk1: None, - pclk2: None, - pclk3: None, - pclk4: None, - pll1: Default::default(), - pll2: Default::default(), - pll3: Default::default(), - adc_clock_source: Default::default(), - voltage_scale: VoltageScale::Scale1, - } - } -} - -/// Setup traceclk -/// Returns a pll1_r_ck -fn traceclk_setup(config: &mut Config, sys_use_pll1_p: bool) { - let pll1_r_ck = match (sys_use_pll1_p, config.pll1.r_ck) { - // pll1_p_ck selected as system clock but pll1_r_ck not - // set. The traceclk mux is synchronous with the system - // clock mux, but has pll1_r_ck as an input. In order to - // keep traceclk running, we force a pll1_r_ck. - (true, None) => Some(Hertz(unwrap!(config.pll1.p_ck).0 / 2)), - - // Either pll1 not selected as system clock, free choice - // of pll1_r_ck. Or pll1 is selected, assume user has set - // a suitable pll1_r_ck frequency. - _ => config.pll1.r_ck, - }; - config.pll1.r_ck = pll1_r_ck; -} - -/// Divider calculator for pclk 1 - 4 -/// -/// Returns real pclk, bits, ppre and the timer kernel clock -fn ppre_calculate( - requested_pclk: u32, - hclk: u32, - max_pclk: u32, - tim_pre: Option, -) -> (u32, u8, u8, Option) { - let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk { - 0 => panic!(), - 1 => (0b000, 1), - 2 => (0b100, 2), - 3..=5 => (0b101, 4), - 6..=11 => (0b110, 8), - _ => (0b111, 16), - }; - let real_pclk = hclk / u32::from(ppre); - assert!(real_pclk <= max_pclk); - - let tim_ker_clk = if let Some(tim_pre) = tim_pre { - let clk = match (bits, tim_pre) { - (0b101, Timpre::DEFAULTX2) => hclk / 2, - (0b110, Timpre::DEFAULTX4) => hclk / 2, - (0b110, Timpre::DEFAULTX2) => hclk / 4, - (0b111, Timpre::DEFAULTX4) => hclk / 4, - (0b111, Timpre::DEFAULTX2) => hclk / 8, - _ => hclk, - }; - Some(clk) - } else { - None - }; - (real_pclk, bits, ppre, tim_ker_clk) -} - -/// Setup sys_ck -/// Returns sys_ck frequency, and a pll1_p_ck -fn sys_ck_setup(config: &mut Config, srcclk: Hertz) -> (Hertz, bool) { - // Compare available with wanted clocks - let sys_ck = config.sys_ck.unwrap_or(srcclk); - - if sys_ck != srcclk { - // The requested system clock is not the immediately available - // HSE/HSI clock. Perhaps there are other ways of obtaining - // the requested system clock (such as `HSIDIV`) but we will - // ignore those for now. - // - // Therefore we must use pll1_p_ck - let pll1_p_ck = match config.pll1.p_ck { - Some(p_ck) => { - assert!( - p_ck == sys_ck, - "Error: Cannot set pll1_p_ck independently as it must be used to generate sys_ck" - ); - Some(p_ck) - } - None => Some(sys_ck), - }; - config.pll1.p_ck = pll1_p_ck; - - (sys_ck, true) - } else { - // sys_ck is derived directly from a source clock - // (HSE/HSI). pll1_p_ck can be as requested - (sys_ck, false) - } -} - -fn flash_setup(rcc_aclk: u32, vos: VoltageScale) { - use crate::pac::FLASH; - - // ACLK in MHz, round down and subtract 1 from integers. eg. - // 61_999_999 -> 61MHz - // 62_000_000 -> 61MHz - // 62_000_001 -> 62MHz - let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000; - - // See RM0433 Rev 7 Table 17. FLASH recommended number of wait - // states and programming delay - #[cfg(flash_h7)] - let (wait_states, progr_delay) = match vos { - // VOS 0 range VCORE 1.26V - 1.40V - VoltageScale::Scale0 => match rcc_aclk_mhz { - 0..=69 => (0, 0), - 70..=139 => (1, 1), - 140..=184 => (2, 1), - 185..=209 => (2, 2), - 210..=224 => (3, 2), - 225..=239 => (4, 2), - _ => (7, 3), - }, - // VOS 1 range VCORE 1.15V - 1.26V - VoltageScale::Scale1 => match rcc_aclk_mhz { - 0..=69 => (0, 0), - 70..=139 => (1, 1), - 140..=184 => (2, 1), - 185..=209 => (2, 2), - 210..=224 => (3, 2), - _ => (7, 3), - }, - // VOS 2 range VCORE 1.05V - 1.15V - VoltageScale::Scale2 => match rcc_aclk_mhz { - 0..=54 => (0, 0), - 55..=109 => (1, 1), - 110..=164 => (2, 1), - 165..=224 => (3, 2), - _ => (7, 3), - }, - // VOS 3 range VCORE 0.95V - 1.05V - VoltageScale::Scale3 => match rcc_aclk_mhz { - 0..=44 => (0, 0), - 45..=89 => (1, 1), - 90..=134 => (2, 1), - 135..=179 => (3, 2), - 180..=224 => (4, 2), - _ => (7, 3), - }, - }; - - // See RM0455 Rev 10 Table 16. FLASH recommended number of wait - // states and programming delay - #[cfg(flash_h7ab)] - let (wait_states, progr_delay) = match vos { - // VOS 0 range VCORE 1.25V - 1.35V - VoltageScale::Scale0 => match rcc_aclk_mhz { - 0..=42 => (0, 0), - 43..=84 => (1, 0), - 85..=126 => (2, 1), - 127..=168 => (3, 1), - 169..=210 => (4, 2), - 211..=252 => (5, 2), - 253..=280 => (6, 3), - _ => (7, 3), - }, - // VOS 1 range VCORE 1.15V - 1.25V - VoltageScale::Scale1 => match rcc_aclk_mhz { - 0..=38 => (0, 0), - 39..=76 => (1, 0), - 77..=114 => (2, 1), - 115..=152 => (3, 1), - 153..=190 => (4, 2), - 191..=225 => (5, 2), - _ => (7, 3), - }, - // VOS 2 range VCORE 1.05V - 1.15V - VoltageScale::Scale2 => match rcc_aclk_mhz { - 0..=34 => (0, 0), - 35..=68 => (1, 0), - 69..=102 => (2, 1), - 103..=136 => (3, 1), - 137..=160 => (4, 2), - _ => (7, 3), - }, - // VOS 3 range VCORE 0.95V - 1.05V - VoltageScale::Scale3 => match rcc_aclk_mhz { - 0..=22 => (0, 0), - 23..=44 => (1, 0), - 45..=66 => (2, 1), - 67..=88 => (3, 1), - _ => (7, 3), - }, - }; - - FLASH.acr().write(|w| { - w.set_wrhighfreq(progr_delay); - w.set_latency(wait_states) - }); - while FLASH.acr().read().latency() != wait_states {} -} - -pub enum McoClock { - Disabled, - Bypassed, - Divided(u8), -} - -impl McoClock { - fn into_raw(&self) -> u8 { - match self { - McoClock::Disabled => 0, - McoClock::Bypassed => 1, - McoClock::Divided(divisor) => { - if *divisor > 15 { - panic!("Mco divisor must be less than 15. Refer to the reference manual for more information.") - } - *divisor - } - } - } -} - -#[derive(Copy, Clone)] -pub enum Mco1Source { - Hsi, - Lse, - Hse, - Pll1Q, - Hsi48, -} - -impl Default for Mco1Source { - fn default() -> Self { - Self::Hsi - } -} - -pub trait McoSource { - type Raw; - - fn into_raw(&self) -> Self::Raw; -} - -impl McoSource for Mco1Source { - type Raw = Mco1; - fn into_raw(&self) -> Self::Raw { - match self { - Mco1Source::Hsi => Mco1::HSI, - Mco1Source::Lse => Mco1::LSE, - Mco1Source::Hse => Mco1::HSE, - Mco1Source::Pll1Q => Mco1::PLL1_Q, - Mco1Source::Hsi48 => Mco1::HSI48, - } - } -} - -#[derive(Copy, Clone)] -pub enum Mco2Source { - SysClk, - Pll2Q, - Hse, - Pll1Q, - Csi, - Lsi, -} - -impl Default for Mco2Source { - fn default() -> Self { - Self::SysClk - } -} - -impl McoSource for Mco2Source { - type Raw = Mco2; - fn into_raw(&self) -> Self::Raw { - match self { - Mco2Source::SysClk => Mco2::SYSCLK, - Mco2Source::Pll2Q => Mco2::PLL2_P, - Mco2Source::Hse => Mco2::HSE, - Mco2Source::Pll1Q => Mco2::PLL1_P, - Mco2Source::Csi => Mco2::CSI, - Mco2Source::Lsi => Mco2::LSI, - } - } -} - -pub(crate) mod sealed { - pub trait McoInstance { - type Source; - unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8); - } -} - -pub trait McoInstance: sealed::McoInstance + 'static {} - -pin_trait!(McoPin, McoInstance); - -macro_rules! impl_peri { - ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => { - impl sealed::McoInstance for peripherals::$peri { - type Source = $source; - - unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) { - RCC.cfgr().modify(|w| { - w.$set_source(source); - w.$set_prescaler(prescaler); - }); - } - } - - impl McoInstance for peripherals::$peri {} - }; -} - -impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre); -impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre); - -pub struct Mco<'d, T: McoInstance> { - phantom: PhantomData<&'d mut T>, -} - -impl<'d, T: McoInstance> Mco<'d, T> { - pub fn new( - _peri: impl Peripheral

+ 'd, - pin: impl Peripheral

> + 'd, - source: impl McoSource, - prescaler: McoClock, - ) -> Self { - into_ref!(pin); - - critical_section::with(|_| unsafe { - T::apply_clock_settings(source.into_raw(), prescaler.into_raw()); - pin.set_as_af(pin.af_num(), AFType::OutputPushPull); - pin.set_speed(Speed::VeryHigh); - }); - - Self { phantom: PhantomData } - } -} - -pub(crate) unsafe fn init(mut config: Config) { - // NB. The lower bytes of CR3 can only be written once after - // POR, and must be written with a valid combination. Refer to - // RM0433 Rev 7 6.8.4. This is partially enforced by dropping - // `self` at the end of this method, but of course we cannot - // know what happened between the previous POR and here. - #[cfg(pwr_h7rm0433)] - PWR.cr3().modify(|w| { - w.set_scuen(true); - w.set_ldoen(true); - w.set_bypass(false); - }); - - #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))] - PWR.cr3().modify(|w| { - // hardcode "Direct SPMS" for now, this is what works on nucleos with the - // default solderbridge configuration. - w.set_sden(true); - w.set_ldoen(false); - }); - - // Validate the supply configuration. If you are stuck here, it is - // because the voltages on your board do not match those specified - // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset - // VOS = Scale 3, so check that the voltage on the VCAP pins = - // 1.0V. - info!("a"); - while !PWR.csr1().read().actvosrdy() {} - info!("b"); - - #[cfg(syscfg_h7)] - { - // in chips without the overdrive bit, we can go from any scale to any scale directly. - PWR.d3cr().modify(|w| { - w.set_vos(match config.voltage_scale { - VoltageScale::Scale0 => Vos::SCALE0, - VoltageScale::Scale1 => Vos::SCALE1, - VoltageScale::Scale2 => Vos::SCALE2, - VoltageScale::Scale3 => Vos::SCALE3, - }) - }); - while !PWR.d3cr().read().vosrdy() {} - } - - #[cfg(syscfg_h7od)] - { - match config.voltage_scale { - VoltageScale::Scale0 => { - // to go to scale0, we must go to Scale1 first... - PWR.d3cr().modify(|w| w.set_vos(Vos::SCALE1)); - while !PWR.d3cr().read().vosrdy() {} - - // Then enable overdrive. - critical_section::with(|_| { - RCC.apb4enr().modify(|w| w.set_syscfgen(true)); - SYSCFG.pwrcr().modify(|w| w.set_oden(1)); - }); - while !PWR.d3cr().read().vosrdy() {} - } - _ => { - // for all other scales, we can go directly. - PWR.d3cr().modify(|w| { - w.set_vos(match config.voltage_scale { - VoltageScale::Scale0 => unreachable!(), - VoltageScale::Scale1 => Vos::SCALE1, - VoltageScale::Scale2 => Vos::SCALE2, - VoltageScale::Scale3 => Vos::SCALE3, - }) - }); - while !PWR.d3cr().read().vosrdy() {} - } - } - } - - // Freeze the core clocks, returning a Core Clocks Distribution - // and Reset (CCDR) structure. The actual frequency of the clocks - // configured is returned in the `clocks` member of the CCDR - // structure. - // - // Note that `freeze` will never result in a clock _faster_ than - // that specified. It may result in a clock that is a factor of [1, - // 2) slower. - // - // `syscfg` is required to enable the I/O compensation cell. - // - // # Panics - // - // If a clock specification cannot be achieved within the - // hardware specification then this function will panic. This - // function may also panic if a clock specification can be - // achieved, but the mechanism for doing so is not yet - // implemented here. - - let srcclk = config.hse.unwrap_or(HSI_FREQ); // Available clocks - let (sys_ck, sys_use_pll1_p) = sys_ck_setup(&mut config, srcclk); - - // Configure traceclk from PLL if needed - traceclk_setup(&mut config, sys_use_pll1_p); - - let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0); - let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1); - let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2); - - let sys_ck = if sys_use_pll1_p { - Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup - } else { - sys_ck - }; - - // This routine does not support HSIDIV != 1. To - // do so it would need to ensure all PLLxON bits are clear - // before changing the value of HSIDIV - let cr = RCC.cr().read(); - assert!(cr.hsion()); - assert!(cr.hsidiv() == Hsidiv::DIV1); - - RCC.csr().modify(|w| w.set_lsion(true)); - while !RCC.csr().read().lsirdy() {} - - // per_ck from HSI by default - let (per_ck, ckpersel) = match (config.per_ck == config.hse, config.per_ck) { - (true, Some(hse)) => (hse, Ckpersel::HSE), // HSE - (_, Some(CSI_FREQ)) => (CSI_FREQ, Ckpersel::CSI), // CSI - _ => (HSI_FREQ, Ckpersel::HSI), // HSI - }; - - // D1 Core Prescaler - // Set to 1 - let d1cpre_bits = 0; - let d1cpre_div = 1; - let sys_d1cpre_ck = sys_ck.0 / d1cpre_div; - - // Refer to part datasheet "General operating conditions" - // table for (rev V). We do not assert checks for earlier - // revisions which may have lower limits. - let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match config.voltage_scale { - VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000), - VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000), - VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000), - VoltageScale::Scale3 => (200_000_000, 100_000_000, 50_000_000), - }; - assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max); - - let rcc_hclk = config.hclk.map(|v| v.0).unwrap_or(sys_d1cpre_ck / 2); - assert!(rcc_hclk <= rcc_hclk_max); - - // Estimate divisor - let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk { - 0 => panic!(), - 1 => (Hpre::DIV1, 1), - 2 => (Hpre::DIV2, 2), - 3..=5 => (Hpre::DIV4, 4), - 6..=11 => (Hpre::DIV8, 8), - 12..=39 => (Hpre::DIV16, 16), - 40..=95 => (Hpre::DIV64, 64), - 96..=191 => (Hpre::DIV128, 128), - 192..=383 => (Hpre::DIV256, 256), - _ => (Hpre::DIV512, 512), - }; - // Calculate real AXI and AHB clock - let rcc_hclk = sys_d1cpre_ck / hpre_div; - assert!(rcc_hclk <= rcc_hclk_max); - let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7 - // Timer prescaler selection - let timpre = Timpre::DEFAULTX2; - - let requested_pclk1 = config.pclk1.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); - let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) = - ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre)); - - let requested_pclk2 = config.pclk2.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); - let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) = - ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre)); - - let requested_pclk3 = config.pclk3.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); - let (rcc_pclk3, ppre3_bits, ppre3, _) = ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None); - - let requested_pclk4 = config.pclk4.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); - let (rcc_pclk4, ppre4_bits, ppre4, _) = ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None); - - // Start switching clocks ------------------- - - // Ensure CSI is on and stable - RCC.cr().modify(|w| w.set_csion(true)); - while !RCC.cr().read().csirdy() {} - - // Ensure HSI48 is on and stable - RCC.cr().modify(|w| w.set_hsi48on(true)); - while !RCC.cr().read().hsi48on() {} - - // XXX: support MCO ? - - let hse_ck = match config.hse { - Some(hse) => { - // Ensure HSE is on and stable - RCC.cr().modify(|w| { - w.set_hseon(true); - w.set_hsebyp(config.bypass_hse); - }); - while !RCC.cr().read().hserdy() {} - Some(hse) - } - None => None, - }; - - let pllsrc = if config.hse.is_some() { Pllsrc::HSE } else { Pllsrc::HSI }; - RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc)); - - let enable_pll = |pll| { - RCC.cr().modify(|w| w.set_pllon(pll, true)); - while !RCC.cr().read().pllrdy(pll) {} - }; - - if pll1_p_ck.is_some() { - enable_pll(0); - } - - if pll2_p_ck.is_some() { - enable_pll(1); - } - - if pll3_p_ck.is_some() { - enable_pll(2); - } - - // Core Prescaler / AHB Prescaler / APB3 Prescaler - RCC.d1cfgr().modify(|w| { - w.set_d1cpre(Hpre::from_bits(d1cpre_bits)); - w.set_d1ppre(Ppre::from_bits(ppre3_bits)); - w.set_hpre(hpre_bits) - }); - // Ensure core prescaler value is valid before future lower - // core voltage - while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {} - - flash_setup(rcc_aclk, config.voltage_scale); - - // APB1 / APB2 Prescaler - RCC.d2cfgr().modify(|w| { - w.set_d2ppre1(Ppre::from_bits(ppre1_bits)); - w.set_d2ppre2(Ppre::from_bits(ppre2_bits)); - }); - - // APB4 Prescaler - RCC.d3cfgr().modify(|w| w.set_d3ppre(Ppre::from_bits(ppre4_bits))); - - // Peripheral Clock (per_ck) - RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel)); - - // ADC clock MUX - RCC.d3ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel())); - - let adc_ker_ck = match config.adc_clock_source { - AdcClockSource::Pll2PCk => pll2_p_ck.map(Hertz), - AdcClockSource::Pll3RCk => pll3_r_ck.map(Hertz), - AdcClockSource::PerCk => Some(per_ck), - }; - - // Set timer clocks prescaler setting - RCC.cfgr().modify(|w| w.set_timpre(timpre)); - - // Select system clock source - let sw = match (sys_use_pll1_p, config.hse.is_some()) { - (true, _) => Sw::PLL1, - (false, true) => Sw::HSE, - _ => Sw::HSI, - }; - RCC.cfgr().modify(|w| w.set_sw(sw)); - while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {} - - // IO compensation cell - Requires CSI clock and SYSCFG - assert!(RCC.cr().read().csirdy()); - RCC.apb4enr().modify(|w| w.set_syscfgen(true)); - - // Enable the compensation cell, using back-bias voltage code - // provide by the cell. - critical_section::with(|_| { - SYSCFG.cccsr().modify(|w| { - w.set_en(true); - w.set_cs(false); - w.set_hslv(false); - }) - }); - while !SYSCFG.cccsr().read().ready() {} - - let core_clocks = CoreClocks { - hclk: Hertz(rcc_hclk), - pclk1: Hertz(rcc_pclk1), - pclk2: Hertz(rcc_pclk2), - pclk3: Hertz(rcc_pclk3), - pclk4: Hertz(rcc_pclk4), - ppre1, - ppre2, - ppre3, - ppre4, - csi_ck: Some(CSI_FREQ), - hsi_ck: Some(HSI_FREQ), - hsi48_ck: Some(HSI48_FREQ), - lsi_ck: Some(LSI_FREQ), - per_ck: Some(per_ck), - hse_ck, - pll1_p_ck: pll1_p_ck.map(Hertz), - pll1_q_ck: pll1_q_ck.map(Hertz), - pll1_r_ck: pll1_r_ck.map(Hertz), - pll2_p_ck: pll2_p_ck.map(Hertz), - pll2_q_ck: pll2_q_ck.map(Hertz), - pll2_r_ck: pll2_r_ck.map(Hertz), - pll3_p_ck: pll3_p_ck.map(Hertz), - pll3_q_ck: pll3_q_ck.map(Hertz), - pll3_r_ck: pll3_r_ck.map(Hertz), - timx_ker_ck: rcc_timerx_ker_ck.map(Hertz), - timy_ker_ck: rcc_timery_ker_ck.map(Hertz), - adc_ker_ck, - sys_ck, - c_ck: Hertz(sys_d1cpre_ck), - }; - - set_freqs(Clocks { - sys: core_clocks.c_ck, - ahb1: core_clocks.hclk, - ahb2: core_clocks.hclk, - ahb3: core_clocks.hclk, - ahb4: core_clocks.hclk, - apb1: core_clocks.pclk1, - apb2: core_clocks.pclk2, - apb4: core_clocks.pclk4, - apb1_tim: core_clocks.timx_ker_ck.unwrap_or(core_clocks.pclk1), - apb2_tim: core_clocks.timy_ker_ck.unwrap_or(core_clocks.pclk2), - adc: core_clocks.adc_ker_ck, - }); -} - -mod pll { - use super::{Hertz, RCC}; - - const VCO_MIN: u32 = 150_000_000; - const VCO_MAX: u32 = 420_000_000; - - #[derive(Default)] - pub struct PllConfig { - pub p_ck: Option, - pub q_ck: Option, - pub r_ck: Option, - } - - pub(super) struct PllConfigResults { - pub ref_x_ck: u32, - pub pll_x_m: u32, - pub pll_x_p: u32, - pub vco_ck_target: u32, - } - - fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) { - let pll_x_p = if plln == 0 { - if output > VCO_MAX / 2 { - 1 - } else { - ((VCO_MAX / output) | 1) - 1 // Must be even or unity - } - } else { - // Specific to PLL2/3, will subtract 1 later - if output > VCO_MAX / 2 { - 1 - } else { - VCO_MAX / output - } - }; - - let vco_ck = output * pll_x_p; - - assert!(pll_x_p < 128); - assert!(vco_ck >= VCO_MIN); - assert!(vco_ck <= VCO_MAX); - - (vco_ck, pll_x_p) - } - - /// # Safety - /// - /// Must have exclusive access to the RCC register block - fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults { - use crate::pac::rcc::vals::{Pllrge, Pllvcosel}; - - let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln); - - // Input divisor, resulting in a reference clock in the range - // 1 to 2 MHz. Choose the highest reference clock (lowest m) - let pll_x_m = (pll_src + 1_999_999) / 2_000_000; - assert!(pll_x_m < 64); - - // Calculate resulting reference clock - let ref_x_ck = pll_src / pll_x_m; - assert!((1_000_000..=2_000_000).contains(&ref_x_ck)); - - RCC.pllcfgr().modify(|w| { - w.set_pllvcosel(plln, Pllvcosel::MEDIUMVCO); - w.set_pllrge(plln, Pllrge::RANGE1); - }); - PllConfigResults { - ref_x_ck, - pll_x_m, - pll_x_p, - vco_ck_target, - } - } - - /// # Safety - /// - /// Must have exclusive access to the RCC register block - pub(super) fn pll_setup(pll_src: u32, config: &PllConfig, plln: usize) -> (Option, Option, Option) { - use crate::pac::rcc::vals::Divp; - - match config.p_ck { - Some(requested_output) => { - let config_results = vco_setup(pll_src, requested_output.0, plln); - let PllConfigResults { - ref_x_ck, - pll_x_m, - pll_x_p, - vco_ck_target, - } = config_results; - - RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8)); - - // Feedback divider. Integer only - let pll_x_n = vco_ck_target / ref_x_ck; - assert!(pll_x_n >= 4); - assert!(pll_x_n <= 512); - RCC.plldivr(plln).modify(|w| w.set_divn1((pll_x_n - 1) as u16)); - - // No FRACN - RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false)); - let vco_ck = ref_x_ck * pll_x_n; - - RCC.plldivr(plln) - .modify(|w| w.set_divp1(Divp::from_bits((pll_x_p - 1) as u8))); - RCC.pllcfgr().modify(|w| w.set_divpen(plln, true)); - - // Calulate additional output dividers - let q_ck = match config.q_ck { - Some(Hertz(ck)) if ck > 0 => { - let div = (vco_ck + ck - 1) / ck; - RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8)); - RCC.pllcfgr().modify(|w| w.set_divqen(plln, true)); - Some(vco_ck / div) - } - _ => None, - }; - let r_ck = match config.r_ck { - Some(Hertz(ck)) if ck > 0 => { - let div = (vco_ck + ck - 1) / ck; - RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8)); - RCC.pllcfgr().modify(|w| w.set_divren(plln, true)); - Some(vco_ck / div) - } - _ => None, - }; - - (Some(vco_ck / pll_x_p), q_ck, r_ck) - } - None => { - assert!( - config.q_ck.is_none(), - "Must set PLL P clock for Q clock to take effect!" - ); - assert!( - config.r_ck.is_none(), - "Must set PLL P clock for R clock to take effect!" - ); - (None, None, None) - } - } - } -} diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs new file mode 100644 index 000000000..2453ed821 --- /dev/null +++ b/embassy-stm32/src/rcc/mco.rs @@ -0,0 +1,71 @@ +use core::marker::PhantomData; + +use embassy_hal_internal::into_ref; + +use crate::gpio::sealed::AFType; +use crate::gpio::Speed; +pub use crate::pac::rcc::vals::{Mco1 as Mco1Source, Mco2 as Mco2Source}; +use crate::pac::RCC; +use crate::{peripherals, Peripheral}; + +pub(crate) mod sealed { + pub trait McoInstance { + type Source; + unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8); + } +} + +pub trait McoInstance: sealed::McoInstance + 'static {} + +pin_trait!(McoPin, McoInstance); + +macro_rules! impl_peri { + ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => { + impl sealed::McoInstance for peripherals::$peri { + type Source = $source; + + unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) { + RCC.cfgr().modify(|w| { + w.$set_source(source); + w.$set_prescaler(prescaler); + }); + } + } + + impl McoInstance for peripherals::$peri {} + }; +} + +impl_peri!(MCO1, Mco1Source, set_mco1, set_mco1pre); +impl_peri!(MCO2, Mco2Source, set_mco2, set_mco2pre); + +pub struct Mco<'d, T: McoInstance> { + phantom: PhantomData<&'d mut T>, +} + +impl<'d, T: McoInstance> Mco<'d, T> { + /// Create a new MCO instance. + /// + /// `prescaler` must be between 1 and 15. + pub fn new( + _peri: impl Peripheral

+ 'd, + pin: impl Peripheral

> + 'd, + source: T::Source, + prescaler: u8, + ) -> Self { + into_ref!(pin); + + assert!( + 1 <= prescaler && prescaler <= 15, + "Mco prescaler must be between 1 and 15. Refer to the reference manual for more information." + ); + + critical_section::with(|_| unsafe { + T::apply_clock_settings(source, prescaler); + pin.set_as_af(pin.af_num(), AFType::OutputPushPull); + pin.set_speed(Speed::VeryHigh); + }); + + Self { phantom: PhantomData } + } +} diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index ff9b9bac8..0d6b0e308 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -1,12 +1,17 @@ #![macro_use] -pub(crate) mod bd; -pub mod bus; use core::mem::MaybeUninit; pub use crate::rcc::bd::RtcClockSource; use crate::time::Hertz; +pub(crate) mod bd; +mod bus; +#[cfg(any(stm32h5, stm32h7))] +mod mco; +#[cfg(any(stm32h5, stm32h7))] +pub use mco::*; + #[cfg_attr(rcc_f0, path = "f0.rs")] #[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")] #[cfg_attr(rcc_f2, path = "f2.rs")] @@ -16,7 +21,7 @@ use crate::time::Hertz; #[cfg_attr(rcc_c0, path = "c0.rs")] #[cfg_attr(rcc_g0, path = "g0.rs")] #[cfg_attr(rcc_g4, path = "g4.rs")] -#[cfg_attr(any(rcc_h7, rcc_h7ab), path = "h7.rs")] +#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab), path = "h.rs")] #[cfg_attr(rcc_l0, path = "l0.rs")] #[cfg_attr(rcc_l1, path = "l1.rs")] #[cfg_attr(rcc_l4, path = "l4.rs")] @@ -25,7 +30,6 @@ use crate::time::Hertz; #[cfg_attr(rcc_wb, path = "wb.rs")] #[cfg_attr(rcc_wba, path = "wba.rs")] #[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")] -#[cfg_attr(any(rcc_h5, rcc_h50), path = "h5.rs")] mod _version; pub use _version::*; #[cfg(feature = "low-power")] @@ -53,7 +57,7 @@ pub struct Clocks { pub apb2: Hertz, #[cfg(not(any(rcc_c0, rcc_g0)))] pub apb2_tim: Hertz, - #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_u5))] + #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_u5))] pub apb3: Hertz, #[cfg(any(rcc_h7, rcc_h7ab))] pub apb4: Hertz, -- cgit From 7cf327130e97f2569e1be73054a778ba5bf39d5b Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 21 Sep 2023 19:32:48 -0500 Subject: stm32/low-power: create one critical-section for all time ops --- embassy-stm32/src/rtc/v2.rs | 46 ++++++++--------- embassy-stm32/src/time_driver.rs | 104 ++++++++++++++++++++------------------- 2 files changed, 78 insertions(+), 72 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index aa3c31ee1..d139f2f47 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -64,7 +64,11 @@ impl super::Rtc { #[cfg(feature = "low-power")] /// start the wakeup alarm and wtih a duration that is as close to but less than /// the requested duration, and record the instant the wakeup alarm was started - pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) { + pub(crate) fn start_wakeup_alarm( + &self, + requested_duration: embassy_time::Duration, + cs: critical_section::CriticalSection, + ) { use embassy_time::{Duration, TICK_HZ}; #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] @@ -102,25 +106,13 @@ impl super::Rtc { self.instant(), ); - critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())) - } - - #[cfg(feature = "low-power")] - pub(crate) fn enable_wakeup_line(&self) { - use crate::interrupt::typelevel::Interrupt; - use crate::pac::EXTI; - - ::WakeupInterrupt::unpend(); - unsafe { ::WakeupInterrupt::enable() }; - - EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); - EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none()) } #[cfg(feature = "low-power")] /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` /// was called, otherwise none - pub(crate) fn stop_wakeup_alarm(&self) -> Option { + pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option { use crate::interrupt::typelevel::Interrupt; trace!("rtc: stop wakeup alarm at {}", self.instant()); @@ -137,13 +129,23 @@ impl super::Rtc { ::WakeupInterrupt::unpend(); }); - critical_section::with(|cs| { - if let Some(stop_time) = self.stop_time.borrow(cs).take() { - Some(self.instant() - stop_time) - } else { - None - } - }) + if let Some(stop_time) = self.stop_time.borrow(cs).take() { + Some(self.instant() - stop_time) + } else { + None + } + } + + #[cfg(feature = "low-power")] + pub(crate) fn enable_wakeup_line(&self) { + use crate::interrupt::typelevel::Interrupt; + use crate::pac::EXTI; + + ::WakeupInterrupt::unpend(); + unsafe { ::WakeupInterrupt::enable() }; + + EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); } /// Applies the RTC config diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 887e54f65..5b01937f5 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -266,32 +266,28 @@ impl RtcDriver { f(alarm.ctx.get()); } - #[cfg(feature = "low-power")] - /// Set the rtc but panic if it's already been set - pub(crate) fn set_rtc(&self, rtc: &'static Rtc) { - critical_section::with(|cs| assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none())); - } + /* + Low-power private functions: all operate within a critical seciton + */ #[cfg(feature = "low-power")] /// Compute the approximate amount of time until the next alarm - fn time_until_next_alarm(&self) -> embassy_time::Duration { - critical_section::with(|cs| { - let now = self.now() + 32; - - embassy_time::Duration::from_ticks( - self.alarms - .borrow(cs) - .iter() - .map(|alarm: &AlarmState| alarm.timestamp.get().saturating_sub(now)) - .min() - .unwrap_or(u64::MAX), - ) - }) + fn time_until_next_alarm(&self, cs: CriticalSection) -> embassy_time::Duration { + let now = self.now() + 32; + + embassy_time::Duration::from_ticks( + self.alarms + .borrow(cs) + .iter() + .map(|alarm: &AlarmState| alarm.timestamp.get().saturating_sub(now)) + .min() + .unwrap_or(u64::MAX), + ) } #[cfg(feature = "low-power")] /// Add the given offset to the current time - fn add_time(&self, offset: embassy_time::Duration) { + fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { let offset = offset.as_ticks(); let cnt = T::regs_gp16().cnt().read().cnt() as u32; let period = self.period.load(Ordering::SeqCst); @@ -322,51 +318,57 @@ impl RtcDriver { T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); // Now, recompute all alarms - critical_section::with(|cs| { - for i in 0..ALARM_COUNT { - let alarm_handle = unsafe { AlarmHandle::new(i as u8) }; - let alarm = self.get_alarm(cs, alarm_handle); + for i in 0..ALARM_COUNT { + let alarm_handle = unsafe { AlarmHandle::new(i as u8) }; + let alarm = self.get_alarm(cs, alarm_handle); - self.set_alarm(alarm_handle, alarm.timestamp.get()); - } - }) + self.set_alarm(alarm_handle, alarm.timestamp.get()); + } } #[cfg(feature = "low-power")] /// Stop the wakeup alarm, if enabled, and add the appropriate offset - fn stop_wakeup_alarm(&self) { - critical_section::with(|cs| { - if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm() { - self.add_time(offset); - } - }); + fn stop_wakeup_alarm(&self, cs: CriticalSection) { + if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(cs) { + self.add_time(offset, cs); + } + } + + /* + Low-power public functions: all create a critical section + */ + #[cfg(feature = "low-power")] + /// Set the rtc but panic if it's already been set + pub(crate) fn set_rtc(&self, rtc: &'static Rtc) { + critical_section::with(|cs| assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none())); } #[cfg(feature = "low-power")] /// Pause the timer if ready; return err if not pub(crate) fn pause_time(&self) -> Result<(), ()> { - /* - If the wakeup timer is currently running, then we need to stop it and - add the elapsed time to the current time - */ - self.stop_wakeup_alarm(); - - let time_until_next_alarm = self.time_until_next_alarm(); - if time_until_next_alarm < embassy_time::Duration::from_millis(250) { - Err(()) - } else { - critical_section::with(|cs| { + critical_section::with(|cs| { + /* + If the wakeup timer is currently running, then we need to stop it and + add the elapsed time to the current time, as this will impact the result + of `time_until_next_alarm`. + */ + self.stop_wakeup_alarm(cs); + + let time_until_next_alarm = self.time_until_next_alarm(cs); + if time_until_next_alarm < embassy_time::Duration::from_millis(250) { + Err(()) + } else { self.rtc .borrow(cs) .get() .unwrap() - .start_wakeup_alarm(time_until_next_alarm); - }); + .start_wakeup_alarm(time_until_next_alarm, cs); - T::regs_gp16().cr1().modify(|w| w.set_cen(false)); + T::regs_gp16().cr1().modify(|w| w.set_cen(false)); - Ok(()) - } + Ok(()) + } + }) } #[cfg(feature = "low-power")] @@ -378,9 +380,11 @@ impl RtcDriver { return; } - self.stop_wakeup_alarm(); + critical_section::with(|cs| { + self.stop_wakeup_alarm(cs); - T::regs_gp16().cr1().modify(|w| w.set_cen(true)); + T::regs_gp16().cr1().modify(|w| w.set_cen(true)); + }) } } -- cgit From c849620cd6bfc1aec6999109e818a91cb061a578 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 22 Sep 2023 15:35:20 -0500 Subject: stm32/lp: clamp requested_duration to avoid overflow --- embassy-stm32/src/rtc/v2.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index d139f2f47..05b85ef46 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -71,21 +71,27 @@ impl super::Rtc { ) { use embassy_time::{Duration, TICK_HZ}; + // Panic if the rcc mod knows we're not using low-power rtc #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] unsafe { crate::rcc::get_freqs() }.rtc.unwrap(); + /* + If the requested duration is u64::MAX, don't even set the alarm + + Otherwise clamp the requested duration to u32::MAX so that we can do math + */ + if requested_duration.as_ticks() == u64::MAX { + return; + } + + let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); let rtc_hz = Self::frequency().0 as u64; - let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ; + let rtc_ticks = requested_duration * rtc_hz / TICK_HZ; let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); // adjust the rtc ticks to the prescaler and subtract one rtc tick let rtc_ticks = rtc_ticks / prescaler as u64; - let rtc_ticks = if rtc_ticks >= u16::MAX as u64 { - u16::MAX - 1 - } else { - rtc_ticks as u16 - } - .saturating_sub(1); + let rtc_ticks = rtc_ticks.clamp(0, (u16::MAX - 1) as u64).saturating_sub(1) as u16; self.write(false, |regs| { regs.cr().modify(|w| w.set_wute(false)); -- cgit From e03239e88d7f2d01f31de5e5eef2b4d79522679d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 24 Sep 2023 23:54:32 +0200 Subject: stm32: centralize enabling pwr, syscfg, flash. --- embassy-stm32/src/eth/v1/mod.rs | 1 - embassy-stm32/src/eth/v2/mod.rs | 1 - embassy-stm32/src/exti.rs | 5 ----- embassy-stm32/src/gpio.rs | 3 +++ embassy-stm32/src/lib.rs | 10 ++++++++++ embassy-stm32/src/rcc/f2.rs | 5 +---- embassy-stm32/src/rcc/f4.rs | 3 --- embassy-stm32/src/rcc/f7.rs | 8 +------- embassy-stm32/src/rcc/h.rs | 5 ----- embassy-stm32/src/rcc/l0.rs | 7 ------- embassy-stm32/src/rcc/l4.rs | 4 ---- embassy-stm32/src/rtc/v2.rs | 14 -------------- embassy-stm32/src/usb/usb.rs | 5 +---- embassy-stm32/src/usb_otg/usb.rs | 12 ++---------- 14 files changed, 18 insertions(+), 65 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index a1e0240c8..4d19103dd 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -129,7 +129,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { #[cfg(any(eth_v1b, eth_v1c))] critical_section::with(|_| { - RCC.apb2enr().modify(|w| w.set_syscfgen(true)); RCC.ahb1enr().modify(|w| { w.set_ethen(true); w.set_ethtxen(true); diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index ada495fdb..f03ea2e31 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -80,7 +80,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { // Enable the necessary Clocks #[cfg(not(rcc_h5))] critical_section::with(|_| { - crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true)); crate::pac::RCC.ahb1enr().modify(|w| { w.set_eth1macen(true); w.set_eth1txen(true); diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index efa51fb24..62f321709 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -371,9 +371,4 @@ pub(crate) unsafe fn init() { use crate::interrupt::typelevel::Interrupt; foreach_exti_irq!(enable_irq); - - #[cfg(not(any(rcc_wb, rcc_wl5, rcc_wle, stm32f1, exti_h5, exti_h50)))] - ::enable(); - #[cfg(stm32f1)] - ::enable(); } diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index a382cb742..c709d46da 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -758,6 +758,9 @@ foreach_pin!( ); pub(crate) unsafe fn init() { + #[cfg(afio)] + ::enable(); + crate::_generated::init_gpio(); } diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 6a53f8762..9231aa0f2 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -117,6 +117,7 @@ pub(crate) use stm32_metapac as pac; use crate::interrupt::Priority; #[cfg(feature = "rt")] pub use crate::pac::NVIC_PRIO_BITS; +use crate::rcc::sealed::RccPeripheral; #[non_exhaustive] pub struct Config { @@ -179,6 +180,15 @@ pub fn init(config: Config) -> Peripherals { }); } + #[cfg(not(any(stm32f1, stm32h5, stm32wb, stm32wl)))] + peripherals::SYSCFG::enable(); + #[cfg(sbs)] + peripherals::SBS::enable(); + #[cfg(not(any(stm32h5, stm32h7, stm32wb, stm32wl)))] + peripherals::PWR::enable(); + #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] + peripherals::FLASH::enable(); + unsafe { gpio::init(); dma::init( diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index 1a34c2cbe..44de5bf19 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -4,7 +4,7 @@ use core::ops::{Div, Mul}; pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::flash::vals::Latency; use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw}; -use crate::pac::{FLASH, PWR, RCC}; +use crate::pac::{FLASH, RCC}; use crate::rcc::bd::BackupDomain; use crate::rcc::{set_freqs, Clocks}; use crate::rtc::RtcClockSource; @@ -435,9 +435,6 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().modify(|w| w.set_hsion(false)); } - RCC.apb1enr().modify(|w| w.set_pwren(true)); - PWR.cr().read(); - BackupDomain::configure_ls( config.rtc.unwrap_or(RtcClockSource::NOCLOCK), config.lsi, diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index d8d0312bc..5914c926a 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -3,7 +3,6 @@ use core::marker::PhantomData; use embassy_hal_internal::into_ref; use stm32_metapac::rcc::vals::{Mco1, Mco2, Mcopre}; -use super::sealed::RccPeripheral; use crate::gpio::sealed::AFType; use crate::gpio::Speed; use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; @@ -332,8 +331,6 @@ fn flash_setup(sysclk: u32) { } pub(crate) unsafe fn init(config: Config) { - crate::peripherals::PWR::enable(); - let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0); let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); let sysclk_on_pll = sysclk != pllsrcclk; diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs index 85cb9c661..234511b00 100644 --- a/embassy-stm32/src/rcc/f7.rs +++ b/embassy-stm32/src/rcc/f7.rs @@ -1,4 +1,3 @@ -use super::sealed::RccPeripheral; use crate::pac::pwr::vals::Vos; use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; @@ -111,8 +110,6 @@ fn flash_setup(sysclk: u32) { } pub(crate) unsafe fn init(config: Config) { - crate::peripherals::PWR::enable(); - if let Some(hse) = config.hse { if config.bypass_hse { assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0)); @@ -212,10 +209,7 @@ pub(crate) unsafe fn init(config: Config) { if plls.use_pll { RCC.cr().modify(|w| w.set_pllon(false)); - // enable PWR and setup VOSScale - - RCC.apb1enr().modify(|w| w.set_pwren(true)); - + // setup VOSScale let vos_scale = if sysclk <= 144_000_000 { 3 } else if sysclk <= 168_000_000 { diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index a4730ed49..43e8db22e 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -215,11 +215,6 @@ impl Default for Config { } pub(crate) unsafe fn init(config: Config) { - #[cfg(stm32h7)] - RCC.apb4enr().modify(|w| w.set_syscfgen(true)); - #[cfg(stm32h5)] - RCC.apb3enr().modify(|w| w.set_sbsen(true)); - // NB. The lower bytes of CR3 can only be written once after // POR, and must be written with a valid combination. Refer to // RM0433 Rev 7 6.8.4. This is partially enforced by dropping diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index 1c655592e..67355afbe 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -283,13 +283,6 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(crs)] if config.enable_hsi48 { - // Reset SYSCFG peripheral - RCC.apb2rstr().modify(|w| w.set_syscfgrst(true)); - RCC.apb2rstr().modify(|w| w.set_syscfgrst(false)); - - // Enable SYSCFG peripheral - RCC.apb2enr().modify(|w| w.set_syscfgen(true)); - // Reset CRS peripheral RCC.apb1rstr().modify(|w| w.set_crsrst(true)); RCC.apb1rstr().modify(|w| w.set_crsrst(false)); diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index f7b9354a6..6f1f7458c 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -409,8 +409,6 @@ pub(crate) unsafe fn init(config: Config) { while RCC.cfgr().read().sws() != Sw::MSI {} } - RCC.apb1enr1().modify(|w| w.set_pwren(true)); - BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default())); let (sys_clk, sw) = match config.mux { @@ -608,8 +606,6 @@ pub(crate) unsafe fn init(config: Config) { } }; - RCC.apb1enr1().modify(|w| w.set_pwren(true)); - set_freqs(Clocks { sys: Hertz(sys_clk), ahb1: Hertz(ahb_freq), diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 05b85ef46..ab562d2b6 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -295,20 +295,6 @@ impl sealed::Instance for crate::peripherals::RTC { // read to allow the pwr clock to enable crate::pac::PWR.cr1().read(); } - #[cfg(any(rtc_v2f2))] - { - // enable peripheral clock for communication - crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true)); - - // read to allow the pwr clock to enable - crate::pac::PWR.cr().read(); - } - - #[cfg(any(rtc_v2f0, rtc_v2l0))] - { - // enable peripheral clock for communication - crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true)); - } } fn read_backup_register(rtc: &Rtc, register: usize) -> Option { diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index cef196355..b24fc74eb 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -264,10 +264,7 @@ impl<'d, T: Instance> Driver<'d, T> { let regs = T::regs(); #[cfg(stm32l5)] - { - crate::peripherals::PWR::enable(); - crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); - } + crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); #[cfg(pwr_h5)] crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)); diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index 348f0f79d..1fe010bbb 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs @@ -540,10 +540,7 @@ impl<'d, T: Instance> Bus<'d, T> { impl<'d, T: Instance> Bus<'d, T> { fn init(&mut self) { #[cfg(stm32l4)] - { - crate::peripherals::PWR::enable(); - critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); - } + critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); #[cfg(stm32f7)] { @@ -618,15 +615,10 @@ impl<'d, T: Instance> Bus<'d, T> { { // Enable USB power critical_section::with(|_| { - crate::pac::RCC.ahb3enr().modify(|w| { - w.set_pwren(true); - }); - cortex_m::asm::delay(2); - crate::pac::PWR.svmcr().modify(|w| { w.set_usv(true); w.set_uvmen(true); - }); + }) }); // Wait for USB power to stabilize -- cgit From 9f2fc04caa2da6a6739e8dfd0dbef96bc10cc56a Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 24 Sep 2023 18:37:09 -0500 Subject: stm32: fix bd lsi --- embassy-stm32/src/rcc/bd.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 4915d5e2a..5bae3edd9 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -100,13 +100,14 @@ impl BackupDomain { #[cfg(not(rtc_v3u5))] let csr = crate::pac::RCC.csr(); - Self::modify(|_| { - #[cfg(not(any(rcc_wb, rcc_wba)))] - csr.modify(|w| w.set_lsion(true)); + // Disable backup domain write protection + Self::modify(|_| {}); - #[cfg(any(rcc_wb, rcc_wba))] - csr.modify(|w| w.set_lsi1on(true)); - }); + #[cfg(not(any(rcc_wb, rcc_wba)))] + csr.modify(|w| w.set_lsion(true)); + + #[cfg(any(rcc_wb, rcc_wba))] + csr.modify(|w| w.set_lsi1on(true)); #[cfg(not(any(rcc_wb, rcc_wba)))] while !csr.read().lsirdy() {} -- cgit From bd9021ca1db721334a518c0cfab42cfa6e373c74 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 25 Sep 2023 22:34:41 +0200 Subject: Make irq token Copy+Clone --- embassy-stm32/src/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 9231aa0f2..db79546ba 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -88,6 +88,7 @@ pub use crate::_generated::interrupt; #[macro_export] macro_rules! bind_interrupts { ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { + #[derive(Copy, Clone)] $vis struct $name; $( -- cgit From 04b09a2acb465dbb87dfc4e8b24b4c587f21b472 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 25 Sep 2023 16:26:29 -0500 Subject: stm32/rtc: use rccperi enable --- embassy-stm32/src/rcc/bd.rs | 5 ----- embassy-stm32/src/rtc/mod.rs | 10 +++++++--- embassy-stm32/src/rtc/v2.rs | 11 ----------- embassy-stm32/src/rtc/v3.rs | 17 ----------------- 4 files changed, 7 insertions(+), 36 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 5bae3edd9..de27130f2 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -88,11 +88,6 @@ impl BackupDomain { ))] #[allow(dead_code, unused_variables)] pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option) { - if lsi || lse.is_some() { - use crate::rtc::sealed::Instance; - crate::peripherals::RTC::enable_peripheral_clk(); - } - if lsi { #[cfg(rtc_v3u5)] let csr = crate::pac::RCC.bdcr(); diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 7eafedec4..b26b5ef35 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -10,6 +10,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; +use crate::rcc::sealed::RccPeripheral; pub use crate::rcc::RtcClockSource; use crate::time::Hertz; @@ -111,11 +112,12 @@ impl RtcTimeProvider { } } -#[non_exhaustive] /// RTC Abstraction pub struct Rtc { #[cfg(feature = "low-power")] stop_time: Mutex>>, + #[cfg(not(feature = "low-power"))] + _private: (), } #[non_exhaustive] @@ -154,9 +156,13 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { + RTC::enable(); + let mut this = Self { #[cfg(feature = "low-power")] stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), + #[cfg(not(feature = "low-power"))] + _private: (), }; let frequency = Self::frequency(); @@ -292,8 +298,6 @@ pub(crate) mod sealed { crate::pac::RTC } - fn enable_peripheral_clk(); - /// Read content of the backup register. /// /// The registers retain their values during wakes from standby mode or system resets. They also diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index ab562d2b6..331792a04 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -286,17 +286,6 @@ impl sealed::Instance for crate::peripherals::RTC { #[cfg(all(feature = "low-power", stm32l0))] type WakeupInterrupt = crate::interrupt::typelevel::RTC; - fn enable_peripheral_clk() { - #[cfg(any(rtc_v2l4, rtc_v2wb))] - { - // enable peripheral clock for communication - crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true)); - - // read to allow the pwr clock to enable - crate::pac::PWR.cr1().read(); - } - } - fn read_backup_register(rtc: &Rtc, register: usize) -> Option { if register < Self::BACKUP_REGISTER_COUNT { Some(rtc.bkpr(register).read().bkp()) diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 9ac9f9f85..a6b2655d8 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -128,23 +128,6 @@ impl super::Rtc { impl sealed::Instance for crate::peripherals::RTC { const BACKUP_REGISTER_COUNT: usize = 32; - fn enable_peripheral_clk() { - #[cfg(any(rcc_wle, rcc_wl5, rcc_g4))] - { - // enable peripheral clock for communication - crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true)); - } - - #[cfg(rcc_g0)] - { - // enable peripheral clock for communication - crate::pac::RCC.apbenr1().modify(|w| w.set_rtcapben(true)); - } - - // read to allow the pwr clock to enable - crate::pac::PWR.cr1().read(); - } - fn read_backup_register(_rtc: &Rtc, register: usize) -> Option { #[allow(clippy::if_same_then_else)] if register < Self::BACKUP_REGISTER_COUNT { -- cgit From dc400a05393fa9765a9ecb91cbbec10300a5e238 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 25 Sep 2023 16:27:08 -0500 Subject: stm32/rtc: always set wakeup alarm --- embassy-stm32/src/rtc/v2.rs | 9 --------- 1 file changed, 9 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 331792a04..4608d3114 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -75,15 +75,6 @@ impl super::Rtc { #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] unsafe { crate::rcc::get_freqs() }.rtc.unwrap(); - /* - If the requested duration is u64::MAX, don't even set the alarm - - Otherwise clamp the requested duration to u32::MAX so that we can do math - */ - if requested_duration.as_ticks() == u64::MAX { - return; - } - let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); let rtc_hz = Self::frequency().0 as u64; let rtc_ticks = requested_duration * rtc_hz / TICK_HZ; -- cgit From 96edbd84fbdc10a5b9b37a343941bc057be59467 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 25 Sep 2023 16:38:30 -0500 Subject: rtc: use enable on known working chips only --- embassy-stm32/src/rtc/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index b26b5ef35..73b78f253 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -10,7 +10,6 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; -use crate::rcc::sealed::RccPeripheral; pub use crate::rcc::RtcClockSource; use crate::time::Hertz; @@ -156,7 +155,8 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { - RTC::enable(); + #[cfg(any(rcc_wle, rcc_wl5, rcc_g4, rcc_g0, rtc_v2l4, rtc_v2wb))] + ::enable(); let mut this = Self { #[cfg(feature = "low-power")] -- cgit From 5d8817d1095589e1916a92adc9db3feb1a3b91b5 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 26 Sep 2023 00:14:52 +0200 Subject: stm32/usart: return error instead of panicking on bad baudrate. --- embassy-stm32/src/usart/buffered.rs | 26 +++++----- embassy-stm32/src/usart/mod.rs | 87 ++++++++++++++++++++------------- embassy-stm32/src/usart/ringbuffered.rs | 6 +-- 3 files changed, 70 insertions(+), 49 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 323d83818..e2d6e42af 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -118,7 +118,7 @@ impl<'d, T: BasicInstance> SetConfig for BufferedUart<'d, T> { type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.set_config(config) + unwrap!(self.set_config(config)) } } @@ -126,7 +126,7 @@ impl<'d, T: BasicInstance> SetConfig for BufferedUartRx<'d, T> { type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.set_config(config) + unwrap!(self.set_config(config)) } } @@ -134,7 +134,7 @@ impl<'d, T: BasicInstance> SetConfig for BufferedUartTx<'d, T> { type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.set_config(config) + unwrap!(self.set_config(config)) } } @@ -147,7 +147,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, - ) -> BufferedUart<'d, T> { + ) -> Result { // UartRx and UartTx have one refcount ea. T::enable(); T::enable(); @@ -166,7 +166,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, - ) -> BufferedUart<'d, T> { + ) -> Result { into_ref!(cts, rts); // UartRx and UartTx have one refcount ea. @@ -194,7 +194,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, - ) -> BufferedUart<'d, T> { + ) -> Result { into_ref!(de); // UartRx and UartTx have one refcount ea. @@ -217,7 +217,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, - ) -> BufferedUart<'d, T> { + ) -> Result { into_ref!(_peri, rx, tx); let state = T::buffered_state(); @@ -230,7 +230,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { rx.set_as_af(rx.af_num(), AFType::Input); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - configure(r, &config, T::frequency(), T::KIND, true, true); + configure(r, &config, T::frequency(), T::KIND, true, true)?; r.cr1().modify(|w| { #[cfg(lpuart_v2)] @@ -243,17 +243,17 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - Self { + Ok(Self { rx: BufferedUartRx { phantom: PhantomData }, tx: BufferedUartTx { phantom: PhantomData }, - } + }) } pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { (self.tx, self.rx) } - pub fn set_config(&mut self, config: &Config) { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } } @@ -333,7 +333,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { } } - pub fn set_config(&mut self, config: &Config) { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } } @@ -407,7 +407,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { } } - pub fn set_config(&mut self, config: &Config) { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index ff02d0a63..45580fe30 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -13,11 +13,10 @@ use futures::future::{select, Either}; use crate::dma::{NoDma, Transfer}; use crate::gpio::sealed::AFType; use crate::interrupt::typelevel::Interrupt; -#[cfg(not(any(usart_v1, usart_v2)))] #[allow(unused_imports)] +#[cfg(not(any(usart_v1, usart_v2)))] use crate::pac::usart::regs::Isr as Sr; #[cfg(any(usart_v1, usart_v2))] -#[allow(unused_imports)] use crate::pac::usart::regs::Sr; #[cfg(not(any(usart_v1, usart_v2)))] use crate::pac::usart::Lpuart as Regs; @@ -76,12 +75,14 @@ impl interrupt::typelevel::Handler for Interrupt } #[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum DataBits { DataBits8, DataBits9, } #[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Parity { ParityNone, ParityEven, @@ -89,6 +90,7 @@ pub enum Parity { } #[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum StopBits { #[doc = "1 stop bit"] STOP1, @@ -100,6 +102,14 @@ pub enum StopBits { STOP1P5, } +#[non_exhaustive] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ConfigError { + BaudrateTooLow, + BaudrateTooHigh, +} + #[non_exhaustive] #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct Config { @@ -173,8 +183,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.tx.set_config(config); - self.rx.set_config(config); + unwrap!(self.tx.set_config(config)); + unwrap!(self.rx.set_config(config)); } } @@ -187,7 +197,7 @@ impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> { type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.set_config(config); + unwrap!(self.set_config(config)); } } @@ -203,7 +213,7 @@ impl<'d, T: BasicInstance, RxDma> SetConfig for UartRx<'d, T, RxDma> { type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.set_config(config); + unwrap!(self.set_config(config)); } } @@ -214,7 +224,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { tx: impl Peripheral

> + 'd, tx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { T::enable(); T::reset(); @@ -227,7 +237,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { cts: impl Peripheral

> + 'd, tx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { into_ref!(cts); T::enable(); @@ -245,25 +255,25 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { tx: impl Peripheral

> + 'd, tx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { into_ref!(_peri, tx, tx_dma); let r = T::regs(); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - configure(r, &config, T::frequency(), T::KIND, false, true); + configure(r, &config, T::frequency(), T::KIND, false, true)?; // create state once! let _s = T::state(); - Self { + Ok(Self { tx_dma, phantom: PhantomData, - } + }) } - pub fn set_config(&mut self, config: &Config) { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } @@ -307,7 +317,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { rx: impl Peripheral

> + 'd, rx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { T::enable(); T::reset(); @@ -321,7 +331,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { rts: impl Peripheral

> + 'd, rx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { into_ref!(rts); T::enable(); @@ -340,14 +350,14 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { rx: impl Peripheral

> + 'd, rx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { into_ref!(peri, rx, rx_dma); let r = T::regs(); rx.set_as_af(rx.af_num(), AFType::Input); - configure(r, &config, T::frequency(), T::KIND, true, false); + configure(r, &config, T::frequency(), T::KIND, true, false)?; T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; @@ -355,16 +365,16 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { // create state once! let _s = T::state(); - Self { + Ok(Self { _peri: peri, rx_dma, detect_previous_overrun: config.detect_previous_overrun, #[cfg(any(usart_v1, usart_v2))] buffered_sr: stm32_metapac::usart::regs::Sr(0), - } + }) } - pub fn set_config(&mut self, config: &Config) { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } @@ -680,7 +690,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { // UartRx and UartTx have one refcount ea. T::enable(); T::enable(); @@ -699,7 +709,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { into_ref!(cts, rts); // UartRx and UartTx have one refcount ea. @@ -726,7 +736,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { into_ref!(de); // UartRx and UartTx have one refcount ea. @@ -748,7 +758,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, config: Config, - ) -> Self { + ) -> Result { into_ref!(peri, rx, tx, tx_dma, rx_dma); let r = T::regs(); @@ -770,7 +780,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { } } - configure(r, &config, T::frequency(), T::KIND, true, true); + configure(r, &config, T::frequency(), T::KIND, true, true)?; T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; @@ -778,7 +788,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { // create state once! let _s = T::state(); - Self { + Ok(Self { tx: UartTx { tx_dma, phantom: PhantomData, @@ -790,10 +800,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { #[cfg(any(usart_v1, usart_v2))] buffered_sr: stm32_metapac::usart::regs::Sr(0), }, - } + }) } - pub fn set_config(&mut self, config: &Config) { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } @@ -842,18 +852,27 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { } } -fn reconfigure(config: &Config) { +fn reconfigure(config: &Config) -> Result<(), ConfigError> { T::Interrupt::disable(); let r = T::regs(); let cr = r.cr1().read(); - configure(r, config, T::frequency(), T::KIND, cr.re(), cr.te()); + configure(r, config, T::frequency(), T::KIND, cr.re(), cr.te())?; T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; + + Ok(()) } -fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: bool, enable_tx: bool) { +fn configure( + r: Regs, + config: &Config, + pclk_freq: Hertz, + kind: Kind, + enable_rx: bool, + enable_tx: bool, +) -> Result<(), ConfigError> { if !enable_rx && !enable_tx { panic!("USART: At least one of RX or TX should be enabled"); } @@ -921,7 +940,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: found_brr = Some(brr); break; } - panic!("USART: baudrate too high"); + return Err(ConfigError::BaudrateTooHigh); } if brr < brr_max { @@ -933,7 +952,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: } } - let brr = found_brr.expect("USART: baudrate too low"); + let brr = found_brr.ok_or(ConfigError::BaudrateTooLow)?; #[cfg(not(usart_v1))] let oversampling = if over8 { "8 bit" } else { "16 bit" }; @@ -985,6 +1004,8 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: r.cr3().modify(|w| { w.set_onebit(config.assume_noise_free); }); + + Ok(()) } mod eh02 { diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index eed5ef5d6..347aae7c9 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -7,7 +7,7 @@ use embassy_embedded_hal::SetConfig; use embassy_hal_internal::PeripheralRef; use futures::future::{select, Either}; -use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, Error, UartRx}; +use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, UartRx}; use crate::dma::ReadableRingBuffer; use crate::usart::{Regs, Sr}; @@ -20,7 +20,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> SetConfig for RingBufferedUar type Config = Config; fn set_config(&mut self, config: &Self::Config) { - self.set_config(config); + unwrap!(self.set_config(config)); } } @@ -63,7 +63,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> RingBufferedUartRx<'d, T, RxD Err(err) } - pub fn set_config(&mut self, config: &Config) { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { self.teardown_uart(); reconfigure::(config) } -- cgit From 44bb40568302c6c7d766bfc7e42a15f02bdf89cd Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 26 Sep 2023 04:22:25 +0200 Subject: stm32/usart: enable fifo mode on usartv4. --- embassy-stm32/src/usart/mod.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 45580fe30..9835f1ace 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -998,6 +998,8 @@ fn configure( }); #[cfg(not(usart_v1))] w.set_over8(vals::Over8::from_bits(over8 as _)); + #[cfg(usart_v4)] + w.set_fifoen(true); }); #[cfg(not(usart_v1))] -- cgit From c604d8a8f1b633874117fcf01018121f4fe05867 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 26 Sep 2023 05:14:05 +0200 Subject: stm32/rcc: add voltage_scale, flash waitstates. --- embassy-stm32/src/rcc/l0.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index 67355afbe..7358be31b 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -1,10 +1,11 @@ use super::bd::BackupDomain; pub use super::bus::{AHBPrescaler, APBPrescaler}; use super::RtcClockSource; +pub use crate::pac::pwr::vals::Vos as VoltageScale; use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; -use crate::pac::RCC; #[cfg(crs)] use crate::pac::{crs, CRS, SYSCFG}; +use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -140,6 +141,7 @@ pub struct Config { pub rtc: Option, pub lse: Option, pub lsi: bool, + pub voltage_scale: VoltageScale, } impl Default for Config { @@ -155,11 +157,17 @@ impl Default for Config { rtc: None, lse: None, lsi: false, + voltage_scale: VoltageScale::RANGE1, } } } pub(crate) unsafe fn init(config: Config) { + // Set voltage scale + while PWR.csr().read().vosf() {} + PWR.cr().write(|w| w.set_vos(config.voltage_scale)); + while PWR.csr().read().vosf() {} + let (sys_clk, sw) = match config.mux { ClockSrc::MSI(range) => { // Set MSI range @@ -245,6 +253,22 @@ pub(crate) unsafe fn init(config: Config) { config.lse.map(|_| Default::default()), ); + let wait_states = match config.voltage_scale { + VoltageScale::RANGE1 => match sys_clk { + ..=16_000_000 => 0, + _ => 1, + }, + VoltageScale::RANGE2 => match sys_clk { + ..=8_000_000 => 0, + _ => 1, + }, + VoltageScale::RANGE3 => 0, + _ => unreachable!(), + }; + FLASH.acr().modify(|w| { + w.set_latency(wait_states != 0); + }); + RCC.cfgr().modify(|w| { w.set_sw(sw); w.set_hpre(config.ahb_pre.into()); -- cgit From a57e48459eadff1776574f284a2d0a5d0b58a375 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 26 Sep 2023 05:14:21 +0200 Subject: stm32/rcc: remove bad limits on l5. --- embassy-stm32/src/rcc/l5.rs | 5 ----- 1 file changed, 5 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs index 553b1619e..652bdcb7b 100644 --- a/embassy-stm32/src/rcc/l5.rs +++ b/embassy-stm32/src/rcc/l5.rs @@ -317,11 +317,6 @@ pub(crate) unsafe fn init(config: Config) { let freq = (src_freq / prediv.to_div() * mul.to_mul()) / div.to_div(); - #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))] - assert!(freq <= 120_000_000); - #[cfg(not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx)))] - assert!(freq <= 80_000_000); - RCC.pllcfgr().write(move |w| { w.set_plln(mul.into()); w.set_pllm(prediv.into()); -- cgit From e1951f3ddffdeffab03bd0d20ebc1f7210738002 Mon Sep 17 00:00:00 2001 From: Mateusz Butkiewicz Date: Wed, 27 Sep 2023 15:13:43 +0200 Subject: feat(stm32f7): restore rtc configuration for stm32f7 series --- embassy-stm32/src/rcc/f7.rs | 18 ++++++++++++++++++ embassy-stm32/src/rcc/mod.rs | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs index 234511b00..f32559e26 100644 --- a/embassy-stm32/src/rcc/f7.rs +++ b/embassy-stm32/src/rcc/f7.rs @@ -1,6 +1,7 @@ use crate::pac::pwr::vals::Vos; use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -22,6 +23,9 @@ pub struct Config { pub pclk2: Option, pub pll48: bool, + pub rtc: Option, + pub lsi: bool, + pub lse: Option, } fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option, pll48clk: bool) -> PllResults { @@ -259,6 +263,18 @@ pub(crate) unsafe fn init(config: Config) { }) }); + BackupDomain::configure_ls( + config.rtc.unwrap_or(RtcClockSource::NOCLOCK), + config.lsi, + config.lse.map(|_| Default::default()), + ); + + let rtc = match config.rtc { + Some(RtcClockSource::LSI) => Some(LSI_FREQ), + Some(RtcClockSource::LSE) => Some(config.lse.unwrap()), + _ => None, + }; + set_freqs(Clocks { sys: Hertz(sysclk), apb1: Hertz(pclk1), @@ -272,6 +288,8 @@ pub(crate) unsafe fn init(config: Config) { ahb3: Hertz(hclk), pll48: plls.pll48clk.map(Hertz), + + rtc, }); } diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 0d6b0e308..9ccf2ac4f 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -97,7 +97,7 @@ pub struct Clocks { #[cfg(stm32f334)] pub hrtim: Option, - #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] + #[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_f7))] /// Set only if the lsi or lse is configured, indicates stop is supported pub rtc: Option, -- cgit From f866735802e142530491086adcb3f173c38ec570 Mon Sep 17 00:00:00 2001 From: Daniel Berlin Date: Wed, 27 Sep 2023 20:15:24 -0400 Subject: Add support for input capture function --- embassy-stm32/src/timer/mod.rs | 231 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 839548a53..ea72b36ae 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -15,6 +15,7 @@ pub mod low_level { } pub(crate) mod sealed { + use super::*; pub trait Basic16bitInstance: RccPeripheral { type Interrupt: interrupt::typelevel::Interrupt; @@ -32,10 +33,16 @@ pub(crate) mod sealed { fn clear_update_interrupt(&mut self) -> bool; fn enable_update_interrupt(&mut self, enable: bool); + + fn set_autoreload_preload(&mut self, enable: vals::Arpe); } pub trait GeneralPurpose16bitInstance: Basic16bitInstance { fn regs_gp16() -> crate::pac::timer::TimGp16; + + fn set_count_direction(&mut self, direction: vals::Dir); + + fn set_clock_division(&mut self, ckd: vals::Ckd); } pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { @@ -49,6 +56,16 @@ pub(crate) mod sealed { } pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { + fn clear_input_interrupt(&mut self, channel: Channel); + + fn enable_input_interrupt(&mut self, channel: Channel, enable: bool); + + fn set_input_capture_prescaler(&mut self, channel: Channel, val: u8); + + fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection); + + fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode); + /// Global output enable. Does not do anything on non-advanced timers. fn enable_outputs(&mut self, enable: bool); @@ -60,6 +77,8 @@ pub(crate) mod sealed { fn set_compare_value(&mut self, channel: Channel, value: u16); + fn get_capture_value(&mut self, channel: Channel) -> u16; + fn get_max_compare_value(&self) -> u16; } @@ -74,6 +93,16 @@ pub(crate) mod sealed { } pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance { + fn clear_input_interrupt(&mut self, channel: Channel); + + fn enable_input_interrupt(&mut self, channel: Channel, enable: bool); + + fn set_input_capture_prescaler(&mut self, channel: Channel, val: u8); + + fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection); + + fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode); + fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity); @@ -82,6 +111,8 @@ pub(crate) mod sealed { fn set_compare_value(&mut self, channel: Channel, value: u32); + fn get_capture_value(&mut self, channel: Channel) -> u32; + fn get_max_compare_value(&self) -> u32; } } @@ -105,6 +136,30 @@ impl Channel { } } +#[derive(Clone, Copy)] +pub enum InputCaptureMode { + Rising, + Falling, + BothEdges, +} + +#[derive(Clone, Copy)] +pub enum InputTISelection { + Normal, + Alternate, + TRC, +} + +impl From for stm32_metapac::timer::vals::CcmrInputCcs { + fn from(tisel: InputTISelection) -> Self { + match tisel { + InputTISelection::Normal => stm32_metapac::timer::vals::CcmrInputCcs::TI4, + InputTISelection::Alternate => stm32_metapac::timer::vals::CcmrInputCcs::TI3, + InputTISelection::TRC => stm32_metapac::timer::vals::CcmrInputCcs::TRC, + } + } +} + #[derive(Clone, Copy)] pub enum OutputCompareMode { Frozen, @@ -242,6 +297,10 @@ macro_rules! impl_basic_16bit_timer { fn enable_update_interrupt(&mut self, enable: bool) { Self::regs().dier().write(|r| r.set_uie(enable)); } + + fn set_autoreload_preload(&mut self, enable: vals::Arpe) { + Self::regs().cr1().modify(|r| r.set_arpe(enable)); + } } }; } @@ -279,6 +338,51 @@ macro_rules! impl_32bit_timer { macro_rules! impl_compare_capable_16bit { ($inst:ident) => { impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { + fn clear_input_interrupt(&mut self, channel: Channel) { + use sealed::GeneralPurpose16bitInstance; + Self::regs_gp16() + .sr() + .modify(|r| r.set_ccif(channel.raw(), false)); + } + + fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { + use sealed::GeneralPurpose16bitInstance; + Self::regs_gp16() + .dier() + .modify(|r| r.set_ccie(channel.raw(), enable)); + } + fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { + use sealed::GeneralPurpose16bitInstance; + let raw_channel = channel.raw(); + Self::regs_gp16() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icpsc(raw_channel % 2, factor)); + } + + fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { + use sealed::GeneralPurpose16bitInstance; + let raw_channel = channel.raw(); + Self::regs_gp16() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); + } + fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { + use sealed::GeneralPurpose16bitInstance; + Self::regs_gp16().ccer().modify(|r| match mode { + InputCaptureMode::Rising => { + r.set_ccnp(channel.raw(), false); + r.set_ccp(channel.raw(), false); + } + InputCaptureMode::Falling => { + r.set_ccnp(channel.raw(), false); + r.set_ccp(channel.raw(), true); + } + InputCaptureMode::BothEdges => { + r.set_ccnp(channel.raw(), true); + r.set_ccp(channel.raw(), true); + } + }); + } fn enable_outputs(&mut self, _enable: bool) {} fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { @@ -308,6 +412,11 @@ macro_rules! impl_compare_capable_16bit { Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); } + fn get_capture_value(&mut self, channel: Channel) -> u16 { + use sealed::GeneralPurpose16bitInstance; + Self::regs_gp16().ccr(channel.raw()).read().ccr() + } + fn get_max_compare_value(&self) -> u16 { use sealed::GeneralPurpose16bitInstance; Self::regs_gp16().arr().read().arr() @@ -332,6 +441,14 @@ foreach_interrupt! { fn regs_gp16() -> crate::pac::timer::TimGp16 { crate::pac::$inst } + + fn set_count_direction(&mut self, direction: vals::Dir) { + Self::regs_gp16().cr1().modify(|r| r.set_dir(direction)); + } + + fn set_clock_division(&mut self, ckd: vals::Ckd) { + Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); + } } }; @@ -346,6 +463,51 @@ foreach_interrupt! { impl GeneralPurpose32bitInstance for crate::peripherals::$inst {} impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst { + fn clear_input_interrupt(&mut self, channel: Channel) { + use sealed::GeneralPurpose32bitInstance; + Self::regs_gp32() + .sr() + .modify(|r| r.set_ccif(channel.raw(), false)); + } + fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { + use sealed::GeneralPurpose32bitInstance; + Self::regs_gp32() + .dier() + .modify(|r| r.set_ccie(channel.raw(), enable)); + } + fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { + use crate::timer::sealed::GeneralPurpose32bitInstance; + let raw_channel = channel.raw(); + Self::regs_gp32() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icpsc(raw_channel % 2, factor)); + } + + fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { + use crate::timer::sealed::GeneralPurpose32bitInstance; + let raw_channel = channel.raw(); + Self::regs_gp32() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); + } + + fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { + use crate::timer::sealed::GeneralPurpose32bitInstance; + Self::regs_gp32().ccer().modify(|r| match mode { + InputCaptureMode::Rising => { + r.set_ccnp(channel.raw(), false); + r.set_ccp(channel.raw(), false); + } + InputCaptureMode::Falling => { + r.set_ccnp(channel.raw(), false); + r.set_ccp(channel.raw(), true); + } + InputCaptureMode::BothEdges => { + r.set_ccnp(channel.raw(), true); + r.set_ccp(channel.raw(), true); + } + }); + } fn set_output_compare_mode( &mut self, channel: Channel, @@ -373,6 +535,11 @@ foreach_interrupt! { Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); } + fn get_capture_value(&mut self, channel: Channel) -> u32 { + use crate::timer::sealed::GeneralPurpose32bitInstance; + Self::regs_gp32().ccr(channel.raw()).read().ccr() + } + fn get_max_compare_value(&self) -> u32 { use crate::timer::sealed::GeneralPurpose32bitInstance; Self::regs_gp32().arr().read().arr() as u32 @@ -383,6 +550,14 @@ foreach_interrupt! { fn regs_gp16() -> crate::pac::timer::TimGp16 { unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } } + + fn set_count_direction(&mut self, direction: vals::Dir) { + Self::regs_gp16().cr1().modify(|r| r.set_dir(direction)); + } + + fn set_clock_division(&mut self, ckd: vals::Ckd) { + Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); + } } }; @@ -399,6 +574,14 @@ foreach_interrupt! { fn regs_gp16() -> crate::pac::timer::TimGp16 { unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } } + + fn set_count_direction(&mut self, direction: vals::Dir) { + Self::regs_gp16().cr1().modify(|r| r.set_dir(direction)); + } + + fn set_clock_division(&mut self, ckd: vals::Ckd) { + Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); + } } impl sealed::AdvancedControlInstance for crate::peripherals::$inst { @@ -408,6 +591,49 @@ foreach_interrupt! { } impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { + fn clear_input_interrupt(&mut self, channel: Channel) { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced() + .sr() + .modify(|r| r.set_ccif(channel.raw(), false)); + } + fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced() + .dier() + .modify(|r| r.set_ccie(channel.raw(), enable)); + } + fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { + use crate::timer::sealed::AdvancedControlInstance; + let raw_channel = channel.raw(); + Self::regs_advanced() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icpsc(raw_channel % 2, factor)); + } + fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { + use crate::timer::sealed::AdvancedControlInstance; + let raw_channel = channel.raw(); + Self::regs_advanced() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); + } + fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced().ccer().modify(|r| match mode { + InputCaptureMode::Rising => { + r.set_ccnp(channel.raw(), false); + r.set_ccp(channel.raw(), false); + } + InputCaptureMode::Falling => { + r.set_ccnp(channel.raw(), false); + r.set_ccp(channel.raw(), true); + } + InputCaptureMode::BothEdges => { + r.set_ccnp(channel.raw(), true); + r.set_ccp(channel.raw(), true); + } + }); + } fn enable_outputs(&mut self, enable: bool) { use crate::timer::sealed::AdvancedControlInstance; let r = Self::regs_advanced(); @@ -440,6 +666,11 @@ foreach_interrupt! { .modify(|w| w.set_cce(channel.raw(), enable)); } + fn get_capture_value(&mut self, channel: Channel) -> u16 { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced().ccr(channel.raw()).read().ccr() + } + fn set_compare_value(&mut self, channel: Channel, value: u16) { use crate::timer::sealed::AdvancedControlInstance; Self::regs_advanced() -- cgit From 79146c4bd5cdbd8337d0dbdfd93219b9cb330c47 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 27 Sep 2023 20:58:46 -0500 Subject: stm32/adc: cleanup f1, f3, v1, and v2 --- embassy-stm32/src/adc/f1.rs | 51 ++++++++++++++++++++++++++++++++++++++------ embassy-stm32/src/adc/f3.rs | 20 +++++++++++++++++ embassy-stm32/src/adc/mod.rs | 18 +++++++++++----- embassy-stm32/src/adc/v1.rs | 35 +++++++++++------------------- embassy-stm32/src/adc/v2.rs | 36 +++++++++++-------------------- 5 files changed, 103 insertions(+), 57 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index 147349de6..c13264819 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -1,16 +1,37 @@ +use core::future::poll_fn; +use core::marker::PhantomData; +use core::task::Poll; + use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; use crate::adc::{Adc, AdcPin, Instance, SampleTime}; use crate::rcc::get_freqs; use crate::time::Hertz; -use crate::Peripheral; +use crate::{interrupt, Peripheral}; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; // No calibration data for F103, voltage should be 1.2v pub const VREF_INT: u32 = 1200; +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + if T::regs().sr().read().eoc() { + T::regs().cr1().modify(|w| w.set_eocie(false)); + } else { + return; + } + + T::state().waker.wake(); + } +} + pub struct Vref; impl AdcPin for Vref {} impl super::sealed::AdcPin for Vref { @@ -95,18 +116,28 @@ impl<'d, T: Instance> Adc<'d, T> { } /// Perform a single conversion. - fn convert(&mut self) -> u16 { + async fn convert(&mut self) -> u16 { T::regs().cr2().modify(|reg| { reg.set_adon(true); reg.set_swstart(true); }); - while T::regs().cr2().read().swstart() {} - while !T::regs().sr().read().eoc() {} + T::regs().cr1().modify(|w| w.set_eocie(true)); + + poll_fn(|cx| { + T::state().waker.register(cx.waker()); + + if !T::regs().cr2().read().swstart() && T::regs().sr().read().eoc() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; T::regs().dr().read().0 as u16 } - pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { + pub async fn read(&mut self, pin: &mut impl AdcPin) -> u16 { Self::set_channel_sample_time(pin.channel(), self.sample_time); T::regs().cr1().modify(|reg| { reg.set_scan(false); @@ -123,7 +154,7 @@ impl<'d, T: Instance> Adc<'d, T> { // Configure the channel to sample T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())); - self.convert() + self.convert().await } fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { @@ -135,3 +166,11 @@ impl<'d, T: Instance> Adc<'d, T> { } } } + +impl<'d, T: Instance> Drop for Adc<'d, T> { + fn drop(&mut self) { + T::regs().cr2().modify(|reg| reg.set_adon(false)); + + T::disable(); + } +} diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 5d2ea1daa..7c13f8106 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -173,3 +173,23 @@ impl<'d, T: Instance> Adc<'d, T> { } } } + +impl<'d, T: Instance> Drop for Adc<'d, T> { + fn drop(&mut self) { + use crate::pac::adc::vals; + + T::regs().cr().modify(|w| w.set_adstp(true)); + + while T::regs().cr().read().adstp() {} + + T::regs().cr().modify(|w| w.set_addis(true)); + + while T::regs().cr().read().aden() {} + + // Disable the adc regulator + T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE)); + T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::DISABLED)); + + T::disable(); + } +} diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 2f8f8f9e3..365738a31 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -31,15 +31,15 @@ pub struct Adc<'d, T: Instance> { } pub(crate) mod sealed { - #[cfg(any(adc_f3, adc_v1))] + #[cfg(any(adc_f1, adc_f3, adc_v1))] use embassy_sync::waitqueue::AtomicWaker; - #[cfg(any(adc_f3, adc_v1))] + #[cfg(any(adc_f1, adc_f3, adc_v1))] pub struct State { pub waker: AtomicWaker, } - #[cfg(any(adc_f3, adc_v1))] + #[cfg(any(adc_f1, adc_f3, adc_v1))] impl State { pub const fn new() -> Self { Self { @@ -58,11 +58,14 @@ pub(crate) mod sealed { fn common_regs() -> crate::pac::adccommon::AdcCommon; #[cfg(adc_f3)] fn frequency() -> crate::time::Hertz; - #[cfg(any(adc_f3, adc_v1))] + #[cfg(any(adc_f1, adc_f3, adc_v1))] fn state() -> &'static State; } pub trait AdcPin { + #[cfg(any(adc_v1, adc_v2))] + fn set_as_analog(&mut self) {} + fn channel(&self) -> u8; } @@ -96,7 +99,7 @@ foreach_adc!( unsafe { crate::rcc::get_freqs() }.$clock.unwrap() } - #[cfg(any(adc_f3, adc_v1))] + #[cfg(any(adc_f1, adc_f3, adc_v1))] fn state() -> &'static sealed::State { static STATE: sealed::State = sealed::State::new(); &STATE @@ -120,6 +123,11 @@ macro_rules! impl_adc_pin { impl crate::adc::AdcPin for crate::peripherals::$pin {} impl crate::adc::sealed::AdcPin for crate::peripherals::$pin { + #[cfg(any(adc_v1, adc_v2))] + fn set_as_analog(&mut self) { + ::set_as_analog(self); + } + fn channel(&self) -> u8 { $ch } diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 15b2dc593..fded26e40 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -5,7 +5,7 @@ use core::task::Poll; use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; -use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; +use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC; use crate::{interrupt, Peripheral}; @@ -31,24 +31,24 @@ impl interrupt::typelevel::Handler for InterruptHandl } pub struct Vbat; -impl InternalChannel for Vbat {} -impl super::sealed::InternalChannel for Vbat { +impl AdcPin for Vbat {} +impl super::sealed::AdcPin for Vbat { fn channel(&self) -> u8 { 18 } } pub struct Vref; -impl InternalChannel for Vref {} -impl super::sealed::InternalChannel for Vref { +impl AdcPin for Vref {} +impl super::sealed::AdcPin for Vref { fn channel(&self) -> u8 { 17 } } pub struct Temperature; -impl InternalChannel for Temperature {} -impl super::sealed::InternalChannel for Temperature { +impl AdcPin for Temperature {} +impl super::sealed::AdcPin for Temperature { fn channel(&self) -> u8 { 16 } @@ -134,18 +134,14 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); } - pub async fn read

(&mut self, pin: &mut P) -> u16 - where - P: AdcPin + crate::gpio::sealed::Pin, - { + pub async fn read(&mut self, pin: &mut impl AdcPin) -> u16 { let channel = pin.channel(); pin.set_as_analog(); - self.read_channel(channel).await - } - pub async fn read_internal(&mut self, channel: &mut impl InternalChannel) -> u16 { - let channel = channel.channel(); - self.read_channel(channel).await + // A.7.5 Single conversion sequence code example - Software trigger + T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true)); + + self.convert().await } async fn convert(&mut self) -> u16 { @@ -171,13 +167,6 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().dr().read().data() } - - async fn read_channel(&mut self, channel: u8) -> u16 { - // A.7.5 Single conversion sequence code example - Software trigger - T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true)); - - self.convert().await - } } impl<'d, T: Instance> Drop for Adc<'d, T> { diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index f583c08a9..a669013c9 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -1,7 +1,6 @@ use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; -use super::InternalChannel; use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::peripherals::ADC1; use crate::time::Hertz; @@ -16,8 +15,8 @@ pub const VREF_CALIB_MV: u32 = 3300; pub const ADC_POWERUP_TIME_US: u32 = 3; pub struct VrefInt; -impl InternalChannel for VrefInt {} -impl super::sealed::InternalChannel for VrefInt { +impl AdcPin for VrefInt {} +impl super::sealed::AdcPin for VrefInt { fn channel(&self) -> u8 { 17 } @@ -31,8 +30,8 @@ impl VrefInt { } pub struct Temperature; -impl InternalChannel for Temperature {} -impl super::sealed::InternalChannel for Temperature { +impl AdcPin for Temperature {} +impl super::sealed::AdcPin for Temperature { fn channel(&self) -> u8 { cfg_if::cfg_if! { if #[cfg(any(stm32f40, stm32f41))] { @@ -52,8 +51,8 @@ impl Temperature { } pub struct Vbat; -impl InternalChannel for Vbat {} -impl super::sealed::InternalChannel for Vbat { +impl AdcPin for Vbat {} +impl super::sealed::AdcPin for Vbat { fn channel(&self) -> u8 { 18 } @@ -176,22 +175,11 @@ where T::regs().dr().read().0 as u16 } - pub fn read

(&mut self, pin: &mut P) -> u16 - where - P: AdcPin, - P: crate::gpio::sealed::Pin, - { + pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { pin.set_as_analog(); - self.read_channel(pin.channel()) - } - - pub fn read_internal(&mut self, channel: &mut impl InternalChannel) -> u16 { - self.read_channel(channel.channel()) - } - - fn read_channel(&mut self, channel: u8) -> u16 { // Configure ADC + let channel = pin.channel(); // Select channel T::regs().sqr3().write(|reg| reg.set_sq(0, channel)); @@ -199,9 +187,7 @@ where // Configure channel Self::set_channel_sample_time(channel, self.sample_time); - let val = self.convert(); - - val + self.convert() } fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { @@ -216,6 +202,10 @@ where impl<'d, T: Instance> Drop for Adc<'d, T> { fn drop(&mut self) { + T::regs().cr2().modify(|reg| { + reg.set_adon(false); + }); + T::disable(); } } -- cgit From 6200d22438be21a014d95b9d4dde872fab18a51b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 28 Sep 2023 05:12:35 +0200 Subject: stm32/eth: fix receiving large frames on v2. --- embassy-stm32/src/eth/v2/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index f03ea2e31..b7fe4766c 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -34,8 +34,6 @@ impl interrupt::typelevel::Handler for InterruptHandl } } -const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet - pub struct Ethernet<'d, T: Instance, P: PHY> { _peri: PeripheralRef<'d, T>, pub(crate) tx: TDesRing<'d>, @@ -163,7 +161,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ? dma.dmacrx_cr().modify(|w| { w.set_rxpbl(1); // 32 ? - w.set_rbsz(MTU as u16); + w.set_rbsz(RX_BUFFER_SIZE as u16); }); // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called -- cgit From 23f3889167903c6e800f056517c2c831e73ed081 Mon Sep 17 00:00:00 2001 From: Daniel Berlin Date: Thu, 28 Sep 2023 09:35:43 -0400 Subject: Add support for STM32 input capture filter --- embassy-stm32/src/timer/mod.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index ea72b36ae..1d642ed37 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -56,6 +56,8 @@ pub(crate) mod sealed { } pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { + fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf); + fn clear_input_interrupt(&mut self, channel: Channel); fn enable_input_interrupt(&mut self, channel: Channel, enable: bool); @@ -93,6 +95,8 @@ pub(crate) mod sealed { } pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance { + fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf); + fn clear_input_interrupt(&mut self, channel: Channel); fn enable_input_interrupt(&mut self, channel: Channel, enable: bool); @@ -338,6 +342,14 @@ macro_rules! impl_32bit_timer { macro_rules! impl_compare_capable_16bit { ($inst:ident) => { impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { + fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { + use sealed::GeneralPurpose16bitInstance; + let raw_channel = channel.raw(); + Self::regs_gp16() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icf(raw_channel % 2, icf)); + } + fn clear_input_interrupt(&mut self, channel: Channel) { use sealed::GeneralPurpose16bitInstance; Self::regs_gp16() @@ -463,6 +475,14 @@ foreach_interrupt! { impl GeneralPurpose32bitInstance for crate::peripherals::$inst {} impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst { + fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { + use sealed::GeneralPurpose32bitInstance; + let raw_channel = channel.raw(); + Self::regs_gp32() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icf(raw_channel % 2, icf)); + } + fn clear_input_interrupt(&mut self, channel: Channel) { use sealed::GeneralPurpose32bitInstance; Self::regs_gp32() @@ -591,6 +611,14 @@ foreach_interrupt! { } impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { + fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { + use crate::timer::sealed::AdvancedControlInstance; + let raw_channel = channel.raw(); + Self::regs_advanced() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icf(raw_channel % 2, icf)); + } + fn clear_input_interrupt(&mut self, channel: Channel) { use crate::timer::sealed::AdvancedControlInstance; Self::regs_advanced() -- cgit From 322a4a8401480de8d51fa85ac6cedfabd033c743 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 28 Sep 2023 15:48:46 -0500 Subject: stm32/hrtim: move traits out of macro def'n --- embassy-stm32/src/hrtim/traits.rs | 148 +++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 81 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index 37cfb9b90..34a363a1f 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs @@ -78,12 +78,76 @@ pub(crate) mod sealed { pub trait Instance: RccPeripheral { fn regs() -> crate::pac::hrtim::Hrtim; - fn set_master_frequency(frequency: Hertz); + fn set_master_frequency(frequency: Hertz) { + 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) + } else { + Prescaler::compute_min_low_res(psc_min) + }; + + let timer_f = 32 * (timer_f / psc as u32); + let per: u16 = (timer_f / f) as u16; + + let regs = Self::regs(); + + regs.mcr().modify(|w| w.set_ckpsc(psc.into())); + regs.mper().modify(|w| w.set_mper(per)); + } + + fn set_channel_frequency(channel: usize, frequency: Hertz) { + 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) + } else { + Prescaler::compute_min_low_res(psc_min) + }; - fn set_channel_frequency(channnel: usize, frequency: Hertz); + let timer_f = 32 * (timer_f / psc as u32); + let per: u16 = (timer_f / f) as u16; + + let regs = Self::regs(); + + regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into())); + regs.tim(channel).per().modify(|w| w.set_per(per)); + } /// Set the dead time as a proportion of max_duty - fn set_channel_dead_time(channnel: usize, dead_time: u16); + + fn set_channel_dead_time(channel: usize, dead_time: u16) { + let regs = Self::regs(); + + let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into(); + + // The dead-time base clock runs 4 times slower than the hrtim base clock + // u9::MAX = 511 + let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511); + let psc = if Self::regs().isr().read().dllrdy() { + Prescaler::compute_min_high_res(psc_min) + } else { + Prescaler::compute_min_low_res(psc_min) + }; + + let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32); + + regs.tim(channel).dt().modify(|w| { + w.set_dtprsc(psc.into()); + w.set_dtf(dt_val as u16); + w.set_dtr(dt_val as u16); + }); + } // fn enable_outputs(enable: bool); // @@ -99,84 +163,6 @@ foreach_interrupt! { fn regs() -> crate::pac::hrtim::Hrtim { crate::pac::$inst } - - fn set_master_frequency(frequency: Hertz) { - 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) - } else { - Prescaler::compute_min_low_res(psc_min) - }; - - let timer_f = 32 * (timer_f / psc as u32); - let per: u16 = (timer_f / f) as u16; - - let regs = Self::regs(); - - regs.mcr().modify(|w| w.set_ckpsc(psc.into())); - regs.mper().modify(|w| w.set_mper(per)); - } - - fn set_channel_frequency(channel: usize, frequency: Hertz) { - 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) - } else { - Prescaler::compute_min_low_res(psc_min) - }; - - let timer_f = 32 * (timer_f / psc as u32); - let per: u16 = (timer_f / f) as u16; - - let regs = Self::regs(); - - regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into())); - regs.tim(channel).per().modify(|w| w.set_per(per)); - } - - fn set_channel_dead_time(channel: usize, dead_time: u16) { - - let regs = Self::regs(); - - let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into(); - - // The dead-time base clock runs 4 times slower than the hrtim base clock - // u9::MAX = 511 - let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511); - let psc = if Self::regs().isr().read().dllrdy() { - Prescaler::compute_min_high_res(psc_min) - } else { - Prescaler::compute_min_low_res(psc_min) - }; - - let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32); - - regs.tim(channel).dt().modify(|w| { - w.set_dtprsc(psc.into()); - w.set_dtf(dt_val as u16); - w.set_dtr(dt_val as u16); - }); - } } impl Instance for crate::peripherals::$inst { -- cgit From e70143ef8f5303b5916a160f9d43d04d7ab55cd7 Mon Sep 17 00:00:00 2001 From: Daniel Berlin Date: Thu, 28 Sep 2023 17:04:19 -0400 Subject: Forgot set_count_direction and set_clock_division in 32 bit instance --- embassy-stm32/src/timer/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 1d642ed37..9b79f9b4e 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -49,6 +49,10 @@ pub(crate) mod sealed { fn regs_gp32() -> crate::pac::timer::TimGp32; fn set_frequency(&mut self, frequency: Hertz); + + fn set_count_direction(&mut self, direction: vals::Dir); + + fn set_clock_division(&mut self, ckd: vals::Ckd); } pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { @@ -317,6 +321,14 @@ macro_rules! impl_32bit_timer { crate::pac::$inst } + fn set_count_direction(&mut self, direction: vals::Dir) { + Self::regs_gp32().cr1().modify(|r| r.set_dir(direction)); + } + + fn set_clock_division(&mut self, ckd: vals::Ckd) { + Self::regs_gp32().cr1().modify(|r| r.set_ckd(ckd)); + } + fn set_frequency(&mut self, frequency: Hertz) { use core::convert::TryInto; let f = frequency.0; -- cgit From 39f1b26a3954a3ffbc2a0960a8c7fd952f928648 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 28 Sep 2023 19:21:02 -0500 Subject: stm32: update metapac and remove sbs --- embassy-stm32/src/eth/v2/mod.rs | 4 ++-- embassy-stm32/src/lib.rs | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index b7fe4766c..6efd40e3e 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -99,9 +99,9 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { }); // RMII - crate::pac::SBS + crate::pac::SYSCFG .pmcr() - .modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4)); + .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4)); }); config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index db79546ba..1e184f9d7 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -181,10 +181,8 @@ pub fn init(config: Config) -> Peripherals { }); } - #[cfg(not(any(stm32f1, stm32h5, stm32wb, stm32wl)))] + #[cfg(not(any(stm32f1, stm32wb, stm32wl)))] peripherals::SYSCFG::enable(); - #[cfg(sbs)] - peripherals::SBS::enable(); #[cfg(not(any(stm32h5, stm32h7, stm32wb, stm32wl)))] peripherals::PWR::enable(); #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] -- cgit From dffdb9268bfb32580efe32067bab50fe62900c5f Mon Sep 17 00:00:00 2001 From: Daniel Berlin Date: Thu, 28 Sep 2023 21:56:18 -0400 Subject: Revert "Forgot set_count_direction and set_clock_division in 32 bit instance" --- embassy-stm32/src/timer/mod.rs | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 9b79f9b4e..1d642ed37 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -49,10 +49,6 @@ pub(crate) mod sealed { fn regs_gp32() -> crate::pac::timer::TimGp32; fn set_frequency(&mut self, frequency: Hertz); - - fn set_count_direction(&mut self, direction: vals::Dir); - - fn set_clock_division(&mut self, ckd: vals::Ckd); } pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { @@ -321,14 +317,6 @@ macro_rules! impl_32bit_timer { crate::pac::$inst } - fn set_count_direction(&mut self, direction: vals::Dir) { - Self::regs_gp32().cr1().modify(|r| r.set_dir(direction)); - } - - fn set_clock_division(&mut self, ckd: vals::Ckd) { - Self::regs_gp32().cr1().modify(|r| r.set_ckd(ckd)); - } - fn set_frequency(&mut self, frequency: Hertz) { use core::convert::TryInto; let f = frequency.0; -- cgit