diff options
| author | everdrone <[email protected]> | 2025-09-27 15:47:48 +0200 |
|---|---|---|
| committer | everdrone <[email protected]> | 2025-09-27 15:47:48 +0200 |
| commit | 791ce77dba0a9302ebb1ec0aaca0b121b6cf554e (patch) | |
| tree | f36869a88bdf5f223826426d2d364266392a8725 /embassy-stm32/src/rcc | |
| parent | 81cc2f1e9fe76ad6584b6ecc8bc855946bd131b0 (diff) | |
Port RCC initialization from CMSIS HAL
Diffstat (limited to 'embassy-stm32/src/rcc')
| -rw-r--r-- | embassy-stm32/src/rcc/n6.rs | 640 |
1 files changed, 550 insertions, 90 deletions
diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs index c8dae6303..08ea2fc4e 100644 --- a/embassy-stm32/src/rcc/n6.rs +++ b/embassy-stm32/src/rcc/n6.rs | |||
| @@ -1,10 +1,15 @@ | |||
| 1 | use stm32_metapac::rcc::vals::{Cpusws, Hseext, Hsitrim, Pllsel, Syssws}; | 1 | use stm32_metapac::rcc::vals::{ |
| 2 | pub use stm32_metapac::rcc::vals::{Hsidiv as HsiPrescaler, Hsitrim as HsiCalibration, Syssw as Sysclk}; | 2 | Cpusw, Cpusws, Hseext, Hsitrim, Icint, Icsel, Msifreqsel, Plldivm, Pllmodssdis, Pllpdiv, Pllsel, Syssw, Syssws, |
| 3 | }; | ||
| 4 | pub use stm32_metapac::rcc::vals::{ | ||
| 5 | Hpre as AhbPrescaler, Hsidiv as HsiPrescaler, Hsitrim as HsiCalibration, Ppre as ApbPrescaler, | ||
| 6 | }; | ||
| 3 | 7 | ||
| 4 | use crate::pac::{PWR, RCC, SYSCFG}; | 8 | use crate::pac::{PWR, RCC, SYSCFG}; |
| 5 | use crate::time::Hertz; | 9 | use crate::time::Hertz; |
| 6 | 10 | ||
| 7 | pub const HSI_FREQ: Hertz = Hertz(64_000_000); | 11 | pub const HSI_FREQ: Hertz = Hertz(64_000_000); |
| 12 | pub const LSE_FREQ: Hertz = Hertz(32_768); | ||
| 8 | 13 | ||
| 9 | #[derive(Clone, Copy, Eq, PartialEq)] | 14 | #[derive(Clone, Copy, Eq, PartialEq)] |
| 10 | pub enum HseMode { | 15 | pub enum HseMode { |
| @@ -27,7 +32,7 @@ pub struct Hse { | |||
| 27 | #[derive(Clone, Copy, Eq, PartialEq)] | 32 | #[derive(Clone, Copy, Eq, PartialEq)] |
| 28 | pub struct Hsi { | 33 | pub struct Hsi { |
| 29 | pub pre: HsiPrescaler, | 34 | pub pre: HsiPrescaler, |
| 30 | pub calib: Hsitrim, | 35 | pub trim: Hsitrim, |
| 31 | } | 36 | } |
| 32 | 37 | ||
| 33 | #[derive(Clone, Copy, PartialEq)] | 38 | #[derive(Clone, Copy, PartialEq)] |
| @@ -36,13 +41,108 @@ pub enum SupplyConfig { | |||
| 36 | External, | 41 | External, |
| 37 | } | 42 | } |
| 38 | 43 | ||
| 44 | #[derive(Clone, Copy, PartialEq)] | ||
| 45 | pub enum CpuClk { | ||
| 46 | Hse, | ||
| 47 | Pll { source: Icsel, divider: Icint }, | ||
| 48 | Msi, | ||
| 49 | Hsi, | ||
| 50 | } | ||
| 51 | |||
| 52 | impl CpuClk { | ||
| 53 | const fn to_bits(self) -> u8 { | ||
| 54 | match self { | ||
| 55 | Self::Hsi => 0x0, | ||
| 56 | Self::Msi => 0x1, | ||
| 57 | Self::Hse => 0x2, | ||
| 58 | Self::Pll { .. } => 0x3, | ||
| 59 | } | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | #[derive(Clone, Copy, PartialEq)] | ||
| 64 | pub struct IcConfig { | ||
| 65 | source: Icsel, | ||
| 66 | divider: Icint, | ||
| 67 | } | ||
| 68 | |||
| 69 | #[derive(Clone, Copy, PartialEq)] | ||
| 70 | pub enum SysClk { | ||
| 71 | Hse, | ||
| 72 | Pll { | ||
| 73 | ic2: IcConfig, | ||
| 74 | ic6: IcConfig, | ||
| 75 | ic11: IcConfig, | ||
| 76 | }, | ||
| 77 | Msi, | ||
| 78 | Hsi, | ||
| 79 | } | ||
| 80 | |||
| 81 | impl SysClk { | ||
| 82 | const fn to_bits(self) -> u8 { | ||
| 83 | match self { | ||
| 84 | Self::Hsi => 0x0, | ||
| 85 | Self::Msi => 0x1, | ||
| 86 | Self::Hse => 0x2, | ||
| 87 | Self::Pll { .. } => 0x3, | ||
| 88 | } | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | #[derive(Clone, Copy, PartialEq)] | ||
| 93 | pub struct Msi { | ||
| 94 | pub freq: Msifreqsel, | ||
| 95 | pub trim: u8, | ||
| 96 | } | ||
| 97 | |||
| 98 | #[derive(Clone, Copy, PartialEq)] | ||
| 99 | pub struct PllOscillator { | ||
| 100 | pub source: Pllsel, | ||
| 101 | pub divm: Plldivm, | ||
| 102 | pub fractional: u32, | ||
| 103 | pub divn: u16, | ||
| 104 | pub divp1: Pllpdiv, | ||
| 105 | pub divp2: Pllpdiv, | ||
| 106 | } | ||
| 107 | |||
| 108 | #[derive(Clone, Copy, PartialEq)] | ||
| 109 | pub enum Pll { | ||
| 110 | Oscillator { | ||
| 111 | source: Pllsel, | ||
| 112 | m: Plldivm, | ||
| 113 | fractional: u32, | ||
| 114 | n: u16, | ||
| 115 | p1: Pllpdiv, | ||
| 116 | p2: Pllpdiv, | ||
| 117 | }, | ||
| 118 | Bypass { | ||
| 119 | source: Pllsel, | ||
| 120 | }, | ||
| 121 | } | ||
| 122 | |||
| 39 | /// Configuration of the core clocks | 123 | /// Configuration of the core clocks |
| 40 | #[non_exhaustive] | 124 | #[non_exhaustive] |
| 41 | #[derive(Clone, Copy)] | 125 | #[derive(Clone, Copy)] |
| 42 | pub struct Config { | 126 | pub struct Config { |
| 43 | pub hsi: Option<Hsi>, | 127 | pub hsi: Option<Hsi>, |
| 44 | pub hse: Option<Hse>, | 128 | pub hse: Option<Hse>, |
| 45 | pub sys: Sysclk, | 129 | pub msi: Option<Msi>, |
| 130 | pub lsi: bool, | ||
| 131 | pub lse: bool, | ||
| 132 | |||
| 133 | pub sys: SysClk, | ||
| 134 | pub cpu: CpuClk, | ||
| 135 | |||
| 136 | pub pll1: Option<Pll>, | ||
| 137 | pub pll2: Option<Pll>, | ||
| 138 | pub pll3: Option<Pll>, | ||
| 139 | pub pll4: Option<Pll>, | ||
| 140 | |||
| 141 | pub ahb: AhbPrescaler, | ||
| 142 | pub apb1: ApbPrescaler, | ||
| 143 | pub apb2: ApbPrescaler, | ||
| 144 | pub apb4: ApbPrescaler, | ||
| 145 | pub apb5: ApbPrescaler, | ||
| 46 | 146 | ||
| 47 | pub supply_config: SupplyConfig, | 147 | pub supply_config: SupplyConfig, |
| 48 | } | 148 | } |
| @@ -52,13 +152,160 @@ impl Config { | |||
| 52 | Self { | 152 | Self { |
| 53 | hsi: None, | 153 | hsi: None, |
| 54 | hse: None, | 154 | hse: None, |
| 55 | sys: Sysclk::HSI, | 155 | msi: None, |
| 156 | lsi: true, | ||
| 157 | lse: false, | ||
| 158 | sys: SysClk::Hsi, | ||
| 159 | cpu: CpuClk::Hsi, | ||
| 160 | pll1: None, | ||
| 161 | pll2: None, | ||
| 162 | pll3: None, | ||
| 163 | pll4: None, | ||
| 164 | |||
| 165 | ahb: AhbPrescaler::DIV1, | ||
| 166 | apb1: ApbPrescaler::DIV1, | ||
| 167 | apb2: ApbPrescaler::DIV1, | ||
| 168 | apb4: ApbPrescaler::DIV1, | ||
| 169 | apb5: ApbPrescaler::DIV1, | ||
| 56 | 170 | ||
| 57 | supply_config: SupplyConfig::Smps, | 171 | supply_config: SupplyConfig::Smps, |
| 58 | } | 172 | } |
| 59 | } | 173 | } |
| 60 | } | 174 | } |
| 61 | 175 | ||
| 176 | fn HAL_RCC_ClockConfig(config: Config) { | ||
| 177 | // handle increasing dividers | ||
| 178 | debug!("configuring increasing pclk dividers"); | ||
| 179 | RCC.cfgr2().modify(|w| { | ||
| 180 | if config.apb1 > w.ppre1() { | ||
| 181 | debug!(" - APB1"); | ||
| 182 | w.set_ppre1(config.apb1); | ||
| 183 | } | ||
| 184 | if config.apb2 > w.ppre2() { | ||
| 185 | debug!(" - APB2"); | ||
| 186 | w.set_ppre2(config.apb2); | ||
| 187 | } | ||
| 188 | if config.apb4 > w.ppre4() { | ||
| 189 | debug!(" - APB4"); | ||
| 190 | w.set_ppre4(config.apb4); | ||
| 191 | } | ||
| 192 | if config.apb5 > w.ppre5() { | ||
| 193 | debug!(" - APB5"); | ||
| 194 | w.set_ppre5(config.apb5); | ||
| 195 | } | ||
| 196 | if config.ahb > w.hpre() { | ||
| 197 | debug!(" - AHB"); | ||
| 198 | w.set_hpre(config.ahb); | ||
| 199 | } | ||
| 200 | }); | ||
| 201 | // cpuclk | ||
| 202 | debug!("configuring cpuclk"); | ||
| 203 | match config.cpu { | ||
| 204 | CpuClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"), | ||
| 205 | CpuClk::Pll { source, divider } => { | ||
| 206 | if !RCC_IC_CheckPLLSources(RCC.iccfgr(0).read().icsel().to_bits(), source.to_bits()) { | ||
| 207 | panic!("ICx clock switch requires both origin and destination clock source to be active") | ||
| 208 | } | ||
| 209 | |||
| 210 | RCC.iccfgr(0).write(|w| { | ||
| 211 | w.set_icsel(source); | ||
| 212 | w.set_icint(divider); | ||
| 213 | }); | ||
| 214 | RCC.divensr().modify(|w| w.set_ic1ens(true)); | ||
| 215 | } | ||
| 216 | CpuClk::Msi if !RCC.sr().read().msirdy() => panic!("MSI is not ready to be selected as CPU clock source"), | ||
| 217 | CpuClk::Hsi if !RCC.sr().read().hsirdy() => panic!("HSI is not ready to be selected as CPU clock source"), | ||
| 218 | _ => {} | ||
| 219 | } | ||
| 220 | // set source | ||
| 221 | let cpusw = Cpusw::from_bits(config.cpu.to_bits()); | ||
| 222 | RCC.cfgr().modify(|w| w.set_cpusw(cpusw)); | ||
| 223 | // wait for changes to take effect | ||
| 224 | while RCC.cfgr().read().cpusws() != Cpusws::from_bits(config.cpu.to_bits()) {} | ||
| 225 | |||
| 226 | // sysclk | ||
| 227 | debug!("configuring sysclk"); | ||
| 228 | match config.sys { | ||
| 229 | SysClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"), | ||
| 230 | SysClk::Pll { ic2, ic6, ic11 } => { | ||
| 231 | if !RCC_IC_CheckPLLSources(RCC.iccfgr(1).read().icsel().to_bits(), ic2.source.to_bits()) { | ||
| 232 | panic!("IC2 clock switch requires both origin and destination clock source to be active") | ||
| 233 | } | ||
| 234 | if !RCC_IC_CheckPLLSources(RCC.iccfgr(5).read().icsel().to_bits(), ic6.source.to_bits()) { | ||
| 235 | panic!("IC6 clock switch requires both origin and destination clock source to be active") | ||
| 236 | } | ||
| 237 | if !RCC_IC_CheckPLLSources(RCC.iccfgr(10).read().icsel().to_bits(), ic11.source.to_bits()) { | ||
| 238 | panic!("IC11 clock switch requires both origin and destination clock source to be active") | ||
| 239 | } | ||
| 240 | |||
| 241 | RCC.iccfgr(1).write(|w| { | ||
| 242 | w.set_icsel(ic2.source); | ||
| 243 | w.set_icint(ic2.divider); | ||
| 244 | }); | ||
| 245 | RCC.iccfgr(5).write(|w| { | ||
| 246 | w.set_icsel(ic6.source); | ||
| 247 | w.set_icint(ic6.divider); | ||
| 248 | }); | ||
| 249 | RCC.iccfgr(10).write(|w| { | ||
| 250 | w.set_icsel(ic11.source); | ||
| 251 | w.set_icint(ic11.divider); | ||
| 252 | }); | ||
| 253 | RCC.divensr().modify(|w| { | ||
| 254 | w.set_ic2ens(true); | ||
| 255 | w.set_ic6ens(true); | ||
| 256 | w.set_ic11ens(true); | ||
| 257 | }); | ||
| 258 | } | ||
| 259 | SysClk::Msi if !RCC.sr().read().msirdy() => panic!("MSI is not ready to be selected as CPU clock source"), | ||
| 260 | SysClk::Hsi if !RCC.sr().read().hsirdy() => panic!("HSI is not ready to be selected as CPU clock source"), | ||
| 261 | _ => {} | ||
| 262 | } | ||
| 263 | // switch the system bus clock | ||
| 264 | let syssw = Syssw::from_bits(config.sys.to_bits()); | ||
| 265 | RCC.cfgr().modify(|w| w.set_syssw(syssw)); | ||
| 266 | // wait for changes to be applied | ||
| 267 | while RCC.cfgr().read().syssws() != Syssws::from_bits(config.sys.to_bits()) {} | ||
| 268 | |||
| 269 | // decreasing dividers | ||
| 270 | debug!("configuring decreasing pclk dividers"); | ||
| 271 | RCC.cfgr2().modify(|w| { | ||
| 272 | if config.ahb < w.hpre() { | ||
| 273 | debug!(" - AHB"); | ||
| 274 | w.set_hpre(config.ahb); | ||
| 275 | } | ||
| 276 | if config.apb1 < w.ppre1() { | ||
| 277 | debug!(" - APB1"); | ||
| 278 | w.set_ppre1(config.apb1); | ||
| 279 | } | ||
| 280 | if config.apb2 < w.ppre2() { | ||
| 281 | debug!(" - APB2"); | ||
| 282 | w.set_ppre2(config.apb2); | ||
| 283 | } | ||
| 284 | if config.apb4 < w.ppre4() { | ||
| 285 | debug!(" - APB4"); | ||
| 286 | w.set_ppre4(config.apb4); | ||
| 287 | } | ||
| 288 | if config.apb5 < w.ppre5() { | ||
| 289 | debug!(" - APB5"); | ||
| 290 | w.set_ppre5(config.apb5); | ||
| 291 | } | ||
| 292 | }); | ||
| 293 | } | ||
| 294 | |||
| 295 | fn RCC_PLL_Source_IsReady(source: u8) -> bool { | ||
| 296 | match source { | ||
| 297 | 0x0 if !RCC.sr().read().pllrdy(0) && !RCC.pllcfgr1(0).read().pllbyp() => false, | ||
| 298 | 0x1 if !RCC.sr().read().pllrdy(1) && !RCC.pllcfgr1(1).read().pllbyp() => false, | ||
| 299 | 0x2 if !RCC.sr().read().pllrdy(2) && !RCC.pllcfgr1(2).read().pllbyp() => false, | ||
| 300 | 0x3 if !RCC.sr().read().pllrdy(3) && !RCC.pllcfgr1(3).read().pllbyp() => false, | ||
| 301 | _ => true, | ||
| 302 | } | ||
| 303 | } | ||
| 304 | |||
| 305 | fn RCC_IC_CheckPLLSources(source1: u8, source2: u8) -> bool { | ||
| 306 | RCC_PLL_Source_IsReady(source1) && RCC_PLL_Source_IsReady(source2) | ||
| 307 | } | ||
| 308 | |||
| 62 | impl Default for Config { | 309 | impl Default for Config { |
| 63 | fn default() -> Self { | 310 | fn default() -> Self { |
| 64 | Self::new() | 311 | Self::new() |
| @@ -78,104 +325,310 @@ fn power_supply_config(supply_config: SupplyConfig) { | |||
| 78 | while !PWR.voscr().read().actvosrdy() {} | 325 | while !PWR.voscr().read().actvosrdy() {} |
| 79 | } | 326 | } |
| 80 | 327 | ||
| 81 | fn osc_config(config: Config) -> (Option<Hertz>, Option<Hertz>) { | 328 | fn pll_config(pll_config: Option<Pll>, pll_index: usize) { |
| 82 | let (cpu_clk_src, sys_clk_src) = { | 329 | let cfgr1 = RCC.pllcfgr1(pll_index); |
| 83 | let cfgr = RCC.cfgr().read(); | 330 | let cfgr2 = RCC.pllcfgr2(pll_index); |
| 84 | (cfgr.cpusws(), cfgr.syssws()) | 331 | let cfgr3 = RCC.pllcfgr3(pll_index); |
| 85 | }; | 332 | |
| 86 | let pll1_clk_src = RCC.pll1cfgr1().read().pllsel(); | 333 | match pll_config { |
| 87 | let pll2_clk_src = RCC.pll2cfgr1().read().pllsel(); | 334 | Some(Pll::Oscillator { |
| 88 | let pll3_clk_src = RCC.pll3cfgr1().read().pllsel(); | 335 | source, |
| 89 | let pll4_clk_src = RCC.pll4cfgr1().read().pllsel(); | 336 | m, |
| 90 | let sr = RCC.sr().read(); | 337 | fractional, |
| 338 | n, | ||
| 339 | p1, | ||
| 340 | p2, | ||
| 341 | }) => { | ||
| 342 | // ensure pll is disabled | ||
| 343 | RCC.ccr().write(|w| w.set_pllonc(pll_index, true)); | ||
| 344 | while RCC.sr().read().pllrdy(pll_index) {} | ||
| 345 | |||
| 346 | // ensure PLLxMODSSDIS=1 | ||
| 347 | cfgr3.modify(|w| w.set_pllmodssdis(Pllmodssdis::FRACTIONAL_DIVIDE)); | ||
| 348 | // clear bypass mode | ||
| 349 | cfgr1.modify(|w| w.set_pllbyp(false)); | ||
| 350 | // configure the pll clock source, mul and div factors | ||
| 351 | cfgr1.modify(|w| { | ||
| 352 | w.set_pllsel(source); | ||
| 353 | w.set_plldivm(m); | ||
| 354 | w.set_plldivn(n); | ||
| 355 | }); | ||
| 356 | cfgr3.modify(|w| { | ||
| 357 | w.set_pllpdiv1(p1); | ||
| 358 | w.set_pllpdiv2(p2); | ||
| 359 | }); | ||
| 360 | // configure pll divnfrac | ||
| 361 | cfgr2.modify(|w| w.set_plldivnfrac(fractional)); | ||
| 362 | // clear pllxmoddsen | ||
| 363 | cfgr3.modify(|w| w.set_pllmoddsen(false)); | ||
| 364 | // fractional mode | ||
| 365 | if fractional != 0 { | ||
| 366 | cfgr3.modify(|w| { | ||
| 367 | w.set_pllmoddsen(true); | ||
| 368 | w.set_plldacen(true); | ||
| 369 | }) | ||
| 370 | } | ||
| 371 | // enable pll post divider output | ||
| 372 | cfgr3.modify(|w| { | ||
| 373 | w.set_pllmodssrst(true); | ||
| 374 | w.set_pllpdiven(true); | ||
| 375 | }); | ||
| 376 | // enable the pll | ||
| 377 | RCC.csr().write(|w| w.pllons(pll_index)); | ||
| 378 | // wait until ready | ||
| 379 | while RCC.sr().read().pllrdy(pll_index) {} | ||
| 380 | } | ||
| 381 | Some(Pll::Bypass { source }) => { | ||
| 382 | // check if source is ready | ||
| 383 | if !RCC_PLL_Source_IsReady(source.to_bits()) { | ||
| 384 | panic!("PLL source is not ready") | ||
| 385 | } | ||
| 91 | 386 | ||
| 92 | let hsi = match config.hsi { | 387 | // ensure pll is disabled |
| 388 | RCC.ccr().write(|w| w.set_pllonc(pll_index, true)); | ||
| 389 | while RCC.sr().read().pllrdy(pll_index) {} | ||
| 390 | |||
| 391 | cfgr1.modify(|w| { | ||
| 392 | w.set_pllbyp(true); | ||
| 393 | w.set_pllsel(source); | ||
| 394 | }) | ||
| 395 | } | ||
| 93 | None => { | 396 | None => { |
| 94 | if (cpu_clk_src == Cpusws::HSI || sys_clk_src == Syssws::HSI) | 397 | cfgr3.modify(|w| w.set_pllpdiven(false)); |
| 95 | || (pll1_clk_src == Pllsel::HSI && sr.pllrdy(0)) | 398 | RCC.ccr().write(|w| w.set_pllonc(pll_index, true)); |
| 96 | || (pll2_clk_src == Pllsel::HSI && sr.pllrdy(1)) | 399 | // wait till disabled |
| 97 | || (pll3_clk_src == Pllsel::HSI && sr.pllrdy(2)) | 400 | while RCC.sr().read().pllrdy(pll_index) {} |
| 98 | || (pll4_clk_src == Pllsel::HSI && sr.pllrdy(3)) | ||
| 99 | { | ||
| 100 | if config.hse.is_none() { | ||
| 101 | panic!("When the HSI is used as CPU or system bus clock source, it is not allowed to be disabled"); | ||
| 102 | } | ||
| 103 | } else { | ||
| 104 | // disable the HSI | ||
| 105 | RCC.ccr().write(|w| w.set_hsionc(true)); | ||
| 106 | // wait until HSI is disabled | ||
| 107 | while RCC.sr().read().hsirdy() {} | ||
| 108 | } | ||
| 109 | 401 | ||
| 110 | None | 402 | // clear bypass mode |
| 403 | cfgr1.modify(|w| w.set_pllbyp(false)); | ||
| 111 | } | 404 | } |
| 112 | Some(hsi_config) => { | 405 | } |
| 113 | RCC.hsicfgr().modify(|w| { | 406 | } |
| 114 | w.set_hsidiv(hsi_config.pre); | 407 | |
| 115 | w.set_hsitrim(hsi_config.calib); | 408 | fn HAL_RCC_OscConfig(config: Config) { |
| 116 | }); | 409 | let (cpu_src, sys_src) = { |
| 117 | Some(HSI_FREQ / hsi_config.pre) | 410 | let reg = RCC.cfgr().read(); |
| 411 | (reg.cpusws(), reg.syssws()) | ||
| 412 | }; | ||
| 413 | let pll1_src = RCC.pllcfgr1(0).read().pllsel(); | ||
| 414 | let pll2_src = RCC.pllcfgr1(1).read().pllsel(); | ||
| 415 | let pll3_src = RCC.pllcfgr1(2).read().pllsel(); | ||
| 416 | let pll4_src = RCC.pllcfgr1(3).read().pllsel(); | ||
| 417 | let rcc_sr = RCC.sr().read(); | ||
| 418 | |||
| 419 | debug!("configuring HSE"); | ||
| 420 | |||
| 421 | // hse configuration | ||
| 422 | let hse = if let Some(hse) = config.hse { | ||
| 423 | match hse.mode { | ||
| 424 | HseMode::Oscillator => { | ||
| 425 | debug!("HSE in oscillator mode"); | ||
| 426 | } | ||
| 427 | HseMode::Bypass => { | ||
| 428 | debug!("HSE in bypass mode"); | ||
| 429 | RCC.hsecfgr().modify(|w| { | ||
| 430 | w.set_hsebyp(true); | ||
| 431 | w.set_hseext(Hseext::ANALOG); | ||
| 432 | }); | ||
| 433 | } | ||
| 434 | HseMode::BypassDigital => { | ||
| 435 | debug!("HSE in bypass digital mode"); | ||
| 436 | RCC.hsecfgr().modify(|w| { | ||
| 437 | w.set_hsebyp(true); | ||
| 438 | w.set_hseext(Hseext::DIGITAL); | ||
| 439 | }); | ||
| 440 | } | ||
| 118 | } | 441 | } |
| 442 | RCC.csr().write(|w| w.set_hseons(true)); | ||
| 443 | |||
| 444 | // wait until the hse is ready | ||
| 445 | while !RCC.sr().read().hserdy() {} | ||
| 446 | |||
| 447 | Some(hse.freq) | ||
| 448 | } else if cpu_src == Cpusws::HSE | ||
| 449 | || sys_src == Syssws::HSE | ||
| 450 | || (pll1_src == Pllsel::HSE && rcc_sr.pllrdy(0)) | ||
| 451 | || (pll2_src == Pllsel::HSE && rcc_sr.pllrdy(1)) | ||
| 452 | || (pll3_src == Pllsel::HSE && rcc_sr.pllrdy(2)) | ||
| 453 | || (pll4_src == Pllsel::HSE && rcc_sr.pllrdy(3)) | ||
| 454 | { | ||
| 455 | panic!("When the HSE is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"); | ||
| 456 | } else { | ||
| 457 | debug!("HSE off"); | ||
| 458 | |||
| 459 | RCC.ccr().write(|w| w.set_hseonc(true)); | ||
| 460 | RCC.hsecfgr().modify(|w| { | ||
| 461 | w.set_hseext(Hseext::ANALOG); | ||
| 462 | w.set_hsebyp(false); | ||
| 463 | }); | ||
| 464 | |||
| 465 | // wait until the hse is disabled | ||
| 466 | while RCC.sr().read().hserdy() {} | ||
| 467 | |||
| 468 | None | ||
| 119 | }; | 469 | }; |
| 120 | 470 | ||
| 121 | let hse = match config.hse { | 471 | // hsi configuration |
| 122 | None => { | 472 | debug!("configuring HSI"); |
| 123 | if ((cpu_clk_src == Cpusws::HSE || sys_clk_src == Syssws::HSE) | 473 | let hsi = if let Some(hsi) = config.hsi { |
| 124 | || (pll1_clk_src == Pllsel::HSE && sr.pllrdy(0)) | 474 | RCC.csr().write(|w| w.set_hsions(true)); |
| 125 | || (pll2_clk_src == Pllsel::HSE && sr.pllrdy(1)) | 475 | while !RCC.sr().read().hsirdy() {} |
| 126 | || (pll3_clk_src == Pllsel::HSE && sr.pllrdy(2)) | 476 | |
| 127 | || (pll4_clk_src == Pllsel::HSE && sr.pllrdy(3))) | 477 | // set divider and calibration |
| 128 | && config.hse.is_none() | 478 | RCC.hsicfgr().modify(|w| { |
| 129 | { | 479 | w.set_hsidiv(hsi.pre); |
| 130 | panic!("When the HSE is used as CPU or system bus clock source, it is not allowed to be disabled"); | 480 | w.set_hsitrim(hsi.trim); |
| 481 | }); | ||
| 482 | |||
| 483 | Some(HSI_FREQ / hsi.pre) | ||
| 484 | } else if cpu_src == Cpusws::HSI | ||
| 485 | || sys_src == Syssws::HSI | ||
| 486 | || (pll1_src == Pllsel::HSI && rcc_sr.pllrdy(0)) | ||
| 487 | || (pll2_src == Pllsel::HSI && rcc_sr.pllrdy(1)) | ||
| 488 | || (pll3_src == Pllsel::HSI && rcc_sr.pllrdy(2)) | ||
| 489 | || (pll4_src == Pllsel::HSI && rcc_sr.pllrdy(3)) | ||
| 490 | { | ||
| 491 | panic!("When the HSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"); | ||
| 492 | } else { | ||
| 493 | debug!("HSI off"); | ||
| 494 | |||
| 495 | RCC.ccr().write(|w| w.set_hsionc(true)); | ||
| 496 | while RCC.sr().read().hsirdy() {} | ||
| 497 | |||
| 498 | None | ||
| 499 | }; | ||
| 500 | |||
| 501 | // msi configuration | ||
| 502 | debug!("configuring MSI"); | ||
| 503 | let msi = if let Some(msi) = config.msi { | ||
| 504 | RCC.msicfgr().modify(|w| w.set_msifreqsel(msi.freq)); | ||
| 505 | RCC.csr().write(|w| w.set_msions(true)); | ||
| 506 | while !RCC.sr().read().msirdy() {} | ||
| 507 | RCC.msicfgr().modify(|w| w.set_msitrim(msi.trim)); | ||
| 508 | |||
| 509 | Some(match msi.freq { | ||
| 510 | Msifreqsel::_4MHZ => Hertz::mhz(4), | ||
| 511 | Msifreqsel::_16MHZ => Hertz::mhz(16), | ||
| 512 | }) | ||
| 513 | } else if cpu_src == Cpusws::MSI | ||
| 514 | || sys_src == Syssws::MSI | ||
| 515 | || (pll1_src == Pllsel::MSI && rcc_sr.pllrdy(0)) | ||
| 516 | || (pll2_src == Pllsel::MSI && rcc_sr.pllrdy(1)) | ||
| 517 | || (pll3_src == Pllsel::MSI && rcc_sr.pllrdy(2)) | ||
| 518 | || (pll4_src == Pllsel::MSI && rcc_sr.pllrdy(3)) | ||
| 519 | { | ||
| 520 | panic!("When the MSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"); | ||
| 521 | } else { | ||
| 522 | RCC.ccr().write(|w| w.set_msionc(true)); | ||
| 523 | while RCC.sr().read().msirdy() {} | ||
| 524 | |||
| 525 | None | ||
| 526 | }; | ||
| 527 | |||
| 528 | // lsi configuration | ||
| 529 | debug!("configuring LSI"); | ||
| 530 | let lsi = if config.lsi { | ||
| 531 | RCC.csr().write(|w| w.set_lsions(true)); | ||
| 532 | while !RCC.sr().read().lsirdy() {} | ||
| 533 | Some(super::LSI_FREQ) | ||
| 534 | } else { | ||
| 535 | RCC.ccr().write(|w| w.set_lsionc(true)); | ||
| 536 | while RCC.sr().read().lsirdy() {} | ||
| 537 | None | ||
| 538 | }; | ||
| 539 | |||
| 540 | // lse configuration | ||
| 541 | debug!("configuring LSE"); | ||
| 542 | let lse = if config.lse { | ||
| 543 | RCC.csr().write(|w| w.set_lseons(true)); | ||
| 544 | while !RCC.sr().read().lserdy() {} | ||
| 545 | Some(LSE_FREQ) | ||
| 546 | } else { | ||
| 547 | RCC.ccr().write(|w| w.set_lseonc(true)); | ||
| 548 | while RCC.sr().read().lserdy() {} | ||
| 549 | None | ||
| 550 | }; | ||
| 551 | |||
| 552 | // pll1,2,3,4 config | ||
| 553 | let pll_configs = [config.pll1, config.pll2, config.pll3, config.pll4]; | ||
| 554 | for (n, &pll) in pll_configs.iter().enumerate() { | ||
| 555 | debug!("configuring PLL{}", n + 1); | ||
| 556 | let pll_ready = RCC.sr().read().pllrdy(n); | ||
| 557 | |||
| 558 | if RCC_PLL_IsNewConfig(pll, 0) { | ||
| 559 | let ic1_src = RCC.iccfgr(0).read().icsel(); | ||
| 560 | let ic2_src = RCC.iccfgr(1).read().icsel(); | ||
| 561 | let ic6_src = RCC.iccfgr(5).read().icsel(); | ||
| 562 | let ic11_src = RCC.iccfgr(10).read().icsel(); | ||
| 563 | |||
| 564 | let this_pll = Icsel::from_bits(n as u8); | ||
| 565 | |||
| 566 | if cpu_src == Cpusws::IC1 && ic1_src == this_pll { | ||
| 567 | panic!("PLL should not be disabled / reconfigured if used for IC1 (cpuclksrc)") | ||
| 131 | } | 568 | } |
| 132 | 569 | ||
| 133 | // hse off | 570 | if sys_src == Syssws::IC2 && (ic2_src == this_pll || ic6_src == this_pll || ic11_src == this_pll) { |
| 134 | RCC.csr().modify(|w| w.set_hseons(false)); | 571 | panic!("PLL should not be disabled / reconfigured if used for IC2, IC6 or IC11 (sysclksrc)") |
| 135 | RCC.hsecfgr().modify(|w| { | 572 | } |
| 136 | w.set_hseext(Hseext::ANALOG); | ||
| 137 | w.set_hsebyp(false); | ||
| 138 | }); | ||
| 139 | 573 | ||
| 140 | // wait until hse is off | 574 | pll_config(pll, 0); |
| 141 | while RCC.sr().read().hserdy() {} | 575 | } else if pll.is_some() && !pll_ready { |
| 142 | 576 | debug!("PLL{} off", n + 1); | |
| 143 | None | 577 | RCC.csr().write(|w| w.pllons(n)); |
| 144 | } | 578 | while !RCC.sr().read().pllrdy(n) {} |
| 145 | Some(hse_config) => { | ||
| 146 | match hse_config.mode { | ||
| 147 | HseMode::Oscillator => RCC.csr().modify(|w| w.set_hseons(true)), | ||
| 148 | HseMode::Bypass => { | ||
| 149 | RCC.hsecfgr().modify(|w| { | ||
| 150 | w.set_hsebyp(true); | ||
| 151 | w.set_hseext(Hseext::ANALOG); | ||
| 152 | }); | ||
| 153 | RCC.csr().modify(|w| w.set_hseons(true)); | ||
| 154 | } | ||
| 155 | HseMode::BypassDigital => { | ||
| 156 | RCC.hsecfgr().modify(|w| { | ||
| 157 | w.set_hsebyp(true); | ||
| 158 | w.set_hseext(Hseext::DIGITAL) | ||
| 159 | }); | ||
| 160 | } | ||
| 161 | }; | ||
| 162 | |||
| 163 | // wait until the hse is ready | ||
| 164 | while !RCC.sr().read().hserdy() {} | ||
| 165 | |||
| 166 | Some(hse_config.freq) | ||
| 167 | } | 579 | } |
| 168 | }; | 580 | } |
| 581 | } | ||
| 582 | |||
| 583 | fn RCC_PLL_IsNewConfig(pll: Option<Pll>, pll_index: usize) -> bool { | ||
| 584 | let cfgr1 = RCC.pllcfgr1(pll_index).read(); | ||
| 585 | let cfgr2 = RCC.pllcfgr2(pll_index).read(); | ||
| 586 | let cfgr3 = RCC.pllcfgr3(pll_index).read(); | ||
| 587 | |||
| 588 | let ready = RCC.sr().read().pllrdy(pll_index); | ||
| 589 | let bypass = cfgr1.pllbyp(); | ||
| 590 | |||
| 591 | match (pll, ready, bypass) { | ||
| 592 | (None, true, _) => return true, | ||
| 593 | (Some(_), false, _) => return true, | ||
| 594 | (Some(conf), true, bypass) => match (conf, bypass) { | ||
| 595 | (Pll::Bypass { .. }, false) => return true, | ||
| 596 | (Pll::Oscillator { .. }, true) => return true, | ||
| 597 | _ => {} | ||
| 598 | }, | ||
| 599 | _ => {} | ||
| 600 | } | ||
| 169 | 601 | ||
| 170 | (hsi, hse) | 602 | match pll { |
| 603 | Some(Pll::Bypass { source }) => cfgr1.pllsel() != source, | ||
| 604 | Some(Pll::Oscillator { | ||
| 605 | source, | ||
| 606 | m, | ||
| 607 | fractional, | ||
| 608 | n, | ||
| 609 | p1, | ||
| 610 | p2, | ||
| 611 | }) => { | ||
| 612 | cfgr1.pllsel() != source | ||
| 613 | || cfgr1.plldivm() != m | ||
| 614 | || cfgr1.plldivn() != n | ||
| 615 | || cfgr2.plldivnfrac() != fractional | ||
| 616 | || cfgr3.pllpdiv1() != p1 | ||
| 617 | || cfgr3.pllpdiv2() != p2 | ||
| 618 | } | ||
| 619 | None => false, | ||
| 620 | } | ||
| 171 | } | 621 | } |
| 172 | 622 | ||
| 173 | pub(crate) unsafe fn init(config: Config) { | 623 | pub(crate) unsafe fn init(config: Config) { |
| 624 | debug!("enabling SYSCFG"); | ||
| 174 | // system configuration setup | 625 | // system configuration setup |
| 175 | RCC.apb4hensr().write(|w| w.set_syscfgens(true)); | 626 | RCC.apb4hensr().write(|w| w.set_syscfgens(true)); |
| 176 | // delay after RCC peripheral clock enabling | 627 | // delay after RCC peripheral clock enabling |
| 177 | core::ptr::read_volatile(RCC.apb4hensr().as_ptr()); | 628 | core::ptr::read_volatile(RCC.apb4hensr().as_ptr()); |
| 178 | 629 | ||
| 630 | debug!("setting VTOR"); | ||
| 631 | |||
| 179 | let vtor = unsafe { | 632 | let vtor = unsafe { |
| 180 | let p = cortex_m::Peripherals::steal(); | 633 | let p = cortex_m::Peripherals::steal(); |
| 181 | p.SCB.vtor.read() | 634 | p.SCB.vtor.read() |
| @@ -186,33 +639,40 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 186 | // read back the value to ensure it is written before deactivating SYSCFG | 639 | // read back the value to ensure it is written before deactivating SYSCFG |
| 187 | core::ptr::read_volatile(SYSCFG.initsvtorcr().as_ptr()); | 640 | core::ptr::read_volatile(SYSCFG.initsvtorcr().as_ptr()); |
| 188 | 641 | ||
| 642 | debug!("deactivating SYSCFG"); | ||
| 643 | |||
| 189 | // deactivate SYSCFG | 644 | // deactivate SYSCFG |
| 190 | RCC.apb4hensr().write(|w| w.set_syscfgens(false)); | 645 | RCC.apb4hensr().write(|w| w.set_syscfgens(false)); |
| 191 | 646 | ||
| 647 | debug!("enabling FPU"); | ||
| 648 | |||
| 192 | // enable fpu | 649 | // enable fpu |
| 193 | unsafe { | 650 | unsafe { |
| 194 | let p = cortex_m::Peripherals::steal(); | 651 | let p = cortex_m::Peripherals::steal(); |
| 195 | p.SCB.cpacr.modify(|w| w | (3 << 20) | (3 << 22)); | 652 | p.SCB.cpacr.modify(|w| w | (3 << 20) | (3 << 22)); |
| 196 | } | 653 | } |
| 197 | 654 | ||
| 655 | debug!("setting power supply config"); | ||
| 656 | |||
| 198 | power_supply_config(config.supply_config); | 657 | power_supply_config(config.supply_config); |
| 199 | 658 | ||
| 200 | let (hsi, hse) = osc_config(config); | 659 | HAL_RCC_OscConfig(config); |
| 660 | HAL_RCC_ClockConfig(config); | ||
| 201 | 661 | ||
| 202 | let sys = match config.sys { | 662 | let sys = match config.sys { |
| 203 | Sysclk::HSE => unwrap!(hse), | 663 | SysClk::Hse => todo!(), |
| 204 | Sysclk::HSI => unwrap!(hsi), | 664 | SysClk::Hsi => Hertz(64_000_000), |
| 205 | Sysclk::MSI => todo!(), | 665 | SysClk::Msi => todo!(), |
| 206 | Sysclk::IC2 => todo!(), | 666 | SysClk::Pll { .. } => todo!(), |
| 207 | }; | 667 | }; |
| 208 | 668 | ||
| 209 | // TODO: sysb, sysc, sysd must have the same clock source | 669 | // TODO: sysb, sysc, sysd must have the same clock source |
| 210 | 670 | ||
| 211 | set_clocks!( | 671 | set_clocks!( |
| 212 | sys: Some(sys), | 672 | sys: Some(sys), |
| 213 | hsi: hsi, | 673 | hsi: None, |
| 214 | hsi_div: None, | 674 | hsi_div: None, |
| 215 | hse: hse, | 675 | hse: None, |
| 216 | hclk1: None, | 676 | hclk1: None, |
| 217 | hclk2: None, | 677 | hclk2: None, |
| 218 | hclk3: None, | 678 | hclk3: None, |
