From bd01e90bfa4895b45e41ad538cb24a959b0b58ab Mon Sep 17 00:00:00 2001 From: chemicstry Date: Sun, 10 Jul 2022 20:38:30 +0300 Subject: [PATCH 1/9] Implement IWDG timeout calculation --- embassy-stm32/src/wdg/mod.rs | 50 ++++++++++++++++++++++++++++++--- examples/stm32f4/src/bin/wdt.rs | 44 +++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 examples/stm32f4/src/bin/wdt.rs diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index da25692a..b4d59ff2 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs @@ -1,21 +1,63 @@ use core::marker::PhantomData; +use embassy::time::Duration; use embassy_hal_common::{unborrow, Unborrow}; -use stm32_metapac::iwdg::vals::Key; -pub use stm32_metapac::iwdg::vals::Pr as Prescaler; +use stm32_metapac::iwdg::vals::{Key, Pr}; + +use crate::time::Hertz; pub struct IndependentWatchdog<'d, T: Instance> { wdg: PhantomData<&'d mut T>, } +// Some STM32 families have 40 kHz LSI clock instead of 32 kHz +cfg_if::cfg_if! { + if #[cfg(any(stm32f0, stm32f1))] { + pub const IWDG_FREQ: Hertz = Hertz(40_000); + } else { + pub const IWDG_FREQ: Hertz = Hertz(32_000); + } +} + +// 12-bit counter +const MAX_RL: u16 = 0xFFF; + +/// Calculates maximum watchdog timeout (RL = 0xFFF) for a given prescaler +const fn max_timeout(prescaler: u8) -> Duration { + Duration::from_micros(1_000_000 / (IWDG_FREQ.0 / prescaler as u32) as u64 * MAX_RL as u64) +} + +/// Calculates watchdog reload value for the given prescaler and desired timeout +const fn reload_value(prescaler: u8, timeout: Duration) -> u16 { + ((IWDG_FREQ.0 / prescaler as u32) as u64 * timeout.as_micros() / 1_000_000) as u16 +} + impl<'d, T: Instance> IndependentWatchdog<'d, T> { - pub fn new(_instance: impl Unborrow + 'd, presc: Prescaler) -> Self { + pub fn new(_instance: impl Unborrow + 'd, timeout: Duration) -> Self { unborrow!(_instance); + // Find lowest prescaler value, which makes watchdog period longer or equal to timeout. + // This iterates from 4 (2^2) to 256 (2^8). + let psc_power = unwrap!((2..=8).find(|psc_power| { + let psc = 2u8.pow(*psc_power); + timeout <= max_timeout(psc) + })); + + // Prescaler value + let psc = 2u8.pow(psc_power); + + // Convert prescaler power to PR register value + let pr = psc_power as u8 - 2; + assert!(pr <= 0b110); + + // Reload value + let rl = reload_value(psc, timeout); + let wdg = T::regs(); unsafe { wdg.kr().write(|w| w.set_key(Key::ENABLE)); - wdg.pr().write(|w| w.set_pr(presc)); + wdg.pr().write(|w| w.set_pr(Pr(pr))); + wdg.rlr().write(|w| w.set_rl(rl)); } IndependentWatchdog { diff --git a/examples/stm32f4/src/bin/wdt.rs b/examples/stm32f4/src/bin/wdt.rs new file mode 100644 index 00000000..41e1f4c7 --- /dev/null +++ b/examples/stm32f4/src/bin/wdt.rs @@ -0,0 +1,44 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy::executor::Spawner; +use embassy::time::{Duration, Timer}; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::wdg::IndependentWatchdog; +use embassy_stm32::Peripherals; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + info!("Hello World!"); + + let mut led = Output::new(p.PB7, Level::High, Speed::Low); + + let mut wdt = IndependentWatchdog::new(p.IWDG, Duration::from_secs(1)); + unsafe { + wdt.unleash(); + } + + let mut i = 0; + + loop { + info!("high"); + led.set_high(); + Timer::after(Duration::from_millis(300)).await; + + info!("low"); + led.set_low(); + Timer::after(Duration::from_millis(300)).await; + + if i < 5 { + info!("Petting watchdog"); + unsafe { + wdt.pet(); + } + } + + i += 1; + } +} From 1fd5022e72956ebd0c5c985f3ccf581dabf98f69 Mon Sep 17 00:00:00 2001 From: chemicstry Date: Sun, 10 Jul 2022 20:59:36 +0300 Subject: [PATCH 2/9] Refactor IWDG to use LSI frequency from RCC --- embassy-stm32/src/rcc/f0.rs | 10 +++++++--- embassy-stm32/src/rcc/f1.rs | 10 +++++++--- embassy-stm32/src/rcc/f2.rs | 7 +++++-- embassy-stm32/src/rcc/f3.rs | 16 ++++++++++------ embassy-stm32/src/rcc/f4.rs | 8 ++++++-- embassy-stm32/src/rcc/f7.rs | 8 ++++++-- embassy-stm32/src/rcc/g0.rs | 8 ++++---- embassy-stm32/src/rcc/g4.rs | 6 +++--- embassy-stm32/src/rcc/h7.rs | 31 +++++++++++++++++++------------ embassy-stm32/src/rcc/l0.rs | 11 +++++++---- embassy-stm32/src/rcc/l1.rs | 9 ++++++--- embassy-stm32/src/rcc/l4.rs | 11 +++++++---- embassy-stm32/src/rcc/l5.rs | 11 +++++++---- embassy-stm32/src/rcc/u5.rs | 11 +++++++---- embassy-stm32/src/rcc/wb.rs | 7 +++++-- embassy-stm32/src/rcc/wl.rs | 12 ++++++++---- embassy-stm32/src/wdg/mod.rs | 14 +++----------- 17 files changed, 117 insertions(+), 73 deletions(-) diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs index 10b075da..eb62ab66 100644 --- a/embassy-stm32/src/rcc/f0.rs +++ b/embassy-stm32/src/rcc/f0.rs @@ -3,7 +3,11 @@ use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Sw, Usbsw}; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; -const HSI: u32 = 8_000_000; +/// HSI speed +pub const HSI_FREQ: Hertz = Hertz(8_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(40_000); /// Configuration of the clocks /// @@ -24,14 +28,14 @@ pub struct Config { } pub(crate) unsafe fn init(config: Config) { - let sysclk = config.sys_ck.map(|v| v.0).unwrap_or(HSI); + let sysclk = config.sys_ck.map(|v| v.0).unwrap_or(HSI_FREQ.0); let (src_clk, use_hsi48) = config.hse.map(|v| (v.0, false)).unwrap_or_else(|| { #[cfg(not(stm32f0x0))] if config.hsi48 { return (48_000_000, true); } - (HSI, false) + (HSI_FREQ.0, false) }); let (pllmul_bits, real_sysclk) = if sysclk == src_clk { diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs index 8e2e6684..e667dbf9 100644 --- a/embassy-stm32/src/rcc/f1.rs +++ b/embassy-stm32/src/rcc/f1.rs @@ -6,7 +6,11 @@ use crate::pac::rcc::vals::*; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; -const HSI: u32 = 8_000_000; +/// HSI speed +pub const HSI_FREQ: Hertz = Hertz(8_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(40_000); /// Configuration of the clocks /// @@ -23,12 +27,12 @@ pub struct Config { } pub(crate) unsafe fn init(config: Config) { - let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI / 2); + let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0 / 2); let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); let pllmul = sysclk / pllsrcclk; let (pllmul_bits, real_sysclk) = if pllmul == 1 { - (None, config.hse.map(|hse| hse.0).unwrap_or(HSI)) + (None, config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0)) } else { let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16); (Some(pllmul as u8 - 2), pllsrcclk * pllmul) diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index 65fa78f8..cfc52763 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -8,7 +8,10 @@ use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; /// HSI speed -pub const HSI: Hertz = Hertz(16_000_000); +pub const HSI_FREQ: Hertz = Hertz(16_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(32_000); #[derive(Clone, Copy)] pub struct HSEConfig { @@ -429,7 +432,7 @@ pub(crate) unsafe fn init(config: Config) { .unwrap_or_else(|| panic!("HSE must be configured to be used as PLL input")); hse_config.frequency } - PLLSrc::HSI => HSI, + PLLSrc::HSI => HSI_FREQ, }; // Reference: STM32F215xx/217xx datasheet Table 33. Main PLL characteristics diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index c2aec04c..2deee80d 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -4,7 +4,11 @@ use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; -const HSI: u32 = 8_000_000; +/// HSI speed +pub const HSI_FREQ: Hertz = Hertz(8_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(40_000); /// Clocks configutation #[non_exhaustive] @@ -180,7 +184,7 @@ pub(crate) unsafe fn init(config: Config) { fn get_sysclk(config: &Config) -> (Hertz, Option) { match (config.sysclk, config.hse) { (Some(sysclk), Some(hse)) if sysclk == hse => (hse, None), - (Some(sysclk), None) if sysclk.0 == HSI => (Hertz(HSI), None), + (Some(sysclk), None) if sysclk == HSI_FREQ => (HSI_FREQ, None), // If the user selected System clock is different from HSI or HSE // we will have to setup PLL clock source (Some(sysclk), _) => { @@ -188,7 +192,7 @@ fn get_sysclk(config: &Config) -> (Hertz, Option) { (sysclk, Some(pll_config)) } (None, Some(hse)) => (hse, None), - (None, None) => (Hertz(HSI), None), + (None, None) => (HSI_FREQ, None), } } @@ -228,15 +232,15 @@ fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) { stm32f302xd, stm32f302xe, stm32f303xd, stm32f303xe, stm32f398xe ))] { - let (multiplier, divisor) = get_mul_div(sysclk, HSI); + let (multiplier, divisor) = get_mul_div(sysclk, HSI_FREQ.0); ( - Hertz((HSI / divisor) * multiplier), + Hertz((HSI_FREQ.0 / divisor) * multiplier), Pllsrc::HSI_DIV_PREDIV, into_pll_mul(multiplier), Some(into_pre_div(divisor)), ) } else { - let pllsrcclk = HSI / 2; + let pllsrcclk = HSI_FREQ.0 / 2; let multiplier = sysclk / pllsrcclk; assert!(multiplier <= 16); ( diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index 21f3ad15..200bcce9 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -4,7 +4,11 @@ use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; -const HSI: u32 = 16_000_000; +/// HSI speed +pub const HSI_FREQ: Hertz = Hertz(16_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(32_000); /// Clocks configuration #[non_exhaustive] @@ -108,7 +112,7 @@ unsafe 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); + 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 d98aa401..2d21326a 100644 --- a/embassy-stm32/src/rcc/f7.rs +++ b/embassy-stm32/src/rcc/f7.rs @@ -5,7 +5,11 @@ use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; -const HSI: u32 = 16_000_000; +/// HSI speed +pub const HSI_FREQ: Hertz = Hertz(16_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(32_000); /// Clocks configuration #[non_exhaustive] @@ -117,7 +121,7 @@ pub(crate) unsafe fn init(config: Config) { } } - let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI); + 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/g0.rs b/embassy-stm32/src/rcc/g0.rs index 36b49c71..3ca65cf3 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -5,10 +5,10 @@ use crate::rcc::{set_freqs, Clocks}; use crate::time::{Hertz, U32Ext}; /// HSI speed -pub const HSI_FREQ: u32 = 16_000_000; +pub const HSI_FREQ: Hertz = Hertz(16_000_000); /// LSI speed -pub const LSI_FREQ: u32 = 32_000; +pub const LSI_FREQ: Hertz = Hertz(32_000); /// System clock mux source #[derive(Clone, Copy)] @@ -248,7 +248,7 @@ impl PllConfig { pub(crate) unsafe fn init(self) -> u32 { assert!(self.n >= 8 && self.n <= 86); let (src, input_freq) = match self.source { - PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ), + PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ.0), PllSrc::HSE(freq) => (vals::Pllsrc::HSE, freq.0), }; @@ -344,7 +344,7 @@ pub(crate) unsafe fn init(config: Config) { }); while !RCC.cr().read().hsirdy() {} - (HSI_FREQ >> div.0, Sw::HSI) + (HSI_FREQ.0 >> div.0, Sw::HSI) } ClockSrc::HSE(freq) => { // Enable HSE diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 2b8c2b57..d9c15727 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -3,10 +3,10 @@ use crate::rcc::{set_freqs, Clocks}; use crate::time::{Hertz, U32Ext}; /// HSI speed -pub const HSI_FREQ: u32 = 16_000_000; +pub const HSI_FREQ: Hertz = Hertz(16_000_000); /// LSI speed -pub const LSI_FREQ: u32 = 32_000; +pub const LSI_FREQ: Hertz = Hertz(32_000); /// System clock mux source #[derive(Clone, Copy)] @@ -96,7 +96,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - (HSI_FREQ, 0x01) + (HSI_FREQ.0, 0x01) } ClockSrc::HSE(freq) => { // Enable HSE diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs index 4fa01ade..83e5d297 100644 --- a/embassy-stm32/src/rcc/h7.rs +++ b/embassy-stm32/src/rcc/h7.rs @@ -12,10 +12,17 @@ use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; use crate::{peripherals, Unborrow}; -const HSI: Hertz = Hertz(64_000_000); -const CSI: Hertz = Hertz(4_000_000); -const HSI48: Hertz = Hertz(48_000_000); -const LSI: Hertz = Hertz(32_000); +/// 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); /// Voltage Scale /// @@ -461,7 +468,7 @@ pub(crate) unsafe fn init(mut config: Config) { // achieved, but the mechanism for doing so is not yet // implemented here. - let srcclk = config.hse.unwrap_or(HSI); // Available clocks + 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 @@ -490,9 +497,9 @@ pub(crate) unsafe fn init(mut config: Config) { // 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)) => (CSI, Ckpersel::CSI), // CSI - _ => (HSI, Ckpersel::HSI), // HSI + (true, Some(hse)) => (hse, Ckpersel::HSE), // HSE + (_, Some(HSI_FREQ)) => (CSI_FREQ, Ckpersel::CSI), // CSI + _ => (HSI_FREQ, Ckpersel::HSI), // HSI }; // D1 Core Prescaler @@ -664,10 +671,10 @@ pub(crate) unsafe fn init(mut config: Config) { ppre2, ppre3, ppre4, - csi_ck: Some(CSI), - hsi_ck: Some(HSI), - hsi48_ck: Some(HSI48), - lsi_ck: Some(LSI), + 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), diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index 2e23833c..2ca25aa2 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -5,8 +5,11 @@ use crate::pac::{CRS, SYSCFG}; use crate::rcc::{set_freqs, Clocks}; use crate::time::{Hertz, U32Ext}; -/// HSI16 speed -pub const HSI16_FREQ: u32 = 16_000_000; +/// HSI speed +pub const HSI_FREQ: Hertz = Hertz(16_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(32_000); /// System clock mux source #[derive(Clone, Copy)] @@ -217,7 +220,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().write(|w| w.set_hsi16on(true)); while !RCC.cr().read().hsi16rdyf() {} - (HSI16_FREQ, Sw::HSI16) + (HSI_FREQ.0, Sw::HSI16) } ClockSrc::HSE(freq) => { // Enable HSE @@ -238,7 +241,7 @@ pub(crate) unsafe fn init(config: Config) { // Enable HSI RCC.cr().write(|w| w.set_hsi16on(true)); while !RCC.cr().read().hsi16rdyf() {} - HSI16_FREQ + HSI_FREQ.0 } }; diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs index 80290632..8c315f29 100644 --- a/embassy-stm32/src/rcc/l1.rs +++ b/embassy-stm32/src/rcc/l1.rs @@ -4,7 +4,10 @@ use crate::rcc::{set_freqs, Clocks}; use crate::time::{Hertz, U32Ext}; /// HSI speed -pub const HSI_FREQ: u32 = 16_000_000; +pub const HSI_FREQ: Hertz = Hertz(16_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(32_000); /// System clock mux source #[derive(Clone, Copy)] @@ -211,7 +214,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - (HSI_FREQ, Sw::HSI) + (HSI_FREQ.0, Sw::HSI) } ClockSrc::HSE(freq) => { // Enable HSE @@ -232,7 +235,7 @@ pub(crate) unsafe fn init(config: Config) { // Enable HSI RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - HSI_FREQ + HSI_FREQ.0 } }; diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 71a93855..fedfb0ed 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -3,8 +3,11 @@ use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::{Hertz, U32Ext}; -/// HSI16 speed -pub const HSI16_FREQ: u32 = 16_000_000; +/// HSI speed +pub const HSI_FREQ: Hertz = Hertz(16_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(32_000); /// System clock mux source #[derive(Clone, Copy)] @@ -321,7 +324,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - (HSI16_FREQ, Sw::HSI16) + (HSI_FREQ.0, Sw::HSI16) } ClockSrc::HSE(freq) => { // Enable HSE @@ -342,7 +345,7 @@ pub(crate) unsafe fn init(config: Config) { // Enable HSI RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - HSI16_FREQ + HSI_FREQ.0 } PLLSource::MSI(range) => { // Enable MSI diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs index 60e1dade..edcdafe0 100644 --- a/embassy-stm32/src/rcc/l5.rs +++ b/embassy-stm32/src/rcc/l5.rs @@ -5,8 +5,11 @@ use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::{Hertz, U32Ext}; -/// HSI16 speed -pub const HSI16_FREQ: u32 = 16_000_000; +/// HSI speed +pub const HSI_FREQ: Hertz = Hertz(16_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(32_000); /// System clock mux source #[derive(Clone, Copy)] @@ -322,7 +325,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - (HSI16_FREQ, Sw::HSI16) + (HSI_FREQ.0, Sw::HSI16) } ClockSrc::HSE(freq) => { // Enable HSE @@ -343,7 +346,7 @@ pub(crate) unsafe fn init(config: Config) { // Enable HSI RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - HSI16_FREQ + HSI_FREQ.0 } PLLSource::MSI(range) => { // Enable MSI diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index f09e467c..701eeb89 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -4,8 +4,11 @@ use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::{Hertz, U32Ext}; -/// HSI16 speed -pub const HSI16_FREQ: u32 = 16_000_000; +/// HSI speed +pub const HSI_FREQ: Hertz = Hertz(16_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(32_000); /// Voltage Scale /// @@ -333,13 +336,13 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - HSI16_FREQ + HSI_FREQ.0 } ClockSrc::PLL1R(src, m, n, div) => { let freq = match src { PllSrc::MSI(_) => MSIRange::default().into(), PllSrc::HSE(hertz) => hertz.0, - PllSrc::HSI16 => HSI16_FREQ, + PllSrc::HSI16 => HSI_FREQ.0, }; // disable diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index d950e28f..aec74c4b 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -8,7 +8,10 @@ use crate::time::{Hertz, U32Ext}; /// Only the basic setup using the HSE and HSI clocks are supported as of now. /// HSI speed -pub const HSI_FREQ: u32 = 16_000_000; +pub const HSI_FREQ: Hertz = Hertz(16_000_000); + +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(32_000); /// System clock mux source #[derive(Clone, Copy)] @@ -106,7 +109,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - (HSI_FREQ, 0x01) + (HSI_FREQ.0, 0x01) } ClockSrc::HSE(freq) => { // Enable HSE diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 1f2fbaf8..195e8c8a 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -8,9 +8,13 @@ use crate::time::U32Ext; /// Only the basic setup using the HSE and HSI clocks are supported as of now. /// HSI speed -pub const HSI_FREQ: u32 = 16_000_000; +pub const HSI_FREQ: Hertz = Hertz(16_000_000); -pub const HSE32_FREQ: u32 = 32_000_000; +/// LSI speed +pub const LSI_FREQ: Hertz = Hertz(32_000); + +/// HSE32 speed +pub const HSE32_FREQ: Hertz = Hertz(32_000_000); /// System clock mux source #[derive(Clone, Copy)] @@ -203,7 +207,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - (HSI_FREQ, 0x01, VoltageScale::Range2) + (HSI_FREQ.0, 0x01, VoltageScale::Range2) } ClockSrc::HSE32 => { // Enable HSE32 @@ -213,7 +217,7 @@ pub(crate) unsafe fn init(config: Config) { }); while !RCC.cr().read().hserdy() {} - (HSE32_FREQ, 0x02, VoltageScale::Range1) + (HSE32_FREQ.0, 0x02, VoltageScale::Range1) } ClockSrc::MSI(range) => { RCC.cr().write(|w| { diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index b4d59ff2..5dbbb5a5 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs @@ -4,32 +4,24 @@ use embassy::time::Duration; use embassy_hal_common::{unborrow, Unborrow}; use stm32_metapac::iwdg::vals::{Key, Pr}; +use crate::rcc::LSI_FREQ; use crate::time::Hertz; pub struct IndependentWatchdog<'d, T: Instance> { wdg: PhantomData<&'d mut T>, } -// Some STM32 families have 40 kHz LSI clock instead of 32 kHz -cfg_if::cfg_if! { - if #[cfg(any(stm32f0, stm32f1))] { - pub const IWDG_FREQ: Hertz = Hertz(40_000); - } else { - pub const IWDG_FREQ: Hertz = Hertz(32_000); - } -} - // 12-bit counter const MAX_RL: u16 = 0xFFF; /// Calculates maximum watchdog timeout (RL = 0xFFF) for a given prescaler const fn max_timeout(prescaler: u8) -> Duration { - Duration::from_micros(1_000_000 / (IWDG_FREQ.0 / prescaler as u32) as u64 * MAX_RL as u64) + Duration::from_micros(1_000_000 / (LSI_FREQ.0 / prescaler as u32) as u64 * MAX_RL as u64) } /// Calculates watchdog reload value for the given prescaler and desired timeout const fn reload_value(prescaler: u8, timeout: Duration) -> u16 { - ((IWDG_FREQ.0 / prescaler as u32) as u64 * timeout.as_micros() / 1_000_000) as u16 + ((LSI_FREQ.0 / prescaler as u32) as u64 * timeout.as_micros() / 1_000_000) as u16 } impl<'d, T: Instance> IndependentWatchdog<'d, T> { From bd741a40191d127e804d668366e92a8fc43c5b18 Mon Sep 17 00:00:00 2001 From: chemicstry Date: Sun, 10 Jul 2022 21:08:30 +0300 Subject: [PATCH 3/9] Add comments to watchdog example --- examples/stm32f4/src/bin/wdt.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/stm32f4/src/bin/wdt.rs b/examples/stm32f4/src/bin/wdt.rs index 41e1f4c7..a23cfe9c 100644 --- a/examples/stm32f4/src/bin/wdt.rs +++ b/examples/stm32f4/src/bin/wdt.rs @@ -32,6 +32,8 @@ async fn main(_spawner: Spawner, p: Peripherals) { led.set_low(); Timer::after(Duration::from_millis(300)).await; + // Pet watchdog for 5 iterations and then stop. + // MCU should restart in 1 second after the last pet. if i < 5 { info!("Petting watchdog"); unsafe { From 85054a7233f3beca236ca7ac3763065b021fa10d Mon Sep 17 00:00:00 2001 From: chemicstry Date: Sun, 10 Jul 2022 21:15:38 +0300 Subject: [PATCH 4/9] Fix typo --- embassy-stm32/src/rcc/h7.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs index 83e5d297..6b101431 100644 --- a/embassy-stm32/src/rcc/h7.rs +++ b/embassy-stm32/src/rcc/h7.rs @@ -498,7 +498,7 @@ pub(crate) unsafe fn init(mut config: Config) { // 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(HSI_FREQ)) => (CSI_FREQ, Ckpersel::CSI), // CSI + (_, Some(CSI_FREQ)) => (CSI_FREQ, Ckpersel::CSI), // CSI _ => (HSI_FREQ, Ckpersel::HSI), // HSI }; From f43545f36ed6bd154c59106c8b7602b10d635a42 Mon Sep 17 00:00:00 2001 From: chemicstry Date: Sun, 10 Jul 2022 21:16:54 +0300 Subject: [PATCH 5/9] Fix warnings --- embassy-stm32/src/wdg/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index 5dbbb5a5..7f63de21 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs @@ -5,7 +5,6 @@ use embassy_hal_common::{unborrow, Unborrow}; use stm32_metapac::iwdg::vals::{Key, Pr}; use crate::rcc::LSI_FREQ; -use crate::time::Hertz; pub struct IndependentWatchdog<'d, T: Instance> { wdg: PhantomData<&'d mut T>, From 3bf1e1d4aaefeeed9836060ea62b9d064e4fbe58 Mon Sep 17 00:00:00 2001 From: chemicstry Date: Sun, 10 Jul 2022 21:46:14 +0300 Subject: [PATCH 6/9] Fix f2, wl compilation --- embassy-stm32/src/rcc/f2.rs | 2 +- embassy-stm32/src/rcc/wl.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index cfc52763..d543888c 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -454,7 +454,7 @@ pub(crate) unsafe fn init(config: Config) { let (sys_clk, sw) = match config.mux { ClockSrc::HSI => { assert!(config.hsi, "HSI must be enabled to be used as system clock"); - (HSI, Sw::HSI) + (HSI_FREQ, Sw::HSI) } ClockSrc::HSE => { let hse_config = config diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 195e8c8a..33ecaa36 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,6 +1,6 @@ use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; -use crate::time::U32Ext; +use crate::time::{Hertz, U32Ext}; /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, /// and with the addition of the init function to configure a system clock. From d7d1e46a5fb115b0993d4ac37c0152b1dd5f78c3 Mon Sep 17 00:00:00 2001 From: chemicstry Date: Mon, 11 Jul 2022 00:00:33 +0300 Subject: [PATCH 7/9] Use u32 instead of Duration for IWDG --- embassy-stm32/src/wdg/mod.rs | 21 ++++++++++++--------- examples/stm32f4/src/bin/wdt.rs | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index 7f63de21..c4b2609b 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs @@ -1,6 +1,5 @@ use core::marker::PhantomData; -use embassy::time::Duration; use embassy_hal_common::{unborrow, Unborrow}; use stm32_metapac::iwdg::vals::{Key, Pr}; @@ -13,25 +12,29 @@ pub struct IndependentWatchdog<'d, T: Instance> { // 12-bit counter const MAX_RL: u16 = 0xFFF; -/// Calculates maximum watchdog timeout (RL = 0xFFF) for a given prescaler -const fn max_timeout(prescaler: u8) -> Duration { - Duration::from_micros(1_000_000 / (LSI_FREQ.0 / prescaler as u32) as u64 * MAX_RL as u64) +/// Calculates maximum watchdog timeout in us (RL = 0xFFF) for a given prescaler +const fn max_timeout(prescaler: u8) -> u32 { + 1_000_000 * MAX_RL as u32 / (LSI_FREQ.0 / prescaler as u32) } /// Calculates watchdog reload value for the given prescaler and desired timeout -const fn reload_value(prescaler: u8, timeout: Duration) -> u16 { - ((LSI_FREQ.0 / prescaler as u32) as u64 * timeout.as_micros() / 1_000_000) as u16 +const fn reload_value(prescaler: u8, timeout_us: u32) -> u16 { + (timeout_us / prescaler as u32 * LSI_FREQ.0 / 1_000_000) as u16 } impl<'d, T: Instance> IndependentWatchdog<'d, T> { - pub fn new(_instance: impl Unborrow + 'd, timeout: Duration) -> Self { + /// Creates an IWDG (Independent Watchdog) instance with a given timeout value in microseconds. + /// + /// [Self] has to be started with [Self::unleash()]. + /// Once timer expires, MCU will be reset. To prevent this, timer must be reloaded by repeatedly calling [Self::pet()] within timeout interval. + pub fn new(_instance: impl Unborrow + 'd, timeout_us: u32) -> Self { unborrow!(_instance); // Find lowest prescaler value, which makes watchdog period longer or equal to timeout. // This iterates from 4 (2^2) to 256 (2^8). let psc_power = unwrap!((2..=8).find(|psc_power| { let psc = 2u8.pow(*psc_power); - timeout <= max_timeout(psc) + timeout_us <= max_timeout(psc) })); // Prescaler value @@ -42,7 +45,7 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> { assert!(pr <= 0b110); // Reload value - let rl = reload_value(psc, timeout); + let rl = reload_value(psc, timeout_us); let wdg = T::regs(); unsafe { diff --git a/examples/stm32f4/src/bin/wdt.rs b/examples/stm32f4/src/bin/wdt.rs index a23cfe9c..bfc487c3 100644 --- a/examples/stm32f4/src/bin/wdt.rs +++ b/examples/stm32f4/src/bin/wdt.rs @@ -16,7 +16,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { let mut led = Output::new(p.PB7, Level::High, Speed::Low); - let mut wdt = IndependentWatchdog::new(p.IWDG, Duration::from_secs(1)); + let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000); unsafe { wdt.unleash(); } From 5044361ddd6e26ff3372519d7947e603d75a8a60 Mon Sep 17 00:00:00 2001 From: chemicstry Date: Mon, 11 Jul 2022 00:17:15 +0300 Subject: [PATCH 8/9] Bump stm32-data --- stm32-data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stm32-data b/stm32-data index 56d5b8b2..b90d7cf8 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit 56d5b8b2aee7026b4f9bcffc427bb8f9d48afeb5 +Subproject commit b90d7cf8cb0610e333e4eef7127ae8c519558603 From 5a208d28d011761d88e12881a69ab9c0663149e2 Mon Sep 17 00:00:00 2001 From: chemicstry Date: Mon, 11 Jul 2022 00:37:00 +0300 Subject: [PATCH 9/9] Fix g0 rcc build --- embassy-stm32/src/rcc/g0.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index 3ca65cf3..6bfae46b 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -361,7 +361,7 @@ pub(crate) unsafe fn init(config: Config) { // Enable LSI RCC.csr().write(|w| w.set_lsion(true)); while !RCC.csr().read().lsirdy() {} - (LSI_FREQ, Sw::LSI) + (LSI_FREQ.0, Sw::LSI) } };