stm32f1_hal/rcc/
mod.rs

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