stm32f1xx_hal/
rcc.rs

1//! # Reset & Control Clock
2
3use core::ops::{Deref, DerefMut};
4
5use crate::pac::{
6    rcc::{self, RegisterBlock as RccRB},
7    BKP, PWR, RCC,
8};
9
10use crate::flash::ACR;
11#[cfg(any(feature = "stm32f103", feature = "connectivity"))]
12use crate::time::MHz;
13use fugit::{HertzU32 as Hertz, RateExtU32};
14
15use crate::backup_domain::BackupDomain;
16
17mod enable;
18
19/// Extension trait that constrains the `RCC` peripheral
20pub trait RccExt {
21    /// Constrains the `RCC` peripheral so it plays nicely with the other abstractions
22    fn constrain(self) -> Rcc;
23
24    /// Constrains the `RCC` peripheral and apply clock configuration
25    fn freeze(self, rcc_cfg: impl Into<RawConfig>, acr: &mut ACR) -> Rcc;
26}
27
28impl RccExt for RCC {
29    fn constrain(self) -> Rcc {
30        Rcc {
31            rb: self,
32            clocks: Clocks::default(),
33        }
34    }
35
36    fn freeze(self, rcc_cfg: impl Into<RawConfig>, acr: &mut ACR) -> Rcc {
37        self.constrain().freeze(rcc_cfg, acr)
38    }
39}
40
41/// Constrained RCC peripheral
42///
43/// Aquired by calling the [constrain](../trait.RccExt.html#tymethod.constrain) method
44/// on the Rcc struct from the `PAC`
45///
46/// ```rust
47/// let dp = pac::Peripherals::take().unwrap();
48/// let mut rcc = dp.RCC.constrain();
49/// ```
50pub struct Rcc {
51    pub clocks: Clocks,
52    pub(crate) rb: RCC,
53}
54
55impl Deref for Rcc {
56    type Target = RCC;
57    fn deref(&self) -> &Self::Target {
58        &self.rb
59    }
60}
61
62impl DerefMut for Rcc {
63    fn deref_mut(&mut self) -> &mut Self::Target {
64        &mut self.rb
65    }
66}
67
68macro_rules! bus_struct {
69    ($($busX:ident => ($EN:ident, $en:ident, $($RST:ident, $rst:ident,)? $doc:literal),)+) => {
70        $(
71            #[doc = $doc]
72            #[non_exhaustive]
73            pub struct $busX;
74
75            impl $busX {
76                pub(crate) fn enr(rcc: &RccRB) -> &rcc::$EN {
77                    rcc.$en()
78                }
79                $(
80                    pub(crate) fn rstr(rcc: &RccRB) -> &rcc::$RST {
81                        rcc.$rst()
82                    }
83                )?
84            }
85        )+
86    };
87}
88use bus_struct;
89
90bus_struct! {
91    APB1 => (APB1ENR, apb1enr, APB1RSTR, apb1rstr, "Advanced Peripheral Bus 1 (APB1) registers"),
92    APB2 => (APB2ENR, apb2enr, APB2RSTR, apb2rstr, "Advanced Peripheral Bus 2 (APB2) registers"),
93    AHB => (AHBENR, ahbenr, "Advanced High-performance Bus (AHB) registers"),
94}
95
96const HSI: u32 = 8_000_000; // Hz
97
98/// Clock configuration
99///
100/// Used to configure the frequencies of the clocks present in the processor.
101///
102/// After setting all frequencies, call the [freeze](#method.freeze) function to
103/// apply the configuration.
104///
105/// **NOTE**: Currently, it is not guaranteed that the exact frequencies selected will be
106/// used, only frequencies close to it.
107#[derive(Debug, Default, PartialEq, Eq)]
108pub struct Config {
109    hse: Option<u32>,
110    hse_bypass: bool,
111    hclk: Option<u32>,
112    pclk1: Option<u32>,
113    pclk2: Option<u32>,
114    sysclk: Option<u32>,
115    adcclk: Option<u32>,
116}
117
118impl Config {
119    pub const DEFAULT: Self = Self {
120        hse: None,
121        hse_bypass: false,
122        hclk: None,
123        pclk1: None,
124        pclk2: None,
125        sysclk: None,
126        adcclk: None,
127    };
128
129    pub fn hsi() -> Self {
130        Self::DEFAULT
131    }
132
133    pub fn hse(freq: Hertz) -> Self {
134        Self::DEFAULT.use_hse(freq)
135    }
136
137    /// Uses HSE (external oscillator) instead of HSI (internal RC oscillator) as the clock source.
138    /// Will result in a hang if an external oscillator is not connected or it fails to start.
139    /// The frequency specified must be the frequency of the external oscillator
140    #[inline(always)]
141    pub fn use_hse(mut self, freq: Hertz) -> Self {
142        self.hse = Some(freq.raw());
143        self
144    }
145
146    /// Bypasses the high-speed external oscillator and uses an external clock input on the OSC_IN
147    /// pin.
148    ///
149    /// For this configuration, the OSC_IN pin should be connected to a clock source with a
150    /// frequency specified in the call to use_hse(), and the OSC_OUT pin should not be connected.
151    ///
152    /// This function has no effect unless use_hse() is also called.
153    pub fn bypass_hse_oscillator(self) -> Self {
154        Self {
155            hse_bypass: true,
156            ..self
157        }
158    }
159
160    /// Sets the desired frequency for the HCLK clock
161    #[inline(always)]
162    pub fn hclk(mut self, freq: Hertz) -> Self {
163        self.hclk = Some(freq.raw());
164        self
165    }
166
167    /// Sets the desired frequency for the PCKL1 clock
168    #[inline(always)]
169    pub fn pclk1(mut self, freq: Hertz) -> Self {
170        self.pclk1 = Some(freq.raw());
171        self
172    }
173
174    /// Sets the desired frequency for the PCLK2 clock
175    #[inline(always)]
176    pub fn pclk2(mut self, freq: Hertz) -> Self {
177        self.pclk2 = Some(freq.raw());
178        self
179    }
180
181    /// Sets the desired frequency for the SYSCLK clock
182    #[inline(always)]
183    pub fn sysclk(mut self, freq: Hertz) -> Self {
184        self.sysclk = Some(freq.raw());
185        self
186    }
187
188    /// Sets the desired frequency for the ADCCLK clock
189    #[inline(always)]
190    pub fn adcclk(mut self, freq: Hertz) -> Self {
191        self.adcclk = Some(freq.raw());
192        self
193    }
194}
195
196impl Rcc {
197    /// Applies the clock configuration and returns a `Clocks` struct that signifies that the
198    /// clocks are frozen, and contains the frequencies used. After this function is called,
199    /// the clocks can not change
200    ///
201    /// Usage:
202    ///
203    /// ```rust
204    /// let dp = pac::Peripherals::take().unwrap();
205    /// let mut flash = dp.FLASH.constrain();
206    /// let mut rcc = dp.RCC.constrain();
207    /// let clocks = rcc.cfgr.freeze(&mut flash.acr);
208    /// ```
209    #[inline(always)]
210    pub fn freeze(self, cfg: impl Into<RawConfig>, acr: &mut ACR) -> Self {
211        let cfg = cfg.into();
212        let clocks = cfg.get_clocks();
213        // adjust flash wait states
214        #[cfg(any(feature = "stm32f103", feature = "connectivity"))]
215        unsafe {
216            acr.acr().write(|w| {
217                w.latency().bits(if clocks.sysclk <= MHz(24) {
218                    0b000
219                } else if clocks.sysclk <= MHz(48) {
220                    0b001
221                } else {
222                    0b010
223                })
224            });
225        }
226
227        let rcc = unsafe { &*RCC::ptr() };
228
229        if cfg.hse.is_some() {
230            // enable HSE and wait for it to be ready
231
232            rcc.cr().modify(|_, w| {
233                if cfg.hse_bypass {
234                    w.hsebyp().bypassed();
235                }
236                w.hseon().set_bit()
237            });
238
239            while rcc.cr().read().hserdy().bit_is_clear() {}
240        }
241
242        if let Some(pllmul_bits) = cfg.pllmul {
243            // enable PLL and wait for it to be ready
244
245            #[allow(unused_unsafe)]
246            rcc.cfgr().modify(|_, w| unsafe {
247                w.pllmul().bits(pllmul_bits).pllsrc().bit(cfg.hse.is_some())
248            });
249
250            rcc.cr().modify(|_, w| w.pllon().set_bit());
251
252            while rcc.cr().read().pllrdy().bit_is_clear() {}
253        }
254
255        // set prescalers and clock source
256        #[cfg(feature = "connectivity")]
257        rcc.cfgr().modify(|_, w| unsafe {
258            w.adcpre().variant(cfg.adcpre);
259            w.ppre2().bits(cfg.ppre2 as u8);
260            w.ppre1().bits(cfg.ppre1 as u8);
261            w.hpre().bits(cfg.hpre as u8);
262            w.otgfspre().variant(cfg.usbpre);
263            w.sw().bits(if cfg.pllmul.is_some() {
264                // PLL
265                0b10
266            } else if cfg.hse.is_some() {
267                // HSE
268                0b1
269            } else {
270                // HSI
271                0b0
272            })
273        });
274
275        #[cfg(feature = "stm32f103")]
276        rcc.cfgr().modify(|_, w| unsafe {
277            w.adcpre().variant(cfg.adcpre);
278            w.ppre2().bits(cfg.ppre2 as u8);
279            w.ppre1().bits(cfg.ppre1 as u8);
280            w.hpre().bits(cfg.hpre as u8);
281            w.usbpre().variant(cfg.usbpre);
282            w.sw().bits(if cfg.pllmul.is_some() {
283                // PLL
284                0b10
285            } else {
286                // HSE or HSI
287                u8::from(cfg.hse.is_some())
288            })
289        });
290
291        #[cfg(any(feature = "stm32f100", feature = "stm32f101"))]
292        rcc.cfgr().modify(|_, w| unsafe {
293            w.adcpre().variant(cfg.adcpre);
294            w.ppre2().bits(cfg.ppre2 as u8);
295            w.ppre1().bits(cfg.ppre1 as u8);
296            w.hpre().bits(cfg.hpre as u8);
297            w.sw().bits(if cfg.pllmul.is_some() {
298                // PLL
299                0b10
300            } else if cfg.hse.is_some() {
301                // HSE
302                0b1
303            } else {
304                // HSI
305                0b0
306            })
307        });
308
309        Self {
310            rb: self.rb,
311            clocks,
312        }
313    }
314}
315
316pub trait BkpExt {
317    /// Enables write access to the registers in the backup domain
318    fn constrain(self, pwr: &mut PWR, rcc: &mut RCC) -> BackupDomain;
319}
320
321impl BkpExt for BKP {
322    fn constrain(self, pwr: &mut PWR, rcc: &mut RCC) -> BackupDomain {
323        // Enable the backup interface by setting PWREN and BKPEN
324        BKP::enable(rcc);
325        PWR::enable(rcc);
326
327        // Enable access to the backup registers
328        pwr.cr().modify(|_r, w| w.dbp().set_bit());
329
330        BackupDomain { _regs: self }
331    }
332}
333
334/// Frozen clock frequencies
335///
336/// The existence of this value indicates that the clock configuration can no longer be changed
337///
338/// To acquire it, use the freeze function on the `rcc.cfgr` register. If desired, you can adjust
339/// the frequencies using the methods on [cfgr](struct.CFGR.html) before calling freeze.
340///
341/// ```rust
342/// let dp = pac::Peripherals::take().unwrap();
343/// let mut rcc = dp.RCC.constrain();
344/// let mut flash = dp.FLASH.constrain();
345///
346/// let clocks = rcc.cfgr.freeze(&mut flash.acr);
347/// ```
348#[derive(Clone, Copy, Debug, PartialEq, Eq)]
349pub struct Clocks {
350    hclk: Hertz,
351    pclk1: Hertz,
352    pclk2: Hertz,
353    ppre1: u8,
354    ppre2: u8,
355    sysclk: Hertz,
356    adcclk: Hertz,
357    #[cfg(any(feature = "stm32f103", feature = "connectivity"))]
358    usbclk_valid: bool,
359}
360
361impl Default for Clocks {
362    fn default() -> Clocks {
363        let freq = HSI.Hz();
364        Clocks {
365            hclk: freq,
366            pclk1: freq,
367            pclk2: freq,
368            ppre1: 1,
369            ppre2: 1,
370            sysclk: freq,
371            adcclk: freq / 2,
372            #[cfg(any(feature = "stm32f103", feature = "connectivity"))]
373            usbclk_valid: false,
374        }
375    }
376}
377
378impl Clocks {
379    /// Returns the frequency of the AHB
380    pub const fn hclk(&self) -> Hertz {
381        self.hclk
382    }
383
384    /// Returns the frequency of the APB1
385    pub const fn pclk1(&self) -> Hertz {
386        self.pclk1
387    }
388
389    /// Returns the frequency of the APB2
390    pub const fn pclk2(&self) -> Hertz {
391        self.pclk2
392    }
393
394    /// Returns the frequency of the APB1 Timers
395    pub const fn pclk1_tim(&self) -> Hertz {
396        Hertz::from_raw(self.pclk1.raw() * if self.ppre1() == 1 { 1 } else { 2 })
397    }
398
399    /// Returns the frequency of the APB2 Timers
400    pub const fn pclk2_tim(&self) -> Hertz {
401        Hertz::from_raw(self.pclk2.raw() * if self.ppre2() == 1 { 1 } else { 2 })
402    }
403
404    pub(crate) const fn ppre1(&self) -> u8 {
405        self.ppre1
406    }
407
408    // TODO remove `allow`
409    #[allow(dead_code)]
410    pub(crate) const fn ppre2(&self) -> u8 {
411        self.ppre2
412    }
413
414    /// Returns the system (core) frequency
415    pub const fn sysclk(&self) -> Hertz {
416        self.sysclk
417    }
418
419    /// Returns the adc clock frequency
420    pub const fn adcclk(&self) -> Hertz {
421        self.adcclk
422    }
423
424    /// Returns whether the USBCLK clock frequency is valid for the USB peripheral
425    #[cfg(any(feature = "stm32f103", feature = "connectivity"))]
426    pub const fn usbclk_valid(&self) -> bool {
427        self.usbclk_valid
428    }
429}
430
431/// Frequency on bus that peripheral is connected in
432pub trait BusClock {
433    /// Calculates frequency depending on `Clock` state
434    fn clock(clocks: &Clocks) -> Hertz;
435}
436
437/// Frequency on bus that timer is connected in
438pub trait BusTimerClock {
439    /// Calculates base frequency of timer depending on `Clock` state
440    fn timer_clock(clocks: &Clocks) -> Hertz;
441}
442
443impl<T> BusClock for T
444where
445    T: RccBus,
446    T::Bus: BusClock,
447{
448    fn clock(clocks: &Clocks) -> Hertz {
449        T::Bus::clock(clocks)
450    }
451}
452
453impl<T> BusTimerClock for T
454where
455    T: RccBus,
456    T::Bus: BusTimerClock,
457{
458    fn timer_clock(clocks: &Clocks) -> Hertz {
459        T::Bus::timer_clock(clocks)
460    }
461}
462
463impl BusClock for AHB {
464    fn clock(clocks: &Clocks) -> Hertz {
465        clocks.hclk
466    }
467}
468
469impl BusClock for APB1 {
470    fn clock(clocks: &Clocks) -> Hertz {
471        clocks.pclk1
472    }
473}
474
475impl BusClock for APB2 {
476    fn clock(clocks: &Clocks) -> Hertz {
477        clocks.pclk2
478    }
479}
480
481impl BusTimerClock for APB1 {
482    fn timer_clock(clocks: &Clocks) -> Hertz {
483        clocks.pclk1_tim()
484    }
485}
486
487impl BusTimerClock for APB2 {
488    fn timer_clock(clocks: &Clocks) -> Hertz {
489        clocks.pclk2_tim()
490    }
491}
492
493/// Bus associated to peripheral
494pub trait RccBus: crate::Sealed {
495    /// Bus type;
496    type Bus;
497}
498
499/// Enable/disable peripheral
500pub trait Enable: RccBus {
501    /// Enables peripheral
502    fn enable(rcc: &mut RCC);
503
504    /// Disables peripheral
505    fn disable(rcc: &mut RCC);
506
507    /// Check if peripheral enabled
508    fn is_enabled() -> bool;
509
510    /// Check if peripheral disabled
511    #[inline]
512    fn is_disabled() -> bool {
513        !Self::is_enabled()
514    }
515
516    /// # Safety
517    ///
518    /// Enables peripheral. Takes access to RCC internally
519    unsafe fn enable_unchecked() {
520        let mut rcc = RCC::steal();
521        Self::enable(&mut rcc);
522    }
523
524    /// # Safety
525    ///
526    /// Disables peripheral. Takes access to RCC internally
527    unsafe fn disable_unchecked() {
528        let mut rcc = RCC::steal();
529        Self::disable(&mut rcc);
530    }
531}
532
533/// Reset peripheral
534pub trait Reset: RccBus {
535    /// Resets peripheral
536    fn reset(rcc: &mut RCC);
537
538    /// # Safety
539    ///
540    /// Resets peripheral. Takes access to RCC internally
541    unsafe fn reset_unchecked() {
542        let mut rcc = RCC::steal();
543        Self::reset(&mut rcc);
544    }
545}
546
547#[derive(Clone, Copy, Debug, PartialEq)]
548pub struct RawConfig {
549    pub hse: Option<u32>,
550    pub hse_bypass: bool,
551    pub pllmul: Option<u8>,
552    pub hpre: HPre,
553    pub ppre1: PPre,
554    pub ppre2: PPre,
555    #[cfg(any(feature = "stm32f103", feature = "connectivity"))]
556    pub usbpre: UsbPre,
557    pub adcpre: AdcPre,
558    pub allow_overclock: bool,
559}
560
561impl Default for RawConfig {
562    fn default() -> Self {
563        Self {
564            hse: None,
565            hse_bypass: false,
566            pllmul: None,
567            hpre: HPre::Div1,
568            ppre1: PPre::Div1,
569            ppre2: PPre::Div1,
570            #[cfg(any(feature = "stm32f103", feature = "connectivity"))]
571            usbpre: UsbPre::Div1_5,
572            adcpre: AdcPre::Div2,
573            allow_overclock: false,
574        }
575    }
576}
577
578#[repr(u8)]
579#[derive(Clone, Copy, Debug, PartialEq, Eq)]
580pub enum HPre {
581    /// SYSCLK not divided
582    Div1 = 7,
583    /// SYSCLK divided by 2
584    Div2 = 8,
585    /// SYSCLK divided by 4
586    Div4 = 9,
587    /// SYSCLK divided by 8
588    Div8 = 10,
589    /// SYSCLK divided by 16
590    Div16 = 11,
591    /// SYSCLK divided by 64
592    Div64 = 12,
593    /// SYSCLK divided by 128
594    Div128 = 13,
595    /// SYSCLK divided by 256
596    Div256 = 14,
597    /// SYSCLK divided by 512
598    Div512 = 15,
599}
600
601#[derive(Clone, Copy, Debug, PartialEq, Eq)]
602#[repr(u8)]
603pub enum PPre {
604    /// HCLK not divided
605    Div1 = 3,
606    /// HCLK divided by 2
607    Div2 = 4,
608    /// HCLK divided by 4
609    Div4 = 5,
610    /// HCLK divided by 8
611    Div8 = 6,
612    /// HCLK divided by 16
613    Div16 = 7,
614}
615
616#[cfg(feature = "stm32f103")]
617pub type UsbPre = rcc::cfgr::USBPRE;
618#[cfg(feature = "connectivity")]
619pub type UsbPre = rcc::cfgr::OTGFSPRE;
620pub type AdcPre = rcc::cfgr::ADCPRE;
621
622impl From<Config> for RawConfig {
623    #[inline(always)]
624    fn from(cfgr: Config) -> Self {
625        Self::from_cfgr(cfgr)
626    }
627}
628
629impl RawConfig {
630    pub const fn from_cfgr(cfgr: Config) -> Self {
631        let hse = cfgr.hse;
632        let hse_bypass = cfgr.hse_bypass;
633        let pllsrcclk = if let Some(hse) = hse { hse } else { HSI / 2 };
634
635        let pllmul = if let Some(sysclk) = cfgr.sysclk {
636            sysclk / pllsrcclk
637        } else {
638            1
639        };
640
641        let (pllmul_bits, sysclk) = if pllmul == 1 {
642            (None, if let Some(hse) = hse { hse } else { HSI })
643        } else {
644            #[cfg(not(feature = "connectivity"))]
645            let pllmul = match pllmul {
646                1..=16 => pllmul,
647                0 => 1,
648                _ => 16,
649            };
650
651            #[cfg(feature = "connectivity")]
652            let pllmul = match pllmul {
653                4..=9 => pllmul,
654                0..=3 => 4,
655                _ => 9,
656            };
657
658            (Some(pllmul as u8 - 2), pllsrcclk * pllmul)
659        };
660
661        let hpre_bits = if let Some(hclk) = cfgr.hclk {
662            match sysclk / hclk {
663                0..=1 => HPre::Div1,
664                2 => HPre::Div2,
665                3..=5 => HPre::Div4,
666                6..=11 => HPre::Div8,
667                12..=39 => HPre::Div16,
668                40..=95 => HPre::Div64,
669                96..=191 => HPre::Div128,
670                192..=383 => HPre::Div256,
671                _ => HPre::Div512,
672            }
673        } else {
674            HPre::Div1
675        };
676
677        let hclk = if hpre_bits as u8 >= 0b1100 {
678            sysclk / (1 << (hpre_bits as u8 - 0b0110))
679        } else {
680            sysclk / (1 << (hpre_bits as u8 - 0b0111))
681        };
682
683        let pclk1 = if let Some(pclk1) = cfgr.pclk1 {
684            pclk1
685        } else if hclk < 36_000_000 {
686            hclk
687        } else {
688            36_000_000
689        };
690        let ppre1_bits = match (hclk + pclk1 - 1) / pclk1 {
691            0 | 1 => PPre::Div1,
692            2 => PPre::Div2,
693            3..=5 => PPre::Div4,
694            6..=11 => PPre::Div8,
695            _ => PPre::Div16,
696        };
697
698        let ppre2_bits = if let Some(pclk2) = cfgr.pclk2 {
699            match hclk / pclk2 {
700                0..=1 => PPre::Div1,
701                2 => PPre::Div2,
702                3..=5 => PPre::Div4,
703                6..=11 => PPre::Div8,
704                _ => PPre::Div16,
705            }
706        } else {
707            PPre::Div1
708        };
709
710        let ppre2 = 1 << (ppre2_bits as u8 - 0b011);
711        let pclk2 = hclk / (ppre2 as u32);
712
713        // usbpre == false: divide clock by 1.5, otherwise no division
714        #[cfg(any(feature = "stm32f103", feature = "connectivity"))]
715        let usbpre = match (hse, pllmul_bits, sysclk) {
716            (Some(_), Some(_), 72_000_000) => UsbPre::Div1_5,
717            _ => UsbPre::Div1,
718        };
719
720        let apre_bits = if let Some(adcclk) = cfgr.adcclk {
721            match pclk2 / adcclk {
722                0..=2 => AdcPre::Div2,
723                3..=4 => AdcPre::Div4,
724                5..=7 => AdcPre::Div6,
725                _ => AdcPre::Div8,
726            }
727        } else {
728            AdcPre::Div8
729        };
730
731        Self {
732            hse,
733            hse_bypass,
734            pllmul: pllmul_bits,
735            hpre: hpre_bits,
736            ppre1: ppre1_bits,
737            ppre2: ppre2_bits,
738            #[cfg(any(feature = "stm32f103", feature = "connectivity"))]
739            usbpre,
740            adcpre: apre_bits,
741            allow_overclock: false,
742        }
743    }
744
745    // NOTE: to maintain the invariant that the existence of a Clocks
746    // value implies frozen clocks, this function must not be pub.
747    fn get_clocks(&self) -> Clocks {
748        let sysclk = if let Some(pllmul_bits) = self.pllmul {
749            let pllsrcclk = if let Some(hse) = self.hse {
750                hse
751            } else {
752                HSI / 2
753            };
754            pllsrcclk * (pllmul_bits as u32 + 2)
755        } else if let Some(hse) = self.hse {
756            hse
757        } else {
758            HSI
759        };
760
761        let hclk = if self.hpre as u8 >= 0b1100 {
762            sysclk / (1 << (self.hpre as u8 - 0b0110))
763        } else {
764            sysclk / (1 << (self.hpre as u8 - 0b0111))
765        };
766
767        let ppre1 = 1 << (self.ppre1 as u8 - 0b011);
768        let pclk1 = hclk / (ppre1 as u32);
769
770        let ppre2 = 1 << (self.ppre2 as u8 - 0b011);
771        let pclk2 = hclk / (ppre2 as u32);
772
773        let apre = (self.adcpre as u8 + 1) << 1;
774        let adcclk = pclk2 / (apre as u32);
775
776        // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the
777        // PLL output frequency is a supported one.
778        #[cfg(any(feature = "stm32f103", feature = "connectivity"))]
779        let usbclk_valid = matches!(
780            (self.hse, self.pllmul, sysclk),
781            (Some(_), Some(_), 72_000_000) | (Some(_), Some(_), 48_000_000)
782        );
783
784        assert!(
785            self.allow_overclock
786                || (sysclk <= 72_000_000
787                    && hclk <= 72_000_000
788                    && pclk1 <= 36_000_000
789                    && pclk2 <= 72_000_000
790                    && adcclk <= 14_000_000)
791        );
792
793        Clocks {
794            hclk: hclk.Hz(),
795            pclk1: pclk1.Hz(),
796            pclk2: pclk2.Hz(),
797            ppre1,
798            ppre2,
799            sysclk: sysclk.Hz(),
800            adcclk: adcclk.Hz(),
801            #[cfg(any(feature = "stm32f103", feature = "connectivity"))]
802            usbclk_valid,
803        }
804    }
805}
806
807#[test]
808fn rcc_config_usb() {
809    let cfgr = Config::default()
810        .use_hse(8.MHz())
811        .sysclk(48.MHz())
812        .pclk1(24.MHz());
813
814    let config = RawConfig::from_cfgr(cfgr);
815    let config_expected = RawConfig {
816        hse: Some(8_000_000),
817        hse_bypass: false,
818        pllmul: Some(4),
819        hpre: HPre::Div1,
820        ppre1: PPre::Div2,
821        ppre2: PPre::Div1,
822        #[cfg(any(feature = "stm32f103", feature = "connectivity"))]
823        usbpre: UsbPre::Div1,
824        adcpre: AdcPre::Div8,
825        allow_overclock: false,
826    };
827    assert_eq!(config, config_expected);
828
829    let clocks = config.get_clocks();
830    let clocks_expected = Clocks {
831        hclk: 48.MHz(),
832        pclk1: 24.MHz(),
833        pclk2: 48.MHz(),
834        ppre1: 2,
835        ppre2: 1,
836        sysclk: 48.MHz(),
837        adcclk: 6.MHz(),
838        #[cfg(any(feature = "stm32f103", feature = "connectivity"))]
839        usbclk_valid: true,
840    };
841    assert_eq!(clocks, clocks_expected);
842}