stm32f1_hal/rcc/
mod.rs

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