854: Implement IWDG timeout calculation r=Dirbaio a=chemicstry

Allow specifying `IndependentWatchdog` timeout as `Duration` instead of prescaler value.

Since IWDG is clocked from LSI, which differs between families, I standardized HSI/LSI definitions in RCC and used that.

Co-authored-by: chemicstry <chemicstry@gmail.com>
This commit is contained in:
bors[bot] 2022-07-10 21:45:34 +00:00 committed by GitHub
commit c6a11db39e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 204 additions and 70 deletions

View file

@ -3,7 +3,11 @@ use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Sw, Usbsw};
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, RCC};
use crate::time::Hertz; 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 /// Configuration of the clocks
/// ///
@ -24,14 +28,14 @@ pub struct Config {
} }
pub(crate) unsafe fn init(config: 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(|| { let (src_clk, use_hsi48) = config.hse.map(|v| (v.0, false)).unwrap_or_else(|| {
#[cfg(not(stm32f0x0))] #[cfg(not(stm32f0x0))]
if config.hsi48 { if config.hsi48 {
return (48_000_000, true); return (48_000_000, true);
} }
(HSI, false) (HSI_FREQ.0, false)
}); });
let (pllmul_bits, real_sysclk) = if sysclk == src_clk { let (pllmul_bits, real_sysclk) = if sysclk == src_clk {

View file

@ -6,7 +6,11 @@ use crate::pac::rcc::vals::*;
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, RCC};
use crate::time::Hertz; 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 /// Configuration of the clocks
/// ///
@ -23,12 +27,12 @@ pub struct Config {
} }
pub(crate) unsafe fn init(config: 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 sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
let pllmul = sysclk / pllsrcclk; let pllmul = sysclk / pllsrcclk;
let (pllmul_bits, real_sysclk) = if pllmul == 1 { 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 { } else {
let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16); let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16);
(Some(pllmul as u8 - 2), pllsrcclk * pllmul) (Some(pllmul as u8 - 2), pllsrcclk * pllmul)

View file

@ -8,7 +8,10 @@ use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
/// HSI speed /// 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)] #[derive(Clone, Copy)]
pub struct HSEConfig { 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")); .unwrap_or_else(|| panic!("HSE must be configured to be used as PLL input"));
hse_config.frequency hse_config.frequency
} }
PLLSrc::HSI => HSI, PLLSrc::HSI => HSI_FREQ,
}; };
// Reference: STM32F215xx/217xx datasheet Table 33. Main PLL characteristics // Reference: STM32F215xx/217xx datasheet Table 33. Main PLL characteristics
@ -451,7 +454,7 @@ pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw) = match config.mux { let (sys_clk, sw) = match config.mux {
ClockSrc::HSI => { ClockSrc::HSI => {
assert!(config.hsi, "HSI must be enabled to be used as system clock"); assert!(config.hsi, "HSI must be enabled to be used as system clock");
(HSI, Sw::HSI) (HSI_FREQ, Sw::HSI)
} }
ClockSrc::HSE => { ClockSrc::HSE => {
let hse_config = config let hse_config = config

View file

@ -4,7 +4,11 @@ use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; 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 /// Clocks configutation
#[non_exhaustive] #[non_exhaustive]
@ -180,7 +184,7 @@ pub(crate) unsafe fn init(config: Config) {
fn get_sysclk(config: &Config) -> (Hertz, Option<PllConfig>) { fn get_sysclk(config: &Config) -> (Hertz, Option<PllConfig>) {
match (config.sysclk, config.hse) { match (config.sysclk, config.hse) {
(Some(sysclk), Some(hse)) if sysclk == hse => (hse, None), (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 // If the user selected System clock is different from HSI or HSE
// we will have to setup PLL clock source // we will have to setup PLL clock source
(Some(sysclk), _) => { (Some(sysclk), _) => {
@ -188,7 +192,7 @@ fn get_sysclk(config: &Config) -> (Hertz, Option<PllConfig>) {
(sysclk, Some(pll_config)) (sysclk, Some(pll_config))
} }
(None, Some(hse)) => (hse, None), (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, stm32f302xd, stm32f302xe, stm32f303xd,
stm32f303xe, stm32f398xe 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, Pllsrc::HSI_DIV_PREDIV,
into_pll_mul(multiplier), into_pll_mul(multiplier),
Some(into_pre_div(divisor)), Some(into_pre_div(divisor)),
) )
} else { } else {
let pllsrcclk = HSI / 2; let pllsrcclk = HSI_FREQ.0 / 2;
let multiplier = sysclk / pllsrcclk; let multiplier = sysclk / pllsrcclk;
assert!(multiplier <= 16); assert!(multiplier <= 16);
( (

View file

@ -4,7 +4,11 @@ use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; 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 /// Clocks configuration
#[non_exhaustive] #[non_exhaustive]
@ -108,7 +112,7 @@ unsafe fn flash_setup(sysclk: u32) {
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
crate::peripherals::PWR::enable(); 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 = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
let sysclk_on_pll = sysclk != pllsrcclk; let sysclk_on_pll = sysclk != pllsrcclk;

View file

@ -5,7 +5,11 @@ use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; 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 /// Clocks configuration
#[non_exhaustive] #[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 = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
let sysclk_on_pll = sysclk != pllsrcclk; let sysclk_on_pll = sysclk != pllsrcclk;

View file

@ -5,10 +5,10 @@ use crate::rcc::{set_freqs, Clocks};
use crate::time::{Hertz, U32Ext}; use crate::time::{Hertz, U32Ext};
/// HSI speed /// HSI speed
pub const HSI_FREQ: u32 = 16_000_000; pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed /// LSI speed
pub const LSI_FREQ: u32 = 32_000; pub const LSI_FREQ: Hertz = Hertz(32_000);
/// System clock mux source /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -248,7 +248,7 @@ impl PllConfig {
pub(crate) unsafe fn init(self) -> u32 { pub(crate) unsafe fn init(self) -> u32 {
assert!(self.n >= 8 && self.n <= 86); assert!(self.n >= 8 && self.n <= 86);
let (src, input_freq) = match self.source { 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), PllSrc::HSE(freq) => (vals::Pllsrc::HSE, freq.0),
}; };
@ -344,7 +344,7 @@ pub(crate) unsafe fn init(config: Config) {
}); });
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
(HSI_FREQ >> div.0, Sw::HSI) (HSI_FREQ.0 >> div.0, Sw::HSI)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // Enable HSE
@ -361,7 +361,7 @@ pub(crate) unsafe fn init(config: Config) {
// Enable LSI // Enable LSI
RCC.csr().write(|w| w.set_lsion(true)); RCC.csr().write(|w| w.set_lsion(true));
while !RCC.csr().read().lsirdy() {} while !RCC.csr().read().lsirdy() {}
(LSI_FREQ, Sw::LSI) (LSI_FREQ.0, Sw::LSI)
} }
}; };

View file

@ -3,10 +3,10 @@ use crate::rcc::{set_freqs, Clocks};
use crate::time::{Hertz, U32Ext}; use crate::time::{Hertz, U32Ext};
/// HSI speed /// HSI speed
pub const HSI_FREQ: u32 = 16_000_000; pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed /// LSI speed
pub const LSI_FREQ: u32 = 32_000; pub const LSI_FREQ: Hertz = Hertz(32_000);
/// System clock mux source /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -96,7 +96,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
(HSI_FREQ, 0x01) (HSI_FREQ.0, 0x01)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // Enable HSE

View file

@ -12,10 +12,17 @@ use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
use crate::{peripherals, Unborrow}; use crate::{peripherals, Unborrow};
const HSI: Hertz = Hertz(64_000_000); /// HSI speed
const CSI: Hertz = Hertz(4_000_000); pub const HSI_FREQ: Hertz = Hertz(64_000_000);
const HSI48: Hertz = Hertz(48_000_000);
const LSI: Hertz = Hertz(32_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 /// Voltage Scale
/// ///
@ -461,7 +468,7 @@ pub(crate) unsafe fn init(mut config: Config) {
// achieved, but the mechanism for doing so is not yet // achieved, but the mechanism for doing so is not yet
// implemented here. // 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); let (sys_ck, sys_use_pll1_p) = sys_ck_setup(&mut config, srcclk);
// Configure traceclk from PLL if needed // Configure traceclk from PLL if needed
@ -491,8 +498,8 @@ pub(crate) unsafe fn init(mut config: Config) {
// per_ck from HSI by default // per_ck from HSI by default
let (per_ck, ckpersel) = match (config.per_ck == config.hse, config.per_ck) { let (per_ck, ckpersel) = match (config.per_ck == config.hse, config.per_ck) {
(true, Some(hse)) => (hse, Ckpersel::HSE), // HSE (true, Some(hse)) => (hse, Ckpersel::HSE), // HSE
(_, Some(CSI)) => (CSI, Ckpersel::CSI), // CSI (_, Some(CSI_FREQ)) => (CSI_FREQ, Ckpersel::CSI), // CSI
_ => (HSI, Ckpersel::HSI), // HSI _ => (HSI_FREQ, Ckpersel::HSI), // HSI
}; };
// D1 Core Prescaler // D1 Core Prescaler
@ -664,10 +671,10 @@ pub(crate) unsafe fn init(mut config: Config) {
ppre2, ppre2,
ppre3, ppre3,
ppre4, ppre4,
csi_ck: Some(CSI), csi_ck: Some(CSI_FREQ),
hsi_ck: Some(HSI), hsi_ck: Some(HSI_FREQ),
hsi48_ck: Some(HSI48), hsi48_ck: Some(HSI48_FREQ),
lsi_ck: Some(LSI), lsi_ck: Some(LSI_FREQ),
per_ck: Some(per_ck), per_ck: Some(per_ck),
hse_ck, hse_ck,
pll1_p_ck: pll1_p_ck.map(Hertz), pll1_p_ck: pll1_p_ck.map(Hertz),

View file

@ -5,8 +5,11 @@ use crate::pac::{CRS, SYSCFG};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::{Hertz, U32Ext}; use crate::time::{Hertz, U32Ext};
/// HSI16 speed /// HSI speed
pub const HSI16_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 /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -217,7 +220,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().write(|w| w.set_hsi16on(true)); RCC.cr().write(|w| w.set_hsi16on(true));
while !RCC.cr().read().hsi16rdyf() {} while !RCC.cr().read().hsi16rdyf() {}
(HSI16_FREQ, Sw::HSI16) (HSI_FREQ.0, Sw::HSI16)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // Enable HSE
@ -238,7 +241,7 @@ pub(crate) unsafe fn init(config: Config) {
// Enable HSI // Enable HSI
RCC.cr().write(|w| w.set_hsi16on(true)); RCC.cr().write(|w| w.set_hsi16on(true));
while !RCC.cr().read().hsi16rdyf() {} while !RCC.cr().read().hsi16rdyf() {}
HSI16_FREQ HSI_FREQ.0
} }
}; };

View file

@ -4,7 +4,10 @@ use crate::rcc::{set_freqs, Clocks};
use crate::time::{Hertz, U32Ext}; use crate::time::{Hertz, U32Ext};
/// HSI speed /// 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 /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -211,7 +214,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
(HSI_FREQ, Sw::HSI) (HSI_FREQ.0, Sw::HSI)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // Enable HSE
@ -232,7 +235,7 @@ pub(crate) unsafe fn init(config: Config) {
// Enable HSI // Enable HSI
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
HSI_FREQ HSI_FREQ.0
} }
}; };

View file

@ -3,8 +3,11 @@ use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::{Hertz, U32Ext}; use crate::time::{Hertz, U32Ext};
/// HSI16 speed /// HSI speed
pub const HSI16_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 /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -321,7 +324,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
(HSI16_FREQ, Sw::HSI16) (HSI_FREQ.0, Sw::HSI16)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // Enable HSE
@ -342,7 +345,7 @@ pub(crate) unsafe fn init(config: Config) {
// Enable HSI // Enable HSI
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
HSI16_FREQ HSI_FREQ.0
} }
PLLSource::MSI(range) => { PLLSource::MSI(range) => {
// Enable MSI // Enable MSI

View file

@ -5,8 +5,11 @@ use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::{Hertz, U32Ext}; use crate::time::{Hertz, U32Ext};
/// HSI16 speed /// HSI speed
pub const HSI16_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 /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -322,7 +325,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
(HSI16_FREQ, Sw::HSI16) (HSI_FREQ.0, Sw::HSI16)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // Enable HSE
@ -343,7 +346,7 @@ pub(crate) unsafe fn init(config: Config) {
// Enable HSI // Enable HSI
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
HSI16_FREQ HSI_FREQ.0
} }
PLLSource::MSI(range) => { PLLSource::MSI(range) => {
// Enable MSI // Enable MSI

View file

@ -4,8 +4,11 @@ use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::{Hertz, U32Ext}; use crate::time::{Hertz, U32Ext};
/// HSI16 speed /// HSI speed
pub const HSI16_FREQ: u32 = 16_000_000; pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
/// Voltage Scale /// Voltage Scale
/// ///
@ -333,13 +336,13 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
HSI16_FREQ HSI_FREQ.0
} }
ClockSrc::PLL1R(src, m, n, div) => { ClockSrc::PLL1R(src, m, n, div) => {
let freq = match src { let freq = match src {
PllSrc::MSI(_) => MSIRange::default().into(), PllSrc::MSI(_) => MSIRange::default().into(),
PllSrc::HSE(hertz) => hertz.0, PllSrc::HSE(hertz) => hertz.0,
PllSrc::HSI16 => HSI16_FREQ, PllSrc::HSI16 => HSI_FREQ.0,
}; };
// disable // disable

View file

@ -8,7 +8,10 @@ use crate::time::{Hertz, U32Ext};
/// Only the basic setup using the HSE and HSI clocks are supported as of now. /// Only the basic setup using the HSE and HSI clocks are supported as of now.
/// HSI speed /// 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 /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -106,7 +109,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
(HSI_FREQ, 0x01) (HSI_FREQ.0, 0x01)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // Enable HSE

View file

@ -1,6 +1,6 @@
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks}; 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, /// 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. /// and with the addition of the init function to configure a system clock.
@ -8,9 +8,13 @@ use crate::time::U32Ext;
/// Only the basic setup using the HSE and HSI clocks are supported as of now. /// Only the basic setup using the HSE and HSI clocks are supported as of now.
/// HSI speed /// 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 /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -203,7 +207,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
(HSI_FREQ, 0x01, VoltageScale::Range2) (HSI_FREQ.0, 0x01, VoltageScale::Range2)
} }
ClockSrc::HSE32 => { ClockSrc::HSE32 => {
// Enable HSE32 // Enable HSE32
@ -213,7 +217,7 @@ pub(crate) unsafe fn init(config: Config) {
}); });
while !RCC.cr().read().hserdy() {} while !RCC.cr().read().hserdy() {}
(HSE32_FREQ, 0x02, VoltageScale::Range1) (HSE32_FREQ.0, 0x02, VoltageScale::Range1)
} }
ClockSrc::MSI(range) => { ClockSrc::MSI(range) => {
RCC.cr().write(|w| { RCC.cr().write(|w| {

View file

@ -1,21 +1,57 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use embassy_hal_common::{unborrow, Unborrow}; use embassy_hal_common::{unborrow, Unborrow};
use stm32_metapac::iwdg::vals::Key; use stm32_metapac::iwdg::vals::{Key, Pr};
pub use stm32_metapac::iwdg::vals::Pr as Prescaler;
use crate::rcc::LSI_FREQ;
pub struct IndependentWatchdog<'d, T: Instance> { pub struct IndependentWatchdog<'d, T: Instance> {
wdg: PhantomData<&'d mut T>, wdg: PhantomData<&'d mut T>,
} }
// 12-bit counter
const MAX_RL: u16 = 0xFFF;
/// 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_us: u32) -> u16 {
(timeout_us / prescaler as u32 * LSI_FREQ.0 / 1_000_000) as u16
}
impl<'d, T: Instance> IndependentWatchdog<'d, T> { impl<'d, T: Instance> IndependentWatchdog<'d, T> {
pub fn new(_instance: impl Unborrow<Target = T> + 'd, presc: Prescaler) -> 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<Target = T> + 'd, timeout_us: u32) -> Self {
unborrow!(_instance); 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_us <= 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_us);
let wdg = T::regs(); let wdg = T::regs();
unsafe { unsafe {
wdg.kr().write(|w| w.set_key(Key::ENABLE)); 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 { IndependentWatchdog {

View file

@ -0,0 +1,46 @@
#![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, 1_000_000);
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;
// 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 {
wdt.pet();
}
}
i += 1;
}
}

@ -1 +1 @@
Subproject commit 56d5b8b2aee7026b4f9bcffc427bb8f9d48afeb5 Subproject commit b90d7cf8cb0610e333e4eef7127ae8c519558603