stm32_hal2/clocks/
baseline.rs

1//! Clock config for STM32L, G, and W-series MCUs. Uses a `Clocks` struct to configure
2//! settings, starting with a `Default::default()` implementation. Uses the `setup` method
3//! to write changes.
4
5// Similar in from to the H7 clocks module, but includes notable differendes.
6
7use cfg_if::cfg_if;
8
9#[cfg(any(feature = "l4", feature = "l5", feature = "wb", feature = "g4"))]
10use crate::pac::CRS;
11#[cfg(not(any(feature = "wb", feature = "wl")))]
12use crate::util::rcc_en_reset;
13use crate::{
14    clocks::RccError,
15    error::{Error, Result},
16    pac::{self, FLASH, RCC},
17    util::bounded_loop,
18};
19
20// todo: WB is missing second LSI2, and perhaps other things.
21
22#[cfg(not(any(feature = "g0", feature = "wl", feature = "c0")))]
23#[derive(Clone, Copy, PartialEq)]
24#[repr(u8)]
25pub enum Clk48Src {
26    // Note: On G4 which only has HSI48 and PLLQ, PLLSai1 and MSI are marked "reserved", and
27    // The values it has are the same as on L4/5.
28    Hsi48 = 0b00, // Not valid for some L4 variants.
29    #[cfg(not(feature = "g4"))]
30    PllSai1 = 0b01, // Not avail on G4
31    Pllq = 0b10,
32    #[cfg(msi)]
33    Msi = 0b11,
34}
35
36#[cfg(feature = "c071")]
37#[derive(Clone, Copy, PartialEq)]
38#[repr(u8)]
39/// Sets `RCC_CCIPR2` register, `USBSEL` field.
40pub enum Clk48Src {
41    HsiUsb48 = 0,
42    Hse = 1,
43}
44
45#[cfg(any(feature = "l4", feature = "l5", feature = "wb", feature = "g4"))]
46#[derive(Clone, Copy)]
47#[repr(u8)]
48/// Select the SYNC signal source. Sets the CRS_CFGR register, SYNCSRC field.
49pub enum CrsSyncSrc {
50    Gpio = 0b00,
51    Lse = 0b01,
52    Usb = 0b10,
53}
54
55#[cfg(not(any(feature = "g0", feature = "g4", feature = "c0")))]
56#[derive(Clone, Copy, PartialEq)]
57pub enum PllSrc {
58    None,
59    Msi(MsiRange),
60    Hsi,
61    Hse(u32),
62}
63
64#[cfg(any(feature = "g0", feature = "g4", feature = "c0"))]
65#[derive(Clone, Copy, PartialEq)]
66pub enum PllSrc {
67    None,
68    Hsi,
69    Hse(u32),
70}
71
72impl PllSrc {
73    /// Required due to numerical value on non-uniform discrim being experimental.
74    /// (ie, can't set on `Pll(Pllsrc)`.
75    /// Sets PLLCFGR reg (PLLSYSCFGR on G0), PLLSRC field.
76    pub fn bits(&self) -> u8 {
77        // L4 RM, 6.4.4
78        #[cfg(not(any(feature = "g0", feature = "g4", feature = "c0")))]
79        match self {
80            Self::None => 0b00,
81            Self::Msi(_) => 0b01,
82            Self::Hsi => 0b10,
83            Self::Hse(_) => 0b11,
84        }
85        #[cfg(any(feature = "g0", feature = "g4", feature = "c0"))]
86        match self {
87            Self::None => 0b00,
88            Self::Hsi => 0b10,
89            Self::Hse(_) => 0b11,
90        }
91    }
92}
93
94#[cfg(any(feature = "l4", feature = "l5", feature = "wb", feature = "wl"))]
95#[derive(Clone, Copy, PartialEq)]
96#[repr(u8)]
97/// Select the system clock used when exiting Stop mode. Sets RCC_CFGR register, STOPWUCK field.
98pub enum StopWuck {
99    Msi = 0,
100    Hsi = 1,
101}
102
103cfg_if! {
104    if #[cfg(feature = "c0")] {
105        #[derive(Clone, Copy, PartialEq)]
106        /// Clock input source, also known as system clock switch. Sets RCC_CFGR register, SW field.
107        pub enum InputSrc {
108            /// Called "hsisys" in the RM; keeping it as Hsi here for consistency.
109            Hsi,
110            Hse(u32), // freq in Mhz,
111            #[cfg(feature = "c071")]
112            HsiUsb48,
113            Lsi,
114            Lse,
115        }
116
117        impl InputSrc {
118            /// Required due to numerical value on non-uniform discrim being experimental.
119            /// (ie, can't set on `Pll(Pllsrc)`. G0 RM, section 5.4.3.
120            pub fn bits(&self) -> u8 {
121                match self {
122                    Self::Hsi => 0b000,
123                    Self::Hse(_) => 0b001,
124                    #[cfg(feature = "c071")]
125                    Self::HsiUsb48 => 0b010,
126                    Self::Lsi => 0b011,
127                    Self::Lse => 0b100,
128                }
129            }
130        }
131    } else if #[cfg(feature = "g0")] {
132        #[derive(Clone, Copy, PartialEq)]
133        /// Clock input source, also known as system clock switch. Sets RCC_CFGR register, SW field.
134        pub enum InputSrc {
135            Hsi,
136            Hse(u32), // freq in Mhz,
137            Pll(PllSrc),
138            Lsi,
139            Lse,
140        }
141
142        impl InputSrc {
143            /// Required due to numerical value on non-uniform discrim being experimental.
144            /// (ie, can't set on `Pll(Pllsrc)`. G0 RM, section 5.4.3.
145            pub fn bits(&self) -> u8 {
146                match self {
147                    Self::Hsi => 0b000,
148                    Self::Hse(_) => 0b001,
149                    Self::Pll(_) => 0b010,
150                    Self::Lsi => 0b011,
151                    Self::Lse => 0b100,
152                }
153            }
154        }
155    } else if #[cfg(feature = "g4")] {
156        #[derive(Clone, Copy, PartialEq)]
157        pub enum InputSrc {
158            Hsi,
159            Hse(u32), // freq in Hz,
160            Pll(PllSrc),
161        }
162
163        impl InputSrc {
164            /// Required due to numerical value on non-uniform discrim being experimental.
165            /// (ie, can't set on `Pll(Pllsrc)`.
166            pub fn bits(&self) -> u8 {
167                match self {
168                    Self::Hsi => 0b01,
169                    Self::Hse(_) => 0b10,
170                    Self::Pll(_) => 0b11,
171                }
172            }
173        }
174    } else {  // ie L4 and L5
175        #[derive(Clone, Copy, PartialEq)]
176        pub enum InputSrc {
177            Msi(MsiRange),
178            Hsi,
179            Hse(u32), // freq in Hz,
180            Pll(PllSrc),
181        }
182
183        impl InputSrc {
184            /// Required due to numerical value on non-uniform discrim being experimental.
185            /// (ie, can't set on `Pll(Pllsrc)`.
186            pub fn bits(&self) -> u8 {
187                match self {
188                    Self::Msi(_) => 0b00,
189                    Self::Hsi => 0b01,
190                    Self::Hse(_) => 0b10,
191                    Self::Pll(_) => 0b11,
192                }
193            }
194        }
195    }
196}
197
198#[cfg(feature = "wb")]
199#[derive(Clone, Copy, PartialEq)]
200#[repr(u8)]
201/// RF system wakeup clock source selection
202pub enum RfWakeupSrc {
203    NoClock = 0b00,
204    /// LSE oscillator clock used as RF system wakeup clock
205    Lse = 0b01,
206    /// HSE oscillator clock divided by 1024 used as RF system wakeup clock
207    Hse = 0b11,
208}
209
210// L4 uses 0 - 4 only. Others use 1 - 15, but it's not clear when you'd
211// set more than WS5 or so.
212#[derive(Clone, Copy)]
213#[repr(u8)]
214/// Represents Flash wait states in the FLASH_ACR register.
215enum WaitState {
216    W0 = 0,
217    W1 = 1,
218    #[cfg(not(feature = "c0"))]
219    W2 = 2,
220    #[cfg(not(any(feature = "wl", feature = "c0")))]
221    W3 = 3,
222    #[cfg(not(any(feature = "wb", feature = "wl", feature = "c0")))]
223    W4 = 4,
224    #[cfg(feature = "l5")]
225    W5 = 5,
226}
227
228#[cfg(not(any(feature = "g0", feature = "g4", feature = "c0")))]
229#[derive(Clone, Copy, PartialEq)]
230#[repr(u8)]
231/// Specify the range of MSI - this is effectively it's oscillation speed.
232pub enum MsiRange {
233    R100k = 0b0000,
234    R200k = 0b0001,
235    R400k = 0b0010,
236    R800k = 0b0011,
237    R1M = 0b0100,
238    R2M = 0b0101,
239    R4M = 0b0110, // default
240    R8M = 0b0111,
241    R16M = 0b1000,
242    R24M = 0b1001,
243    R32M = 0b1010,
244    R48M = 0b1011,
245}
246
247#[cfg(not(any(feature = "g0", feature = "g4", feature = "c0")))]
248impl MsiRange {
249    // Calculate the approximate frequency, in Hz.
250    const fn value(&self) -> u32 {
251        match self {
252            Self::R100k => 100_000,
253            Self::R200k => 200_000,
254            Self::R400k => 400_000,
255            Self::R800k => 800_000,
256            Self::R1M => 1_000_000,
257            Self::R2M => 2_000_000,
258            Self::R4M => 4_000_000,
259            Self::R8M => 8_000_000,
260            Self::R16M => 16_000_000,
261            Self::R24M => 24_000_000,
262            Self::R32M => 32_000_000,
263            Self::R48M => 48_000_000,
264        }
265    }
266}
267
268#[cfg(feature = "c0")]
269#[derive(Clone, Copy, PartialEq)]
270#[repr(u8)]
271/// Sets CR reg, HSDIV field. Hardware default of Div4.
272pub enum HsiDiv {
273    Div1 = 0b000,
274    Div2 = 0b001,
275    Div4 = 0b010,
276    Div8 = 0b011,
277    Div16 = 0b100,
278    Div32 = 0b101,
279    Div64 = 0b110,
280    Div128 = 0b111,
281}
282
283#[cfg(feature = "c0")]
284impl HsiDiv {
285    pub const fn value(&self) -> u32 {
286        match self {
287            HsiDiv::Div1 => 1,
288            HsiDiv::Div2 => 2,
289            HsiDiv::Div4 => 4,
290            HsiDiv::Div8 => 8,
291            HsiDiv::Div16 => 16,
292            HsiDiv::Div32 => 32,
293            HsiDiv::Div64 => 64,
294            HsiDiv::Div128 => 128,
295        }
296    }
297}
298
299#[cfg(feature = "c071")]
300#[derive(Clone, Copy, PartialEq)]
301#[repr(u8)]
302/// Sets CR reg, SYSDIV field. Hardware default of Div1.
303pub enum SysDiv {
304    Div1 = 0b000,
305    Div2 = 0b001,
306    Div3 = 0b010,
307    Div4 = 0b011,
308    Div5 = 0b100,
309    Div6 = 0b101,
310    Div7 = 0b110,
311    Div8 = 0b111,
312}
313
314#[cfg(feature = "c071")]
315impl SysDiv {
316    pub const fn value(&self) -> u32 {
317        match self {
318            SysDiv::Div1 => 1,
319            SysDiv::Div2 => 2,
320            SysDiv::Div3 => 3,
321            SysDiv::Div4 => 4,
322            SysDiv::Div5 => 5,
323            SysDiv::Div6 => 6,
324            SysDiv::Div7 => 7,
325            SysDiv::Div8 => 8,
326        }
327    }
328}
329
330/// Configures the speeds, and enable status of an individual PLL (PLL1, or SAIPLL). Note that the `enable`
331/// field has no effect for PLL1.
332pub struct PllCfg {
333    /// Only relevant for PLLSAI1.
334    pub enabled: bool,
335    pub pllr_en: bool,
336    pub pllq_en: bool,
337    pub pllp_en: bool,
338    /// Only relevant for The main PLL.
339    pub divm: Pllm,
340    pub divn: u8,
341    pub divr: Pllr,
342    pub divq: Pllr,
343    pub divp: Pllp,
344    /// Defaults to 0, which causes the PLLP setting to take effect (of 7 or 17), instead of this
345    /// field.  Unused on "wb", "wl", "l4x5", and "l4x3" variants.
346    pub pdiv: u8,
347}
348
349impl Default for PllCfg {
350    fn default() -> Self {
351        // todo: Different defaults for different variants.
352        Self {
353            enabled: true,
354            pllr_en: true,
355            pllq_en: false,
356            pllp_en: false,
357            divm: Pllm::Div4,
358            #[cfg(feature = "l4")]
359            divn: 40,
360            #[cfg(feature = "l5")]
361            divn: 55,
362            #[cfg(feature = "g0")]
363            divn: 32,
364            #[cfg(feature = "g4")]
365            divn: 85,
366            #[cfg(feature = "wb")]
367            divn: 64,
368            #[cfg(feature = "wl")]
369            divn: 24,
370            #[cfg(feature = "c0")]
371            divn: 24, // todo: Guess; QC this.
372            #[cfg(not(feature = "wb"))]
373            divr: Pllr::Div2,
374            #[cfg(feature = "wb")]
375            divr: Pllr::Div4,
376            divq: Pllr::Div4,
377            divp: Pllp::Div7,
378            pdiv: 0,
379        }
380    }
381}
382
383impl PllCfg {
384    pub fn disabled() -> Self {
385        Self {
386            enabled: false,
387            pllp_en: false,
388            pllr_en: false,
389            pllq_en: false,
390            ..Default::default()
391        }
392    }
393
394    pub const fn pvalue(&self) -> u8 {
395        match self.pdiv {
396            0 => self.divp.value(),
397            pdiv => pdiv,
398        }
399    }
400}
401
402#[cfg(not(any(feature = "l5", feature = "g4")))]
403#[derive(Clone, Copy)]
404#[repr(u8)]
405pub enum Pllm {
406    Div1 = 0b000,
407    Div2 = 0b001,
408    Div3 = 0b010,
409    Div4 = 0b011,
410    Div5 = 0b100,
411    Div6 = 0b101,
412    Div7 = 0b110,
413    Div8 = 0b111,
414}
415
416#[cfg(any(feature = "l5", feature = "g4"))]
417#[derive(Clone, Copy)]
418#[repr(u8)]
419pub enum Pllm {
420    Div1 = 0b0000,
421    Div2 = 0b0001,
422    Div3 = 0b0010,
423    Div4 = 0b0011,
424    Div5 = 0b0100,
425    Div6 = 0b0101,
426    Div7 = 0b0110,
427    Div8 = 0b0111,
428    Div9 = 0b1000,
429    Div10 = 0b1001,
430    Div11 = 0b1010,
431    Div12 = 0b1011,
432    Div13 = 0b1100,
433    Div14 = 0b1101,
434    Div15 = 0b1110,
435    Div16 = 0b1111,
436}
437
438impl Pllm {
439    pub const fn value(&self) -> u8 {
440        #[cfg(not(any(feature = "l5", feature = "g4")))]
441        match self {
442            Self::Div1 => 1,
443            Self::Div2 => 2,
444            Self::Div3 => 3,
445            Self::Div4 => 4,
446            Self::Div5 => 5,
447            Self::Div6 => 6,
448            Self::Div7 => 7,
449            Self::Div8 => 8,
450        }
451
452        #[cfg(any(feature = "l5", feature = "g4"))]
453        match self {
454            Self::Div1 => 1,
455            Self::Div2 => 2,
456            Self::Div3 => 3,
457            Self::Div4 => 4,
458            Self::Div5 => 5,
459            Self::Div6 => 6,
460            Self::Div7 => 7,
461            Self::Div8 => 8,
462            Self::Div9 => 9,
463            Self::Div10 => 10,
464            Self::Div11 => 11,
465            Self::Div12 => 12,
466            Self::Div13 => 13,
467            Self::Div14 => 14,
468            Self::Div15 => 15,
469            Self::Div16 => 16,
470        }
471    }
472}
473
474#[cfg(any(feature = "g0", feature = "wb"))]
475#[derive(Clone, Copy)]
476#[repr(u8)]
477/// Main PLL division factor for PLLCLK (system clock). Also usd for PllQ.
478/// Sets `PLLCFGR` reg.
479pub enum Pllr {
480    Div2 = 0b001,
481    Div3 = 0b010,
482    Div4 = 0b011,
483    Div5 = 0b100,
484    Div6 = 0b101,
485    Div7 = 0b110,
486    Div8 = 0b111,
487}
488
489#[cfg(any(feature = "g0", feature = "wb"))]
490impl Pllr {
491    pub const fn value(&self) -> u8 {
492        match self {
493            Self::Div2 => 2,
494            Self::Div3 => 3,
495            Self::Div4 => 4,
496            Self::Div5 => 5,
497            Self::Div6 => 6,
498            Self::Div7 => 7,
499            Self::Div8 => 8,
500        }
501    }
502}
503
504#[cfg(not(any(feature = "g0", feature = "wb")))]
505#[derive(Clone, Copy)]
506#[repr(u8)]
507/// Main PLL division factor for PLLCLK (system clock). G4 RM 7.4.4. Also used to set PLLQ.
508pub enum Pllr {
509    Div2 = 0b00,
510    Div4 = 0b01,
511    Div6 = 0b10,
512    Div8 = 0b11,
513}
514
515#[cfg(not(any(feature = "g0", feature = "wb")))]
516impl Pllr {
517    pub const fn value(&self) -> u8 {
518        match self {
519            Self::Div2 => 2,
520            Self::Div4 => 4,
521            Self::Div6 => 6,
522            Self::Div8 => 8,
523        }
524    }
525}
526
527#[derive(Clone, Copy)]
528#[repr(u8)]
529/// Divisor for PLLP. Sets `PLLCFGR` reg, `PLLP` field.
530pub enum Pllp {
531    Div7 = 0,
532    Div17 = 1,
533}
534
535impl Pllp {
536    pub const fn value(&self) -> u8 {
537        match self {
538            Self::Div7 => 7,
539            Self::Div17 => 17,
540        }
541    }
542}
543
544#[derive(Clone, Copy)]
545#[repr(u8)]
546/// Division factor for the AHB clock. Also known as AHB Prescaler. L4 RM, 6.4.3
547/// on WB, used for all 3 HCLK prescalers.
548pub enum HclkPrescaler {
549    Div1 = 0b0000,
550    #[cfg(feature = "wb")]
551    Div3 = 0b0001,
552    #[cfg(feature = "wb")]
553    Div5 = 0b0010,
554    #[cfg(feature = "wb")]
555    Div6 = 0b0101,
556    #[cfg(feature = "wb")]
557    Div10 = 0b0110,
558    #[cfg(feature = "wb")]
559    Div32 = 0b0111,
560    Div2 = 0b1000,
561    Div4 = 0b1001,
562    Div8 = 0b1010,
563    Div16 = 0b1011,
564    Div64 = 0b1100,
565    Div128 = 0b1101,
566    Div256 = 0b1110,
567    Div512 = 0b1111,
568}
569
570impl HclkPrescaler {
571    pub const fn value(&self) -> u16 {
572        match self {
573            Self::Div1 => 1,
574            #[cfg(feature = "wb")]
575            Self::Div3 => 3,
576            #[cfg(feature = "wb")]
577            Self::Div5 => 5,
578            #[cfg(feature = "wb")]
579            Self::Div6 => 6,
580            #[cfg(feature = "wb")]
581            Self::Div10 => 10,
582            #[cfg(feature = "wb")]
583            Self::Div32 => 32,
584            Self::Div2 => 2,
585            Self::Div4 => 4,
586            Self::Div8 => 8,
587            Self::Div16 => 16,
588            Self::Div64 => 64,
589            Self::Div128 => 128,
590            Self::Div256 => 256,
591            Self::Div512 => 512,
592        }
593    }
594}
595
596#[derive(Clone, Copy)]
597#[repr(u8)]
598/// For use with `RCC_APBPPRE1`, and `RCC_APBPPRE2`. Ie, low-speed and high-speed prescalers respectively.
599pub enum ApbPrescaler {
600    Div1 = 0b000,
601    Div2 = 0b100,
602    Div4 = 0b101,
603    Div8 = 0b110,
604    Div16 = 0b111,
605}
606
607impl ApbPrescaler {
608    pub const fn value(&self) -> u8 {
609        match self {
610            Self::Div1 => 1,
611            Self::Div2 => 2,
612            Self::Div4 => 4,
613            Self::Div8 => 8,
614            Self::Div16 => 16,
615        }
616    }
617}
618
619#[derive(Clone, Copy, PartialEq)]
620#[repr(u8)]
621/// SAI clock input source. Sets RCC_CCIPR register, SAIxSEL fields.
622pub enum SaiSrc {
623    /// PLLSAI1 “P” clock (PLLSAI1PCLK) selected as SAI1 clock
624    PllSai1P = 0b00,
625    /// PLL “P” clock (PLLPCLK) selected as SAI1 clock
626    Pllp = 0b01,
627    /// HSI16 clock selected as SAI1 clock
628    Hsi = 0b10,
629    /// External input SAI1_EXTCLK selected as SAI1 clock
630    ExtClk = 0b11,
631}
632
633#[cfg(any(feature = "g0", feature = "g4"))]
634#[derive(Clone, Copy, PartialEq)]
635#[repr(u8)]
636/// CAN clock input source. Sets RCC_CCIPR register, FDCANSEL field.
637pub enum CanSrc {
638    /// hse_ck clock is selected as FDCAN kernel clock
639    Hse = 0b00,
640    /// PLL1Q
641    PllQ = 0b01,
642    /// PCLK1 (APB1) selected as FDCAN clock
643    Pclk = 0b10,
644}
645
646// todo: Impl this. RCC_CCIPR.
647#[cfg(not(any(feature = "f", feature = "l", feature = "g0")))]
648#[derive(Clone, Copy, PartialEq)]
649#[repr(u8)]
650/// LpUart clock sources. Defaults to Pclk.
651pub enum LpUartSrc {
652    Pclk = 0b00,
653    Sysclk = 0b01,
654    Hsi16 = 0b10,
655    Lse = 0b11,
656}
657
658/// Settings used to configure clocks. Create this struct by using its `Default::default()`
659/// implementation, then modify as required, referencing your RM's clock tree,
660/// or Stm32Cube IDE's interactive clock manager. Apply settings by running `.setup()`.
661pub struct Clocks {
662    /// The input source for the system and peripheral clocks. Eg HSE, HSI, PLL etc
663    pub input_src: InputSrc,
664    /// Enable and speed status for the main PLL
665    #[cfg(not(feature = "c0"))]
666    pub pll: PllCfg,
667    /// Enable and speed status for the SAI PLL
668    #[cfg(not(any(feature = "g0", feature = "g4", feature = "wl", feature = "c0")))]
669    pub pllsai1: PllCfg,
670    #[cfg(any(feature = "l4x5", feature = "l4x6"))]
671    pub pllsai2: PllCfg,
672    /// The value to divide SYSCLK by, to get systick and peripheral clocks. Also known as AHB divider
673    pub hclk_prescaler: HclkPrescaler,
674    #[cfg(feature = "wb")]
675    /// The value to divide SYSCLK by for HCLK2. (CPU2)
676    pub hclk2_prescaler: HclkPrescaler,
677    #[cfg(feature = "wl")]
678    /// The value to divide SYSCLK by for HCLK3.
679    pub hclk3_prescaler: HclkPrescaler,
680    #[cfg(feature = "wb")]
681    /// The value to divide SYSCLK by for HCLK4.
682    pub hclk4_prescaler: HclkPrescaler,
683    /// The divider of HCLK to get the APB1 peripheral clock
684    pub apb1_prescaler: ApbPrescaler,
685    #[cfg(not(any(feature = "g0", feature = "c0")))]
686    /// The divider of HCLK to get the APB2 peripheral clock
687    pub apb2_prescaler: ApbPrescaler,
688    // Bypass the HSE output, for use with oscillators that don't need it. Saves power, and
689    // frees up the pin for use as GPIO.
690    #[cfg(not(any(feature = "g0", feature = "wl", feature = "c011", feature = "c031")))]
691    /// The input source for the 48Mhz clock used by USB.
692    pub clk48_src: Clk48Src,
693    #[cfg(not(any(feature = "f", feature = "l", feature = "g0", feature = "c0")))]
694    pub lpuart_src: LpUartSrc,
695    /// Bypass the HSE output, for use with oscillators that don't need it. Saves power, and
696    /// frees up the pin for use as GPIO.
697    pub hse_bypass: bool,
698    pub security_system: bool,
699    #[cfg(not(any(feature = "g0", feature = "wl", feature = "c011", feature = "c031")))]
700    /// Enable the HSI48. For L4, this is only applicable for some devices.
701    pub hsi48_on: bool,
702    #[cfg(any(feature = "l4", feature = "l5", feature = "wb", feature = "wl"))]
703    /// Select the input source to use after waking up from `stop` mode. Eg HSI or MSI.
704    pub stop_wuck: StopWuck,
705    #[cfg(feature = "wb")]
706    /// Select the RF wakeup source.
707    pub rf_wakeup_src: RfWakeupSrc,
708    #[cfg(not(any(feature = "g0", feature = "g4", feature = "wl", feature = "c0")))]
709    /// SAI1 kernel clock source selection
710    pub sai1_src: SaiSrc,
711    #[cfg(feature = "g4")]
712    /// Range 1 boost mode: Used to increase regulator voltage to 1.28v, for when system
713    /// clock frequency is up to 170Mhz. Defaults to true.
714    pub boost_mode: bool,
715    #[cfg(any(feature = "g0", feature = "g4"))]
716    /// FDCAN kernel clock selection. Defaults to APB1.
717    pub can_src: CanSrc,
718    #[cfg(feature = "c0")]
719    pub hsi_div: HsiDiv,
720    #[cfg(feature = "c071")]
721    pub sys_div: SysDiv,
722}
723
724// todo: On L4/5, add a way to enable the MSI for use as CLK48.
725
726impl Clocks {
727    /// Setup common and return Ok if the config is valid. Abort the setup if speeds
728    /// are invalid.
729    /// Use the STM32CubeIDE Clock Configuration tab to help identify valid configs.
730    /// Use the `default()` implementation as a safe baseline.
731    pub fn setup(&self) -> Result<()> {
732        if let Err(e) = self.validate_speeds() {
733            return Err(e);
734        }
735
736        let rcc = unsafe { &(*RCC::ptr()) };
737        let flash = unsafe { &(*FLASH::ptr()) };
738        #[cfg(feature = "l5")]
739        let icache = unsafe { &(*pac::ICACHE::ptr()) };
740
741        // Enable and reset System Configuration Controller, ie for interrupts.
742        // todo: Is this the right module to do this in?
743        #[cfg(not(any(feature = "wb", feature = "wl")))]
744        rcc_en_reset!(apb2, syscfg, rcc);
745
746        // Adjust flash wait states according to the HCLK frequency.
747        // We need to do this before enabling PLL, or it won't enable.
748        let sysclk = self.sysclk();
749
750        cfg_if! {
751            if #[cfg(feature = "wb")] {
752                let hclk = sysclk / self.hclk4_prescaler.value() as u32;
753            } else if #[cfg(feature = "wl")] {
754                let hclk = sysclk / self.hclk3_prescaler.value() as u32;
755            } else {
756                let hclk = sysclk / self.hclk_prescaler.value() as u32;
757            }
758        }
759
760        cfg_if! {
761            if #[cfg(feature = "g4")] {
762                if self.boost_mode {
763                    // The sequence to switch from Range1 normal mode to Range1 boost mode is:
764                    // 1. The system clock must be divided by 2 using the AHB prescaler before switching to a
765                    // higher system frequency.
766                    rcc.cfgr().modify(|_, w| unsafe { w.hpre().bits(HclkPrescaler::Div2 as u8) });
767                    // 2. Clear the R1MODE bit is in the PWR_CR5 register.
768                    let pwr = unsafe { &(*pac::PWR::ptr()) };
769                    pwr.cr5().modify(|_, w| w.r1mode().clear_bit());
770                }
771
772                // (Remaining steps accomplished below)
773                // 3. Adjust the number of wait states according to the new frequency target in range1 boost
774                // mode
775                // 4. Configure and switch to new system frequency.
776                // 5. Wait for at least 1us and then reconfigure the AHB prescaler to get the needed HCLK
777                // clock frequency.
778            }
779        }
780
781        cfg_if! {
782            if #[cfg(feature = "l4")] {  // RM section 3.3.3
783                let wait_state = if hclk <= 16_000_000 {
784                    WaitState::W0
785                } else if hclk <= 32_000_000 {
786                    WaitState::W1
787                } else if hclk <= 48_000_000 {
788                    WaitState::W2
789                } else if hclk <= 64_000_000 {
790                    WaitState::W3
791                } else {
792                    WaitState::W4
793                };
794            } else if #[cfg(feature = "l5")] {  // RM section 6.3.3
795                let wait_state = if hclk <= 20_000_000 {
796                    WaitState::W0
797                } else if hclk <= 40_000_000 {
798                    WaitState::W1
799                } else if hclk <= 60_000_000 {
800                    WaitState::W2
801                } else if hclk <= 80_000_000 {
802                    WaitState::W3
803                } else if hclk <= 100_000_000 {
804                    WaitState::W4
805                } else {
806                    WaitState::W5
807                };
808            } else if #[cfg(feature = "g0")] {  // G0. RM section 3.3.4
809                let wait_state = if hclk <= 24_000_000 {
810                    WaitState::W0
811                } else if hclk <= 48_000_000 {
812                    WaitState::W1
813                } else {
814                    WaitState::W2
815                };
816            } else if #[cfg(feature = "c0")] { // C0 RM, section 4.3.2, table 14.
817                let wait_state = if hclk <= 24_000_000 {
818                    WaitState::W0
819                } else {
820                    WaitState::W1
821                };
822            } else if #[cfg(feature = "wb")] {  // WB. RM section 3.3.4, Table 4.
823                // Note: This applies to HCLK4 HCLK. (See HCLK4 used above for hclk var.)
824                let wait_state = if hclk <= 18_000_000 {
825                    WaitState::W0
826                } else if hclk <= 36_000_000 {
827                    WaitState::W1
828                } else if hclk <= 54_000_000 {
829                    WaitState::W2
830                } else {
831                    WaitState::W3
832                };
833            } else if #[cfg(any(feature = "wb", feature = "wl"))] {  // WL. RM section 3.3.4, Table 5.
834                // Note: This applies to HCLK3 HCLK. (See HCLK3 used above for hclk var.)
835                let wait_state = if hclk <= 18_000_000 {
836                    WaitState::W0
837                } else if hclk <= 36_000_000 {
838                    WaitState::W1
839                } else {
840                    WaitState::W2
841                };
842            } else {  // G4. RM section 3.3.3
843                let wait_state = if self.boost_mode {
844                    // Vcore Range 1 boost mode
845                    if hclk <= 34_000_000 {
846                        WaitState::W0
847                    } else if hclk <= 68_000_000 {
848                        WaitState::W1
849                    } else if hclk <= 102_000_000 {
850                        WaitState::W2
851                    } else if hclk <= 136_000_000 {
852                        WaitState::W3
853                    } else {
854                        WaitState::W4
855                    }
856                } else {
857                    // Vcore Range 1 normal mode.
858                    if hclk <= 30_000_000 {
859                        WaitState::W0
860                    } else if hclk <= 60_000_000 {
861                        WaitState::W1
862                    } else if hclk <= 90_000_000 {
863                        WaitState::W2
864                    } else if hclk <= 120_000_000 {
865                        WaitState::W3
866                    } else {
867                        WaitState::W4
868                    }
869                };
870            }
871        }
872
873        // Enable instruction and data caches, for a potential performance increase.
874        // Note that this can make a significant performance impact for some CPU-bound tasks.
875        // Note: This can increase power use.
876
877        #[cfg(not(feature = "l5"))]
878        flash.acr().modify(|_, w| unsafe {
879            #[cfg(not(any(feature = "g0", feature = "c0")))]
880            w.dcrst().bit(true);
881            w.icrst().bit(true)
882        });
883
884        // Note: At least on G4, Dcache and ICache are enabled by default in hardware. Although Prefetch isn't.
885        #[cfg(not(feature = "l5"))]
886        flash.acr().modify(|_, w| unsafe {
887            // G0: Instruction cache, but no data cache.
888            w.latency().bits(wait_state as u8);
889            #[cfg(not(any(feature = "g0", feature = "c0")))]
890            w.dcen().bit(true);
891            w.icen().bit(true);
892            // Prefetch on the ICode bus can be used to read the next sequential instruction line from the
893            // Flash memory while the current instruction line is being requested by the CPU
894            // Prefetch is enabled by setting the PRFTEN bit in the Flash access control register
895            // (FLASH_ACR). This feature is useful if at least one wait state is needed to access the Flash
896            // memory
897            w.prften().bit(true)
898        });
899
900        #[cfg(feature = "l5")]
901        flash
902            .acr()
903            .modify(|_, w| unsafe { w.latency().bits(wait_state as u8) });
904
905        // todo hmm. Removed or renamed in pac 0.16?
906        // icache.icache_cr().modify(|_, w| w.en().bit(true));
907
908        // Reference Manual, 6.2.5:
909        // The device embeds 3 PLLs: PLL, PLLSAI1, PLLSAI2. Each PLL provides up to three
910        // independent outputs. The internal PLLs can be used to multiply the HSI16, HSE or MSI
911        // output clock frequency. The PLLs input frequency must be between 4 and 16 MHz. The
912        // selected clock source is divided by a programmable factor PLLM from 1 to 8 to provide a
913        // clock frequency in the requested input range. Refer to Figure 15: Clock tree (for
914        // STM32L47x/L48x devices) and Figure 16: Clock tree (for STM32L49x/L4Ax devices) and
915        // PLL configuration register (RCC_PLLCFGR).
916        // The PLLs configuration (selection of the input clock and multiplication factor) must be done
917        // before enabling the PLL. Once the PLL is enabled, these parameters cannot be changed.
918        // To modify the PLL configuration, proceed as follows:
919        // 1. Disable the PLL by setting PLLON to 0 in Clock control register (RCC_CR).
920        // 2. Wait until PLLRDY is cleared. The PLL is now fully stopped.
921        // 3. Change the desired parameter.
922        // 4. Enable the PLL again by setting PLLON to 1.
923        // 5. Enable the desired PLL outputs by configuring PLLPEN, PLLQEN, PLLREN in PLL
924        // configuration register (RCC_PLLCFGR).
925
926        // Enable oscillators, and wait until ready.
927        match self.input_src {
928            #[cfg(msi)]
929            InputSrc::Msi(range) => {
930                // MSI initializes to the default clock source. Turn it off before
931                // Adjusting its speed etc.
932                rcc.cr().modify(|_, w| w.msion().clear_bit());
933
934                bounded_loop!(
935                    rcc.cr().read().msirdy().bit_is_set(),
936                    Error::RegisterUnchanged
937                );
938
939                rcc.cr().modify(|_, w| unsafe {
940                    w.msirange().bits(range as u8);
941                    #[cfg(not(any(feature = "wb", feature = "wl")))]
942                    w.msirgsel().bit(true);
943                    w.msion().bit(true)
944                });
945                // Wait for the MSI to be ready.
946                bounded_loop!(
947                    rcc.cr().read().msirdy().bit_is_clear(),
948                    Error::RegisterUnchanged
949                );
950                // todo: If LSE is enabled, calibrate MSI.
951            }
952            InputSrc::Hse(_) => {
953                rcc.cr().modify(|_, w| w.hseon().bit(true));
954                // Wait for the HSE to be ready.
955                bounded_loop!(
956                    rcc.cr().read().hserdy().bit_is_clear(),
957                    Error::RegisterUnchanged
958                );
959            }
960            InputSrc::Hsi => {
961                rcc.cr().modify(|_, w| w.hsion().bit(true));
962
963                bounded_loop!(
964                    rcc.cr().read().hsirdy().bit_is_clear(),
965                    Error::RegisterUnchanged
966                );
967            }
968            #[cfg(not(feature = "c0"))]
969            InputSrc::Pll(pll_src) => {
970                // todo: PLL setup here is DRY with the HSE, HSI, and MSI setup above.
971                match pll_src {
972                    #[cfg(msi)]
973                    PllSrc::Msi(range) => {
974                        rcc.cr().modify(|_, w| unsafe {
975                            w.msirange().bits(range as u8);
976                            #[cfg(not(any(feature = "wb", feature = "wl")))]
977                            w.msirgsel().bit(true);
978                            w.msion().bit(true)
979                        });
980
981                        bounded_loop!(
982                            rcc.cr().read().msirdy().bit_is_clear(),
983                            Error::RegisterUnchanged
984                        );
985                    }
986                    PllSrc::Hse(_) => {
987                        rcc.cr().modify(|_, w| w.hseon().bit(true));
988
989                        bounded_loop!(
990                            rcc.cr().read().hserdy().bit_is_clear(),
991                            Error::RegisterUnchanged
992                        );
993                    }
994                    PllSrc::Hsi => {
995                        rcc.cr().modify(|_, w| w.hsion().bit(true));
996
997                        bounded_loop!(
998                            rcc.cr().read().hsirdy().bit_is_clear(),
999                            Error::RegisterUnchanged
1000                        );
1001                    }
1002                    PllSrc::None => {}
1003                }
1004            }
1005            #[cfg(feature = "g0")]
1006            InputSrc::Lsi => {
1007                rcc.csr().modify(|_, w| w.lsion().bit(true));
1008
1009                bounded_loop!(
1010                    rcc.csr().read().lsirdy().bit_is_clear(),
1011                    Error::RegisterUnchanged
1012                );
1013            }
1014            #[cfg(feature = "g0")]
1015            InputSrc::Lse => {
1016                rcc.bdcr().modify(|_, w| w.lseon().bit(true));
1017
1018                bounded_loop!(
1019                    rcc.bdcr().read().lserdy().bit_is_clear(),
1020                    Error::RegisterUnchanged
1021                );
1022            }
1023            #[cfg(feature = "c0")]
1024            InputSrc::Lsi => {
1025                rcc.csr2().modify(|_, w| w.lsion().bit(true));
1026
1027                bounded_loop!(
1028                    rcc.csr2().read().lsirdy().bit_is_clear(),
1029                    Error::RegisterUnchanged
1030                );
1031            }
1032            #[cfg(feature = "c0")]
1033            InputSrc::Lse => {
1034                rcc.csr1().modify(|_, w| w.lseon().bit(true));
1035
1036                bounded_loop!(
1037                    rcc.csr1().read().lserdy().bit_is_clear(),
1038                    Error::RegisterUnchanged
1039                );
1040            }
1041            #[cfg(feature = "c071")]
1042            InputSrc::HsiUsb48 => {
1043                // todo: A/R
1044            }
1045        }
1046
1047        rcc.cr().modify(|_, w| unsafe {
1048            #[cfg(feature = "c0")]
1049            w.hsidiv().bits(self.hsi_div as u8);
1050            #[cfg(feature = "c071")]
1051            w.sysdiv().bits(self.sys_div as u8);
1052            #[cfg(feature = "wl")]
1053            return w.hsebyppwr().bit(self.hse_bypass);
1054            #[cfg(not(feature = "wl"))]
1055            w.hsebyp().bit(self.hse_bypass)
1056        });
1057
1058        rcc.cfgr().modify(|_, w| unsafe {
1059            w.sw().bits(self.input_src.bits());
1060            w.hpre().bits(self.hclk_prescaler as u8);
1061            #[cfg(not(any(feature = "g0", feature = "c0")))]
1062            w.ppre2().bits(self.apb2_prescaler as u8); // HCLK division for APB2.
1063            #[cfg(any(feature = "l4", feature = "l5"))]
1064            w.stopwuck().bit(self.stop_wuck as u8 != 0);
1065            #[cfg(not(any(feature = "g0", feature = "c0")))]
1066            return w.ppre1().bits(self.apb1_prescaler as u8); // HCLK division for APB1
1067            #[cfg(any(feature = "g0", feature = "c0"))]
1068            return w.ppre().bits(self.apb1_prescaler as u8);
1069        });
1070
1071        // todo: Adapt this logic for H7? Mix H7 into this module?
1072        #[cfg(feature = "wb")]
1073        rcc.extcfgr().modify(|_, w| unsafe {
1074            w.c2hpre().bits(self.hclk2_prescaler as u8);
1075            w.shdhpre().bits(self.hclk4_prescaler as u8)
1076        });
1077
1078        #[cfg(feature = "wl")]
1079        rcc.extcfgr()
1080            .modify(|_, w| unsafe { w.shdhpre().bits(self.hclk3_prescaler as u8) });
1081
1082        rcc.cr().modify(|_, w| w.csson().bit(self.security_system));
1083
1084        // Note that with this code setup, PLLSAI won't work properly unless using
1085        // the input source is PLL.
1086        #[cfg(not(feature = "c0"))]
1087        if let InputSrc::Pll(pll_src) = self.input_src {
1088            // Turn off the PLL: Required for modifying some of the settings below.
1089            rcc.cr().modify(|_, w| w.pllon().clear_bit());
1090            // Wait for the PLL to no longer be ready before executing certain writes.
1091
1092            bounded_loop!(
1093                rcc.cr().read().pllrdy().bit_is_set(),
1094                Error::RegisterUnchanged
1095            );
1096
1097            rcc.pllcfgr().modify(|_, w| unsafe {
1098                w.pllsrc().bits(pll_src.bits());
1099                w.pllren().bit(true);
1100                w.pllqen().bit(self.pll.pllq_en);
1101                w.pllpen().bit(self.pll.pllp_en);
1102                w.plln().bits(self.pll.divn);
1103                w.pllm().bits(self.pll.divm as u8);
1104                w.pllr().bits(self.pll.divr as u8);
1105                #[cfg(not(any(
1106                    feature = "wb",
1107                    feature = "wl",
1108                    feature = "l4x5",
1109                    feature = "l4x3",
1110                    feature = "g0"
1111                )))]
1112                w.pllpdiv().bits(self.pll.pdiv);
1113                #[cfg(not(any(feature = "wb", feature = "wl", feature = "g0")))]
1114                w.pllp().bit(self.pll.divp as u8 != 0);
1115                #[cfg(any(feature = "wb", feature = "wl", feature = "g0"))]
1116                w.pllp().bits(self.pll.divp as u8);
1117                w.pllq().bits(self.pll.divq as u8)
1118            });
1119
1120            rcc.pllcfgr().modify(|_, w| {
1121                w.pllpen().bit(true);
1122                w.pllqen().bit(true);
1123                w.pllren().bit(true)
1124            });
1125
1126            cfg_if! {
1127                // todo: Missing some settings I'm not sure what to make of on L.
1128                if #[cfg(all(any(feature = "l4", feature = "l5"), not(feature = "l412")))] {
1129                    rcc.pllsai1cfgr().modify(|_, w| unsafe {
1130                        w.pllsai1ren().bit(self.pllsai1.pllr_en);
1131                        w.pllsai1qen().bit(self.pllsai1.pllq_en);
1132                        w.pllsai1pen().bit(self.pllsai1.pllp_en);
1133                        w.pllsai1n().bits(self.pllsai1.divn);
1134                        #[cfg(not(any(feature = "l4x5", feature = "l4x3")))]
1135                        w.pllsai1pdiv().bits(self.pllsai1.pdiv);
1136                        w.pllsai1r().bits(self.pllsai1.divr as u8);
1137                        w.pllsai1q().bits(self.pllsai1.divq as u8);
1138                        w.pllsai1p().bit(self.pllsai1.divp as u8 != 0)
1139                    });
1140
1141                    #[cfg(any(feature = "l4x5", feature = "l4x6"))]
1142                    rcc.pllsai2cfgr().modify(|_, w| unsafe {
1143                        w.pllsai2ren().bit(self.pllsai1.pllr_en);
1144                        // w.pllsai2qen().bit(self.pllsai1.pllq_en);
1145                        w.pllsai2pen().bit(self.pllsai1.pllp_en);
1146                        w.pllsai2n().bits(self.pllsai1.divn);
1147                        #[cfg(not(feature = "l4x5"))]
1148                        w.pllsai2pdiv().bits(self.pllsai1.pdiv);
1149                        w.pllsai2r().bits(self.pllsai1.divr as u8);
1150                        // w.pllsai2q().bits(self.pllsai1.divq as u8);
1151                        w.pllsai2p().bit(self.pllsai1.divp as u8 != 0)
1152                    });
1153
1154                } else if #[cfg(feature = "wb")] {
1155                    rcc.pllsai1cfgr().modify(|_, w| unsafe {
1156                        w.pllren().bit(self.pllsai1.pllr_en);
1157                        w.pllqen().bit(self.pllsai1.pllq_en);
1158                        w.pllpen().bit(self.pllsai1.pllp_en);
1159                        w.plln().bits(self.pllsai1.divn);
1160                        w.pllr().bits(self.pllsai1.divr as u8);
1161                        w.pllq().bits(self.pllsai1.divq as u8);
1162                        w.pllp().bits(self.pllsai1.divp as u8)
1163                    });
1164                }
1165            }
1166
1167            rcc.cr().modify(|_, w| w.pllon().bit(true));
1168            bounded_loop!(
1169                rcc.cr().read().pllrdy().bit_is_clear(),
1170                Error::RegisterUnchanged
1171            );
1172
1173            cfg_if! {
1174                if #[cfg(not(any(feature = "g0", feature = "g4", feature = "wl", feature = "l412")))] {
1175                    if self.pllsai1.enabled {
1176                        rcc.cr().modify(|_, w| w.pllsai1on().bit(true));
1177                        bounded_loop!(
1178                            rcc.cr().read().pllsai1rdy().bit_is_clear(),
1179                            Error::RegisterUnchanged
1180                        );
1181                    }
1182                    #[cfg(any(feature = "l4x5", feature = "l4x6",))]
1183                    if self.pllsai2.enabled {
1184                        rcc.cr().modify(|_, w| w.pllsai2on().bit(true));
1185                        bounded_loop!(
1186                            rcc.cr().read().pllsai2rdy().bit_is_clear(),
1187                            Error::RegisterUnchanged
1188                        );
1189                    }
1190                }
1191            }
1192        }
1193
1194        // Enable the HSI48 as required, which is used for USB, RNG, etc.
1195        // Only valid for some devices (On at least L4, and G4.)
1196        #[cfg(not(any(feature = "g0", feature = "wl", feature = "c0")))]
1197        if self.hsi48_on {
1198            rcc.crrcr().modify(|_, w| w.hsi48on().bit(true));
1199            bounded_loop!(
1200                rcc.crrcr().read().hsi48rdy().bit_is_clear(),
1201                Error::RegisterUnchanged
1202            );
1203        }
1204
1205        #[cfg(feature = "c071")]
1206        if self.hsi48_on {
1207            rcc.cr().modify(|_, w| w.hsiusb48on().bit(true));
1208            bounded_loop!(
1209                rcc.cr().read().hsiusb48rdy().bit_is_clear(),
1210                Error::RegisterUnchanged
1211            );
1212        }
1213
1214        // This modification is separate from the other CCIPR writes due to awkward
1215        // feature-gate code
1216        #[cfg(not(any(
1217            feature = "g0",
1218            feature = "g4",
1219            feature = "wl",
1220            feature = "l5",
1221            feature = "l412",
1222            feature = "c0",
1223        )))]
1224        rcc.ccipr()
1225            .modify(|_, w| unsafe { w.sai1sel().bits(self.sai1_src as u8) });
1226
1227        #[cfg(feature = "g4")]
1228        rcc.ccipr()
1229            .modify(|_, w| unsafe { w.fdcansel().bits(self.can_src as u8) });
1230
1231        #[cfg(feature = "g0c1")]
1232        rcc.ccipr2()
1233            .modify(|_, w| unsafe { w.fdcansel().bits(self.can_src as u8) });
1234
1235        #[cfg(feature = "l5")]
1236        rcc.ccipr2()
1237            .modify(|_, w| unsafe { w.sai1sel().bits(self.sai1_src as u8) });
1238
1239        #[cfg(any(feature = "l4", feature = "g4"))]
1240        rcc.ccipr()
1241            .modify(|_, w| unsafe { w.clk48sel().bits(self.clk48_src as u8) });
1242
1243        #[cfg(feature = "l5")]
1244        rcc.ccipr1()
1245            .modify(|_, w| unsafe { w.clk48msel().bits(self.clk48_src as u8) });
1246
1247        #[cfg(feature = "c071")]
1248        // todo: QC this single bit field the PAC expects. Doesn't feel right.
1249        // (vals are 0 or 1 in the DS; not true or false.)
1250        rcc.ccipr2()
1251            .modify(|_, w| unsafe { w.usbsel().bit(self.clk48_src as u8 != 0) });
1252
1253        #[cfg(not(any(feature = "f", feature = "l", feature = "g0", feature = "c0")))]
1254        rcc.ccipr()
1255            // todo: Don't hard-code.
1256            .modify(|_, w| unsafe { w.lpuart1sel().bits(self.lpuart_src as u8) });
1257
1258        // If we're not using the default clock source as input source or for PLL, turn it off.
1259        cfg_if! {
1260            if #[cfg(any(feature = "l4", feature = "l5"))] {
1261                match self.input_src {
1262                    InputSrc::Msi(_) => (),
1263                    InputSrc::Pll(pll_src) => {
1264                        match pll_src {
1265                        PllSrc::Msi(_) => (),
1266                            _ => {
1267                                rcc.cr().modify(|_, w| w.msion().clear_bit());
1268                            }
1269                        }
1270                    }
1271                    _ => {
1272                        rcc.cr().modify(|_, w| w.msion().clear_bit());
1273                   }
1274                }
1275
1276            } else {
1277                match self.input_src {
1278                    InputSrc::Hsi => (),
1279                    #[cfg(not(feature = "c0"))]
1280                    InputSrc::Pll(pll_src) => {
1281                        match pll_src {
1282                        PllSrc::Hsi => (),
1283                            _ => {
1284                                rcc.cr().modify(|_, w| w.hsion().clear_bit());
1285                            }
1286                        }
1287                    }
1288                    _ => {
1289                        rcc.cr().modify(|_, w| w.hsion().clear_bit());
1290                   }
1291                }
1292            }
1293        }
1294
1295        #[cfg(feature = "wb")]
1296        rcc.csr()
1297            .modify(|_, w| unsafe { w.rfwkpsel().bits(self.rf_wakeup_src as u8) });
1298
1299        Ok(())
1300    }
1301
1302    /// Re-select input source; used after Stop and Standby modes, where the system reverts
1303    /// to MSI or HSI after wake.
1304    pub fn reselect_input(&self) -> Result<()> {
1305        let rcc = unsafe { &(*RCC::ptr()) };
1306
1307        // Re-select the input source; useful for changing input source, or reverting
1308        // from stop or standby mode. This assumes we're on a clean init,
1309        // or waking up from stop mode etc.
1310
1311        match self.input_src {
1312            InputSrc::Hse(_) => {
1313                rcc.cr().modify(|_, w| w.hseon().bit(true));
1314                bounded_loop!(
1315                    rcc.cr().read().hserdy().bit_is_clear(),
1316                    Error::RegisterUnchanged
1317                );
1318
1319                rcc.cfgr()
1320                    .modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
1321            }
1322            #[cfg(not(feature = "c0"))]
1323            InputSrc::Pll(pll_src) => {
1324                // todo: DRY with above.
1325                match pll_src {
1326                    PllSrc::Hse(_) => {
1327                        rcc.cr().modify(|_, w| w.hseon().bit(true));
1328                        bounded_loop!(
1329                            rcc.cr().read().hserdy().bit_is_clear(),
1330                            Error::RegisterUnchanged
1331                        );
1332                    }
1333                    PllSrc::Hsi => {
1334                        #[cfg(any(feature = "l4", feature = "l5"))]
1335                        // Generally reverts to MSI (see note below)
1336                        if let StopWuck::Msi = self.stop_wuck {
1337                            rcc.cr().modify(|_, w| w.hsion().bit(true));
1338                            bounded_loop!(
1339                                rcc.cr().read().hsirdy().bit_is_clear(),
1340                                Error::RegisterUnchanged
1341                            );
1342                        }
1343                        // If on G, we'll already be on HSI, so need to take action.
1344                    }
1345                    #[cfg(msi)]
1346                    PllSrc::Msi(range) => {
1347                        // Range initializes to 4Mhz, so set that as well.
1348                        #[cfg(not(feature = "wb"))]
1349                        rcc.cr().modify(|_, w| unsafe {
1350                            w.msirange().bits(range as u8);
1351                            w.msirgsel().bit(true)
1352                        });
1353                        #[cfg(feature = "wb")]
1354                        rcc.cr()
1355                            .modify(|_, w| unsafe { w.msirange().bits(range as u8) });
1356
1357                        if let StopWuck::Hsi = self.stop_wuck {
1358                            rcc.cr().modify(|_, w| w.msion().bit(true));
1359                            bounded_loop!(
1360                                rcc.cr().read().msirdy().bit_is_clear(),
1361                                Error::RegisterUnchanged
1362                            );
1363                        }
1364                    }
1365                    PllSrc::None => (),
1366                }
1367
1368                rcc.cr().modify(|_, w| w.pllon().clear_bit());
1369                bounded_loop!(
1370                    rcc.cr().read().pllrdy().bit_is_set(),
1371                    Error::RegisterUnchanged
1372                );
1373
1374                rcc.cfgr()
1375                    .modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
1376
1377                rcc.cr().modify(|_, w| w.pllon().bit(true));
1378                bounded_loop!(
1379                    rcc.cr().read().pllrdy().bit_is_clear(),
1380                    Error::RegisterUnchanged
1381                );
1382            }
1383            InputSrc::Hsi => {
1384                {
1385                    // (This note applies to L4 and L5 only)
1386                    // From L4 Reference Manual, RCC_CFGR register section:
1387                    // "Configured by HW to force MSI oscillator selection when exiting Standby or Shutdown mode.
1388                    // Configured by HW to force MSI or HSI16 oscillator selection when exiting Stop mode or in
1389                    // case of failure of the HSE oscillator, depending on STOPWUCK value."
1390
1391                    // So, if stopwuck is at its default value of MSI, we need to re-enable HSI,
1392                    // and re-select it. Otherwise, take no action. Reverse for MSI-reselection.
1393                    // For G, we already are using HSI, so need to take action either.
1394                    #[cfg(msi)]
1395                    if let StopWuck::Msi = self.stop_wuck {
1396                        rcc.cr().modify(|_, w| w.hsion().bit(true));
1397                        bounded_loop!(
1398                            rcc.cr().read().hsirdy().bit_is_clear(),
1399                            Error::RegisterUnchanged
1400                        );
1401
1402                        rcc.cfgr()
1403                            .modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
1404                    }
1405                }
1406            }
1407            #[cfg(msi)]
1408            InputSrc::Msi(range) => {
1409                // Range initializes to 4Mhz, so set that as well.
1410                #[cfg(not(feature = "wb"))]
1411                rcc.cr().modify(|_, w| unsafe {
1412                    w.msirange().bits(range as u8);
1413                    w.msirgsel().bit(true)
1414                });
1415                #[cfg(feature = "wb")]
1416                rcc.cr()
1417                    .modify(|_, w| unsafe { w.msirange().bits(range as u8) });
1418
1419                if let StopWuck::Hsi = self.stop_wuck {
1420                    rcc.cr().modify(|_, w| w.msion().bit(true));
1421                    bounded_loop!(
1422                        rcc.cr().read().msirdy().bit_is_clear(),
1423                        Error::RegisterUnchanged
1424                    );
1425
1426                    rcc.cfgr()
1427                        .modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
1428                }
1429            }
1430            #[cfg(feature = "g0")]
1431            InputSrc::Lsi => {
1432                rcc.csr().modify(|_, w| w.lsion().bit(true));
1433                bounded_loop!(
1434                    rcc.csr().read().lsirdy().bit_is_clear(),
1435                    Error::RegisterUnchanged
1436                );
1437                rcc.cfgr()
1438                    .modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
1439            }
1440            #[cfg(feature = "c0")]
1441            InputSrc::Lsi => {
1442                rcc.csr2().modify(|_, w| w.lsion().bit(true));
1443                bounded_loop!(
1444                    rcc.csr2().read().lsirdy().bit_is_clear(),
1445                    Error::RegisterUnchanged
1446                );
1447                rcc.cfgr()
1448                    .modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
1449            }
1450            #[cfg(feature = "g0")]
1451            InputSrc::Lse => {
1452                rcc.bdcr().modify(|_, w| w.lseon().bit(true));
1453                bounded_loop!(
1454                    rcc.bdcr().read().lserdy().bit_is_clear(),
1455                    Error::RegisterUnchanged
1456                );
1457                rcc.cfgr()
1458                    .modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
1459            }
1460            #[cfg(feature = "c0")]
1461            InputSrc::Lse => {
1462                rcc.csr1().modify(|_, w| w.lseon().bit(true));
1463                bounded_loop!(
1464                    rcc.csr1().read().lserdy().bit_is_clear(),
1465                    Error::RegisterUnchanged
1466                );
1467                rcc.cfgr()
1468                    .modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
1469            }
1470            #[cfg(feature = "c071")]
1471            InputSrc::HsiUsb48 => {
1472                // todo: A/R
1473            }
1474        }
1475
1476        Ok(())
1477    }
1478
1479    #[cfg(any(feature = "l4", feature = "l5"))]
1480    /// Use this to change the MSI speed. Run this only if your clock source is MSI.
1481    /// Ends in a state with MSI on at the new speed, and HSI off.
1482    pub fn change_msi_speed(&mut self, range: MsiRange) -> Result<()> {
1483        // todo: Calibrate MSI with LSE / HSE(?) if avail?
1484
1485        let rcc = unsafe { &(*RCC::ptr()) };
1486
1487        match self.input_src {
1488            InputSrc::Msi(_) => (),
1489            _ => panic!("Only change MSI speed using this function if MSI is the input source."),
1490        }
1491
1492        // RM: "`"Warning: MSIRANGE can be modified when MSI is OFF (MSION=0) or when MSI is ready (MSIRDY=1).
1493        // MSIRANGE must NOT be modified when MSI is ON and NOT ready (MSION=1 and MSIRDY=0)"
1494        // So, we can change MSI range while it's running.
1495        bounded_loop!(
1496            rcc.cr().read().msirdy().bit_is_clear(),
1497            Error::RegisterUnchanged
1498        );
1499
1500        rcc.cr()
1501            .modify(|_, w| unsafe { w.msirange().bits(range as u8).msirgsel().bit(true) });
1502
1503        // Update our config to reflect the new speed.
1504        self.input_src = InputSrc::Msi(range);
1505
1506        Ok(())
1507    }
1508
1509    #[cfg(msi)]
1510    /// Enables MSI, and configures it at 48Mhz, and trims it using the LSE. This is useful when using it as
1511    /// the USB clock, ie with `clk48_src: Clk48Src::Msi`. Don't use this if using MSI for the input
1512    /// source or PLL source. You may need to re-run this after exiting `stop` mode. Only works for USB
1513    /// if you have an LSE connected.
1514    /// Note: MSIPLLEN must be enabled after LSE is enabled. So, run this function after RCC clock setup.
1515    pub fn enable_msi_48(&self) -> Result<()> {
1516        let rcc = unsafe { &(*RCC::ptr()) };
1517
1518        if let InputSrc::Msi(_) = self.input_src {
1519            panic!(
1520                "Only use this function to set up MSI as 48MHz oscillator\
1521            if not using it as the input source."
1522            );
1523        }
1524        if let InputSrc::Pll(pll_src) = self.input_src {
1525            if let PllSrc::Msi(_) = pll_src {
1526                panic!(
1527                    "Only use this function to set up MSI as 48MHz oscillator \
1528                if not using it as the input source."
1529                );
1530            }
1531        }
1532
1533        rcc.cr().modify(|_, w| w.msion().clear_bit());
1534        bounded_loop!(
1535            rcc.cr().read().msirdy().bit_is_set(),
1536            Error::RegisterUnchanged
1537        );
1538
1539        // L44 RM, section 6.2.3: When a 32.768 kHz external oscillator is present in the application, it is possible to configure
1540        // the MSI in a PLL-mode by setting the MSIPLLEN bit in the Clock control register (RCC_CR).
1541        // When configured in PLL-mode, the MSI automatically calibrates itself thanks to the LSE.
1542        // This mode is available for all MSI frequency ranges. At 48 MHz, the MSI in PLL-mode can
1543        // be used for the USB FS device, saving the need of an external high-speed crystal.
1544        // MSIPLLEN must be enabled after LSE is enabled
1545        #[cfg(not(feature = "wb"))]
1546        rcc.cr().modify(|_, w| unsafe {
1547            w.msirange()
1548                .bits(MsiRange::R48M as u8)
1549                .msirgsel()
1550                .bit(true)
1551                .msipllen()
1552                .bit(true)
1553                .msion()
1554                .bit(true)
1555        });
1556
1557        bounded_loop!(
1558            rcc.cr().read().msirdy().bit_is_clear(),
1559            Error::RegisterUnchanged
1560        );
1561
1562        Ok(())
1563    }
1564
1565    /// Get the sysclock frequency, in hz.
1566    pub const fn sysclk(&self) -> u32 {
1567        let clk = match self.input_src {
1568            #[cfg(not(feature = "c0"))]
1569            InputSrc::Pll(pll_src) => {
1570                let input_freq = match pll_src {
1571                    #[cfg(not(any(feature = "g0", feature = "g4")))]
1572                    PllSrc::Msi(range) => range.value() as u32,
1573                    PllSrc::Hsi => 16_000_000,
1574                    PllSrc::Hse(freq) => freq,
1575                    PllSrc::None => unimplemented!(),
1576                };
1577                input_freq / self.pll.divm.value() as u32 * self.pll.divn as u32
1578                    / self.pll.divr.value() as u32
1579            }
1580
1581            #[cfg(msi)]
1582            InputSrc::Msi(range) => range.value() as u32,
1583            #[cfg(not(feature = "c0"))]
1584            InputSrc::Hsi => 16_000_000,
1585            #[cfg(feature = "c0")]
1586            InputSrc::Hsi => 48_000_000 / self.hsi_div.value(),
1587            InputSrc::Hse(freq) => freq,
1588            #[cfg(any(feature = "g0", feature = "c0"))]
1589            InputSrc::Lsi => 32_000,
1590            #[cfg(any(feature = "g0", feature = "c0"))]
1591            InputSrc::Lse => 32_768,
1592            #[cfg(feature = "c071")]
1593            InputSrc::HsiUsb48 => 48_000_000,
1594        };
1595        #[cfg(feature = "c071")]
1596        return clk / self.sys_div.value();
1597        #[cfg(not(feature = "c071"))]
1598        return clk;
1599    }
1600
1601    /// Check if the PLL is enabled. This is useful if checking whether to re-enable the PLL
1602    /// after exiting Stop or Standby modes, eg so you don't re-enable if it was already re-enabled
1603    /// in a different context. eg:
1604    /// ```
1605    /// if !clock_cfg.pll_is_enabled() {
1606    ///     clock_cfg.reselect_input();
1607    ///}
1608    #[cfg(not(feature = "c0"))]
1609    pub fn pll_is_enabled(&self) -> bool {
1610        let rcc = unsafe { &(*RCC::ptr()) };
1611        rcc.cr().read().pllon().bit_is_set()
1612    }
1613
1614    /// Get the HCLK frequency, in hz
1615    pub const fn hclk(&self) -> u32 {
1616        self.sysclk() / self.hclk_prescaler.value() as u32
1617    }
1618
1619    /// Get the systick frequency, in hz
1620    ///
1621    /// Note: This function returns the systick core clock frequency.
1622    /// When systick is configured to use the external clock, the systick frequency is `systick() / 8`.
1623    pub const fn systick(&self) -> u32 {
1624        self.hclk()
1625    }
1626
1627    cfg_if! {
1628        if #[cfg(any(feature = "g0", feature = "wl"))] {
1629            pub const fn usb(&self) -> u32 {
1630                // "No USB on G0 or WL"
1631                unimplemented!();
1632            }
1633        } else if #[cfg(any(feature = "g4", feature = "c071"))] {
1634            pub const fn usb(&self) -> u32 {
1635                48_000_000 // Uses hsi48.
1636            }
1637         // todo: Handle c031/11
1638        } else if #[cfg(feature = "c071")] {
1639            match self.clk48_src {
1640                Clk48Src::HsiUsb48 => 48_000_000,
1641                Clk48Src::Hse => unimplemented!(),
1642            }
1643        } else { // L4 and L5
1644            #[cfg(not(feature = "c0"))]
1645            pub const fn usb(&self) -> u32 {
1646                match self.clk48_src {
1647                    Clk48Src::Hsi48 => 48_000_000,
1648                    Clk48Src::PllSai1 => unimplemented!(),
1649                    Clk48Src::Pllq => unimplemented!(),
1650                    Clk48Src::Msi => unimplemented!(),
1651                }
1652            }
1653        }
1654    }
1655
1656    /// Get the APB1 peripheral clock frequency frequency, in hz
1657    pub const fn apb1(&self) -> u32 {
1658        self.hclk() / self.apb1_prescaler.value() as u32
1659    }
1660
1661    /// Get the frequency used by APB1 timers, in hz
1662    pub const fn apb1_timer(&self) -> u32 {
1663        // L4 RM, 6.2.14: The timer clock frequencies are automatically defined by hardware. There are two cases:
1664        // 1. If the APB prescaler equals 1, the timer clock frequencies are set to the same
1665        // frequency as that of the APB domain.
1666        // 2. Otherwise, they are set to twice (×2) the frequency of the APB domain.
1667        if let ApbPrescaler::Div1 = self.apb1_prescaler {
1668            self.apb1()
1669        } else {
1670            self.apb1() * 2
1671        }
1672    }
1673
1674    cfg_if! {
1675        if #[cfg(feature = "g0")] {
1676            // On G0, a single APB prescaler is used for both APB1 and APB2.
1677            pub const fn apb2(&self) -> u32 {
1678                self.hclk() / self.apb1_prescaler.value() as u32
1679            }
1680
1681            pub const fn apb2_timer(&self) -> u32 {
1682                if let ApbPrescaler::Div1 = self.apb1_prescaler {
1683                    self.apb2()
1684                } else {
1685                    self.apb2() * 2
1686                }
1687            }
1688        } else if #[cfg(not(feature = "c0"))] {
1689            /// Get the APB2 peipheral clock frequency, in hz.
1690            pub const fn apb2(&self) -> u32 {
1691                self.hclk() / self.apb2_prescaler.value() as u32
1692            }
1693
1694            pub const fn apb2_timer(&self) -> u32 {
1695                if let ApbPrescaler::Div1 = self.apb2_prescaler {
1696                    self.apb2()
1697                } else {
1698                    self.apb2() * 2
1699                }
1700            }
1701        }
1702    }
1703
1704    /// Get the SAI audio clock frequency, in hz
1705    #[cfg(not(any(feature = "g0", feature = "g4", feature = "wl", feature = "c0")))]
1706    pub const fn sai1_speed(&self) -> u32 {
1707        let pll_src = match self.input_src {
1708            InputSrc::Msi(msi_rng) => PllSrc::Msi(msi_rng),
1709            InputSrc::Hsi => PllSrc::Hsi,
1710            InputSrc::Hse(freq) => PllSrc::Hse(freq),
1711            InputSrc::Pll(pll_src) => pll_src,
1712        };
1713
1714        // todo: DRY with `sysclk`
1715        let input_freq = match pll_src {
1716            PllSrc::Msi(range) => range.value() as u32,
1717            PllSrc::Hsi => 16_000_000,
1718            PllSrc::Hse(freq) => freq,
1719            PllSrc::None => unimplemented!(),
1720        };
1721
1722        match self.sai1_src {
1723            SaiSrc::PllSai1P => {
1724                input_freq / self.pll.divm.value() as u32 * self.pllsai1.divn as u32
1725                    / self.pllsai1.pvalue() as u32
1726            }
1727            SaiSrc::Pllp => {
1728                input_freq / self.pll.divm.value() as u32 * self.pll.divn as u32
1729                    / self.pll.pvalue() as u32
1730            }
1731            SaiSrc::Hsi => 16_000_000,
1732            SaiSrc::ExtClk => unimplemented!(),
1733        }
1734    }
1735
1736    #[cfg(feature = "c0")] // no PLL on C0
1737    pub fn validate_speeds(&self) -> Result<()> {
1738        Ok(()) // todo: A/R
1739    }
1740
1741    #[cfg(not(feature = "c0"))] // no PLL on C0
1742    pub fn validate_speeds(&self) -> Result<()> {
1743        #[cfg(feature = "l4")]
1744        let max_clock = 80_000_000;
1745
1746        #[cfg(feature = "l5")]
1747        let max_clock = 110_000_000;
1748
1749        #[cfg(feature = "g0")]
1750        let max_clock = 64_000_000;
1751
1752        #[cfg(feature = "g4")]
1753        let max_clock = 170_000_000;
1754
1755        #[cfg(feature = "wb")]
1756        let max_clock = 64_000_000;
1757
1758        #[cfg(feature = "wl")]
1759        let max_clock = 48_000_000;
1760
1761        #[cfg(feature = "c0")]
1762        let max_clock = 48_000_000;
1763
1764        // todo: Check valid PLL output range as well. You can use Cube, mousing over the PLL
1765        // todo speed to find these.
1766
1767        // todo: L4+ (ie R, S, P, Q) can go up to 120_000.
1768
1769        #[cfg(any(feature = "l4", feature = "l5", feature = "wb"))]
1770        if self.pll.divn < 7
1771            || self.pll.divn > 86
1772            || self.pllsai1.divn < 7
1773            || self.pllsai1.divn > 86
1774        {
1775            return Err(Error::RccError(RccError::Speed));
1776        }
1777
1778        if self.pll.pdiv == 1 {
1779            return Err(Error::RccError(RccError::Speed));
1780        }
1781
1782        #[cfg(not(any(feature = "g0", feature = "g4", feature = "wl", feature = "c0")))]
1783        if self.pllsai1.pdiv == 1 {
1784            return Err(Error::RccError(RccError::Speed));
1785        }
1786
1787        #[cfg(any(feature = "l4x5", feature = "l4x6"))]
1788        if self.pllsai2.pdiv == 1 {
1789            return Err(Error::RccError(RccError::Speed));
1790        }
1791
1792        #[cfg(feature = "g0")]
1793        if self.pll.divn < 9 || self.pll.divn > 86 {
1794            return Err(Error::RccError(RccError::Speed));
1795        }
1796
1797        #[cfg(feature = "g4")]
1798        if self.pll.divn < 8 || self.pll.divn > 127 {
1799            return Err(Error::RccError(RccError::Speed));
1800        }
1801
1802        // todo: on WB, input src / PlLM * plln Must be between 96 and 344 Mhz.
1803        // todo; Cube will validate this. Others probably have a similar restriction.
1804        // todo: Put this check here.
1805
1806        // todo: QC these limits
1807        // todo: Note that this involves repeatedly calculating sysclk.
1808        // todo. We could work around thsi by calcing it once here.
1809        if self.sysclk() > max_clock {
1810            return Err(Error::RccError(RccError::Speed));
1811        }
1812
1813        // todo: What are the actual hclk limits? Not always sysclk?
1814
1815        if self.hclk() > max_clock {
1816            return Err(Error::RccError(RccError::Speed));
1817        }
1818
1819        if self.apb1() > max_clock {
1820            return Err(Error::RccError(RccError::Speed));
1821        }
1822
1823        #[cfg(not(feature = "g0"))]
1824        if self.apb2() > max_clock {
1825            return Err(Error::RccError(RccError::Speed));
1826        }
1827
1828        Ok(())
1829    }
1830}
1831
1832impl Default for Clocks {
1833    /// This default configures clocks with a HSI, with system and peripheral clocks at full rated speed.
1834    /// All peripheral. Speeds -> L4: 80Mhz. L5: 110Mhz. G0: 64Mhz. G4: 170Mhz. WB: 64Mhz.
1835    fn default() -> Self {
1836        Self {
1837            #[cfg(not(feature = "c0"))]
1838            input_src: InputSrc::Pll(PllSrc::Hsi),
1839            #[cfg(feature = "c0")]
1840            input_src: InputSrc::Hsi,
1841            #[cfg(not(feature = "c0"))]
1842            pll: PllCfg::default(),
1843            #[cfg(not(any(feature = "g0", feature = "g4", feature = "wl", feature = "c0")))]
1844            pllsai1: PllCfg::disabled(),
1845            #[cfg(any(feature = "l4x5", feature = "l4x6"))]
1846            pllsai2: PllCfg::disabled(),
1847            hclk_prescaler: HclkPrescaler::Div1,
1848            #[cfg(feature = "wb")]
1849            hclk2_prescaler: HclkPrescaler::Div2,
1850            #[cfg(feature = "wl")]
1851            hclk3_prescaler: HclkPrescaler::Div1,
1852            #[cfg(feature = "wb")]
1853            hclk4_prescaler: HclkPrescaler::Div1,
1854            apb1_prescaler: ApbPrescaler::Div1,
1855            #[cfg(not(any(feature = "g0", feature = "c0")))]
1856            apb2_prescaler: ApbPrescaler::Div1,
1857            #[cfg(not(any(feature = "g0", feature = "wl", feature = "c0")))]
1858            clk48_src: Clk48Src::Hsi48,
1859            #[cfg(feature = "c071")]
1860            clk48_src: Clk48Src::HsiUsb48,
1861            #[cfg(not(any(feature = "f", feature = "l", feature = "g0", feature = "c0")))]
1862            lpuart_src: LpUartSrc::Pclk,
1863            hse_bypass: false,
1864            security_system: false,
1865            #[cfg(not(any(feature = "g0", feature = "wl", feature = "c011", feature = "c031")))]
1866            hsi48_on: false,
1867            #[cfg(any(feature = "l4", feature = "l5", feature = "wb", feature = "wl"))]
1868            stop_wuck: StopWuck::Msi,
1869            #[cfg(feature = "wb")]
1870            rf_wakeup_src: RfWakeupSrc::Lse,
1871            #[cfg(not(any(feature = "g0", feature = "g4", feature = "wl", feature = "c0")))]
1872            sai1_src: SaiSrc::Pllp,
1873            #[cfg(feature = "g4")]
1874            boost_mode: true,
1875            #[cfg(any(feature = "g0", feature = "g4"))]
1876            can_src: CanSrc::Pclk,
1877            #[cfg(feature = "c0")]
1878            hsi_div: HsiDiv::Div4, // todo: Div1 for full speed?
1879            #[cfg(feature = "c071")]
1880            sys_div: SysDiv::Div1, // todo: What should this be?
1881        }
1882    }
1883}
1884
1885#[cfg(any(feature = "l4", feature = "l5", feature = "g4", feature = "wb"))]
1886/// Enable the Clock Recovery System. L443 User manual:
1887/// "The STM32L443xx devices embed a special block which allows automatic trimming of the
1888/// internal 48 MHz oscillator to guarantee its optimal accuracy over the whole device
1889/// operational range. This automatic trimming is based on the external synchronization signal,
1890/// which could be either derived from USB SOF signalization, from LSE oscillator, from an
1891/// external signal on CRS_SYNC pin or generated by user software. For faster lock-in during
1892/// startup it is also possible to combine automatic trimming with manual trimming action."
1893/// Note: This is for HSI48 only. Note that the HSI will turn off after entering Stop or Standby.
1894pub fn enable_crs(sync_src: CrsSyncSrc) {
1895    let crs = unsafe { &(*CRS::ptr()) };
1896    let rcc = unsafe { &(*RCC::ptr()) };
1897
1898    // todo: CRSEN missing on l4x5 pac: https://github.com/stm32-rs/stm32-rs/issues/572
1899    cfg_if! {
1900        if #[cfg(feature = "l4x5")] {
1901            let val = rcc.apb1enr1().read().bits();
1902            rcc.apb1enr1().write(|w| unsafe { w.bits(val | (1 << 24)) });
1903        } else {
1904            rcc.apb1enr1().modify(|_, w| w.crsen().bit(true));
1905        }
1906    }
1907
1908    crs.cfgr()
1909        .modify(|_, w| unsafe { w.syncsrc().bits(sync_src as u8) });
1910
1911    crs.cr().modify(|_, w| {
1912        // Set autotrim enabled.
1913        w.autotrimen().bit(true);
1914        // Enable CRS
1915        w.cen().bit(true)
1916    });
1917
1918    // "The internal 48 MHz RC oscillator is mainly dedicated to provide a high precision clock to
1919    // the USB peripheral by means of a special Clock Recovery System (CRS) circuitry. The CRS
1920    // can use the USB SOF signal, the LSE or an external signal to automatically and quickly
1921    // adjust the oscillator frequency on-fly. It is disabled as soon as the system enters Stop or
1922    // Standby mode. When the CRS is not used, the HSI48 RC oscillator runs on its default
1923    // frequency which is subject to manufacturing process variations
1924}