stm32l4xx_hal/
rcc.rs

1//! Reset and Clock Control
2
3use crate::stm32::{rcc, RCC};
4use cast::u32;
5
6use crate::flash::ACR;
7use crate::pwr::Pwr;
8use crate::time::Hertz;
9use fugit::RateExtU32;
10
11mod enable;
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14pub enum MsiFreq {
15    #[doc = "range 0 around 100 kHz"]
16    RANGE100K = 0,
17    #[doc = "range 1 around 200 kHz"]
18    RANGE200K = 1,
19    #[doc = "range 2 around 400 kHz"]
20    RANGE400K = 2,
21    #[doc = "range 3 around 800 kHz"]
22    RANGE800K = 3,
23    #[doc = "range 4 around 1 MHz"]
24    RANGE1M = 4,
25    #[doc = "range 5 around 2 MHz"]
26    RANGE2M = 5,
27    #[doc = "range 6 around 4 MHz"]
28    RANGE4M = 6,
29    #[doc = "range 7 around 8 MHz"]
30    RANGE8M = 7,
31    #[doc = "range 8 around 16 MHz"]
32    RANGE16M = 8,
33    #[doc = "range 9 around 24 MHz"]
34    RANGE24M = 9,
35    #[doc = "range 10 around 32 MHz"]
36    RANGE32M = 10,
37    #[doc = "range 11 around 48 MHz"]
38    RANGE48M = 11,
39}
40
41impl MsiFreq {
42    fn to_hertz(self) -> Hertz {
43        (match self {
44            Self::RANGE100K => 100_000,
45            Self::RANGE200K => 200_000,
46            Self::RANGE400K => 400_000,
47            Self::RANGE800K => 800_000,
48            Self::RANGE1M => 1_000_000,
49            Self::RANGE2M => 2_000_000,
50            Self::RANGE4M => 4_000_000,
51            Self::RANGE8M => 8_000_000,
52            Self::RANGE16M => 16_000_000,
53            Self::RANGE24M => 24_000_000,
54            Self::RANGE32M => 32_000_000,
55            Self::RANGE48M => 48_000_000,
56        })
57        .Hz()
58    }
59}
60
61/// Extension trait that constrains the `RCC` peripheral
62pub trait RccExt {
63    /// Constrains the `RCC` peripheral so it plays nicely with the other abstractions
64    fn constrain(self) -> Rcc;
65}
66
67impl RccExt for RCC {
68    fn constrain(self) -> Rcc {
69        Rcc {
70            ahb1: AHB1::new(),
71            ahb2: AHB2::new(),
72            ahb3: AHB3::new(),
73            apb1r1: APB1R1::new(),
74            apb1r2: APB1R2::new(),
75            apb2: APB2::new(),
76            bdcr: BDCR { _0: () },
77            csr: CSR { _0: () },
78            crrcr: CRRCR { _0: () },
79            ccipr: CCIPR { _0: () },
80            cfgr: CFGR {
81                hse: None,
82                lse: None,
83                msi: None,
84                hsi48: false,
85                lsi: false,
86                hclk: None,
87                pclk1: None,
88                pclk2: None,
89                sysclk: None,
90                pll_source: None,
91                pll_config: None,
92            },
93        }
94    }
95}
96
97/// Constrained RCC peripheral
98pub struct Rcc {
99    /// AMBA High-performance Bus (AHB1) registers
100    pub ahb1: AHB1,
101    /// AMBA High-performance Bus (AHB2) registers
102    pub ahb2: AHB2,
103    /// AMBA High-performance Bus (AHB3) registers
104    pub ahb3: AHB3,
105    /// Advanced Peripheral Bus 1 (APB1) registers
106    pub apb1r1: APB1R1,
107    /// Advanced Peripheral Bus 1 (APB2) registers
108    pub apb1r2: APB1R2,
109    /// Advanced Peripheral Bus 2 (APB2) registers
110    pub apb2: APB2,
111    /// Clock configuration register
112    pub cfgr: CFGR,
113    /// Backup domain control register
114    pub bdcr: BDCR,
115    /// Control/Status Register
116    pub csr: CSR,
117    /// Clock recovery RC register
118    pub crrcr: CRRCR,
119    /// Peripherals independent clock configuration register
120    pub ccipr: CCIPR,
121}
122
123/// CSR Control/Status Register
124pub struct CSR {
125    _0: (),
126}
127
128impl CSR {
129    // TODO remove `allow`
130    #[allow(dead_code)]
131    pub(crate) fn csr(&mut self) -> &rcc::CSR {
132        // NOTE(unsafe) this proxy grants exclusive access to this register
133        unsafe { &(*RCC::ptr()).csr }
134    }
135}
136
137/// Clock recovery RC register
138pub struct CRRCR {
139    _0: (),
140}
141
142impl CRRCR {
143    // TODO remove `allow`
144    #[allow(dead_code)]
145    pub(crate) fn crrcr(&mut self) -> &rcc::CRRCR {
146        // NOTE(unsafe) this proxy grants exclusive access to this register
147        unsafe { &(*RCC::ptr()).crrcr }
148    }
149
150    /// Checks if the 48 MHz HSI is enabled
151    pub fn is_hsi48_on(&mut self) -> bool {
152        self.crrcr().read().hsi48on().bit()
153    }
154
155    /// Checks if the 48 MHz HSI is ready
156    pub fn is_hsi48_ready(&mut self) -> bool {
157        self.crrcr().read().hsi48rdy().bit()
158    }
159}
160
161/// Peripherals independent clock configuration register
162pub struct CCIPR {
163    _0: (),
164}
165
166impl CCIPR {
167    #[allow(dead_code)]
168    pub(crate) fn ccipr(&mut self) -> &rcc::CCIPR {
169        // NOTE(unsafe) this proxy grants exclusive access to this register
170        unsafe { &(*RCC::ptr()).ccipr }
171    }
172}
173
174/// BDCR Backup domain control register registers
175pub struct BDCR {
176    _0: (),
177}
178
179impl BDCR {
180    // TODO remove `allow`
181    #[allow(dead_code)]
182    pub(crate) fn enr(&mut self) -> &rcc::BDCR {
183        // NOTE(unsafe) this proxy grants exclusive access to this register
184        unsafe { &(*RCC::ptr()).bdcr }
185    }
186}
187
188macro_rules! bus_struct {
189    ($($busX:ident => ($EN:ident, $en:ident, $SMEN:ident, $smen:ident, $RST:ident, $rst:ident, $doc:literal),)+) => {
190        $(
191            #[doc = $doc]
192            pub struct $busX {
193                _0: (),
194            }
195
196            impl $busX {
197                pub(crate) fn new() -> Self {
198                    Self { _0: () }
199                }
200
201                #[allow(unused)]
202                pub(crate) fn enr(&self) -> &rcc::$EN {
203                    // NOTE(unsafe) this proxy grants exclusive access to this register
204                    unsafe { &(*RCC::ptr()).$en }
205                }
206
207                #[allow(unused)]
208                pub(crate) fn smenr(&self) -> &rcc::$SMEN {
209                    // NOTE(unsafe) this proxy grants exclusive access to this register
210                    unsafe { &(*RCC::ptr()).$smen }
211                }
212
213                #[allow(unused)]
214                pub(crate) fn rstr(&self) -> &rcc::$RST {
215                    // NOTE(unsafe) this proxy grants exclusive access to this register
216                    unsafe { &(*RCC::ptr()).$rst }
217                }
218            }
219        )+
220    };
221}
222
223bus_struct! {
224    AHB1 => (AHB1ENR, ahb1enr, AHB1SMENR, ahb1smenr, AHB1RSTR, ahb1rstr, "Advanced High-performance Bus 1 (AHB1) registers"),
225    AHB2 => (AHB2ENR, ahb2enr, AHB2SMENR, ahb2smenr, AHB2RSTR, ahb2rstr, "Advanced High-performance Bus 2 (AHB2) registers"),
226    AHB3 => (AHB3ENR, ahb3enr, AHB3SMENR, ahb3smenr, AHB3RSTR, ahb3rstr, "Advanced High-performance Bus 3 (AHB3) registers"),
227    APB1R1 => (APB1ENR1, apb1enr1, APB1SMENR1, apb1smenr1, APB1RSTR1, apb1rstr1, "Advanced Peripheral Bus 1 (APB1) registers"),
228    APB1R2 => (APB1ENR2, apb1enr2, APB1SMENR2, apb1smenr2, APB1RSTR2, apb1rstr2, "Advanced Peripheral Bus 1 (APB1) registers"),
229    APB2 => (APB2ENR, apb2enr, APB2SMENR, apb2smenr, APB2RSTR, apb2rstr, "Advanced Peripheral Bus 2 (APB2) registers"),
230}
231
232/// Bus associated to peripheral
233pub trait RccBus: crate::Sealed {
234    /// Bus type;
235    type Bus;
236}
237
238/// Enable/disable peripheral
239pub trait Enable: RccBus {
240    /// Enables peripheral
241    fn enable(bus: &mut Self::Bus);
242
243    /// Disables peripheral
244    fn disable(bus: &mut Self::Bus);
245
246    /// Check if peripheral enabled
247    fn is_enabled() -> bool;
248
249    /// Check if peripheral disabled
250    fn is_disabled() -> bool;
251
252    /// # Safety
253    ///
254    /// Enables peripheral. Takes access to RCC internally
255    unsafe fn enable_unchecked();
256
257    /// # Safety
258    ///
259    /// Disables peripheral. Takes access to RCC internally
260    unsafe fn disable_unchecked();
261}
262
263/// Enable/disable peripheral in sleep mode
264pub trait SMEnable: RccBus {
265    /// Enables peripheral
266    fn enable_in_sleep_mode(bus: &mut Self::Bus);
267
268    /// Disables peripheral
269    fn disable_in_sleep_mode(bus: &mut Self::Bus);
270
271    /// Check if peripheral enabled
272    fn is_enabled_in_sleep_mode() -> bool;
273
274    /// Check if peripheral disabled
275    fn is_disabled_in_sleep_mode() -> bool;
276
277    /// # Safety
278    ///
279    /// Enables peripheral. Takes access to RCC internally
280    unsafe fn enable_in_sleep_mode_unchecked();
281
282    /// # Safety
283    ///
284    /// Disables peripheral. Takes access to RCC internally
285    unsafe fn disable_in_sleep_mode_unchecked();
286}
287
288/// Reset peripheral
289pub trait Reset: RccBus {
290    /// Resets peripheral
291    fn reset(bus: &mut Self::Bus);
292
293    /// # Safety
294    ///
295    /// Resets peripheral. Takes access to RCC internally
296    unsafe fn reset_unchecked();
297}
298
299#[derive(Debug, PartialEq)]
300/// HSE Configuration
301struct HseConfig {
302    /// Clock speed of HSE
303    speed: u32,
304    /// If the clock driving circuitry is bypassed i.e. using an oscillator, not a crystal or
305    /// resonator
306    bypass: CrystalBypass,
307    /// Clock Security System enable/disable
308    css: ClockSecuritySystem,
309}
310
311#[derive(Debug, PartialEq)]
312/// LSE Configuration
313struct LseConfig {
314    /// If the clock driving circuitry is bypassed i.e. using an oscillator, not a crystal or
315    /// resonator
316    bypass: CrystalBypass,
317    /// Clock Security System enable/disable
318    css: ClockSecuritySystem,
319}
320
321/// Crystal bypass selector
322#[derive(Clone, Copy, Debug, PartialEq)]
323pub enum CrystalBypass {
324    /// If the clock driving circuitry is bypassed i.e. using an oscillator
325    Enable,
326    /// If the clock driving circuitry is not bypassed i.e. using a crystal or resonator
327    Disable,
328}
329
330/// Clock Security System (CSS) selector
331///
332/// When this is enabled on HSE it will fire of the NMI interrupt on failure and for the LSE the
333/// MCU will be woken if in Standby and then the LSECSS interrupt will fire. See datasheet on how
334/// to recover for CSS failures.
335#[derive(Clone, Copy, Debug, PartialEq)]
336pub enum ClockSecuritySystem {
337    /// Enable the clock security system to detect clock failures
338    Enable,
339    /// Leave the clock security system disabled
340    Disable,
341}
342
343const HSI: u32 = 16_000_000; // Hz
344
345/// Clock configuration
346pub struct CFGR {
347    hse: Option<HseConfig>,
348    lse: Option<LseConfig>,
349    msi: Option<MsiFreq>,
350    hsi48: bool,
351    lsi: bool,
352    hclk: Option<u32>,
353    pclk1: Option<u32>,
354    pclk2: Option<u32>,
355    sysclk: Option<u32>,
356    pll_source: Option<PllSource>,
357    pll_config: Option<PllConfig>,
358}
359
360impl CFGR {
361    /// Add an HSE to the system
362    pub fn hse(mut self, freq: Hertz, bypass: CrystalBypass, css: ClockSecuritySystem) -> Self {
363        self.hse = Some(HseConfig {
364            speed: freq.raw(),
365            bypass,
366            css,
367        });
368
369        self
370    }
371
372    /// Add an 32.768 kHz LSE to the system
373    pub fn lse(mut self, bypass: CrystalBypass, css: ClockSecuritySystem) -> Self {
374        self.lse = Some(LseConfig { bypass, css });
375
376        self
377    }
378
379    /// Sets a frequency for the AHB bus
380    pub fn hclk(mut self, freq: Hertz) -> Self {
381        self.hclk = Some(freq.raw());
382        self
383    }
384
385    /// Enable the 48 MHz USB, RNG, SDMMC HSI clock source. Not available on all stm32l4x6 series
386    pub fn hsi48(mut self, on: bool) -> Self {
387        self.hsi48 = on;
388        self
389    }
390
391    /// Enables the MSI with the specified speed
392    pub fn msi(mut self, range: MsiFreq) -> Self {
393        self.msi = Some(range);
394        self
395    }
396
397    /// Sets LSI clock on (the default) or off
398    pub fn lsi(mut self, on: bool) -> Self {
399        self.lsi = on;
400        self
401    }
402
403    /// Sets a frequency for the APB1 bus
404    pub fn pclk1(mut self, freq: Hertz) -> Self {
405        self.pclk1 = Some(freq.raw());
406        self
407    }
408
409    /// Sets a frequency for the APB2 bus
410    pub fn pclk2(mut self, freq: Hertz) -> Self {
411        self.pclk2 = Some(freq.raw());
412        self
413    }
414
415    /// Sets the system (core) frequency
416    pub fn sysclk(mut self, freq: Hertz) -> Self {
417        self.sysclk = Some(freq.raw());
418        self
419    }
420
421    /// Sets the system (core) frequency with some pll configuration
422    pub fn sysclk_with_pll(mut self, freq: Hertz, cfg: PllConfig) -> Self {
423        self.pll_config = Some(cfg);
424        self.sysclk = Some(freq.raw());
425        self
426    }
427
428    /// Sets the PLL source
429    pub fn pll_source(mut self, source: PllSource) -> Self {
430        self.pll_source = Some(source);
431        self
432    }
433
434    /// Freezes the clock configuration, making it effective
435    pub fn freeze(&self, acr: &mut ACR, pwr: &mut Pwr) -> Clocks {
436        let rcc = unsafe { &*RCC::ptr() };
437
438        // Switch to MSI to prevent problems with PLL configuration.
439        if rcc.cr.read().msion().bit_is_clear() {
440            // Turn on MSI and configure it to 4MHz.
441            rcc.cr.modify(|_, w| {
442                w.msirgsel().set_bit(); // MSI Range is provided by MSIRANGE[3:0].
443                w.msirange().range4m();
444                w.msipllen().clear_bit();
445                w.msion().set_bit()
446            });
447
448            // Wait until MSI is running
449            while rcc.cr.read().msirdy().bit_is_clear() {}
450        }
451        if rcc.cfgr.read().sws().bits() != 0 {
452            // Set MSI as a clock source, reset prescalers.
453            rcc.cfgr.reset();
454            // Wait for clock switch status bits to change.
455            while rcc.cfgr.read().sws().bits() != 0 {}
456        }
457
458        //
459        // 1. Setup clocks
460        //
461
462        // Turn on the internal 32 kHz LSI oscillator
463        let lsi_used = match (self.lsi, &self.lse) {
464            (true, _)
465            | (
466                _,
467                &Some(LseConfig {
468                    bypass: _,
469                    css: ClockSecuritySystem::Enable,
470                }),
471            ) => {
472                rcc.csr.modify(|_, w| w.lsion().set_bit());
473
474                // Wait until LSI is running
475                while rcc.csr.read().lsirdy().bit_is_clear() {}
476
477                true
478            }
479            _ => false,
480        };
481
482        if let Some(lse_cfg) = &self.lse {
483            // 1. Unlock the backup domain
484            pwr.cr1.reg().modify(|_, w| w.dbp().set_bit());
485
486            // 2. Setup the LSE
487            rcc.bdcr.modify(|_, w| {
488                w.lseon().set_bit(); // Enable LSE
489
490                if lse_cfg.bypass == CrystalBypass::Enable {
491                    w.lsebyp().set_bit();
492                } else {
493                    unsafe {
494                        w.lsedrv().bits(0b11);
495                    } // Max drive strength, TODO: should probably be settable
496                }
497
498                w
499            });
500
501            // Wait until LSE is running
502            while rcc.bdcr.read().lserdy().bit_is_clear() {}
503
504            // Setup CSS
505            if lse_cfg.css == ClockSecuritySystem::Enable {
506                // Enable CSS and interrupt
507                rcc.bdcr.modify(|_, w| w.lsecsson().set_bit());
508                rcc.cier.modify(|_, w| w.lsecssie().set_bit());
509            }
510        }
511
512        // If HSE is available, set it up
513        if let Some(hse_cfg) = &self.hse {
514            rcc.cr.write(|w| {
515                w.hseon().set_bit();
516
517                if hse_cfg.bypass == CrystalBypass::Enable {
518                    w.hsebyp().set_bit();
519                }
520
521                w
522            });
523
524            while rcc.cr.read().hserdy().bit_is_clear() {}
525
526            // Setup CSS
527            if hse_cfg.css == ClockSecuritySystem::Enable {
528                // Enable CSS
529                rcc.cr.modify(|_, w| w.csson().set_bit());
530            }
531        }
532
533        if let Some(msi) = self.msi {
534            unsafe {
535                rcc.cr.modify(|_, w| {
536                    w.msirange()
537                        .bits(msi as u8)
538                        .msirgsel()
539                        .set_bit()
540                        .msion()
541                        .set_bit();
542
543                    // If LSE is enabled, enable calibration of MSI
544                    if self.lse.is_some() {
545                        w.msipllen().set_bit();
546                    }
547
548                    w
549                })
550            };
551
552            // Wait until MSI is running
553            while rcc.cr.read().msirdy().bit_is_clear() {}
554        }
555
556        // Turn on USB, RNG Clock using the HSI48 CLK source
557        if self.hsi48 {
558            // p. 180 in ref-manual
559            rcc.crrcr.modify(|_, w| w.hsi48on().set_bit());
560
561            // Wait until HSI48 is running
562            while rcc.crrcr.read().hsi48rdy().bit_is_clear() {}
563        }
564
565        // Select MSI as clock source for usb48, rng ...
566        if let Some(MsiFreq::RANGE48M) = self.msi {
567            unsafe { rcc.ccipr.modify(|_, w| w.clk48sel().bits(0b11)) };
568        }
569
570        //
571        // 2. Setup PLL
572        //
573
574        // Select PLL source
575        let (clock_speed, pll_source) = if let Some(source) = self.pll_source {
576            match source {
577                PllSource::HSE => {
578                    if let Some(hse) = &self.hse {
579                        (hse.speed, source)
580                    } else {
581                        panic!("HSE selected as PLL source, but not enabled");
582                    }
583                }
584                PllSource::HSI16 => (HSI, source),
585                PllSource::MSI => {
586                    if let Some(msi) = self.msi {
587                        (msi.to_hertz().raw(), source)
588                    } else {
589                        panic!("MSI selected as PLL source, but not enabled");
590                    }
591                }
592            }
593        } else {
594            // No specific PLL source selected, do educated guess
595
596            // 1. HSE
597            if let Some(hse) = &self.hse {
598                (hse.speed, PllSource::HSE)
599            }
600            // 2. MSI
601            else if let Some(msi) = self.msi {
602                (msi.to_hertz().raw(), PllSource::MSI)
603            }
604            // 3. HSI as fallback
605            else {
606                (HSI, PllSource::HSI16)
607            }
608        };
609
610        // Check if HSI should be started
611        if pll_source == PllSource::HSI16 || (self.msi.is_none() && self.hse.is_none()) {
612            rcc.cr.write(|w| w.hsion().set_bit());
613            while rcc.cr.read().hsirdy().bit_is_clear() {}
614        }
615
616        let pllconf = if self.pll_config.is_none() {
617            if let Some(sysclk) = self.sysclk {
618                // Calculate PLL multiplier and create a best effort pll config, just multiply n
619                let plln = (2 * sysclk) / clock_speed;
620
621                Some(PllConfig::new(1, plln as u8, PllDivider::Div2))
622            } else {
623                None
624            }
625        } else {
626            self.pll_config
627        };
628
629        let sysclk = match (self.sysclk, self.msi) {
630            (Some(sysclk), _) => sysclk,
631            (None, Some(msi)) => msi.to_hertz().raw(),
632            (None, None) => MsiFreq::RANGE4M.to_hertz().raw(),
633        };
634
635        assert!(sysclk <= 80_000_000);
636
637        let (hpre_bits, hpre_div) = self
638            .hclk
639            .map(|hclk| match sysclk / hclk {
640                // From p 194 in RM0394
641                0 => unreachable!(),
642                1 => (0b0000, 1),
643                2 => (0b1000, 2),
644                3..=5 => (0b1001, 4),
645                6..=11 => (0b1010, 8),
646                12..=39 => (0b1011, 16),
647                40..=95 => (0b1100, 64),
648                96..=191 => (0b1101, 128),
649                192..=383 => (0b1110, 256),
650                _ => (0b1111, 512),
651            })
652            .unwrap_or((0b0000, 1));
653
654        let hclk = sysclk / hpre_div;
655
656        assert!(hclk <= sysclk);
657
658        let (ppre1_bits, ppre1) = self
659            .pclk1
660            .map(|pclk1| match hclk / pclk1 {
661                // From p 194 in RM0394
662                0 => unreachable!(),
663                1 => (0b000, 1),
664                2 => (0b100, 2),
665                3..=5 => (0b101, 4),
666                6..=11 => (0b110, 8),
667                _ => (0b111, 16),
668            })
669            .unwrap_or((0b000, 1));
670
671        let pclk1: u32 = hclk / u32(ppre1);
672
673        assert!(pclk1 <= sysclk);
674
675        let (ppre2_bits, ppre2) = self
676            .pclk2
677            .map(|pclk2| match hclk / pclk2 {
678                // From p 194 in RM0394
679                0 => unreachable!(),
680                1 => (0b000, 1),
681                2 => (0b100, 2),
682                3..=5 => (0b101, 4),
683                6..=11 => (0b110, 8),
684                _ => (0b111, 16),
685            })
686            .unwrap_or((0b000, 1));
687
688        let pclk2: u32 = hclk / u32(ppre2);
689
690        assert!(pclk2 <= sysclk);
691
692        // adjust flash wait states
693        unsafe {
694            acr.acr().write(|w| {
695                w.latency().bits(if hclk <= 16_000_000 {
696                    0b000
697                } else if hclk <= 32_000_000 {
698                    0b001
699                } else if hclk <= 48_000_000 {
700                    0b010
701                } else if hclk <= 64_000_000 {
702                    0b011
703                } else {
704                    0b100
705                })
706            })
707        }
708
709        let sysclk_src_bits;
710        let mut msi = self.msi;
711        if let Some(pllconf) = pllconf {
712            // Sanity-checks per RM0394, 6.4.4 PLL configuration register (RCC_PLLCFGR)
713            let r = pllconf.r.to_division_factor();
714            let clock_speed = clock_speed / (pllconf.m as u32 + 1);
715            let vco = clock_speed * pllconf.n as u32;
716            let output_clock = vco / r;
717
718            assert!(r <= 8); // Allowed max output divider
719            assert!(pllconf.n >= 8); // Allowed min multiplier
720            assert!(pllconf.n <= 86); // Allowed max multiplier
721            assert!(clock_speed >= 4_000_000); // VCO input clock min
722            assert!(clock_speed <= 16_000_000); // VCO input clock max
723            assert!(vco >= 64_000_000); // VCO output min
724            assert!(vco <= 334_000_000); // VCO output max
725            assert!(output_clock <= 80_000_000); // Max output clock
726
727            // use PLL as source
728            sysclk_src_bits = 0b11;
729            rcc.cr.modify(|_, w| w.pllon().clear_bit());
730            while rcc.cr.read().pllrdy().bit_is_set() {}
731
732            let pllsrc_bits = pll_source.to_pllsrc();
733
734            rcc.pllcfgr.modify(|_, w| unsafe {
735                w.pllsrc()
736                    .bits(pllsrc_bits)
737                    .pllm()
738                    .bits(pllconf.m)
739                    .pllr()
740                    .bits(pllconf.r.to_bits())
741                    .plln()
742                    .bits(pllconf.n)
743            });
744
745            rcc.cr.modify(|_, w| w.pllon().set_bit());
746
747            while rcc.cr.read().pllrdy().bit_is_clear() {}
748
749            rcc.pllcfgr.modify(|_, w| w.pllren().set_bit());
750
751            // SW: PLL selected as system clock
752            rcc.cfgr.modify(|_, w| unsafe {
753                w.ppre2()
754                    .bits(ppre2_bits)
755                    .ppre1()
756                    .bits(ppre1_bits)
757                    .hpre()
758                    .bits(hpre_bits)
759                    .sw()
760                    .bits(sysclk_src_bits)
761            });
762        } else {
763            // use MSI as fallback source for sysclk
764            sysclk_src_bits = 0b00;
765            if msi.is_none() {
766                msi = Some(MsiFreq::RANGE4M);
767            }
768
769            // SW: MSI selected as system clock
770            rcc.cfgr.write(|w| unsafe {
771                w.ppre2()
772                    .bits(ppre2_bits)
773                    .ppre1()
774                    .bits(ppre1_bits)
775                    .hpre()
776                    .bits(hpre_bits)
777                    .sw()
778                    .bits(sysclk_src_bits)
779            });
780        }
781
782        while rcc.cfgr.read().sws().bits() != sysclk_src_bits {}
783
784        //
785        // 3. Shutdown unused clocks that have auto-started
786        //
787
788        // MSI always starts on reset
789        if msi.is_none() {
790            rcc.cr
791                .modify(|_, w| w.msion().clear_bit().msipllen().clear_bit())
792        }
793
794        //
795        // 4. Clock setup done!
796        //
797
798        Clocks {
799            hclk: hclk.Hz(),
800            lsi: lsi_used,
801            lse: self.lse.is_some(),
802            msi,
803            hsi48: self.hsi48,
804            pclk1: pclk1.Hz(),
805            pclk2: pclk2.Hz(),
806            ppre1,
807            ppre2,
808            sysclk: sysclk.Hz(),
809            pll_source: pllconf.map(|_| pll_source),
810        }
811    }
812}
813
814#[derive(Clone, Copy, Debug)]
815/// PLL output divider options
816pub enum PllDivider {
817    /// Divider PLL output by 2
818    Div2 = 0b00,
819    /// Divider PLL output by 4
820    Div4 = 0b01,
821    /// Divider PLL output by 6
822    Div6 = 0b10,
823    /// Divider PLL output by 8
824    Div8 = 0b11,
825}
826
827impl PllDivider {
828    #[inline(always)]
829    fn to_bits(self) -> u8 {
830        self as u8
831    }
832
833    #[inline(always)]
834    fn to_division_factor(self) -> u32 {
835        match self {
836            Self::Div2 => 2,
837            Self::Div4 => 4,
838            Self::Div6 => 6,
839            Self::Div8 => 8,
840        }
841    }
842}
843
844#[derive(Clone, Copy, Debug)]
845/// PLL Configuration
846pub struct PllConfig {
847    // Main PLL division factor
848    m: u8,
849    // Main PLL multiplication factor
850    n: u8,
851    // Main PLL division factor for PLLCLK (system clock)
852    r: PllDivider,
853}
854
855impl PllConfig {
856    /// Create a new PLL config from manual settings
857    ///
858    /// PLL output = ((SourceClk / input_divider) * multiplier) / output_divider
859    pub fn new(input_divider: u8, multiplier: u8, output_divider: PllDivider) -> Self {
860        assert!(input_divider > 0);
861
862        PllConfig {
863            m: input_divider - 1,
864            n: multiplier,
865            r: output_divider,
866        }
867    }
868}
869
870#[derive(Clone, Copy, Debug, PartialEq)]
871/// PLL Source
872pub enum PllSource {
873    /// Multi-speed internal clock
874    MSI,
875    /// High-speed internal clock
876    HSI16,
877    /// High-speed external clock
878    HSE,
879}
880
881impl PllSource {
882    fn to_pllsrc(self) -> u8 {
883        match self {
884            Self::MSI => 0b01,
885            Self::HSI16 => 0b10,
886            Self::HSE => 0b11,
887        }
888    }
889}
890
891/// Frozen clock frequencies
892///
893/// The existence of this value indicates that the clock configuration can no longer be changed
894#[derive(Clone, Copy, Debug)]
895pub struct Clocks {
896    hclk: Hertz,
897    hsi48: bool,
898    msi: Option<MsiFreq>,
899    lsi: bool,
900    lse: bool,
901    pclk1: Hertz,
902    pclk2: Hertz,
903    ppre1: u8,
904    ppre2: u8,
905    sysclk: Hertz,
906    pll_source: Option<PllSource>,
907}
908
909impl Clocks {
910    /// Returns the frequency of the AHB
911    pub fn hclk(&self) -> Hertz {
912        self.hclk
913    }
914
915    /// Returns status of HSI48
916    pub fn hsi48(&self) -> bool {
917        self.hsi48
918    }
919
920    // Returns the status of the MSI
921    pub fn msi(&self) -> Option<MsiFreq> {
922        self.msi
923    }
924
925    /// Returns status of the LSI
926    pub fn lsi(&self) -> bool {
927        self.lsi
928    }
929
930    // Return the status of the LSE
931    pub fn lse(&self) -> bool {
932        self.lse
933    }
934
935    /// Returns the frequency of the APB1
936    pub fn pclk1(&self) -> Hertz {
937        self.pclk1
938    }
939
940    /// Returns the frequency of the APB2
941    pub fn pclk2(&self) -> Hertz {
942        self.pclk2
943    }
944
945    /// Get which source is being used for PLL
946    pub fn pll_source(&self) -> Option<PllSource> {
947        self.pll_source
948    }
949
950    // TODO remove `allow`
951    #[allow(dead_code)]
952    pub(crate) fn ppre1(&self) -> u8 {
953        self.ppre1
954    }
955    // TODO remove `allow`
956    #[allow(dead_code)]
957    pub(crate) fn ppre2(&self) -> u8 {
958        self.ppre2
959    }
960
961    /// Returns the system (core) frequency
962    pub fn sysclk(&self) -> Hertz {
963        self.sysclk
964    }
965}