Merge #854
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:
		
						commit
						c6a11db39e
					
				| @ -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 { | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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
 | ||||
| @ -451,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 | ||||
|  | ||||
| @ -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<PllConfig>) { | ||||
|     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<PllConfig>) { | ||||
|             (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); | ||||
|                     ( | ||||
|  | ||||
| @ -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; | ||||
| 
 | ||||
|  | ||||
| @ -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; | ||||
| 
 | ||||
|  | ||||
| @ -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
 | ||||
| @ -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) | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
| @ -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(CSI_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), | ||||
|  | ||||
| @ -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 | ||||
|                 } | ||||
|             }; | ||||
| 
 | ||||
|  | ||||
| @ -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 | ||||
|                 } | ||||
|             }; | ||||
| 
 | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
| @ -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.
 | ||||
| @ -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| { | ||||
|  | ||||
| @ -1,21 +1,57 @@ | ||||
| use core::marker::PhantomData; | ||||
| 
 | ||||
| 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::rcc::LSI_FREQ; | ||||
| 
 | ||||
| pub struct IndependentWatchdog<'d, T: Instance> { | ||||
|     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> { | ||||
|     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); | ||||
| 
 | ||||
|         // 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(); | ||||
|         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 { | ||||
|  | ||||
							
								
								
									
										46
									
								
								examples/stm32f4/src/bin/wdt.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								examples/stm32f4/src/bin/wdt.rs
									
									
									
									
									
										Normal 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 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user