| @@ -9,7 +9,7 @@ fn main() { | |||||||
|         .expect("No stm32xx Cargo feature enabled") |         .expect("No stm32xx Cargo feature enabled") | ||||||
|         .strip_prefix("CARGO_FEATURE_") |         .strip_prefix("CARGO_FEATURE_") | ||||||
|         .unwrap() |         .unwrap() | ||||||
|         .to_ascii_uppercase(); |         .to_ascii_lowercase(); | ||||||
|  |  | ||||||
|     let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); |     let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||||||
|     let out_file = out_dir.join("generated.rs").to_string_lossy().to_string(); |     let out_file = out_dir.join("generated.rs").to_string_lossy().to_string(); | ||||||
| @@ -30,6 +30,15 @@ fn main() { | |||||||
|         }; |         }; | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|  |     let mut chip_and_core = chip_name.split('_'); | ||||||
|  |     let chip = chip_and_core.next().expect("Unexpected stm32xx feature"); | ||||||
|  |  | ||||||
|  |     if let Some(core) = chip_and_core.next() { | ||||||
|  |         println!("cargo:rustc-cfg={}_{}", &chip[..(chip.len() - 2)], core); | ||||||
|  |     } else { | ||||||
|  |         println!("cargo:rustc-cfg={}", &chip[..(chip.len() - 2)]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     println!("cargo:rerun-if-changed=build.rs"); |     println!("cargo:rerun-if-changed=build.rs"); | ||||||
|     println!("cargo:rerun-if-changed=gen.py"); |     println!("cargo:rerun-if-changed=gen.py"); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								embassy-stm32/src/pwr/f4.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								embassy-stm32/src/pwr/f4.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  |  | ||||||
| @@ -1,4 +1,5 @@ | |||||||
| #[cfg_attr(any(pwr_h7, pwr_h7smps), path = "h7.rs")] | #[cfg_attr(any(pwr_h7, pwr_h7smps), path = "h7.rs")] | ||||||
|  | #[cfg_attr(pwr_f4, path = "f4.rs")] | ||||||
| mod _version; | mod _version; | ||||||
|  |  | ||||||
| pub use _version::*; | pub use _version::*; | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								embassy-stm32/src/rcc/f4/max.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								embassy-stm32/src/rcc/f4/max.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | #[cfg(stm32f401)] | ||||||
|  | pub(crate) const SYSCLK_MAX: u32 = 84_000_000; | ||||||
|  |  | ||||||
|  | #[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))] | ||||||
|  | pub(crate) const SYSCLK_MAX: u32 = 168_000_000; | ||||||
|  |  | ||||||
|  | #[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))] | ||||||
|  | pub(crate) const SYSCLK_MAX: u32 = 100_000_000; | ||||||
|  |  | ||||||
|  | #[cfg(any( | ||||||
|  |     stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479, | ||||||
|  | ))] | ||||||
|  | pub(crate) const SYSCLK_MAX: u32 = 180_000_000; | ||||||
|  |  | ||||||
|  | #[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))] | ||||||
|  | pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX; | ||||||
|  |  | ||||||
|  | #[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))] | ||||||
|  | pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2; | ||||||
|  |  | ||||||
|  | pub(crate) const PCLK1_MAX: u32 = PCLK2_MAX / 2; | ||||||
| @@ -1,207 +1,325 @@ | |||||||
| pub use super::types::*; | use crate::pac::{FLASH, PWR, RCC}; | ||||||
| use crate::pac; | use crate::peripherals; | ||||||
| use crate::peripherals::{self, RCC}; |  | ||||||
| use crate::rcc::{get_freqs, set_freqs, Clocks}; | use crate::rcc::{get_freqs, set_freqs, Clocks}; | ||||||
| use crate::time::Hertz; | use crate::time::Hertz; | ||||||
| use crate::time::U32Ext; |  | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
| use embassy::util::Unborrow; | use embassy::util::Unborrow; | ||||||
| use embassy_hal_common::unborrow; |  | ||||||
| use pac::rcc::vals::{Hpre, Ppre, Sw}; |  | ||||||
|  |  | ||||||
| /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, | mod max; | ||||||
| /// and with the addition of the init function to configure a system clock. | use max::{PCLK1_MAX, PCLK2_MAX}; | ||||||
|  |  | ||||||
| /// Only the basic setup using the HSE and HSI clocks are supported as of now. | const HSI: u32 = 16_000_000; | ||||||
|  |  | ||||||
| /// HSI speed |  | ||||||
| pub const HSI_FREQ: u32 = 16_000_000; |  | ||||||
|  |  | ||||||
| /// System clock mux source |  | ||||||
| #[derive(Clone, Copy)] |  | ||||||
| pub enum ClockSrc { |  | ||||||
|     HSE(Hertz), |  | ||||||
|     HSI16, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl Into<Ppre> 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<Hpre> 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, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /// Clocks configutation | /// Clocks configutation | ||||||
|  | #[non_exhaustive] | ||||||
|  | #[derive(Default)] | ||||||
| pub struct Config { | pub struct Config { | ||||||
|     mux: ClockSrc, |     pub hse: Option<Hertz>, | ||||||
|     ahb_pre: AHBPrescaler, |     pub bypass_hse: bool, | ||||||
|     apb1_pre: APBPrescaler, |     pub pll48: bool, | ||||||
|     apb2_pre: APBPrescaler, |     pub sys_ck: Option<Hertz>, | ||||||
| } |     pub hclk: Option<Hertz>, | ||||||
|  |     pub pclk1: Option<Hertz>, | ||||||
| impl Default for Config { |     pub pclk2: Option<Hertz>, | ||||||
|     #[inline] |     pub enable_debug_wfe: bool, | ||||||
|     fn default() -> Config { |  | ||||||
|         Config { |  | ||||||
|             mux: ClockSrc::HSI16, |  | ||||||
|             ahb_pre: AHBPrescaler::NotDivided, |  | ||||||
|             apb1_pre: APBPrescaler::NotDivided, |  | ||||||
|             apb2_pre: APBPrescaler::NotDivided, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl Config { |  | ||||||
|     #[inline] |  | ||||||
|     pub fn clock_src(mut self, mux: ClockSrc) -> Self { |  | ||||||
|         self.mux = mux; |  | ||||||
|         self |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #[inline] |  | ||||||
|     pub fn ahb_pre(mut self, pre: AHBPrescaler) -> Self { |  | ||||||
|         self.ahb_pre = pre; |  | ||||||
|         self |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #[inline] |  | ||||||
|     pub fn apb1_pre(mut self, pre: APBPrescaler) -> Self { |  | ||||||
|         self.apb1_pre = pre; |  | ||||||
|         self |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #[inline] |  | ||||||
|     pub fn apb2_pre(mut self, pre: APBPrescaler) -> Self { |  | ||||||
|         self.apb2_pre = pre; |  | ||||||
|         self |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /// RCC peripheral | /// RCC peripheral | ||||||
| pub struct Rcc<'d> { | pub struct Rcc<'d> { | ||||||
|     _rb: peripherals::RCC, |     config: Config, | ||||||
|     phantom: PhantomData<&'d mut peripherals::RCC>, |     phantom: PhantomData<&'d mut peripherals::RCC>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d> Rcc<'d> { | impl<'d> Rcc<'d> { | ||||||
|     pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self { |     pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self { | ||||||
|         unborrow!(rcc); |  | ||||||
|         Self { |         Self { | ||||||
|             _rb: rcc, |             config, | ||||||
|             phantom: PhantomData, |             phantom: PhantomData, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn freeze(mut self) -> Clocks { | ||||||
|  |         use super::sealed::RccPeripheral; | ||||||
|  |         use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw}; | ||||||
|  |  | ||||||
|  |         let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI); | ||||||
|  |         let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); | ||||||
|  |         let sysclk_on_pll = sysclk != pllsrcclk; | ||||||
|  |  | ||||||
|  |         let plls = self.setup_pll( | ||||||
|  |             pllsrcclk, | ||||||
|  |             self.config.hse.is_some(), | ||||||
|  |             if sysclk_on_pll { Some(sysclk) } else { None }, | ||||||
|  |             self.config.pll48, | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         if self.config.pll48 { | ||||||
|  |             assert!( | ||||||
|  |                 // USB specification allows +-0.25% | ||||||
|  |                 plls.pll48clk | ||||||
|  |                     .map(|freq| (48_000_000 - freq as i32).abs() <= 120_000) | ||||||
|  |                     .unwrap_or(false) | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let sysclk = if sysclk_on_pll { | ||||||
|  |             plls.pllsysclk.unwrap() | ||||||
|  |         } else { | ||||||
|  |             sysclk | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk); | ||||||
|  |         let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk { | ||||||
|  |             0 => unreachable!(), | ||||||
|  |             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 AHB clock | ||||||
|  |         let hclk = sysclk / hpre_div; | ||||||
|  |  | ||||||
|  |         let pclk1 = self | ||||||
|  |             .config | ||||||
|  |             .pclk1 | ||||||
|  |             .map(|p| p.0) | ||||||
|  |             .unwrap_or_else(|| core::cmp::min(PCLK1_MAX, hclk)); | ||||||
|  |         let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 { | ||||||
|  |             0 => unreachable!(), | ||||||
|  |             1 => (0b000, 1), | ||||||
|  |             2 => (0b100, 2), | ||||||
|  |             3..=5 => (0b101, 4), | ||||||
|  |             6..=11 => (0b110, 8), | ||||||
|  |             _ => (0b111, 16), | ||||||
|  |         }; | ||||||
|  |         let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; | ||||||
|  |  | ||||||
|  |         // Calculate real APB1 clock | ||||||
|  |         let pclk1 = hclk / ppre1; | ||||||
|  |         assert!(pclk1 <= PCLK1_MAX); | ||||||
|  |  | ||||||
|  |         let pclk2 = self | ||||||
|  |             .config | ||||||
|  |             .pclk2 | ||||||
|  |             .map(|p| p.0) | ||||||
|  |             .unwrap_or_else(|| core::cmp::min(PCLK2_MAX, hclk)); | ||||||
|  |         let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 { | ||||||
|  |             0 => unreachable!(), | ||||||
|  |             1 => (0b000, 1), | ||||||
|  |             2 => (0b100, 2), | ||||||
|  |             3..=5 => (0b101, 4), | ||||||
|  |             6..=11 => (0b110, 8), | ||||||
|  |             _ => (0b111, 16), | ||||||
|  |         }; | ||||||
|  |         let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; | ||||||
|  |  | ||||||
|  |         // Calculate real APB2 clock | ||||||
|  |         let pclk2 = hclk / ppre2; | ||||||
|  |         assert!(pclk2 <= PCLK2_MAX); | ||||||
|  |  | ||||||
|  |         Self::flash_setup(sysclk); | ||||||
|  |  | ||||||
|  |         if self.config.hse.is_some() { | ||||||
|  |             // NOTE(unsafe) We own the peripheral block | ||||||
|  |             unsafe { | ||||||
|  |                 RCC.cr().modify(|w| { | ||||||
|  |                     w.set_hsebyp(Hsebyp(self.config.bypass_hse as u8)); | ||||||
|  |                     w.set_hseon(true); | ||||||
|  |                 }); | ||||||
|  |                 while !RCC.cr().read().hserdy() {} | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if plls.use_pll { | ||||||
|  |             unsafe { | ||||||
|  |                 RCC.cr().modify(|w| w.set_pllon(true)); | ||||||
|  |  | ||||||
|  |                 if hclk > 168_000_000 { | ||||||
|  |                     peripherals::PWR::enable(); | ||||||
|  |  | ||||||
|  |                     PWR.cr().modify(|w| w.set_oden(true)); | ||||||
|  |                     while !PWR.csr().read().odrdy() {} | ||||||
|  |  | ||||||
|  |                     PWR.cr().modify(|w| w.set_odswen(true)); | ||||||
|  |                     while !PWR.csr().read().odswrdy() {} | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 while !RCC.cr().read().pllrdy() {} | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         unsafe { | ||||||
|  |             RCC.cfgr().modify(|w| { | ||||||
|  |                 w.set_ppre2(Ppre(ppre2_bits)); | ||||||
|  |                 w.set_ppre1(Ppre(ppre1_bits)); | ||||||
|  |                 w.set_hpre(hpre_bits); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             // Wait for the new prescalers to kick in | ||||||
|  |             // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write" | ||||||
|  |             cortex_m::asm::delay(16); | ||||||
|  |  | ||||||
|  |             RCC.cfgr().modify(|w| { | ||||||
|  |                 w.set_sw(if sysclk_on_pll { | ||||||
|  |                     Sw::PLL | ||||||
|  |                 } else if self.config.hse.is_some() { | ||||||
|  |                     Sw::HSE | ||||||
|  |                 } else { | ||||||
|  |                     Sw::HSI | ||||||
|  |                 }) | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if self.config.enable_debug_wfe { | ||||||
|  |             unsafe { | ||||||
|  |                 RCC.ahb1enr().modify(|w| w.set_dma1en(true)); | ||||||
|  |                 critical_section::with(|_| { | ||||||
|  |                     crate::dbgmcu::Dbgmcu::enable_all(); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Clocks { | ||||||
|  |             sys: Hertz(sysclk), | ||||||
|  |             apb1: Hertz(pclk1), | ||||||
|  |             apb2: Hertz(pclk2), | ||||||
|  |  | ||||||
|  |             apb1_tim: Hertz(pclk1 * timer_mul1), | ||||||
|  |             apb2_tim: Hertz(pclk2 * timer_mul2), | ||||||
|  |  | ||||||
|  |             ahb1: Hertz(hclk), | ||||||
|  |             ahb2: Hertz(hclk), | ||||||
|  |             ahb3: Hertz(hclk), | ||||||
|  |  | ||||||
|  |             pll48: plls.pll48clk.map(Hertz), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // Safety: RCC init must have been called |     // Safety: RCC init must have been called | ||||||
|     pub fn clocks(&self) -> &'static Clocks { |     pub fn clocks(&self) -> &'static Clocks { | ||||||
|         unsafe { get_freqs() } |         unsafe { get_freqs() } | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |  | ||||||
| /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration |     fn setup_pll( | ||||||
| pub trait RccExt { |         &mut self, | ||||||
|     fn freeze(self, config: Config) -> Clocks; |         pllsrcclk: u32, | ||||||
| } |         use_hse: bool, | ||||||
|  |         pllsysclk: Option<u32>, | ||||||
|  |         pll48clk: bool, | ||||||
|  |     ) -> PllResults { | ||||||
|  |         use crate::pac::rcc::vals::{Pllp, Pllsrc}; | ||||||
|  |  | ||||||
| impl RccExt for RCC { |         let sysclk = pllsysclk.unwrap_or(pllsrcclk); | ||||||
|     #[inline] |         if pllsysclk.is_none() && !pll48clk { | ||||||
|     fn freeze(self, cfgr: Config) -> Clocks { |             // NOTE(unsafe) We have a mutable borrow to the owner of the RegBlock | ||||||
|         let rcc = pac::RCC; |             unsafe { | ||||||
|         let (sys_clk, sw) = match cfgr.mux { |                 RCC.pllcfgr() | ||||||
|             ClockSrc::HSI16 => { |                     .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); | ||||||
|                 // Enable HSI16 |  | ||||||
|                 unsafe { |  | ||||||
|                     rcc.cr().modify(|w| w.set_hsion(true)); |  | ||||||
|                     while !rcc.cr().read().hsirdy() {} |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 (HSI_FREQ, Sw::HSI) |  | ||||||
|             } |             } | ||||||
|             ClockSrc::HSE(freq) => { |  | ||||||
|                 // Enable HSE |  | ||||||
|                 unsafe { |  | ||||||
|                     rcc.cr().modify(|w| w.set_hseon(true)); |  | ||||||
|                     while !rcc.cr().read().hserdy() {} |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 (freq.0, Sw::HSE) |             return PllResults { | ||||||
|             } |                 use_pll: false, | ||||||
|  |                 pllsysclk: None, | ||||||
|  |                 pll48clk: None, | ||||||
|  |             }; | ||||||
|  |         } | ||||||
|  |         // Input divisor from PLL source clock, must result to frequency in | ||||||
|  |         // the range from 1 to 2 MHz | ||||||
|  |         let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000; | ||||||
|  |         let pllm_max = pllsrcclk / 1_000_000; | ||||||
|  |  | ||||||
|  |         // Sysclk output divisor must be one of 2, 4, 6 or 8 | ||||||
|  |         let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1); | ||||||
|  |  | ||||||
|  |         let target_freq = if pll48clk { | ||||||
|  |             48_000_000 | ||||||
|  |         } else { | ||||||
|  |             sysclk * sysclk_div | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|  |         // Find the lowest pllm value that minimize the difference between | ||||||
|  |         // target frequency and the real vco_out frequency. | ||||||
|  |         let pllm = (pllm_min..=pllm_max) | ||||||
|  |             .min_by_key(|pllm| { | ||||||
|  |                 let vco_in = pllsrcclk / pllm; | ||||||
|  |                 let plln = target_freq / vco_in; | ||||||
|  |                 target_freq - vco_in * plln | ||||||
|  |             }) | ||||||
|  |             .unwrap(); | ||||||
|  |  | ||||||
|  |         let vco_in = pllsrcclk / pllm; | ||||||
|  |         assert!((1_000_000..=2_000_000).contains(&vco_in)); | ||||||
|  |  | ||||||
|  |         // Main scaler, must result in >= 100MHz (>= 192MHz for F401) | ||||||
|  |         // and <= 432MHz, min 50, max 432 | ||||||
|  |         let plln = if pll48clk { | ||||||
|  |             // try the different valid pllq according to the valid | ||||||
|  |             // main scaller values, and take the best | ||||||
|  |             let pllq = (4..=9) | ||||||
|  |                 .min_by_key(|pllq| { | ||||||
|  |                     let plln = 48_000_000 * pllq / vco_in; | ||||||
|  |                     let pll48_diff = 48_000_000 - vco_in * plln / pllq; | ||||||
|  |                     let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs(); | ||||||
|  |                     (pll48_diff, sysclk_diff) | ||||||
|  |                 }) | ||||||
|  |                 .unwrap(); | ||||||
|  |             48_000_000 * pllq / vco_in | ||||||
|  |         } else { | ||||||
|  |             sysclk * sysclk_div / vco_in | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         let pllp = (sysclk_div / 2) - 1; | ||||||
|  |  | ||||||
|  |         let pllq = (vco_in * plln + 47_999_999) / 48_000_000; | ||||||
|  |         let real_pll48clk = vco_in * plln / pllq; | ||||||
|  |  | ||||||
|         unsafe { |         unsafe { | ||||||
|             rcc.cfgr().modify(|w| { |             RCC.pllcfgr().modify(|w| { | ||||||
|                 w.set_sw(sw.into()); |                 w.set_pllm(pllm as u8); | ||||||
|                 w.set_hpre(cfgr.ahb_pre.into()); |                 w.set_plln(plln as u16); | ||||||
|                 w.set_ppre1(cfgr.apb1_pre.into()); |                 w.set_pllp(Pllp(pllp as u8)); | ||||||
|                 w.set_ppre2(cfgr.apb2_pre.into()); |                 w.set_pllq(pllq as u8); | ||||||
|  |                 w.set_pllsrc(Pllsrc(use_hse as u8)); | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         let ahb_freq: u32 = match cfgr.ahb_pre { |         let real_pllsysclk = vco_in * plln / sysclk_div; | ||||||
|             AHBPrescaler::NotDivided => sys_clk, |  | ||||||
|             pre => { |  | ||||||
|                 let pre: Hpre = pre.into(); |  | ||||||
|                 let pre = 1 << (pre.0 as u32 - 7); |  | ||||||
|                 sys_clk / pre |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { |         PllResults { | ||||||
|             APBPrescaler::NotDivided => (ahb_freq, ahb_freq), |             use_pll: true, | ||||||
|             pre => { |             pllsysclk: Some(real_pllsysclk), | ||||||
|                 let pre: Ppre = pre.into(); |             pll48clk: if pll48clk { Some(real_pll48clk) } else { None }, | ||||||
|                 let pre: u8 = 1 << (pre.0 - 3); |  | ||||||
|                 let freq = ahb_freq / pre as u32; |  | ||||||
|                 (freq, freq * 2) |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { |  | ||||||
|             APBPrescaler::NotDivided => (ahb_freq, ahb_freq), |  | ||||||
|             pre => { |  | ||||||
|                 let pre: Ppre = pre.into(); |  | ||||||
|                 let pre: u8 = 1 << (pre.0 - 3); |  | ||||||
|                 let freq = ahb_freq / (1 << (pre as u8 - 3)); |  | ||||||
|                 (freq, freq * 2) |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         Clocks { |  | ||||||
|             sys: sys_clk.hz(), |  | ||||||
|             ahb1: ahb_freq.hz(), |  | ||||||
|             ahb2: ahb_freq.hz(), |  | ||||||
|             ahb3: ahb_freq.hz(), |  | ||||||
|             apb1: apb1_freq.hz(), |  | ||||||
|             apb2: apb2_freq.hz(), |  | ||||||
|             apb1_tim: apb1_tim_freq.hz(), |  | ||||||
|             apb2_tim: apb2_tim_freq.hz(), |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn flash_setup(sysclk: u32) { | ||||||
|  |         use crate::pac::flash::vals::Latency; | ||||||
|  |  | ||||||
|  |         // Be conservative with voltage ranges | ||||||
|  |         const FLASH_LATENCY_STEP: u32 = 30_000_000; | ||||||
|  |  | ||||||
|  |         critical_section::with(|_| unsafe { | ||||||
|  |             FLASH | ||||||
|  |                 .acr() | ||||||
|  |                 .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| pub unsafe fn init(config: Config) { | pub unsafe fn init(config: Config) { | ||||||
|     let r = <peripherals::RCC as embassy::util::Steal>::steal(); |     let r = <peripherals::RCC as embassy::util::Steal>::steal(); | ||||||
|     let clocks = r.freeze(config); |     let clocks = Rcc::new(r, config).freeze(); | ||||||
|     set_freqs(clocks); |     set_freqs(clocks); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | struct PllResults { | ||||||
|  |     use_pll: bool, | ||||||
|  |     pllsysclk: Option<u32>, | ||||||
|  |     pll48clk: Option<u32>, | ||||||
|  | } | ||||||
|   | |||||||
| @@ -31,6 +31,9 @@ pub struct Clocks { | |||||||
|  |  | ||||||
|     #[cfg(any(rcc_h7))] |     #[cfg(any(rcc_h7))] | ||||||
|     pub apb4: Hertz, |     pub apb4: Hertz, | ||||||
|  |  | ||||||
|  |     #[cfg(rcc_f4)] | ||||||
|  |     pub pll48: Option<Hertz>, | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Frozen clock frequencies | /// Frozen clock frequencies | ||||||
|   | |||||||
							
								
								
									
										34
									
								
								examples/stm32f4/src/bin/hello.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								examples/stm32f4/src/bin/hello.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | #![feature(trait_alias)] | ||||||
|  | #![feature(min_type_alias_impl_trait)] | ||||||
|  | #![feature(impl_trait_in_bindings)] | ||||||
|  | #![feature(type_alias_impl_trait)] | ||||||
|  | #![allow(incomplete_features)] | ||||||
|  |  | ||||||
|  | use defmt::{info, panic}; | ||||||
|  | use embassy::executor::Spawner; | ||||||
|  | use embassy::time::{Duration, Timer}; | ||||||
|  | use embassy_stm32::rcc::Config as RccConfig; | ||||||
|  | use embassy_stm32::time::Hertz; | ||||||
|  | use embassy_stm32::Config; | ||||||
|  | use embassy_stm32::Peripherals; | ||||||
|  |  | ||||||
|  | #[path = "../example_common.rs"] | ||||||
|  | mod example_common; | ||||||
|  |  | ||||||
|  | fn config() -> Config { | ||||||
|  |     let mut rcc_config = RccConfig::default(); | ||||||
|  |     rcc_config.sys_ck = Some(Hertz(84_000_000)); | ||||||
|  |     rcc_config.enable_debug_wfe = true; | ||||||
|  |  | ||||||
|  |     Config::default().rcc(rcc_config) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[embassy::main(config = "config()")] | ||||||
|  | async fn main(_spawner: Spawner, _p: Peripherals) -> ! { | ||||||
|  |     loop { | ||||||
|  |         info!("Hello World!"); | ||||||
|  |         Timer::after(Duration::from_secs(1)).await; | ||||||
|  |     } | ||||||
|  | } | ||||||
 Submodule stm32-data updated: 62c8985228...0ad27b2fd1
									
								
							| @@ -1,5 +1,4 @@ | |||||||
| use chiptool::generate::CommonModule; | use chiptool::generate::CommonModule; | ||||||
| use proc_macro2::TokenStream; |  | ||||||
| use regex::Regex; | use regex::Regex; | ||||||
| use serde::Deserialize; | use serde::Deserialize; | ||||||
| use std::collections::{HashMap, HashSet}; | use std::collections::{HashMap, HashSet}; | ||||||
| @@ -10,7 +9,6 @@ use std::fs::File; | |||||||
| use std::io::Write; | use std::io::Write; | ||||||
| use std::path::Path; | use std::path::Path; | ||||||
| use std::path::PathBuf; | use std::path::PathBuf; | ||||||
| use std::str::FromStr; |  | ||||||
|  |  | ||||||
| use chiptool::util::ToSanitizedSnakeCase; | use chiptool::util::ToSanitizedSnakeCase; | ||||||
| use chiptool::{generate, ir, transform}; | use chiptool::{generate, ir, transform}; | ||||||
| @@ -54,7 +52,7 @@ pub struct Peripheral { | |||||||
|     #[serde(default)] |     #[serde(default)] | ||||||
|     pub dma_channels: HashMap<String, Vec<PeripheralDmaChannel>>, |     pub dma_channels: HashMap<String, Vec<PeripheralDmaChannel>>, | ||||||
|     #[serde(default)] |     #[serde(default)] | ||||||
|     pub interrupts: HashMap<String, String> |     pub interrupts: HashMap<String, String>, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug, Eq, PartialEq, Clone, Deserialize)] | #[derive(Debug, Eq, PartialEq, Clone, Deserialize)] | ||||||
| @@ -353,8 +351,8 @@ pub fn gen(options: Options) { | |||||||
|                     row.push(name.clone()); |                     row.push(name.clone()); | ||||||
|                     row.push(bi.module.clone()); |                     row.push(bi.module.clone()); | ||||||
|                     row.push(bi.block.clone()); |                     row.push(bi.block.clone()); | ||||||
|                     row.push( signal.clone() ); |                     row.push(signal.clone()); | ||||||
|                     row.push( irq_name.to_ascii_uppercase() ); |                     row.push(irq_name.to_ascii_uppercase()); | ||||||
|                     interrupt_table.push(row) |                     interrupt_table.push(row) | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user