diff options
Diffstat (limited to 'embassy-stm32/src/rcc/n6.rs')
| -rw-r--r-- | embassy-stm32/src/rcc/n6.rs | 1066 |
1 files changed, 1066 insertions, 0 deletions
diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs new file mode 100644 index 000000000..178ec57d4 --- /dev/null +++ b/embassy-stm32/src/rcc/n6.rs | |||
| @@ -0,0 +1,1066 @@ | |||
| 1 | use stm32_metapac::rcc::vals::{ | ||
| 2 | Cpusw, Cpusws, Hseext, Hsitrim, Icint, Icsel, Msifreqsel, Plldivm, Pllmodssdis, Pllpdiv, Pllsel, Syssw, Syssws, | ||
| 3 | Timpre, | ||
| 4 | }; | ||
| 5 | pub use stm32_metapac::rcc::vals::{ | ||
| 6 | Hpre as AhbPrescaler, Hsidiv as HsiPrescaler, Hsitrim as HsiCalibration, Ppre as ApbPrescaler, | ||
| 7 | }; | ||
| 8 | |||
| 9 | use crate::pac::{PWR, RCC, SYSCFG}; | ||
| 10 | use crate::time::Hertz; | ||
| 11 | |||
| 12 | pub const HSI_FREQ: Hertz = Hertz(64_000_000); | ||
| 13 | pub const LSE_FREQ: Hertz = Hertz(32_768); | ||
| 14 | |||
| 15 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 16 | pub enum HseMode { | ||
| 17 | /// crystal/ceramic oscillator | ||
| 18 | Oscillator, | ||
| 19 | /// oscillator bypassed with external clock (analog) | ||
| 20 | Bypass, | ||
| 21 | /// oscillator bypassed with external digital clock | ||
| 22 | BypassDigital, | ||
| 23 | } | ||
| 24 | |||
| 25 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 26 | pub struct Hse { | ||
| 27 | /// HSE frequency. | ||
| 28 | pub freq: Hertz, | ||
| 29 | /// HSE oscillator mode. | ||
| 30 | pub mode: HseMode, | ||
| 31 | } | ||
| 32 | |||
| 33 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 34 | pub struct Hsi { | ||
| 35 | pub pre: HsiPrescaler, | ||
| 36 | pub trim: Hsitrim, | ||
| 37 | } | ||
| 38 | |||
| 39 | #[derive(Clone, Copy, PartialEq)] | ||
| 40 | pub enum SupplyConfig { | ||
| 41 | Smps, | ||
| 42 | External, | ||
| 43 | } | ||
| 44 | |||
| 45 | #[derive(Clone, Copy, PartialEq)] | ||
| 46 | pub enum CpuClk { | ||
| 47 | Hse, | ||
| 48 | Ic1 { source: Icsel, divider: Icint }, | ||
| 49 | Msi, | ||
| 50 | Hsi, | ||
| 51 | } | ||
| 52 | |||
| 53 | impl CpuClk { | ||
| 54 | const fn to_bits(self) -> u8 { | ||
| 55 | match self { | ||
| 56 | Self::Hsi => 0x0, | ||
| 57 | Self::Msi => 0x1, | ||
| 58 | Self::Hse => 0x2, | ||
| 59 | Self::Ic1 { .. } => 0x3, | ||
| 60 | } | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | #[derive(Clone, Copy, PartialEq)] | ||
| 65 | pub struct IcConfig { | ||
| 66 | source: Icsel, | ||
| 67 | divider: Icint, | ||
| 68 | } | ||
| 69 | |||
| 70 | #[derive(Clone, Copy, PartialEq)] | ||
| 71 | pub enum SysClk { | ||
| 72 | Hse, | ||
| 73 | Ic2 { | ||
| 74 | ic2: IcConfig, | ||
| 75 | ic6: IcConfig, | ||
| 76 | ic11: IcConfig, | ||
| 77 | }, | ||
| 78 | Msi, | ||
| 79 | Hsi, | ||
| 80 | } | ||
| 81 | |||
| 82 | impl SysClk { | ||
| 83 | const fn to_bits(self) -> u8 { | ||
| 84 | match self { | ||
| 85 | Self::Hsi => 0x0, | ||
| 86 | Self::Msi => 0x1, | ||
| 87 | Self::Hse => 0x2, | ||
| 88 | Self::Ic2 { .. } => 0x3, | ||
| 89 | } | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | #[derive(Clone, Copy, PartialEq)] | ||
| 94 | pub struct Msi { | ||
| 95 | pub freq: Msifreqsel, | ||
| 96 | pub trim: u8, | ||
| 97 | } | ||
| 98 | |||
| 99 | #[derive(Clone, Copy, PartialEq)] | ||
| 100 | pub enum Pll { | ||
| 101 | Oscillator { | ||
| 102 | source: Pllsel, | ||
| 103 | divm: Plldivm, | ||
| 104 | fractional: u32, | ||
| 105 | divn: u16, | ||
| 106 | divp1: Pllpdiv, | ||
| 107 | divp2: Pllpdiv, | ||
| 108 | }, | ||
| 109 | Bypass { | ||
| 110 | source: Pllsel, | ||
| 111 | }, | ||
| 112 | } | ||
| 113 | |||
| 114 | /// Configuration of the core clocks | ||
| 115 | #[non_exhaustive] | ||
| 116 | #[derive(Clone, Copy)] | ||
| 117 | pub struct Config { | ||
| 118 | pub hsi: Option<Hsi>, | ||
| 119 | pub hse: Option<Hse>, | ||
| 120 | pub msi: Option<Msi>, | ||
| 121 | pub lsi: bool, | ||
| 122 | pub lse: bool, | ||
| 123 | |||
| 124 | pub sys: SysClk, | ||
| 125 | pub cpu: CpuClk, | ||
| 126 | |||
| 127 | pub pll1: Option<Pll>, | ||
| 128 | pub pll2: Option<Pll>, | ||
| 129 | pub pll3: Option<Pll>, | ||
| 130 | pub pll4: Option<Pll>, | ||
| 131 | |||
| 132 | pub ahb: AhbPrescaler, | ||
| 133 | pub apb1: ApbPrescaler, | ||
| 134 | pub apb2: ApbPrescaler, | ||
| 135 | pub apb4: ApbPrescaler, | ||
| 136 | pub apb5: ApbPrescaler, | ||
| 137 | |||
| 138 | pub supply_config: SupplyConfig, | ||
| 139 | } | ||
| 140 | |||
| 141 | impl Config { | ||
| 142 | pub const fn new() -> Self { | ||
| 143 | Self { | ||
| 144 | hsi: Some(Hsi { | ||
| 145 | pre: HsiPrescaler::DIV1, | ||
| 146 | trim: HsiCalibration::from_bits(32), | ||
| 147 | }), | ||
| 148 | hse: None, | ||
| 149 | msi: None, | ||
| 150 | lsi: true, | ||
| 151 | lse: false, | ||
| 152 | sys: SysClk::Hsi, | ||
| 153 | cpu: CpuClk::Hsi, | ||
| 154 | pll1: Some(Pll::Bypass { source: Pllsel::HSI }), | ||
| 155 | pll2: Some(Pll::Bypass { source: Pllsel::HSI }), | ||
| 156 | pll3: Some(Pll::Bypass { source: Pllsel::HSI }), | ||
| 157 | pll4: Some(Pll::Bypass { source: Pllsel::HSI }), | ||
| 158 | |||
| 159 | ahb: AhbPrescaler::DIV2, | ||
| 160 | apb1: ApbPrescaler::DIV1, | ||
| 161 | apb2: ApbPrescaler::DIV1, | ||
| 162 | apb4: ApbPrescaler::DIV1, | ||
| 163 | apb5: ApbPrescaler::DIV1, | ||
| 164 | |||
| 165 | supply_config: SupplyConfig::Smps, | ||
| 166 | } | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | #[allow(dead_code)] | ||
| 171 | struct ClocksOutput { | ||
| 172 | cpuclk: Hertz, | ||
| 173 | sysclk: Hertz, | ||
| 174 | pclk_tim: Hertz, | ||
| 175 | ahb: Hertz, | ||
| 176 | apb1: Hertz, | ||
| 177 | apb2: Hertz, | ||
| 178 | apb4: Hertz, | ||
| 179 | apb5: Hertz, | ||
| 180 | } | ||
| 181 | |||
| 182 | struct ClocksInput { | ||
| 183 | hsi: Option<Hertz>, | ||
| 184 | msi: Option<Hertz>, | ||
| 185 | hse: Option<Hertz>, | ||
| 186 | } | ||
| 187 | |||
| 188 | fn init_clocks(config: Config, input: &ClocksInput) -> ClocksOutput { | ||
| 189 | // handle increasing dividers | ||
| 190 | debug!("configuring increasing pclk dividers"); | ||
| 191 | RCC.cfgr2().modify(|w| { | ||
| 192 | if config.apb1 > w.ppre1() { | ||
| 193 | debug!(" - APB1"); | ||
| 194 | w.set_ppre1(config.apb1); | ||
| 195 | } | ||
| 196 | if config.apb2 > w.ppre2() { | ||
| 197 | debug!(" - APB2"); | ||
| 198 | w.set_ppre2(config.apb2); | ||
| 199 | } | ||
| 200 | if config.apb4 > w.ppre4() { | ||
| 201 | debug!(" - APB4"); | ||
| 202 | w.set_ppre4(config.apb4); | ||
| 203 | } | ||
| 204 | if config.apb5 > w.ppre5() { | ||
| 205 | debug!(" - APB5"); | ||
| 206 | w.set_ppre5(config.apb5); | ||
| 207 | } | ||
| 208 | if config.ahb > w.hpre() { | ||
| 209 | debug!(" - AHB"); | ||
| 210 | w.set_hpre(config.ahb); | ||
| 211 | } | ||
| 212 | }); | ||
| 213 | // cpuclk | ||
| 214 | debug!("configuring cpuclk"); | ||
| 215 | match config.cpu { | ||
| 216 | CpuClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"), | ||
| 217 | CpuClk::Ic1 { source, divider } => { | ||
| 218 | if !pll_sources_ready(RCC.iccfgr(0).read().icsel().to_bits(), source.to_bits()) { | ||
| 219 | panic!("ICx clock switch requires both origin and destination clock source to be active") | ||
| 220 | } | ||
| 221 | |||
| 222 | RCC.iccfgr(0).write(|w| { | ||
| 223 | w.set_icsel(source); | ||
| 224 | w.set_icint(divider); | ||
| 225 | }); | ||
| 226 | RCC.divensr().modify(|w| w.set_ic1ens(true)); | ||
| 227 | } | ||
| 228 | CpuClk::Msi if !RCC.sr().read().msirdy() => panic!("MSI is not ready to be selected as CPU clock source"), | ||
| 229 | CpuClk::Hsi if !RCC.sr().read().hsirdy() => panic!("HSI is not ready to be selected as CPU clock source"), | ||
| 230 | _ => {} | ||
| 231 | } | ||
| 232 | // set source | ||
| 233 | let cpusw = Cpusw::from_bits(config.cpu.to_bits()); | ||
| 234 | RCC.cfgr().modify(|w| w.set_cpusw(cpusw)); | ||
| 235 | // wait for changes to take effect | ||
| 236 | while RCC.cfgr().read().cpusws() != Cpusws::from_bits(config.cpu.to_bits()) {} | ||
| 237 | |||
| 238 | // sysclk | ||
| 239 | debug!("configuring sysclk"); | ||
| 240 | match config.sys { | ||
| 241 | SysClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"), | ||
| 242 | SysClk::Ic2 { ic2, ic6, ic11 } => { | ||
| 243 | if !pll_sources_ready(RCC.iccfgr(1).read().icsel().to_bits(), ic2.source.to_bits()) { | ||
| 244 | panic!("IC2 clock switch requires both origin and destination clock source to be active") | ||
| 245 | } | ||
| 246 | if !pll_sources_ready(RCC.iccfgr(5).read().icsel().to_bits(), ic6.source.to_bits()) { | ||
| 247 | panic!("IC6 clock switch requires both origin and destination clock source to be active") | ||
| 248 | } | ||
| 249 | if !pll_sources_ready(RCC.iccfgr(10).read().icsel().to_bits(), ic11.source.to_bits()) { | ||
| 250 | panic!("IC11 clock switch requires both origin and destination clock source to be active") | ||
| 251 | } | ||
| 252 | |||
| 253 | RCC.iccfgr(1).write(|w| { | ||
| 254 | w.set_icsel(ic2.source); | ||
| 255 | w.set_icint(ic2.divider); | ||
| 256 | }); | ||
| 257 | RCC.iccfgr(5).write(|w| { | ||
| 258 | w.set_icsel(ic6.source); | ||
| 259 | w.set_icint(ic6.divider); | ||
| 260 | }); | ||
| 261 | RCC.iccfgr(10).write(|w| { | ||
| 262 | w.set_icsel(ic11.source); | ||
| 263 | w.set_icint(ic11.divider); | ||
| 264 | }); | ||
| 265 | RCC.divensr().modify(|w| { | ||
| 266 | w.set_ic2ens(true); | ||
| 267 | w.set_ic6ens(true); | ||
| 268 | w.set_ic11ens(true); | ||
| 269 | }); | ||
| 270 | } | ||
| 271 | SysClk::Msi if !RCC.sr().read().msirdy() => panic!("MSI is not ready to be selected as CPU clock source"), | ||
| 272 | SysClk::Hsi if !RCC.sr().read().hsirdy() => panic!("HSI is not ready to be selected as CPU clock source"), | ||
| 273 | _ => {} | ||
| 274 | } | ||
| 275 | // switch the system bus clock | ||
| 276 | let syssw = Syssw::from_bits(config.sys.to_bits()); | ||
| 277 | RCC.cfgr().modify(|w| w.set_syssw(syssw)); | ||
| 278 | // wait for changes to be applied | ||
| 279 | while RCC.cfgr().read().syssws() != Syssws::from_bits(config.sys.to_bits()) {} | ||
| 280 | |||
| 281 | // decreasing dividers | ||
| 282 | debug!("configuring decreasing pclk dividers"); | ||
| 283 | RCC.cfgr2().modify(|w| { | ||
| 284 | if config.ahb < w.hpre() { | ||
| 285 | debug!(" - AHB"); | ||
| 286 | w.set_hpre(config.ahb); | ||
| 287 | } | ||
| 288 | if config.apb1 < w.ppre1() { | ||
| 289 | debug!(" - APB1"); | ||
| 290 | w.set_ppre1(config.apb1); | ||
| 291 | } | ||
| 292 | if config.apb2 < w.ppre2() { | ||
| 293 | debug!(" - APB2"); | ||
| 294 | w.set_ppre2(config.apb2); | ||
| 295 | } | ||
| 296 | if config.apb4 < w.ppre4() { | ||
| 297 | debug!(" - APB4"); | ||
| 298 | w.set_ppre4(config.apb4); | ||
| 299 | } | ||
| 300 | if config.apb5 < w.ppre5() { | ||
| 301 | debug!(" - APB5"); | ||
| 302 | w.set_ppre5(config.apb5); | ||
| 303 | } | ||
| 304 | }); | ||
| 305 | |||
| 306 | let cpuclk = match config.cpu { | ||
| 307 | CpuClk::Hsi => unwrap!(input.hsi), | ||
| 308 | CpuClk::Msi => unwrap!(input.msi), | ||
| 309 | CpuClk::Hse => unwrap!(input.hse), | ||
| 310 | CpuClk::Ic1 { .. } => todo!(), | ||
| 311 | }; | ||
| 312 | |||
| 313 | let sysclk = match config.sys { | ||
| 314 | SysClk::Hsi => unwrap!(input.hsi), | ||
| 315 | SysClk::Msi => unwrap!(input.msi), | ||
| 316 | SysClk::Hse => unwrap!(input.hse), | ||
| 317 | SysClk::Ic2 { .. } => todo!(), | ||
| 318 | }; | ||
| 319 | |||
| 320 | let timpre: u32 = match RCC.cfgr2().read().timpre() { | ||
| 321 | Timpre::DIV1 => 1, | ||
| 322 | Timpre::DIV2 => 2, | ||
| 323 | Timpre::DIV4 => 4, | ||
| 324 | Timpre::_RESERVED_3 => 8, | ||
| 325 | }; | ||
| 326 | |||
| 327 | let hpre = periph_prescaler_to_value(config.ahb.to_bits()); | ||
| 328 | let ppre1 = periph_prescaler_to_value(config.apb1.to_bits()); | ||
| 329 | let ppre2 = periph_prescaler_to_value(config.apb2.to_bits()); | ||
| 330 | let ppre4 = periph_prescaler_to_value(config.apb4.to_bits()); | ||
| 331 | let ppre5 = periph_prescaler_to_value(config.apb5.to_bits()); | ||
| 332 | |||
| 333 | // enable all peripherals in sleep mode | ||
| 334 | enable_low_power_peripherals(); | ||
| 335 | |||
| 336 | // enable interrupts | ||
| 337 | unsafe { | ||
| 338 | core::arch::asm!("cpsie i"); | ||
| 339 | } | ||
| 340 | |||
| 341 | ClocksOutput { | ||
| 342 | sysclk, | ||
| 343 | cpuclk, | ||
| 344 | pclk_tim: sysclk / timpre, | ||
| 345 | ahb: Hertz(sysclk.0 / hpre as u32), | ||
| 346 | apb1: sysclk / hpre / ppre1, | ||
| 347 | apb2: sysclk / hpre / ppre2, | ||
| 348 | apb4: sysclk / hpre / ppre4, | ||
| 349 | apb5: sysclk / hpre / ppre5, | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | fn enable_low_power_peripherals() { | ||
| 354 | // AHB1-5 | ||
| 355 | RCC.ahb1lpenr().modify(|w| { | ||
| 356 | w.set_adc12lpen(true); | ||
| 357 | w.set_gpdma1lpen(true); | ||
| 358 | }); | ||
| 359 | RCC.ahb2lpenr().modify(|w| { | ||
| 360 | w.set_adf1lpen(true); | ||
| 361 | w.set_mdf1lpen(true); | ||
| 362 | w.set_ramcfglpen(true); | ||
| 363 | }); | ||
| 364 | RCC.ahb3lpenr().modify(|w| { | ||
| 365 | w.set_risaflpen(true); | ||
| 366 | w.set_iaclpen(true); | ||
| 367 | w.set_rifsclpen(true); | ||
| 368 | w.set_pkalpen(true); | ||
| 369 | w.set_saeslpen(true); | ||
| 370 | w.set_cryplpen(true); | ||
| 371 | w.set_hashlpen(true); | ||
| 372 | w.set_rnglpen(true); | ||
| 373 | }); | ||
| 374 | RCC.ahb4lpenr().modify(|w| { | ||
| 375 | w.set_crclpen(true); | ||
| 376 | w.set_pwrlpen(true); | ||
| 377 | w.set_gpioqlpen(true); | ||
| 378 | w.set_gpioplpen(true); | ||
| 379 | w.set_gpioolpen(true); | ||
| 380 | w.set_gpionlpen(true); | ||
| 381 | w.set_gpiohlpen(true); | ||
| 382 | w.set_gpioglpen(true); | ||
| 383 | w.set_gpioflpen(true); | ||
| 384 | w.set_gpioelpen(true); | ||
| 385 | w.set_gpiodlpen(true); | ||
| 386 | w.set_gpioclpen(true); | ||
| 387 | w.set_gpioblpen(true); | ||
| 388 | w.set_gpioalpen(true); | ||
| 389 | }); | ||
| 390 | RCC.ahb5lpenr().modify(|w| { | ||
| 391 | w.set_npulpen(true); | ||
| 392 | w.set_npucachelpen(true); | ||
| 393 | w.set_otg2lpen(true); | ||
| 394 | w.set_otgphy2lpen(true); | ||
| 395 | w.set_otgphy1lpen(true); | ||
| 396 | w.set_otg1lpen(true); | ||
| 397 | w.set_eth1lpen(true); | ||
| 398 | w.set_eth1rxlpen(true); | ||
| 399 | w.set_eth1txlpen(true); | ||
| 400 | w.set_eth1maclpen(true); | ||
| 401 | w.set_gpulpen(true); | ||
| 402 | w.set_gfxmmulpen(true); | ||
| 403 | w.set_mce4lpen(true); | ||
| 404 | w.set_xspi3lpen(true); | ||
| 405 | w.set_mce3lpen(true); | ||
| 406 | w.set_mce2lpen(true); | ||
| 407 | w.set_mce1lpen(true); | ||
| 408 | w.set_xspimlpen(true); | ||
| 409 | w.set_xspi2lpen(true); | ||
| 410 | w.set_sdmmc1lpen(true); | ||
| 411 | w.set_sdmmc2lpen(true); | ||
| 412 | w.set_pssilpen(true); | ||
| 413 | w.set_xspi1lpen(true); | ||
| 414 | w.set_fmclpen(true); | ||
| 415 | w.set_jpeglpen(true); | ||
| 416 | w.set_dma2dlpen(true); | ||
| 417 | w.set_hpdma1lpen(true); | ||
| 418 | }); | ||
| 419 | |||
| 420 | // APB1-5 | ||
| 421 | RCC.apb1llpenr().modify(|w| { | ||
| 422 | w.set_uart8lpen(true); | ||
| 423 | w.set_uart7lpen(true); | ||
| 424 | w.set_i3c2lpen(true); | ||
| 425 | w.set_i3c1lpen(true); | ||
| 426 | w.set_i2c3lpen(true); | ||
| 427 | w.set_i2c2lpen(true); | ||
| 428 | w.set_i2c1lpen(true); | ||
| 429 | w.set_uart5lpen(true); | ||
| 430 | w.set_uart4lpen(true); | ||
| 431 | w.set_usart3lpen(true); | ||
| 432 | w.set_usart2lpen(true); | ||
| 433 | w.set_spdifrx1lpen(true); | ||
| 434 | w.set_spi3lpen(true); | ||
| 435 | w.set_spi2lpen(true); | ||
| 436 | w.set_tim11lpen(true); | ||
| 437 | w.set_tim10lpen(true); | ||
| 438 | w.set_wwdglpen(true); | ||
| 439 | w.set_lptim1lpen(true); | ||
| 440 | w.set_tim14lpen(true); | ||
| 441 | w.set_tim13lpen(true); | ||
| 442 | w.set_tim12lpen(true); | ||
| 443 | w.set_tim7lpen(true); | ||
| 444 | w.set_tim6lpen(true); | ||
| 445 | w.set_tim5lpen(true); | ||
| 446 | w.set_tim4lpen(true); | ||
| 447 | w.set_tim3lpen(true); | ||
| 448 | w.set_tim2lpen(true); | ||
| 449 | }); | ||
| 450 | RCC.apb1hlpenr().modify(|w| { | ||
| 451 | w.set_ucpd1lpen(true); | ||
| 452 | w.set_fdcanlpen(true); | ||
| 453 | w.set_mdioslpen(true); | ||
| 454 | }); | ||
| 455 | RCC.apb2lpenr().modify(|w| { | ||
| 456 | w.set_sai2lpen(true); | ||
| 457 | w.set_sai1lpen(true); | ||
| 458 | w.set_spi5lpen(true); | ||
| 459 | w.set_tim9lpen(true); | ||
| 460 | w.set_tim17lpen(true); | ||
| 461 | w.set_tim16lpen(true); | ||
| 462 | w.set_tim15lpen(true); | ||
| 463 | w.set_tim18lpen(true); | ||
| 464 | w.set_spi4lpen(true); | ||
| 465 | w.set_spi1lpen(true); | ||
| 466 | w.set_usart10lpen(true); | ||
| 467 | w.set_uart9lpen(true); | ||
| 468 | w.set_usart6lpen(true); | ||
| 469 | w.set_usart1lpen(true); | ||
| 470 | w.set_tim8lpen(true); | ||
| 471 | w.set_tim1lpen(true); | ||
| 472 | }); | ||
| 473 | RCC.apb3lpenr().modify(|w| { | ||
| 474 | w.set_dftlpen(true); | ||
| 475 | }); | ||
| 476 | RCC.apb4llpenr().modify(|w| { | ||
| 477 | w.set_rtcapblpen(true); | ||
| 478 | w.set_rtclpen(true); | ||
| 479 | w.set_vrefbuflpen(true); | ||
| 480 | w.set_lptim5lpen(true); | ||
| 481 | w.set_lptim4lpen(true); | ||
| 482 | w.set_lptim3lpen(true); | ||
| 483 | w.set_lptim2lpen(true); | ||
| 484 | w.set_i2c4lpen(true); | ||
| 485 | w.set_spi6lpen(true); | ||
| 486 | w.set_lpuart1lpen(true); | ||
| 487 | w.set_hdplpen(true); | ||
| 488 | }); | ||
| 489 | RCC.apb4hlpenr().modify(|w| { | ||
| 490 | w.set_dtslpen(true); | ||
| 491 | w.set_bseclpen(true); | ||
| 492 | w.set_syscfglpen(true); | ||
| 493 | }); | ||
| 494 | RCC.apb5lpenr().modify(|w| { | ||
| 495 | w.set_csilpen(true); | ||
| 496 | w.set_venclpen(true); | ||
| 497 | w.set_gfxtimlpen(true); | ||
| 498 | w.set_dcmilpen(true); | ||
| 499 | w.set_ltdclpen(true); | ||
| 500 | }); | ||
| 501 | |||
| 502 | RCC.buslpenr().modify(|w| { | ||
| 503 | w.set_aclknclpen(true); | ||
| 504 | w.set_aclknlpen(true); | ||
| 505 | }); | ||
| 506 | |||
| 507 | RCC.memlpenr().modify(|w| { | ||
| 508 | w.set_bootromlpen(true); | ||
| 509 | w.set_vencramlpen(true); | ||
| 510 | w.set_npucacheramlpen(true); | ||
| 511 | w.set_flexramlpen(true); | ||
| 512 | w.set_axisram2lpen(true); | ||
| 513 | w.set_axisram1lpen(true); | ||
| 514 | w.set_bkpsramlpen(true); | ||
| 515 | w.set_ahbsram2lpen(true); | ||
| 516 | w.set_ahbsram1lpen(true); | ||
| 517 | w.set_axisram6lpen(true); | ||
| 518 | w.set_axisram5lpen(true); | ||
| 519 | w.set_axisram4lpen(true); | ||
| 520 | w.set_axisram3lpen(true); | ||
| 521 | }); | ||
| 522 | |||
| 523 | RCC.misclpenr().modify(|w| { | ||
| 524 | w.set_perlpen(true); | ||
| 525 | w.set_xspiphycomplpen(true); | ||
| 526 | w.set_dbglpen(true); | ||
| 527 | }); | ||
| 528 | } | ||
| 529 | |||
| 530 | const fn periph_prescaler_to_value(bits: u8) -> u8 { | ||
| 531 | match bits { | ||
| 532 | 0 => 1, | ||
| 533 | 1 => 2, | ||
| 534 | 2 => 4, | ||
| 535 | 3 => 8, | ||
| 536 | 4 => 16, | ||
| 537 | 5 => 32, | ||
| 538 | 6 => 64, | ||
| 539 | 7.. => 128, | ||
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 543 | fn pll_source_ready(source: u8) -> bool { | ||
| 544 | match source { | ||
| 545 | 0x0 if !RCC.sr().read().pllrdy(0) && !RCC.pllcfgr1(0).read().pllbyp() => false, | ||
| 546 | 0x1 if !RCC.sr().read().pllrdy(1) && !RCC.pllcfgr1(1).read().pllbyp() => false, | ||
| 547 | 0x2 if !RCC.sr().read().pllrdy(2) && !RCC.pllcfgr1(2).read().pllbyp() => false, | ||
| 548 | 0x3 if !RCC.sr().read().pllrdy(3) && !RCC.pllcfgr1(3).read().pllbyp() => false, | ||
| 549 | _ => true, | ||
| 550 | } | ||
| 551 | } | ||
| 552 | |||
| 553 | fn pll_sources_ready(source1: u8, source2: u8) -> bool { | ||
| 554 | pll_source_ready(source1) && pll_source_ready(source2) | ||
| 555 | } | ||
| 556 | |||
| 557 | impl Default for Config { | ||
| 558 | fn default() -> Self { | ||
| 559 | Self::new() | ||
| 560 | } | ||
| 561 | } | ||
| 562 | |||
| 563 | fn power_supply_config(supply_config: SupplyConfig) { | ||
| 564 | // power supply config | ||
| 565 | PWR.cr1().modify(|w| { | ||
| 566 | w.set_sden(match supply_config { | ||
| 567 | SupplyConfig::External => false, | ||
| 568 | SupplyConfig::Smps => true, | ||
| 569 | }); | ||
| 570 | }); | ||
| 571 | |||
| 572 | // Validate supply configuration | ||
| 573 | while !PWR.voscr().read().actvosrdy() {} | ||
| 574 | } | ||
| 575 | |||
| 576 | struct PllInput { | ||
| 577 | hsi: Option<Hertz>, | ||
| 578 | msi: Option<Hertz>, | ||
| 579 | hse: Option<Hertz>, | ||
| 580 | i2s_ckin: Option<Hertz>, | ||
| 581 | } | ||
| 582 | |||
| 583 | #[derive(Clone, Copy, Default)] | ||
| 584 | #[allow(dead_code)] | ||
| 585 | struct PllOutput { | ||
| 586 | divm: Option<Hertz>, | ||
| 587 | divn: Option<Hertz>, | ||
| 588 | divp1: Option<Hertz>, | ||
| 589 | divp2: Option<Hertz>, | ||
| 590 | output: Option<Hertz>, | ||
| 591 | } | ||
| 592 | |||
| 593 | fn init_pll(pll_config: Option<Pll>, pll_index: usize, input: &PllInput) -> PllOutput { | ||
| 594 | let cfgr1 = RCC.pllcfgr1(pll_index); | ||
| 595 | let cfgr2 = RCC.pllcfgr2(pll_index); | ||
| 596 | let cfgr3 = RCC.pllcfgr3(pll_index); | ||
| 597 | |||
| 598 | match pll_config { | ||
| 599 | Some(Pll::Oscillator { | ||
| 600 | source, | ||
| 601 | divm, | ||
| 602 | fractional, | ||
| 603 | divn, | ||
| 604 | divp1, | ||
| 605 | divp2, | ||
| 606 | }) => { | ||
| 607 | // ensure pll is disabled | ||
| 608 | RCC.ccr().write(|w| w.set_pllonc(pll_index, true)); | ||
| 609 | while RCC.sr().read().pllrdy(pll_index) {} | ||
| 610 | |||
| 611 | // ensure PLLxMODSSDIS=1 to work in fractional mode | ||
| 612 | cfgr3.modify(|w| w.set_pllmodssdis(Pllmodssdis::FRACTIONAL_DIVIDE)); | ||
| 613 | // clear bypass mode | ||
| 614 | cfgr1.modify(|w| w.set_pllbyp(false)); | ||
| 615 | // configure the pll clock source, mul and div factors | ||
| 616 | cfgr1.modify(|w| { | ||
| 617 | w.set_pllsel(source); | ||
| 618 | w.set_plldivm(divm); | ||
| 619 | w.set_plldivn(divn); | ||
| 620 | }); | ||
| 621 | |||
| 622 | let in_clk = match source { | ||
| 623 | Pllsel::HSI => unwrap!(input.hsi), | ||
| 624 | Pllsel::MSI => unwrap!(input.msi), | ||
| 625 | Pllsel::HSE => unwrap!(input.hse), | ||
| 626 | Pllsel::I2S_CKIN => unwrap!(input.i2s_ckin), | ||
| 627 | _ => panic!("reserved PLL source not allowed"), | ||
| 628 | }; | ||
| 629 | |||
| 630 | let m = divm.to_bits() as u32; | ||
| 631 | let n = divn as u32; | ||
| 632 | |||
| 633 | cfgr3.modify(|w| { | ||
| 634 | w.set_pllpdiv1(divp1); | ||
| 635 | w.set_pllpdiv2(divp2); | ||
| 636 | }); | ||
| 637 | |||
| 638 | let p1 = divp1.to_bits() as u32; | ||
| 639 | let p2 = divp2.to_bits() as u32; | ||
| 640 | |||
| 641 | // configure pll divnfrac | ||
| 642 | cfgr2.modify(|w| w.set_plldivnfrac(fractional)); | ||
| 643 | // clear pllxmoddsen | ||
| 644 | cfgr3.modify(|w| w.set_pllmoddsen(false)); | ||
| 645 | // fractional mode | ||
| 646 | if fractional != 0 { | ||
| 647 | cfgr3.modify(|w| { | ||
| 648 | w.set_pllmoddsen(true); | ||
| 649 | w.set_plldacen(true); | ||
| 650 | }) | ||
| 651 | } | ||
| 652 | // enable pll post divider output | ||
| 653 | cfgr3.modify(|w| { | ||
| 654 | w.set_pllmodssrst(true); | ||
| 655 | w.set_pllpdiven(true); | ||
| 656 | }); | ||
| 657 | // enable the pll | ||
| 658 | RCC.csr().write(|w| w.pllons(pll_index)); | ||
| 659 | // wait until ready | ||
| 660 | while RCC.sr().read().pllrdy(pll_index) {} | ||
| 661 | |||
| 662 | PllOutput { | ||
| 663 | divm: Some(Hertz(m)), | ||
| 664 | divn: Some(Hertz(n)), | ||
| 665 | divp1: Some(Hertz(p1)), | ||
| 666 | divp2: Some(Hertz(p2)), | ||
| 667 | output: Some(Hertz(in_clk.0 / m / n / p1 / p2)), | ||
| 668 | } | ||
| 669 | } | ||
| 670 | Some(Pll::Bypass { source }) => { | ||
| 671 | // check if source is ready | ||
| 672 | if !pll_source_ready(source.to_bits()) { | ||
| 673 | panic!("PLL source is not ready") | ||
| 674 | } | ||
| 675 | |||
| 676 | // ensure pll is disabled | ||
| 677 | RCC.ccr().write(|w| w.set_pllonc(pll_index, true)); | ||
| 678 | while RCC.sr().read().pllrdy(pll_index) {} | ||
| 679 | |||
| 680 | cfgr1.modify(|w| { | ||
| 681 | w.set_pllbyp(true); | ||
| 682 | w.set_pllsel(source); | ||
| 683 | }); | ||
| 684 | |||
| 685 | let in_clk = match source { | ||
| 686 | Pllsel::HSI => unwrap!(input.hsi), | ||
| 687 | Pllsel::MSI => unwrap!(input.msi), | ||
| 688 | Pllsel::HSE => unwrap!(input.hse), | ||
| 689 | Pllsel::I2S_CKIN => unwrap!(input.i2s_ckin), | ||
| 690 | _ => panic!("reserved PLL source not allowed"), | ||
| 691 | }; | ||
| 692 | |||
| 693 | PllOutput { | ||
| 694 | output: Some(in_clk), | ||
| 695 | ..Default::default() | ||
| 696 | } | ||
| 697 | } | ||
| 698 | None => { | ||
| 699 | cfgr3.modify(|w| w.set_pllpdiven(false)); | ||
| 700 | RCC.ccr().write(|w| w.set_pllonc(pll_index, true)); | ||
| 701 | // wait till disabled | ||
| 702 | while RCC.sr().read().pllrdy(pll_index) {} | ||
| 703 | |||
| 704 | // clear bypass mode | ||
| 705 | cfgr1.modify(|w| w.set_pllbyp(false)); | ||
| 706 | |||
| 707 | PllOutput::default() | ||
| 708 | } | ||
| 709 | } | ||
| 710 | } | ||
| 711 | |||
| 712 | #[allow(dead_code)] | ||
| 713 | struct OscOutput { | ||
| 714 | hsi: Option<Hertz>, | ||
| 715 | hse: Option<Hertz>, | ||
| 716 | msi: Option<Hertz>, | ||
| 717 | lsi: Option<Hertz>, | ||
| 718 | lse: Option<Hertz>, | ||
| 719 | pll1: Option<Hertz>, | ||
| 720 | pll2: Option<Hertz>, | ||
| 721 | pll3: Option<Hertz>, | ||
| 722 | pll4: Option<Hertz>, | ||
| 723 | ic1sel: Icsel, | ||
| 724 | ic2sel: Icsel, | ||
| 725 | ic6sel: Icsel, | ||
| 726 | ic11sel: Icsel, | ||
| 727 | } | ||
| 728 | |||
| 729 | fn init_osc(config: Config) -> OscOutput { | ||
| 730 | let (cpu_src, sys_src) = { | ||
| 731 | let reg = RCC.cfgr().read(); | ||
| 732 | (reg.cpusws(), reg.syssws()) | ||
| 733 | }; | ||
| 734 | let pll1_src = RCC.pllcfgr1(0).read().pllsel(); | ||
| 735 | let pll2_src = RCC.pllcfgr1(1).read().pllsel(); | ||
| 736 | let pll3_src = RCC.pllcfgr1(2).read().pllsel(); | ||
| 737 | let pll4_src = RCC.pllcfgr1(3).read().pllsel(); | ||
| 738 | let rcc_sr = RCC.sr().read(); | ||
| 739 | |||
| 740 | debug!("configuring HSE"); | ||
| 741 | |||
| 742 | // hse configuration | ||
| 743 | let hse = if let Some(hse) = config.hse { | ||
| 744 | match hse.mode { | ||
| 745 | HseMode::Oscillator => { | ||
| 746 | debug!("HSE in oscillator mode"); | ||
| 747 | } | ||
| 748 | HseMode::Bypass => { | ||
| 749 | debug!("HSE in bypass mode"); | ||
| 750 | RCC.hsecfgr().modify(|w| { | ||
| 751 | w.set_hsebyp(true); | ||
| 752 | w.set_hseext(Hseext::ANALOG); | ||
| 753 | }); | ||
| 754 | } | ||
| 755 | HseMode::BypassDigital => { | ||
| 756 | debug!("HSE in bypass digital mode"); | ||
| 757 | RCC.hsecfgr().modify(|w| { | ||
| 758 | w.set_hsebyp(true); | ||
| 759 | w.set_hseext(Hseext::DIGITAL); | ||
| 760 | }); | ||
| 761 | } | ||
| 762 | } | ||
| 763 | RCC.csr().write(|w| w.set_hseons(true)); | ||
| 764 | |||
| 765 | // wait until the hse is ready | ||
| 766 | while !RCC.sr().read().hserdy() {} | ||
| 767 | |||
| 768 | Some(hse.freq) | ||
| 769 | } else if cpu_src == Cpusws::HSE | ||
| 770 | || sys_src == Syssws::HSE | ||
| 771 | || (pll1_src == Pllsel::HSE && rcc_sr.pllrdy(0)) | ||
| 772 | || (pll2_src == Pllsel::HSE && rcc_sr.pllrdy(1)) | ||
| 773 | || (pll3_src == Pllsel::HSE && rcc_sr.pllrdy(2)) | ||
| 774 | || (pll4_src == Pllsel::HSE && rcc_sr.pllrdy(3)) | ||
| 775 | { | ||
| 776 | panic!( | ||
| 777 | "When the HSE is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled" | ||
| 778 | ); | ||
| 779 | } else { | ||
| 780 | debug!("HSE off"); | ||
| 781 | |||
| 782 | RCC.ccr().write(|w| w.set_hseonc(true)); | ||
| 783 | RCC.hsecfgr().modify(|w| { | ||
| 784 | w.set_hseext(Hseext::ANALOG); | ||
| 785 | w.set_hsebyp(false); | ||
| 786 | }); | ||
| 787 | |||
| 788 | // wait until the hse is disabled | ||
| 789 | while RCC.sr().read().hserdy() {} | ||
| 790 | |||
| 791 | None | ||
| 792 | }; | ||
| 793 | |||
| 794 | // hsi configuration | ||
| 795 | debug!("configuring HSI"); | ||
| 796 | let hsi = if let Some(hsi) = config.hsi { | ||
| 797 | RCC.csr().write(|w| w.set_hsions(true)); | ||
| 798 | while !RCC.sr().read().hsirdy() {} | ||
| 799 | |||
| 800 | // set divider and calibration | ||
| 801 | RCC.hsicfgr().modify(|w| { | ||
| 802 | w.set_hsidiv(hsi.pre); | ||
| 803 | w.set_hsitrim(hsi.trim); | ||
| 804 | }); | ||
| 805 | |||
| 806 | Some(HSI_FREQ / hsi.pre) | ||
| 807 | } else if cpu_src == Cpusws::HSI | ||
| 808 | || sys_src == Syssws::HSI | ||
| 809 | || (pll1_src == Pllsel::HSI && rcc_sr.pllrdy(0)) | ||
| 810 | || (pll2_src == Pllsel::HSI && rcc_sr.pllrdy(1)) | ||
| 811 | || (pll3_src == Pllsel::HSI && rcc_sr.pllrdy(2)) | ||
| 812 | || (pll4_src == Pllsel::HSI && rcc_sr.pllrdy(3)) | ||
| 813 | { | ||
| 814 | panic!( | ||
| 815 | "When the HSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled" | ||
| 816 | ); | ||
| 817 | } else { | ||
| 818 | debug!("HSI off"); | ||
| 819 | |||
| 820 | RCC.ccr().write(|w| w.set_hsionc(true)); | ||
| 821 | while RCC.sr().read().hsirdy() {} | ||
| 822 | |||
| 823 | None | ||
| 824 | }; | ||
| 825 | |||
| 826 | // msi configuration | ||
| 827 | debug!("configuring MSI"); | ||
| 828 | let msi = if let Some(msi) = config.msi { | ||
| 829 | RCC.msicfgr().modify(|w| w.set_msifreqsel(msi.freq)); | ||
| 830 | RCC.csr().write(|w| w.set_msions(true)); | ||
| 831 | while !RCC.sr().read().msirdy() {} | ||
| 832 | RCC.msicfgr().modify(|w| w.set_msitrim(msi.trim)); | ||
| 833 | |||
| 834 | Some(match msi.freq { | ||
| 835 | Msifreqsel::_4MHZ => Hertz::mhz(4), | ||
| 836 | Msifreqsel::_16MHZ => Hertz::mhz(16), | ||
| 837 | }) | ||
| 838 | } else if cpu_src == Cpusws::MSI | ||
| 839 | || sys_src == Syssws::MSI | ||
| 840 | || (pll1_src == Pllsel::MSI && rcc_sr.pllrdy(0)) | ||
| 841 | || (pll2_src == Pllsel::MSI && rcc_sr.pllrdy(1)) | ||
| 842 | || (pll3_src == Pllsel::MSI && rcc_sr.pllrdy(2)) | ||
| 843 | || (pll4_src == Pllsel::MSI && rcc_sr.pllrdy(3)) | ||
| 844 | { | ||
| 845 | panic!( | ||
| 846 | "When the MSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled" | ||
| 847 | ); | ||
| 848 | } else { | ||
| 849 | RCC.ccr().write(|w| w.set_msionc(true)); | ||
| 850 | while RCC.sr().read().msirdy() {} | ||
| 851 | |||
| 852 | None | ||
| 853 | }; | ||
| 854 | |||
| 855 | // lsi configuration | ||
| 856 | debug!("configuring LSI"); | ||
| 857 | let lsi = if config.lsi { | ||
| 858 | RCC.csr().write(|w| w.set_lsions(true)); | ||
| 859 | while !RCC.sr().read().lsirdy() {} | ||
| 860 | Some(super::LSI_FREQ) | ||
| 861 | } else { | ||
| 862 | RCC.ccr().write(|w| w.set_lsionc(true)); | ||
| 863 | while RCC.sr().read().lsirdy() {} | ||
| 864 | None | ||
| 865 | }; | ||
| 866 | |||
| 867 | // lse configuration | ||
| 868 | debug!("configuring LSE"); | ||
| 869 | let lse = if config.lse { | ||
| 870 | RCC.csr().write(|w| w.set_lseons(true)); | ||
| 871 | while !RCC.sr().read().lserdy() {} | ||
| 872 | Some(LSE_FREQ) | ||
| 873 | } else { | ||
| 874 | RCC.ccr().write(|w| w.set_lseonc(true)); | ||
| 875 | while RCC.sr().read().lserdy() {} | ||
| 876 | None | ||
| 877 | }; | ||
| 878 | |||
| 879 | let pll_input = PllInput { | ||
| 880 | hse, | ||
| 881 | msi, | ||
| 882 | hsi, | ||
| 883 | i2s_ckin: None, | ||
| 884 | }; | ||
| 885 | |||
| 886 | // pll1,2,3,4 config | ||
| 887 | let pll_configs = [config.pll1, config.pll2, config.pll3, config.pll4]; | ||
| 888 | let mut pll_outputs: [PllOutput; 4] = [PllOutput::default(); 4]; | ||
| 889 | |||
| 890 | let ic1_src = RCC.iccfgr(0).read().icsel(); | ||
| 891 | let ic2_src = RCC.iccfgr(1).read().icsel(); | ||
| 892 | let ic6_src = RCC.iccfgr(5).read().icsel(); | ||
| 893 | let ic11_src = RCC.iccfgr(10).read().icsel(); | ||
| 894 | |||
| 895 | for (n, (&pll, out)) in pll_configs.iter().zip(pll_outputs.iter_mut()).enumerate() { | ||
| 896 | debug!("configuring PLL{}", n + 1); | ||
| 897 | let pll_ready = RCC.sr().read().pllrdy(n); | ||
| 898 | |||
| 899 | if is_new_pll_config(pll, 0) { | ||
| 900 | let this_pll = Icsel::from_bits(n as u8); | ||
| 901 | |||
| 902 | if cpu_src == Cpusws::IC1 && ic1_src == this_pll { | ||
| 903 | panic!("PLL should not be disabled / reconfigured if used for IC1 (cpuclksrc)") | ||
| 904 | } | ||
| 905 | |||
| 906 | if sys_src == Syssws::IC2 && (ic2_src == this_pll || ic6_src == this_pll || ic11_src == this_pll) { | ||
| 907 | panic!("PLL should not be disabled / reconfigured if used for IC2, IC6 or IC11 (sysclksrc)") | ||
| 908 | } | ||
| 909 | |||
| 910 | *out = init_pll(pll, 0, &pll_input); | ||
| 911 | } else if pll.is_some() && !pll_ready { | ||
| 912 | RCC.csr().write(|w| w.pllons(n)); | ||
| 913 | while !RCC.sr().read().pllrdy(n) {} | ||
| 914 | } | ||
| 915 | } | ||
| 916 | |||
| 917 | OscOutput { | ||
| 918 | hsi, | ||
| 919 | hse, | ||
| 920 | msi, | ||
| 921 | lsi, | ||
| 922 | lse, | ||
| 923 | pll1: pll_outputs[0].output, | ||
| 924 | pll2: pll_outputs[1].output, | ||
| 925 | pll3: pll_outputs[2].output, | ||
| 926 | pll4: pll_outputs[3].output, | ||
| 927 | ic1sel: ic1_src, | ||
| 928 | ic2sel: ic2_src, | ||
| 929 | ic6sel: ic6_src, | ||
| 930 | ic11sel: ic11_src, | ||
| 931 | } | ||
| 932 | } | ||
| 933 | |||
| 934 | fn is_new_pll_config(pll: Option<Pll>, pll_index: usize) -> bool { | ||
| 935 | let cfgr1 = RCC.pllcfgr1(pll_index).read(); | ||
| 936 | let cfgr2 = RCC.pllcfgr2(pll_index).read(); | ||
| 937 | let cfgr3 = RCC.pllcfgr3(pll_index).read(); | ||
| 938 | |||
| 939 | let ready = RCC.sr().read().pllrdy(pll_index); | ||
| 940 | let bypass = cfgr1.pllbyp(); | ||
| 941 | |||
| 942 | match (pll, ready, bypass) { | ||
| 943 | (None, true, _) => return true, | ||
| 944 | (Some(_), false, _) => return true, | ||
| 945 | (Some(conf), true, bypass) => match (conf, bypass) { | ||
| 946 | (Pll::Bypass { .. }, false) => return true, | ||
| 947 | (Pll::Oscillator { .. }, true) => return true, | ||
| 948 | _ => {} | ||
| 949 | }, | ||
| 950 | _ => {} | ||
| 951 | } | ||
| 952 | |||
| 953 | match pll { | ||
| 954 | Some(Pll::Bypass { source }) => cfgr1.pllsel() != source, | ||
| 955 | Some(Pll::Oscillator { | ||
| 956 | source, | ||
| 957 | divm: m, | ||
| 958 | fractional, | ||
| 959 | divn: n, | ||
| 960 | divp1: p1, | ||
| 961 | divp2: p2, | ||
| 962 | }) => { | ||
| 963 | cfgr1.pllsel() != source | ||
| 964 | || cfgr1.plldivm() != m | ||
| 965 | || cfgr1.plldivn() != n | ||
| 966 | || cfgr2.plldivnfrac() != fractional | ||
| 967 | || cfgr3.pllpdiv1() != p1 | ||
| 968 | || cfgr3.pllpdiv2() != p2 | ||
| 969 | } | ||
| 970 | None => false, | ||
| 971 | } | ||
| 972 | } | ||
| 973 | |||
| 974 | pub(crate) unsafe fn init(config: Config) { | ||
| 975 | debug!("enabling SYSCFG"); | ||
| 976 | // system configuration setup | ||
| 977 | RCC.apb4hensr().write(|w| w.set_syscfgens(true)); | ||
| 978 | // delay after RCC peripheral clock enabling | ||
| 979 | RCC.apb4hensr().read(); | ||
| 980 | |||
| 981 | debug!("setting VTOR"); | ||
| 982 | |||
| 983 | let vtor = unsafe { | ||
| 984 | let p = cortex_m::Peripherals::steal(); | ||
| 985 | p.SCB.vtor.read() | ||
| 986 | }; | ||
| 987 | |||
| 988 | // set default vector table location after reset or standby | ||
| 989 | SYSCFG.initsvtorcr().write(|w| w.set_svtor_addr(vtor)); | ||
| 990 | // read back the value to ensure it is written before deactivating SYSCFG | ||
| 991 | SYSCFG.initsvtorcr().read(); | ||
| 992 | |||
| 993 | debug!("deactivating SYSCFG"); | ||
| 994 | |||
| 995 | // deactivate SYSCFG | ||
| 996 | RCC.apb4hensr().write(|w| w.set_syscfgens(false)); | ||
| 997 | |||
| 998 | debug!("enabling FPU"); | ||
| 999 | |||
| 1000 | // enable fpu | ||
| 1001 | unsafe { | ||
| 1002 | let p = cortex_m::Peripherals::steal(); | ||
| 1003 | p.SCB.cpacr.modify(|w| w | (3 << 20) | (3 << 22)); | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | // TODO: ugly workaround for DMA accesses until RIF is properly implemented | ||
| 1007 | debug!("deactivating RIF"); | ||
| 1008 | const RISAF3_BASE_NS: *mut u32 = stm32_metapac::RNG.wrapping_byte_offset(0x8000) as _; // AHB3PERIPH_BASE_NS + 0x8000UL | ||
| 1009 | const RISAF3_REG0_CFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x40); | ||
| 1010 | const RISAF3_REG0_ENDR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x48); | ||
| 1011 | const RISAF3_REG0_CIDCFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x4C); | ||
| 1012 | const RISAF3_REG1_CFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x80); | ||
| 1013 | const RISAF3_REG1_ENDR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x88); | ||
| 1014 | const RISAF3_REG1_CIDCFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x8C); | ||
| 1015 | unsafe { | ||
| 1016 | *RISAF3_REG0_CIDCFGR = 0x000F000F; /* RW for everyone */ | ||
| 1017 | *RISAF3_REG0_ENDR = 0xFFFFFFFF; /* all-encompassing */ | ||
| 1018 | *RISAF3_REG0_CFGR = 0x00000101; /* enabled, secure, unprivileged for everyone */ | ||
| 1019 | *RISAF3_REG1_CIDCFGR = 0x00FF00FF; /* RW for everyone */ | ||
| 1020 | *RISAF3_REG1_ENDR = 0xFFFFFFFF; /* all-encompassing */ | ||
| 1021 | *RISAF3_REG1_CFGR = 0x00000001; /* enabled, non-secure, unprivileged*/ | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | debug!("setting power supply config"); | ||
| 1025 | |||
| 1026 | power_supply_config(config.supply_config); | ||
| 1027 | |||
| 1028 | let osc = init_osc(config); | ||
| 1029 | let clock_inputs = ClocksInput { | ||
| 1030 | hsi: osc.hsi, | ||
| 1031 | msi: osc.msi, | ||
| 1032 | hse: osc.hse, | ||
| 1033 | }; | ||
| 1034 | let clocks = init_clocks(config, &clock_inputs); | ||
| 1035 | |||
| 1036 | // TODO: sysb, sysc, sysd must have the same clock source | ||
| 1037 | |||
| 1038 | set_clocks!( | ||
| 1039 | sys: Some(clocks.sysclk), | ||
| 1040 | hsi: osc.hsi, | ||
| 1041 | hsi_div: None, | ||
| 1042 | hse: osc.hse, | ||
| 1043 | msi: osc.msi, | ||
| 1044 | hclk1: Some(clocks.ahb), | ||
| 1045 | hclk2: Some(clocks.ahb), | ||
| 1046 | hclk3: Some(clocks.ahb), | ||
| 1047 | hclk4: Some(clocks.ahb), | ||
| 1048 | hclk5: Some(clocks.ahb), | ||
| 1049 | pclk1: Some(clocks.apb1), | ||
| 1050 | pclk2: Some(clocks.apb2), | ||
| 1051 | pclk1_tim: Some(clocks.pclk_tim), | ||
| 1052 | pclk2_tim: Some(clocks.pclk_tim), | ||
| 1053 | pclk4: Some(clocks.apb4), | ||
| 1054 | pclk5: Some(clocks.apb5), | ||
| 1055 | per: None, | ||
| 1056 | rtc: None, | ||
| 1057 | i2s_ckin: None, | ||
| 1058 | ic8: None, | ||
| 1059 | ic9: None, | ||
| 1060 | ic10: None, | ||
| 1061 | ic14: None, | ||
| 1062 | ic15: None, | ||
| 1063 | ic17: None, | ||
| 1064 | ic20: None, | ||
| 1065 | ); | ||
| 1066 | } | ||
