stm32_hal2/clocks/
h.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 `baseline` clocks module, but includes notable differendes.
6
7use cfg_if::cfg_if;
8
9#[cfg(not(any(feature = "h5", feature = "h7b3", feature = "h735")))]
10use crate::pac::SYSCFG;
11use crate::{
12    MAX_ITERS,
13    clocks::RccError,
14    pac::{CRS, FLASH, PWR, RCC},
15};
16
17#[derive(Clone, Copy, PartialEq)]
18pub enum PllSrc {
19    None,
20    Csi,
21    Hsi(HsiDiv),
22    Hse(u32),
23}
24
25impl PllSrc {
26    /// Required due to numerical value on non-uniform discrim being experimental.
27    /// (ie, can't set on `Pll(Pllsrc)`.
28    /// See RCC_PLLCKSELR register, PLLSRC field.
29    pub fn bits(&self) -> u8 {
30        match self {
31            Self::Hsi(_) => 0b00,
32            Self::Csi => 0b01,
33            Self::Hse(_) => 0b10,
34            Self::None => 0b11,
35        }
36    }
37}
38
39#[derive(Clone, Copy, PartialEq)]
40#[repr(u8)]
41/// Select the system clock used when exiting Stop mode. Sets RCC_CFGR register, STOPWUCK field.
42pub enum StopWuck {
43    Hsi = 0,
44    Csi = 1,
45}
46
47#[derive(Clone, Copy, PartialEq)]
48#[repr(u8)]
49/// Selects USB clock source. Sets D2CCIP2R reg, USBSEL field.
50pub enum UsbSrc {
51    Disabled = 0b00,
52    Pll1Q = 0b01,
53    Pll3Q = 0b10,
54    Hsi48 = 0b11,
55}
56
57#[derive(Clone, Copy)]
58#[repr(u8)]
59/// Select the SYNC signal source. Sets the CRS_CFGR register, SYNCSRC field.
60pub enum CrsSyncSrc {
61    #[cfg(feature = "h735")] // todo: 735 and 743 are opposites here. QC which use which.
62    /// CRS_SYNC pin selected as SYNC signal source
63    CrsSync = 0b00,
64    #[cfg(not(feature = "h735"))]
65    /// USB2 SOF selected as SYNC signal source
66    Usb2 = 0b00,
67    /// LSE selected as SYNC signal source
68    Lse = 0b01,
69    /// OTG HS1 SOF selected as SYNC signal source
70    OtgHs = 0b10,
71}
72
73#[derive(Clone, Copy, PartialEq)]
74/// Clock input source, also known as system clock switch. Sets RCC_CFGR register, SW field.
75pub enum InputSrc {
76    Hsi(HsiDiv),
77    Csi,
78    Hse(u32), // freq in Mhz,
79    Pll1,
80}
81
82impl InputSrc {
83    /// Required due to numerical value on non-uniform discrim being experimental.
84    /// (ie, can't set on `Pll(Pllsrc)`.
85    /// See RCC_CFGR register, SW field.
86    pub fn bits(&self) -> u8 {
87        match self {
88            Self::Hsi(_) => 0b000,
89            Self::Csi => 0b001,
90            Self::Hse(_) => 0b010,
91            Self::Pll1 => 0b011,
92        }
93    }
94}
95
96/// Configures the speeds, and enable status of an individual PLL. Note that the `enable`
97/// field has no effect for PLL1.
98pub struct PllCfg {
99    pub enabled: bool,
100    // pub fractional: bool,
101    pub pllp_en: bool,
102    pub pllq_en: bool,
103    pub pllr_en: bool,
104    pub divm: u8,
105    pub divn: u16,
106    pub divp: u8,
107    pub divq: u8,
108    pub divr: u8,
109}
110
111impl Default for PllCfg {
112    // Note that this assumes VOS1. (Not full speed)
113    fn default() -> Self {
114        cfg_if! {
115            if #[cfg(feature = "h5")] {
116                let divn = 250;
117            } else if #[cfg(feature = "h7b3")] {
118                let divn = 280;
119            } else {
120                let divn = 400;
121            }
122        }
123
124        Self {
125            enabled: true,
126            // fractional: false,
127            pllp_en: true,
128            pllq_en: false,
129            pllr_en: false,
130            // todo: Getting mixed messages on if HSI on H5 is 16Mhz or 32Mhz.
131            // todo: Great as 32Mhz for now, and see if speed is twice as slow
132            // todo as it should be.
133            #[cfg(feature = "h5")]
134            divm: 32, // todo 16?
135            #[cfg(feature = "h7")]
136            divm: 32,
137            divn,
138            // We override DIVP1 to be 1, and lower DIVN1 to achieve full speed on H723 etc
139            // variants.
140            divp: 2,
141            // Div1Q = 2 Allows <150Mhz SAI clock, if it's configured for PLL1Q (which is its default).
142            // Div1Q = 8 Allows <200Mhz SPI1 clock, if it's configured for PLL1Q (which is its default).
143            // At 400Mhz, Sets SAI clock to 100Mhz. At 480Mhz, sets it to 120Mhz.
144            divq: 8,
145            divr: 2,
146        }
147    }
148}
149
150impl PllCfg {
151    pub fn disabled() -> Self {
152        Self {
153            enabled: false,
154            pllq_en: false,
155            pllp_en: false,
156            pllr_en: false,
157            ..Default::default()
158        }
159    }
160}
161
162#[derive(Clone, Copy)]
163#[repr(u8)]
164/// Division factor for the AHB clock. Also known as AHB Prescaler. See RCC_D1CFGR reg.
165pub enum HclkPrescaler {
166    Div1 = 0b0000,
167    Div2 = 0b1000,
168    Div4 = 0b1001,
169    Div8 = 0b1010,
170    Div16 = 0b1011,
171    Div64 = 0b1100,
172    Div128 = 0b1101,
173    Div256 = 0b1110,
174    Div512 = 0b1111,
175}
176
177impl HclkPrescaler {
178    pub fn value(&self) -> u16 {
179        match self {
180            Self::Div1 => 1,
181            Self::Div2 => 2,
182            Self::Div4 => 4,
183            Self::Div8 => 8,
184            Self::Div16 => 16,
185            Self::Div64 => 64,
186            Self::Div128 => 128,
187            Self::Div256 => 256,
188            Self::Div512 => 512,
189        }
190    }
191}
192
193#[derive(Clone, Copy)]
194#[repr(u8)]
195/// For use with `RCC_APBPPRE1`, and `RCC_APBPPRE2`. Ie, low-speed and high-speed prescalers respectively.
196pub enum ApbPrescaler {
197    Div1 = 0b000,
198    Div2 = 0b100,
199    Div4 = 0b101,
200    Div8 = 0b110,
201    Div16 = 0b111,
202}
203
204impl ApbPrescaler {
205    pub fn value(&self) -> u8 {
206        match self {
207            Self::Div1 => 1,
208            Self::Div2 => 2,
209            Self::Div4 => 4,
210            Self::Div8 => 8,
211            Self::Div16 => 16,
212        }
213    }
214}
215
216#[derive(Clone, Copy, PartialEq)]
217#[repr(u8)]
218/// SAI clock input source. Sets RCC_D2CCIP1R register, SAIxSEL field.
219pub enum SaiSrc {
220    Pll1Q = 0b000,
221    Pll2P = 0b001,
222    Pll3P = 0b010,
223    I2sCkin = 0b011,
224    PerClk = 0100,
225}
226
227#[derive(Clone, Copy, PartialEq)]
228#[repr(u8)]
229/// SPI clock input source. Sets RCC_D2CCIP1R register, SPI123SEL field..
230pub enum Spi123Src {
231    //note: This is the same as SaiSrc.
232    Pll1Q = 0b000, // This is PLL2
233    Pll2P = 0b001,
234    Pll3P = 0b010,
235    I2sCkin = 0b011,
236    PerClk = 0100,
237}
238
239#[derive(Clone, Copy, PartialEq)]
240#[repr(u8)]
241/// SPI clock input source. Sets RCC_D2CCIP1R register, SPI45SEL field.
242pub enum Spi45Src {
243    Apb = 0b000,
244    Pll2Q = 0b001,
245    Pll3Q = 0b010,
246    Hsi = 0b011,
247    Csi = 0100,
248    HseCk = 0b101,
249}
250
251#[derive(Clone, Copy, PartialEq)]
252#[repr(u8)]
253/// SAI clock input source. Sets RCC_D2CCIP1R register, DFSDM1SEL field.
254pub enum DfsdmSrc {
255    /// rcc_pclk2 is selected as DFSDM1 Clk kernel clock (default after reset)
256    Pclk2 = 0,
257    /// sys_ck clock is selected as DFSDM1 Clk kernel clock
258    Sysclk = 1,
259}
260
261#[derive(Clone, Copy, PartialEq)]
262#[repr(u8)]
263/// CAN clock input source. Sets RCC_D2CCIP1R register, FDCANSEL field.
264pub enum CanSrc {
265    /// hse_ck clock is selected as FDCAN kernel clock (default after reset)
266    Hse = 0b00,
267    /// PLL1Q
268    Pll1Q = 0b01,
269    /// PLL2Q
270    Pll2Q = 0b10,
271}
272
273#[derive(Clone, Copy, PartialEq)]
274#[repr(u8)]
275/// Clock divider for the HSI. See RCC_CR register, HSIDIV field.
276pub enum HsiDiv {
277    Div1 = 0b00,
278    Div2 = 0b01,
279    Div4 = 0b10,
280    Div8 = 0b11,
281}
282
283impl HsiDiv {
284    pub fn value(&self) -> u8 {
285        match self {
286            Self::Div1 => 1,
287            Self::Div2 => 2,
288            Self::Div4 => 4,
289            Self::Div8 => 8,
290        }
291    }
292}
293
294#[derive(Clone, Copy, PartialEq)]
295#[repr(u8)]
296/// Range for the VOS. See H743 RM, section 6.8.6: PWR D3 domain control register. Sets PWR_D3CR,
297/// `VOS` field.
298pub enum VosRange {
299    /// 1.26 V - 1.40 V
300    #[cfg(not(feature = "h7b3"))]
301    VOS0 = 0, // This will actually be VOS1, but note that we handle the case of VOS0 activation
302    // differntly than the others, using its special activation sequence.
303    /// 1.15 V - 1.26 V
304    VOS1 = 0b11,
305    /// 1.05 V - 1.15 V
306    VOS2 = 0b10,
307    /// 0.95 V - 1.05 V
308    VOS3 = 0b01,
309}
310
311impl VosRange {
312    /// Power regulator voltage scale.
313    /// Choose the wait states based on VSO range and hclk frequency.. See H743 RM, Table 17: FLASH,
314    /// or RM0468, table 16.
315    /// recommended number of wait states and programming delay. Returns a tuple of (number of wait states,
316    /// programming delay) (FLASH ACR_LATENCY, WRHIGHFREQ) values respectively.
317    pub fn wait_states(&self, hclk: u32) -> (u8, u8) {
318        // todo: 280 Mhz variants.
319        #[cfg(not(feature = "h735"))]
320        match self {
321            #[cfg(not(feature = "h7b3"))]
322            Self::VOS0 => match hclk {
323                0..=70_000_000 => (0, 0),
324                70_000_001..=140_000_000 => (1, 1),
325                140_000_001..=185_000_000 => (2, 1),
326                185_000_001..=210_000_000 => (2, 2),
327                210_000_001..=225_000_000 => (3, 2),
328                225_000_001..=240_000_000 => (4, 2),
329                _ => panic!(
330                    "Can't set higher than 240Mhz HCLK with VSO0 range. (Try changing the `vos_range` setting)."
331                ),
332            },
333            Self::VOS1 => match hclk {
334                0..=70_000_000 => (0, 0),
335                70_000_001..=140_000_000 => (1, 1),
336                140_000_001..=185_000_000 => (2, 1),
337                185_000_001..=210_000_000 => (2, 2),
338                210_000_001..=225_000_000 => (3, 2),
339                _ => panic!(
340                    "Can't set higher than 225Mhz HCLK with VOS1 range. (Try changing the `vos_range` setting)."
341                ),
342            },
343            Self::VOS2 => match hclk {
344                0..=55_000_000 => (0, 0),
345                55_000_001..=110_000_000 => (1, 1),
346                110_000_001..=165_000_000 => (2, 1),
347                165_000_001..=225_000_000 => (3, 2),
348                _ => panic!(
349                    "Can't set higher than 225Mhz HCLK with VSO2 range. (Try changing the `vos_range` setting)."
350                ),
351            },
352            Self::VOS3 => match hclk {
353                0..=45_000_000 => (0, 0),
354                45_000_001..=90_000_000 => (1, 1),
355                90_000_001..=135_000_000 => (2, 1),
356                135_000_001..=180_000_000 => (3, 2),
357                180_000_001..=225_000_000 => (4, 2),
358                _ => panic!(
359                    "Can't set higher than 225Mhz HCLK with VSO3 range. (Try changing the `vos_range` setting)."
360                ),
361            },
362        }
363
364        #[cfg(feature = "h735")]
365        match self {
366            Self::VOS0 => match hclk {
367                0..=70_000_000 => (0, 0b00),
368                70_000_001..=140_000_000 => (1, 0b01),
369                140_000_001..=210_000_000 => (2, 0b10),
370                210_000_001..=275_000_000 => (3, 0b11),
371                _ => panic!(
372                    "Can't set higher than 275Mhz HCLK with VSO0 range. (Try changing the `vos_range` setting)."
373                ),
374            },
375            Self::VOS1 => match hclk {
376                0..=67_000_000 => (0, 0b00),
377                67_000_001..=133_000_000 => (1, 0b01),
378                133_000_001..=200_000_000 => (2, 0b10),
379                _ => panic!(
380                    "Can't set higher than 200Mhz HCLK with VOS1 range. (Try changing the `vos_range` setting)."
381                ),
382            },
383            Self::VOS2 => match hclk {
384                0..=50_000_000 => (0, 0b00),
385                50_000_001..=100_000_000 => (1, 0b01),
386                100_000_001..=150_000_000 => (2, 0b10),
387                _ => panic!(
388                    "Can't set higher than 150Mhz HCLK with VSO2 range. (Try changing the `vos_range` setting)."
389                ),
390            },
391            Self::VOS3 => match hclk {
392                0..=35_000_000 => (0, 0b00),
393                35_000_001..=70_000_000 => (1, 0b01),
394                70_000_001..=85_000_000 => (2, 0b10),
395                _ => panic!(
396                    "Can't set higher than 85Mhz HCLK with VSO3 range. (Try changing the `vos_range` setting)."
397                ),
398            },
399        }
400    }
401}
402
403/// Settings used to configure clocks. Create this struct by using its `Default::default()`
404/// implementation, then modify as required, referencing your RM's clock tree,
405/// or Stm32Cube IDE's interactive clock manager. Apply settings by running `.setup()`.
406pub struct Clocks {
407    /// The main input source
408    pub input_src: InputSrc,
409    /// The source driving all PLLs.
410    pub pll_src: PllSrc,
411    /// Enable and speed status for PLL1. Note that `input_src` controls if PLL1 is enabled, not
412    /// `pll1.enabled()`.
413    pub pll1: PllCfg,
414    /// Enable and speed status for PLL2
415    pub pll2: PllCfg,
416    /// Enable and speed status for PLL3
417    pub pll3: PllCfg,
418    #[cfg(feature = "h7")]
419    /// The prescaler between sysclk and hclk
420    pub d1_core_prescaler: HclkPrescaler,
421    /// The value to divide SYSCLK by, to get systick and peripheral clocks. Also known as AHB divider
422    pub hclk_prescaler: HclkPrescaler,
423    /// APB3 peripheral clocks
424    pub d1_prescaler: ApbPrescaler,
425    /// APB1 peripheral clocks
426    pub d2_prescaler1: ApbPrescaler,
427    // todo: D2 prescaler 2 possibly not on H5.
428    /// APB2 peripheral clocks
429    pub d2_prescaler2: ApbPrescaler,
430    #[cfg(feature = "h7")]
431    /// APB4 peripheral clocks
432    pub d3_prescaler: ApbPrescaler,
433    /// Bypass the HSE output, for use with oscillators that don't need it. Saves power, and
434    /// frees up the pin for use as GPIO.
435    pub hse_bypass: bool,
436    /// USBOTG kernel clock selection. Defaults to HSI48.
437    pub usb_src: UsbSrc,
438    pub security_system: bool,
439    pub hsi48_on: bool,
440    pub stop_wuck: StopWuck,
441    pub vos_range: VosRange,
442    /// SAI1 and DFSDM1 kernel Aclk clock source selection
443    pub sai1_src: SaiSrc,
444    #[cfg(not(feature = "h735"))]
445    /// SAI2 and SAI3 kernel clock source selection
446    pub sai23_src: SaiSrc,
447    pub sai4a_src: SaiSrc,
448    pub sai4b_src: SaiSrc,
449    pub spi123_src: Spi123Src,
450    pub spi45_src: Spi45Src,
451    /// DFSDM1 kernel clock source selection
452    pub dfsdm1_src: DfsdmSrc,
453    /// FDCAN kernel clock selection. Defaults to PLL1Q.
454    pub can_src: CanSrc,
455}
456
457impl Clocks {
458    /// Setup common and return Ok if the config is valid. Abort the setup if speeds
459    /// are invalid.
460    /// Use the STM32CubeIDE Clock Configuration tab to identify valid configs.
461    /// Use the `default()` implementation as a safe baseline.
462    /// This method also configures the PWR VOS setting, and can be used to enable VOS boost,
463    /// if `vos_range` is set to `VosRange::VOS0`.
464    pub fn setup(&self) -> Result<(), RccError> {
465        if let Err(e) = self.validate_speeds() {
466            return Err(e);
467        }
468
469        let rcc = unsafe { &(*RCC::ptr()) };
470        let flash = unsafe { &(*FLASH::ptr()) };
471        let pwr = unsafe { &(*PWR::ptr()) };
472
473        // Enable and reset System Configuration Controller, ie for interrupts.
474        // todo: Is this the right module to do this in?
475        #[cfg(feature = "h7")]
476        {
477            rcc.apb4enr.modify(|_, w| w.syscfgen().set_bit());
478            rcc.apb4rstr.modify(|_, w| w.syscfgrst().set_bit());
479            rcc.apb4rstr.modify(|_, w| w.syscfgrst().clear_bit());
480        }
481
482        let mut i = 0;
483
484        macro_rules! wait_hang {
485            ($i:expr) => {
486                i += 1;
487                if i >= MAX_ITERS {
488                    return Err(RccError::Hardware);
489                }
490            };
491        }
492
493        // H743 RM, sefction 6.8.6, and section 6.6.2: Voltage Scaling
494        //  Voltage scaling selection according to performance
495        // These bits control the VCORE voltage level and allow to obtains the best trade-off between
496        // power consumption and performance:
497        // – When increasing the performance, the voltage scaling shall be changed before increasing
498        // the system frequency.
499        // – When decreasing performance, the system frequency shall first be decreased before
500        // changing the voltage scaling.
501        match self.vos_range {
502            // todo: Do we need this on H5?
503            #[cfg(not(any(feature = "h5", feature = "h7b3", feature = "h735")))]
504            // Note:H735 etc have VOS0, but not oden; the RM doesn't list these steps.
505            VosRange::VOS0 => {
506                let syscfg = unsafe { &(*SYSCFG::ptr()) };
507
508                // VOS0 activation/deactivation sequence: H743 HRM, section 6.6.2:
509                // The system maximum frequency can be reached by boosting the voltage scaling level to
510                // VOS0. This is done through the ODEN bit in the SYSCFG_PWRCR register.
511                // The sequence to activate the VOS0 is the following:
512                // 1. Ensure that the system voltage scaling is set to VOS1 by checking the VOS bits in
513                // PWR D3 domain control register (PWR D3 domain control register (PWR_D3CR))
514                cfg_if! {
515                    if #[cfg(feature = "h7")] {
516                        pwr.d3cr
517                            .modify(|_, w| unsafe { w.vos().bits(VosRange::VOS1 as u8) });
518
519                        i = 0;
520                        while pwr.d3cr.read().vosrdy().bit_is_clear() {wait_hang!(i);}
521                    } else {
522                        pwr.voscr
523                            .modify(|_, w| unsafe { w.vos().bits(VosRange::VOS1 as u8) });
524
525                        i = 0;
526                        while pwr.vossr.read().vosrdy().bit_is_clear() {wait_hang!(i);}
527                    }
528                }
529
530                // 2. Enable the SYSCFG clock in the RCC by setting the SYSCFGEN bit in the
531                // RCC_APB4ENR register.
532                // (Handled above)
533
534                // 3. Enable the ODEN bit in the SYSCFG_PWRCR register.
535                syscfg.pwrcr.modify(|_, w| w.oden().set_bit());
536
537                // 4. Wait for VOSRDY to be set.
538                i = 0;
539                #[cfg(feature = "h7")]
540                while pwr.d3cr.read().vosrdy().bit_is_clear() {
541                    wait_hang!(i);
542                }
543                #[cfg(feature = "h5")]
544                while pwr.vossr.read().vosrdy().bit_is_clear() {
545                    wait_hang!(i);
546                }
547
548                // Once the VCORE supply has reached the required level, the system frequency can be
549                // increased. Figure 31 shows the recommended sequence for switching VCORE from VOS1 to
550                // VOS0 sequence.
551                // The sequence to deactivate the VOS0 is the following:
552                // 1. Ensure that the system frequency was decreased.
553                // 2. Ensure that the SYSCFG clock is enabled in the RCC by setting the SYSCFGEN bit set
554                // in the RCC_APB4ENR register.
555                // 3. Reset the ODEN bit in the SYSCFG_PWRCR register to disable VOS0.
556            }
557            _ => {
558                #[cfg(feature = "h7")]
559                pwr.d3cr
560                    .modify(|_, w| unsafe { w.vos().bits(self.vos_range as u8) });
561                #[cfg(feature = "h5")]
562                pwr.voscr
563                    .modify(|_, w| unsafe { w.vos().bits(self.vos_range as u8) });
564            }
565        }
566
567        // Adjust flash wait states according to the HCLK frequency.
568        // We need to do this before enabling PLL, or it won't enable.
569        // H742 RM, Table 17.
570        let wait_states = self.vos_range.wait_states(self.hclk());
571
572        flash.acr.modify(|_, w| unsafe {
573            w.latency().bits(wait_states.0);
574            w.wrhighfreq().bits(wait_states.1)
575        });
576
577        // Enable oscillators, and wait until ready.
578        match self.input_src {
579            InputSrc::Csi => {
580                rcc.cr.modify(|_, w| w.csion().bit(true));
581                i = 0;
582                while rcc.cr.read().csirdy().bit_is_clear() {
583                    wait_hang!(i);
584                }
585            }
586            InputSrc::Hse(_) => {
587                rcc.cr.modify(|_, w| w.hseon().bit(true));
588                // Wait for the HSE to be ready.
589                i = 0;
590                while rcc.cr.read().hserdy().bit_is_clear() {
591                    wait_hang!(i);
592                }
593            }
594            InputSrc::Hsi(div) => {
595                rcc.cr.modify(|_, w| unsafe {
596                    w.hsidiv().bits(div as u8);
597                    w.hsion().bit(true)
598                });
599                i = 0;
600                while rcc.cr.read().hsirdy().bit_is_clear() {
601                    wait_hang!(i);
602                }
603            }
604            InputSrc::Pll1 => {
605                // todo: PLL setup here is DRY with the HSE, HSI, and Csi setup above.
606                match self.pll_src {
607                    PllSrc::Csi => {
608                        rcc.cr.modify(|_, w| w.csion().bit(true));
609                        i = 0;
610                        while rcc.cr.read().csirdy().bit_is_clear() {
611                            wait_hang!(i);
612                        }
613                    }
614                    PllSrc::Hse(_) => {
615                        rcc.cr.modify(|_, w| w.hseon().bit(true));
616                        i = 0;
617                        while rcc.cr.read().hserdy().bit_is_clear() {
618                            wait_hang!(i);
619                        }
620                    }
621                    PllSrc::Hsi(div) => {
622                        rcc.cr.modify(|_, w| unsafe {
623                            w.hsidiv().bits(div as u8);
624                            w.hsion().bit(true)
625                        });
626                        i = 0;
627                        while rcc.cr.read().hsirdy().bit_is_clear() {
628                            wait_hang!(i);
629                        }
630                    }
631                    PllSrc::None => {}
632                }
633            }
634        }
635
636        rcc.cr.modify(|_, w| {
637            // Enable bypass mode on HSE, since we're using a ceramic oscillator.
638            w.hsebyp().bit(self.hse_bypass)
639        });
640
641        rcc.cfgr.modify(|_, w| unsafe {
642            w.sw().bits(self.input_src.bits());
643            w.stopwuck().bit(self.stop_wuck as u8 != 0)
644        });
645
646        #[cfg(feature = "h7")]
647        rcc.d1cfgr.modify(|_, w| unsafe {
648            w.d1cpre().bits(self.d1_core_prescaler as u8);
649            w.d1ppre().bits(self.d1_prescaler as u8);
650            w.hpre().bits(self.hclk_prescaler as u8)
651        });
652
653        #[cfg(feature = "h7")]
654        rcc.d2cfgr.modify(|_, w| unsafe {
655            w.d2ppre1().bits(self.d2_prescaler1 as u8);
656            w.d2ppre2().bits(self.d2_prescaler2 as u8)
657        });
658
659        #[cfg(feature = "h7")]
660        rcc.d3cfgr
661            .modify(|_, w| unsafe { w.d3ppre().bits(self.d3_prescaler as u8) });
662
663        #[cfg(feature = "h5")]
664        rcc.cfgr2.modify(|_, w| unsafe {
665            w.ppre1().bits(self.d1_prescaler as u8);
666            w.ppre2().bits(self.d2_prescaler1 as u8);
667            w.ppre3().bits(self.d2_prescaler2 as u8);
668            w.hpre().bits(self.hclk_prescaler as u8)
669        });
670
671        #[cfg(not(any(feature = "h7b3", feature = "h5")))]
672        rcc.d2ccip1r.modify(|_, w| unsafe {
673            w.sai1sel().bits(self.sai1_src as u8);
674            #[cfg(not(feature = "h735"))]
675            w.sai23sel().bits(self.sai23_src as u8);
676            w.spi123sel().bits(self.spi123_src as u8);
677            w.spi45sel().bits(self.spi45_src as u8);
678            w.dfsdm1sel().bit(self.dfsdm1_src as u8 != 0);
679            w.fdcansel().bits(self.can_src as u8)
680        });
681
682        // todo: Add config enums for these, and add them as Clocks fields.
683        #[cfg(not(any(feature = "h7b3", feature = "h5")))]
684        rcc.d2ccip2r
685            .modify(|_, w| unsafe { w.usbsel().bits(self.usb_src as u8) });
686
687        #[cfg(not(any(feature = "h7b3", feature = "h5")))]
688        rcc.d3ccipr.modify(|_, w| unsafe {
689            w.sai4asel().bits(self.sai4a_src as u8);
690            w.sai4bsel().bits(self.sai4b_src as u8)
691        });
692
693        // #[cfg(feature = "h5")]
694        // rcc.ccipr1.modify(|_, w| unsafe {
695        // });
696
697        // #[cfg(feature = "h5")]
698        // rcc.ccipr2.modify(|_, w| unsafe {
699        // });
700
701        #[cfg(feature = "h5")]
702        rcc.ccipr3.modify(|_, w| unsafe {
703            // todo: This is broken down into each spi individually on H5.
704            w.spi1sel().bits(self.spi123_src as u8);
705            w.spi2sel().bits(self.spi123_src as u8);
706            w.spi3sel().bits(self.spi45_src as u8);
707            w.spi4sel().bits(self.spi45_src as u8);
708            w.spi5sel().bits(self.spi123_src as u8)
709            // w.spi6sel().bits(self.spi123_src as u8);
710        });
711
712        #[cfg(feature = "h5")]
713        rcc.ccipr4.modify(|_, w| unsafe {
714            w.usbfssel().bits(self.usb_src as u8)
715            // Also: OctoSPI and I2C.
716        });
717
718        #[cfg(feature = "h5")]
719        rcc.ccipr5.modify(|_, w| unsafe {
720            w.sai1sel().bits(self.sai1_src as u8);
721            w.sai2sel().bits(self.sai23_src as u8);
722            w.fdcan12sel().bits(self.can_src as u8)
723            // also: ADC and DAC.
724        });
725
726        rcc.cr.modify(|_, w| w.hsecsson().bit(self.security_system));
727
728        // todo: Allow configuring the PLL in fractional mode.
729
730        #[cfg(feature = "h7")]
731        rcc.pllckselr
732            .modify(|_, w| w.pllsrc().bits(self.pll_src.bits()));
733
734        // Note that with this code setup, PLL2 and PLL3 won't work properly unless using
735        // the input source is PLL1.
736        if let InputSrc::Pll1 = self.input_src {
737            // Turn off the PLL: Required for modifying some of the settings below.
738            rcc.cr.modify(|_, w| w.pll1on().clear_bit());
739            // Wait for the PLL to no longer be ready before executing certain writes.
740            while rcc.cr.read().pll1rdy().bit_is_set() {}
741
742            // Set and reset by software to select the proper reference frequency range used for PLL1.
743            // This bit must be written before enabling the PLL1.
744            let pll1_rng_val = match self.pll_input_speed(self.pll_src, 1) {
745                1_000_000..=2_000_000 => 0b00,
746                2_000_001..=4_000_000 => 0b01,
747                4_000_001..=8_000_000 => 0b10,
748                8_000_001..=16_000_000 => 0b11,
749                _ => panic!("PLL1 input source must be between 1Mhz and 16Mhz."),
750            };
751
752            // todo: Don't enable all these pqr etc by default!
753            // todo don't enable pll2 and 3 by default!!
754            // todo: This has an impact on power consumption.
755
756            // todo: MOre DRY
757            // H743 RM:
758            // 0: Wide VCO range: 192 to 836 MHz (default after reset)
759            // 1: Medium VCO range: 150 to 420 MHz
760            let pll1_vco = match self.pll_input_speed(self.pll_src, 1) {
761                1_000_000..=2_000_000 => 1,
762                2_000_001..=16_000_000 => 0,
763                _ => panic!("PLL1 input source must be between 1Mhz and 16Mhz."),
764            };
765
766            // The user application can then configure the proper VCO: if the frequency of the reference
767            // clock is lower or equal to 2 MHz, then VCOL must be selected, otherwise VCOH must be
768            // chosen. To reduce the power consumption, it is recommended to configure the VCO output
769            // to the lowest frequency.
770
771            // The frequency of the reference clock provided to the PLLs (refx_ck) must range from 1 to
772            // 16 MHz. The user application has to program properly the DIVMx dividers of the RCC PLLs
773            // Clock Source Selection Register (RCC_PLLCKSELR) in order to match this condition. In
774            // addition, the PLLxRGE of the RCC PLLs Configuration Register (RCC_PLLCFGR) field
775            // must be set according to the reference input frequency to guarantee an optimal
776            // performance of the PLL.
777
778            // If using multiple PLLs, we do a write to `PLLCLKSELR` and `PLLCFGR` for each
779            // enabled PLL. This is unecessary, but makes the code clearer. This is worth it, given
780            // we expect the user to run `.setup()` only once.
781            #[cfg(feature = "h7")]
782            rcc.pllckselr.modify(|_, w| w.divm1().bits(self.pll1.divm));
783
784            #[cfg(feature = "h7")]
785            rcc.pllcfgr.modify(|_, w| {
786                w.pll1rge().bits(pll1_rng_val);
787                w.pll1vcosel().bit(pll1_vco != 0);
788                w.divp1en().bit(true);
789                w.divq1en().bit(self.pll1.pllq_en);
790                w.divr1en().bit(self.pll1.pllr_en)
791            });
792
793            #[cfg(feature = "h5")]
794            rcc.pll1cfgr.modify(|_, w| unsafe {
795                w.pll1src().bits(self.pll_src.bits());
796                w.divm1().bits(self.pll1.divm);
797                w.pll1rge().bits(pll1_rng_val);
798                w.pll1vcosel().bit(pll1_vco != 0);
799                w.pll1pen().bit(true);
800                w.pll1qen().bit(self.pll1.pllq_en);
801                w.pll1ren().bit(self.pll1.pllr_en)
802            });
803
804            #[cfg(feature = "h7")]
805            rcc.pll1divr.modify(|_, w| unsafe {
806                w.divn1().bits(self.pll1.divn - 1);
807                w.divp1().bits(self.pll1.divp - 1);
808                w.divq1().bits(self.pll1.divq - 1);
809                w.divr1().bits(self.pll1.divr - 1)
810            });
811
812            #[cfg(feature = "h5")]
813            rcc.pll1divr.modify(|_, w| unsafe {
814                w.pll1n().bits(self.pll1.divn - 1);
815                w.pll1p().bits(self.pll1.divp - 1);
816                w.pll1q().bits(self.pll1.divq - 1);
817                w.pll1r().bits(self.pll1.divr - 1)
818            });
819
820            // Now turn PLL back on, once we're configured things that can only be set with it off.
821            rcc.cr.modify(|_, w| w.pll1on().set_bit());
822            i = 0;
823            while rcc.cr.read().pll1rdy().bit_is_clear() {
824                wait_hang!(i);
825            }
826        }
827
828        // todo DRY
829        if self.pll2.enabled {
830            rcc.cr.modify(|_, w| w.pll2on().clear_bit());
831            i = 0;
832            while rcc.cr.read().pll2rdy().bit_is_set() {
833                wait_hang!(i);
834            }
835
836            let pll2_rng_val = match self.pll_input_speed(self.pll_src, 2) {
837                1_000_000..=2_000_000 => 0b00,
838                2_000_001..=4_000_000 => 0b01,
839                4_000_001..=8_000_000 => 0b10,
840                8_000_001..=16_000_000 => 0b11,
841                _ => panic!("PLL2 input source must be between 1Mhz and 16Mhz."),
842            };
843
844            let pll2_vco = match self.pll_input_speed(self.pll_src, 2) {
845                0..=2_000_000 => 0,
846                _ => 1,
847            };
848
849            #[cfg(feature = "h7")]
850            rcc.pllckselr.modify(|_, w| w.divm2().bits(self.pll2.divm));
851
852            #[cfg(feature = "h7")]
853            rcc.pllcfgr.modify(|_, w| {
854                w.pll2rge().bits(pll2_rng_val);
855                w.pll2vcosel().bit(pll2_vco != 0);
856                w.divp2en().bit(self.pll2.pllp_en);
857                w.divq2en().bit(self.pll2.pllq_en);
858                w.divr2en().bit(self.pll2.pllr_en)
859            });
860
861            #[cfg(feature = "h5")]
862            rcc.pll2cfgr.modify(|_, w| unsafe {
863                w.pll2src().bits(self.pll_src.bits());
864                w.pll2rge().bits(pll2_rng_val);
865                w.pll2vcosel().bit(pll2_vco != 0);
866                w.pll2pen().bit(self.pll2.pllp_en);
867                w.pll2qen().bit(self.pll2.pllq_en);
868                w.pll2ren().bit(self.pll2.pllr_en)
869            });
870
871            #[cfg(feature = "h7")]
872            rcc.pll2divr.modify(|_, w| unsafe {
873                w.divn2().bits(self.pll2.divn - 1);
874                w.divp2().bits(self.pll2.divp - 1);
875                w.divq2().bits(self.pll2.divq - 1);
876                w.divr2().bits(self.pll2.divr - 1)
877            });
878
879            #[cfg(feature = "h5")]
880            rcc.pll2divr.modify(|_, w| unsafe {
881                w.pll2n().bits(self.pll2.divn - 1);
882                w.pll2p().bits(self.pll2.divp - 1);
883                w.pll2q().bits(self.pll2.divq - 1);
884                w.pll2r().bits(self.pll2.divr - 1)
885            });
886
887            rcc.cr.modify(|_, w| w.pll2on().set_bit());
888            i = 0;
889            while rcc.cr.read().pll2rdy().bit_is_clear() {
890                wait_hang!(i);
891            }
892        }
893
894        if self.pll3.enabled {
895            rcc.cr.modify(|_, w| w.pll3on().clear_bit());
896            i = 0;
897            while rcc.cr.read().pll3rdy().bit_is_set() {
898                wait_hang!(i);
899            }
900
901            let pll3_rng_val = match self.pll_input_speed(self.pll_src, 3) {
902                1_000_000..=2_000_000 => 0b00,
903                2_000_001..=4_000_000 => 0b01,
904                4_000_001..=8_000_000 => 0b10,
905                8_000_001..=16_000_000 => 0b11,
906                _ => panic!("PLL3 input source must be between 1Mhz and 16Mhz."),
907            };
908
909            let pll3_vco = match self.pll_input_speed(self.pll_src, 3) {
910                0..=2_000_000 => 0,
911                _ => 1,
912            };
913
914            #[cfg(feature = "h7")]
915            rcc.pllckselr.modify(|_, w| w.divm3().bits(self.pll3.divm));
916
917            #[cfg(feature = "h7")]
918            rcc.pllcfgr.modify(|_, w| {
919                w.pll3rge().bits(pll3_rng_val);
920                w.pll3vcosel().bit(pll3_vco != 0);
921                w.divp3en().bit(self.pll3.pllp_en);
922                w.divq3en().bit(self.pll3.pllq_en);
923                w.divr3en().bit(self.pll3.pllr_en)
924            });
925
926            #[cfg(feature = "h5")]
927            rcc.pll3cfgr.modify(|_, w| unsafe {
928                w.pll3src().bits(self.pll_src.bits());
929                w.pll3rge().bits(pll3_rng_val);
930                w.pll3vcosel().bit(pll3_vco != 0);
931                w.pll3pen().bit(self.pll3.pllp_en);
932                w.pll3qen().bit(self.pll3.pllq_en);
933                w.pll3ren().bit(self.pll3.pllr_en)
934            });
935
936            #[cfg(feature = "h7")]
937            rcc.pll3divr.modify(|_, w| unsafe {
938                w.divn3().bits(self.pll3.divn - 1);
939                w.divp3().bits(self.pll3.divp - 1);
940                w.divq3().bits(self.pll3.divq - 1);
941                w.divr3().bits(self.pll3.divr - 1)
942            });
943
944            #[cfg(feature = "h5")]
945            rcc.pll3divr.modify(|_, w| unsafe {
946                w.pll3n().bits(self.pll3.divn - 1);
947                w.pll3p().bits(self.pll3.divp - 1);
948                w.pll3q().bits(self.pll3.divq - 1);
949                w.pll3r().bits(self.pll3.divr - 1)
950            });
951
952            rcc.cr.modify(|_, w| w.pll3on().set_bit());
953            i = 0;
954            while rcc.cr.read().pll3rdy().bit_is_clear() {
955                wait_hang!(i);
956            }
957        }
958
959        if self.hsi48_on {
960            rcc.cr.modify(|_, w| w.hsi48on().set_bit());
961            i = 0;
962            while rcc.cr.read().hsi48rdy().bit_is_clear() {
963                wait_hang!(i);
964            }
965        }
966
967        Ok(())
968    }
969
970    /// Re-select input source; used on Stop and Standby modes, where the system reverts
971    /// to HSI after wake.
972    pub fn reselect_input(&self) -> Result<(), RccError> {
973        // Re-select the input source; it will revert to HSI during `Stop` or `Standby` mode.
974
975        let rcc = unsafe { &(*RCC::ptr()) };
976
977        let mut i = 0;
978        macro_rules! wait_hang {
979            ($i:expr) => {
980                i += 1;
981                if i >= MAX_ITERS {
982                    return Err(RccError::Hardware);
983                }
984            };
985        }
986
987        // Note: It would save code repetition to pass the `Clocks` struct in and re-run setup
988        // todo: But this saves a few reg writes.
989        match self.input_src {
990            InputSrc::Hse(_) => {
991                rcc.cr.modify(|_, w| w.hseon().set_bit());
992                i = 0;
993                while rcc.cr.read().hserdy().bit_is_clear() {
994                    wait_hang!(i);
995                }
996
997                rcc.cfgr
998                    .modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
999            }
1000            InputSrc::Pll1 => {
1001                // todo: DRY with above.
1002                match self.pll_src {
1003                    PllSrc::Hse(_) => {
1004                        rcc.cr.modify(|_, w| w.hseon().set_bit());
1005                        i = 0;
1006                        while rcc.cr.read().hserdy().bit_is_clear() {
1007                            wait_hang!(i);
1008                        }
1009                    }
1010                    PllSrc::Hsi(div) => {
1011                        // Generally reverts to Csi (see note below)
1012                        rcc.cr.modify(|_, w| unsafe {
1013                            w.hsidiv().bits(div as u8); // todo: Do we need to reset the HSI div after low power?
1014                            w.hsion().bit(true)
1015                        });
1016                        i = 0;
1017                        while rcc.cr.read().hsirdy().bit_is_clear() {
1018                            wait_hang!(i);
1019                        }
1020                    }
1021                    PllSrc::Csi => (), // todo
1022                    PllSrc::None => (),
1023                }
1024
1025                // todo: PLL 2 and 3?
1026                rcc.cr.modify(|_, w| w.pll1on().clear_bit());
1027                i = 0;
1028                while rcc.cr.read().pll1rdy().bit_is_set() {
1029                    wait_hang!(i);
1030                }
1031
1032                rcc.cfgr
1033                    .modify(|_, w| unsafe { w.sw().bits(self.input_src.bits()) });
1034
1035                rcc.cr.modify(|_, w| w.pll1on().set_bit());
1036                i = 0;
1037                while rcc.cr.read().pll1rdy().bit_is_clear() {
1038                    wait_hang!(i);
1039                }
1040            }
1041            InputSrc::Hsi(div) => {
1042                {
1043                    // From Reference Manual, RCC_CFGR register section:
1044                    // "Configured by HW to force Csi oscillator selection when exiting Standby or Shutdown mode.
1045                    // Configured by HW to force Csi or HSI16 oscillator selection when exiting Stop mode or in
1046                    // case of failure of the HSE oscillator, depending on STOPWUCK value."
1047                    // In tests, from stop, it tends to revert to Csi.
1048                    rcc.cr.modify(|_, w| unsafe {
1049                        w.hsidiv().bits(div as u8); // todo: Do we need to reset the HSI div after low power?
1050                        w.hsion().bit(true)
1051                    });
1052                    i = 0;
1053                    while rcc.cr.read().hsirdy().bit_is_clear() {
1054                        wait_hang!(i);
1055                    }
1056                }
1057            }
1058            InputSrc::Csi => (), // ?
1059        }
1060
1061        Ok(())
1062    }
1063
1064    /// Calculate the input speed to the PLL. This must be between 1 and 16 Mhz. Called `refx_ck`
1065    /// in the RM.
1066    pub fn pll_input_speed(&self, pll_src: PllSrc, pll_num: u8) -> u32 {
1067        let input_freq = match pll_src {
1068            PllSrc::Csi => 4_000_000,
1069            // todo: QC if H5 HSI is 64 or 32M.
1070            PllSrc::Hsi(div) => 64_000_000 / (div.value() as u32),
1071            PllSrc::Hse(freq) => freq,
1072            PllSrc::None => 0,
1073        };
1074
1075        match pll_num {
1076            1 => input_freq / (self.pll1.divm as u32),
1077            2 => input_freq / (self.pll2.divm as u32),
1078            3 => input_freq / (self.pll3.divm as u32),
1079            _ => panic!("Pll num must be between 1 and 3."),
1080        }
1081    }
1082
1083    /// Calculate VCO output frequency: = Fref1_ck x DIVN1
1084    pub fn vco_output_freq(&self, pll_src: PllSrc, pll_num: u8) -> u32 {
1085        let input_speed = self.pll_input_speed(pll_src, pll_num);
1086        match pll_num {
1087            1 => input_speed * self.pll1.divn as u32,
1088            2 => input_speed * self.pll2.divn as u32,
1089            3 => input_speed * self.pll3.divn as u32,
1090            _ => panic!("Pll num must be between 1 and 3."),
1091        }
1092    }
1093
1094    /// Check if the PLL is enabled. This is useful if checking whether to re-enable the PLL
1095    /// after exiting Stop or Standby modes, eg so you don't re-enable if it was already re-enabled
1096    /// in a different context. eg:
1097    /// ```
1098    /// if !clock_cfg.pll_is_enabled() {
1099    ///     clock_cfg.reselect_input();
1100    ///}
1101    ///```
1102    pub fn pll_is_enabled(&self) -> bool {
1103        let rcc = unsafe { &(*RCC::ptr()) };
1104        rcc.cr.read().pll1on().bit_is_set()
1105    }
1106
1107    /// Calculate the sysclock frequency, in hz. Note that for dual core variants, this is for CPU1.
1108    /// CPU2 syclock is equal to the HCLK, so use the `hclk()` method.
1109    pub fn sysclk(&self) -> u32 {
1110        match self.input_src {
1111            InputSrc::Pll1 => {
1112                // divm1 is included in `pll_input_speed`.
1113                self.pll_input_speed(self.pll_src, 1) * self.pll1.divn as u32
1114                    / self.pll1.divp as u32
1115            }
1116            InputSrc::Csi => 4_000_000,
1117            // todo: QC if H5 is 32 or 64M.
1118            InputSrc::Hsi(div) => 64_000_000 / (div.value() as u32),
1119            InputSrc::Hse(freq) => freq,
1120        }
1121    }
1122
1123    #[cfg(feature = "h7")]
1124    /// Get the Domain 1 core prescaler frequency, in hz
1125    pub fn d1cpreclk(&self) -> u32 {
1126        self.sysclk() / self.d1_core_prescaler.value() as u32
1127    }
1128
1129    /// Get the HCLK frequency, in hz
1130    pub fn hclk(&self) -> u32 {
1131        #[cfg(feature = "h7")]
1132        return self.sysclk()
1133            / self.d1_core_prescaler.value() as u32
1134            / self.hclk_prescaler.value() as u32;
1135        #[cfg(feature = "h5")]
1136        return self.sysclk() / self.hclk_prescaler.value() as u32;
1137    }
1138
1139    /// Get the systick speed. Note that for dual core variants, this is for CPU1.
1140    /// CPU2 systick is equal to the HCLK (possibly divided by 8), so use the `hclk()` method.
1141    pub fn systick(&self) -> u32 {
1142        // todo: There's an optional /8 divider we're not taking into account here.
1143        #[cfg(feature = "h7")]
1144        return self.d1cpreclk();
1145        #[cfg(feature = "h5")]
1146        return self.sysclk();
1147    }
1148
1149    /// Get the USB clock frequency, in hz
1150    pub fn usb(&self) -> u32 {
1151        // let (input_freq, _) = sysclock(self.input_src, self.divm1, self.divn1, self.divp1);
1152        // (input_freq * 1_000_000) as u32 / self.divm1 as u32 * self.pll_sai1_mul as u32 / 2
1153        0 // todo
1154    }
1155
1156    pub fn apb1(&self) -> u32 {
1157        self.hclk() / self.d2_prescaler1.value() as u32
1158    }
1159
1160    /// Get the frequency used by APB1 timers, in hz
1161    pub fn apb1_timer(&self) -> u32 {
1162        if let ApbPrescaler::Div1 = self.d2_prescaler1 {
1163            self.apb1()
1164        } else {
1165            self.apb1() * 2
1166        }
1167    }
1168
1169    pub fn apb2(&self) -> u32 {
1170        self.hclk() / self.d2_prescaler2.value() as u32
1171    }
1172
1173    /// Get the frequency used by APB2 timers, in hz
1174    pub fn apb2_timer(&self) -> u32 {
1175        if let ApbPrescaler::Div1 = self.d2_prescaler2 {
1176            self.apb2()
1177        } else {
1178            self.apb2() * 2
1179        }
1180    }
1181
1182    /// Get the SAI1 audio clock frequency, in hz
1183    pub fn sai1_speed(&self) -> u32 {
1184        let pll_src = match self.input_src {
1185            InputSrc::Pll1 => self.pll_src,
1186            InputSrc::Csi => PllSrc::Csi,
1187            InputSrc::Hsi(div) => PllSrc::Hsi(div),
1188            InputSrc::Hse(freq) => PllSrc::Hse(freq),
1189        };
1190
1191        match self.sai1_src {
1192            SaiSrc::Pll1Q => {
1193                self.pll_input_speed(pll_src, 1) * self.pll1.divn as u32 / self.pll1.divq as u32
1194            }
1195            SaiSrc::Pll2P => {
1196                self.pll_input_speed(pll_src, 1) * self.pll2.divn as u32 / self.pll2.divp as u32
1197            }
1198            SaiSrc::Pll3P => {
1199                self.pll_input_speed(pll_src, 1) * self.pll3.divn as u32 / self.pll3.divp as u32
1200            }
1201            SaiSrc::I2sCkin => unimplemented!(),
1202            SaiSrc::PerClk => unimplemented!(),
1203        }
1204    }
1205
1206    pub fn validate_speeds(&self) -> Result<(), RccError> {
1207        cfg_if! {
1208            if #[cfg(feature = "h735")] {
1209                let max_sysclk = 480_000_000;
1210            } else {
1211                let max_sysclk = 550_000_000;
1212            }
1213        }
1214        // #[cfg(feature = "h743")]
1215        let max_hclk = 240_000_000;
1216        // #[cfg(feature = "h743")]
1217        let max_apb = 120_000_000; // todo: Different depending on apb
1218
1219        // todo: PLL input (Post DIVM1, pre DIVN1) must be between 1Mhz and 16 Mhz
1220
1221        // todo after pool today: FIgure out what other bit needs to be set to reflect this.
1222
1223        // todo: Are these valid for all H7 configs?
1224        if self.pll1.divm > 63
1225            || self.pll1.divm > 63
1226            || self.pll3.divm > 63
1227            || self.pll1.divn > 512
1228            || self.pll2.divn > 512
1229            || self.pll3.divn > 512
1230            || self.pll1.divp > 128
1231            || self.pll2.divp > 128
1232            || self.pll3.divp > 128
1233            || self.pll1.divp < 2
1234            || self.pll2.divp < 2
1235            || self.pll3.divp < 2
1236        // todo: R and Q
1237        {
1238            return Err(RccError::Speed);
1239        }
1240
1241        if let InputSrc::Pll1 = self.input_src {
1242            let pll_input_speed = self.pll_input_speed(self.pll_src, 1);
1243            if pll_input_speed < 1_000_000 || pll_input_speed > 16_000_000 {
1244                return Err(RccError::Speed);
1245            }
1246            // VCO0: Wide VCO range: 192 to 836 MHz (default after reset) (VCOH)
1247            // Note: The RM appears out of date: Revision "V" supports 960_000_000Mhz
1248            // VCO speed, to allow a max core speed of 480Mhz.
1249            let vco_speed = self.vco_output_freq(self.pll_src, 1);
1250            if pll_input_speed >= 2_000_000 && (vco_speed < 192_000_000 || vco_speed > 960_000_000)
1251            {
1252                return Err(RccError::Speed);
1253            }
1254            // 1: Medium VCO range: 150 to 420 MHz. (VCOL)
1255            // Note: You may get power savings
1256            if pll_input_speed < 2_000_000 && (vco_speed < 150_000_000 || vco_speed > 420_000_000) {
1257                return Err(RccError::Speed);
1258            }
1259        }
1260
1261        // todo: Validate PLL2 and PLL3 speeds.
1262
1263        // todo: More work on this, including feature gates
1264
1265        // todo: QC these limits
1266        // todo: Note that this involves repeatedly calculating sysclk.
1267        // todo. We could work around thsi by calcing it once here.
1268        if self.sysclk() > max_sysclk {
1269            return Err(RccError::Speed);
1270        }
1271
1272        if self.hclk() > max_hclk {
1273            return Err(RccError::Speed);
1274        }
1275
1276        if self.apb1() > max_apb {
1277            return Err(RccError::Speed);
1278        }
1279
1280        if self.apb2() > max_apb {
1281            return Err(RccError::Speed);
1282        }
1283
1284        // todo: Apb3/4
1285
1286        Ok(())
1287    }
1288}
1289
1290// todo: support default for 280Mhz variants.
1291
1292impl Default for Clocks {
1293    /// This default configures clocks with the HSI, and a 400Mhz sysclock speed. (280Mhz sysclock
1294    /// on variants that only go that high). Note that H723-745 still use this default speed
1295    /// due to needing VOS0 for higher.
1296    /// Peripheral and timer clocks are set to 100Mhz or 200Mhz, depending on their limits.
1297    /// HSE output is not bypassed.
1298    fn default() -> Self {
1299        Self {
1300            /// The input source for the system and peripheral clocks. Eg HSE, HSI, PLL etc
1301            input_src: InputSrc::Pll1,
1302            pll_src: PllSrc::Hsi(HsiDiv::Div1),
1303            pll1: PllCfg::default(),
1304            pll2: PllCfg::disabled(),
1305            pll3: PllCfg::disabled(),
1306            #[cfg(feature = "h7")]
1307            d1_core_prescaler: HclkPrescaler::Div1,
1308            d1_prescaler: ApbPrescaler::Div2,
1309            /// The value to divide SYSCLK by, to get systick and peripheral clocks. Also known as AHB divider
1310            #[cfg(feature = "h5")]
1311            hclk_prescaler: HclkPrescaler::Div1,
1312            #[cfg(feature = "h7")]
1313            hclk_prescaler: HclkPrescaler::Div2,
1314            #[cfg(feature = "h5")]
1315            d2_prescaler1: ApbPrescaler::Div1,
1316            #[cfg(feature = "h7")]
1317            d2_prescaler1: ApbPrescaler::Div2,
1318            #[cfg(feature = "h5")]
1319            d2_prescaler2: ApbPrescaler::Div1,
1320            #[cfg(feature = "h7")]
1321            d2_prescaler2: ApbPrescaler::Div2,
1322            #[cfg(feature = "h7")]
1323            d3_prescaler: ApbPrescaler::Div2,
1324            /// Bypass the HSE output, for use with oscillators that don't need it. Saves power, and
1325            /// frees up the pin for use as GPIO.
1326            hse_bypass: false,
1327            usb_src: UsbSrc::Hsi48,
1328            security_system: false,
1329            /// Enable the HSI48.
1330            hsi48_on: false,
1331            /// Select the input source to use after waking up from `stop` mode. Eg HSI or MSI.
1332            stop_wuck: StopWuck::Hsi,
1333            /// Note that to get full speed, we need to use VOS0. These are configured
1334            /// in the `full_speed` method.
1335            vos_range: VosRange::VOS1,
1336            sai1_src: SaiSrc::Pll1Q,
1337            #[cfg(not(feature = "h735"))]
1338            sai23_src: SaiSrc::Pll1Q,
1339            sai4a_src: SaiSrc::Pll1Q,
1340            sai4b_src: SaiSrc::Pll1Q,
1341            spi123_src: Spi123Src::Pll1Q,
1342            spi45_src: Spi45Src::Apb,
1343            dfsdm1_src: DfsdmSrc::Pclk2,
1344            can_src: CanSrc::Pll1Q,
1345        }
1346    }
1347}
1348
1349#[cfg(not(feature = "h7b3"))] // todo
1350impl Clocks {
1351    /// Full speed of 480Mhz, with VC0 range 0. Correspondingly higher periph clock speeds as well.
1352    /// (520Mhz core speed on H723-35) Note that special consideration needs to be taken
1353    /// when using low power modes (ie anything with wfe or wfi) in this mode; may need to manually
1354    /// disable and re-enable it.
1355    ///
1356    /// Note that this overwrites some fields of the pll1 config.
1357    pub fn full_speed() -> Self {
1358        // todo: 550Mhz on on H723 etc instead of 520Mhz. Need to set CPU_FREQ_BOOST as well for that.
1359        // todo: "The CPU frequency boost can be enabled through the CPUFREQ_BOOST option byte in
1360        // todo FLASH_OPTSR2_PRG register."
1361        // todo: The change is
1362        //
1363        cfg_if! {
1364            if #[cfg(feature = "h735")] {
1365                // let flash_regs = unsafe { &(*pac::FLASH::ptr()) };
1366
1367                // To modify user option bytes, follow the sequence below:
1368                // 1.Unlock FLASH_OPTCR register as described in Section 4.5.1: FLASH configuration
1369                // protection, unless the register is already unlocked.
1370                // 2. Write the desired new option byte values in the corresponding option registers
1371                // (FLASH_XXX_PRG).
1372                // flash_regs.optsr2_prg.modify(|_, w| w.cpufreq_boost().set_bit());
1373                // 3. Set the option byte start change OPTSTART bit to 1 in the FLASH_OPTCR register.
1374                // flash_regs.optcr.modify(|_, w| w.optstart().set_bit());
1375                // 4. Wait until OPT_BUSY bit is cleared.
1376                // while flash_regs.optcr.read().opt_busy().bit_is_set() { }
1377
1378                // let divn 275; // for 550Mhz
1379                let divn = 260;
1380                let divp = 1;
1381            } else {
1382                let divn = 480;
1383                let divp = 2;
1384            }
1385        }
1386        Self {
1387            pll1: PllCfg {
1388                divn,
1389                divp,
1390                ..Default::default()
1391            },
1392            vos_range: VosRange::VOS0,
1393            ..Default::default()
1394        }
1395    }
1396}
1397
1398#[cfg(not(feature = "h5"))] // todo: Come back to
1399// todo
1400/// Enable the Clock Recovery System.
1401/// "The STM32L443xx devices embed a special block which allows automatic trimming of the
1402/// internal 48 MHz oscillator to guarantee its optimal accuracy over the whole device
1403/// operational range. This automatic trimming is based on the external synchronization signal,
1404/// which could be either derived from USB SOF signalization, from LSE oscillator, from an
1405/// external signal on CRS_SYNC pin or generated by user software. For faster lock-in during
1406/// startup it is also possible to combine automatic trimming with manual trimming action."
1407/// Note: This is for HSI48 only. Note that the HSI will turn off after entering Stop or Standby.
1408pub fn enable_crs(sync_src: CrsSyncSrc) {
1409    let crs = unsafe { &(*CRS::ptr()) };
1410    let rcc = unsafe { &(*RCC::ptr()) };
1411
1412    rcc.apb1henr.modify(|_, w| w.crsen().set_bit());
1413
1414    crs.cfgr
1415        .modify(|_, w| unsafe { w.syncsrc().bits(sync_src as u8) });
1416
1417    crs.cr.modify(|_, w| {
1418        // Set autotrim enabled.
1419        w.autotrimen().set_bit();
1420        // Enable CRS
1421        w.cen().set_bit()
1422    });
1423
1424    // "The internal 48 MHz RC oscillator is mainly dedicated to provide a high precision clock to
1425    // the USB peripheral by means of a special Clock Recovery System (CRS) circuitry. The CRS
1426    // can use the USB SOF signal, the LSE or an external signal to automatically and quickly
1427    // adjust the oscillator frequency on-fly. It is disabled as soon as the system enters Stop or
1428    // Standby mode. When the CRS is not used, the HSI48 RC oscillator runs on its default
1429    // frequency which is subject to manufacturing process variations
1430}