aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/rcc/n6.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/rcc/n6.rs')
-rw-r--r--embassy-stm32/src/rcc/n6.rs1066
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 @@
1use stm32_metapac::rcc::vals::{
2 Cpusw, Cpusws, Hseext, Hsitrim, Icint, Icsel, Msifreqsel, Plldivm, Pllmodssdis, Pllpdiv, Pllsel, Syssw, Syssws,
3 Timpre,
4};
5pub use stm32_metapac::rcc::vals::{
6 Hpre as AhbPrescaler, Hsidiv as HsiPrescaler, Hsitrim as HsiCalibration, Ppre as ApbPrescaler,
7};
8
9use crate::pac::{PWR, RCC, SYSCFG};
10use crate::time::Hertz;
11
12pub const HSI_FREQ: Hertz = Hertz(64_000_000);
13pub const LSE_FREQ: Hertz = Hertz(32_768);
14
15#[derive(Clone, Copy, Eq, PartialEq)]
16pub 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)]
26pub 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)]
34pub struct Hsi {
35 pub pre: HsiPrescaler,
36 pub trim: Hsitrim,
37}
38
39#[derive(Clone, Copy, PartialEq)]
40pub enum SupplyConfig {
41 Smps,
42 External,
43}
44
45#[derive(Clone, Copy, PartialEq)]
46pub enum CpuClk {
47 Hse,
48 Ic1 { source: Icsel, divider: Icint },
49 Msi,
50 Hsi,
51}
52
53impl 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)]
65pub struct IcConfig {
66 source: Icsel,
67 divider: Icint,
68}
69
70#[derive(Clone, Copy, PartialEq)]
71pub enum SysClk {
72 Hse,
73 Ic2 {
74 ic2: IcConfig,
75 ic6: IcConfig,
76 ic11: IcConfig,
77 },
78 Msi,
79 Hsi,
80}
81
82impl 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)]
94pub struct Msi {
95 pub freq: Msifreqsel,
96 pub trim: u8,
97}
98
99#[derive(Clone, Copy, PartialEq)]
100pub 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)]
117pub 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
141impl 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)]
171struct 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
182struct ClocksInput {
183 hsi: Option<Hertz>,
184 msi: Option<Hertz>,
185 hse: Option<Hertz>,
186}
187
188fn 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
353fn 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
530const 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
543fn 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
553fn pll_sources_ready(source1: u8, source2: u8) -> bool {
554 pll_source_ready(source1) && pll_source_ready(source2)
555}
556
557impl Default for Config {
558 fn default() -> Self {
559 Self::new()
560 }
561}
562
563fn 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
576struct 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)]
585struct PllOutput {
586 divm: Option<Hertz>,
587 divn: Option<Hertz>,
588 divp1: Option<Hertz>,
589 divp2: Option<Hertz>,
590 output: Option<Hertz>,
591}
592
593fn 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)]
713struct 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
729fn 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
934fn 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
974pub(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}