stm32f0xx_hal/
rcc.rs

1use crate::pac::RCC;
2use crate::time::Hertz;
3
4/// Extension trait that sets up the `RCC` peripheral
5pub trait RccExt {
6    /// Configure the clocks of the RCC peripheral
7    fn configure(self) -> CFGR;
8}
9
10impl RccExt for RCC {
11    fn configure(self) -> CFGR {
12        CFGR {
13            hclk: None,
14            pclk: None,
15            sysclk: None,
16            clock_src: SysClkSource::HSI,
17            /// CRS is only available on devices with HSI48
18            #[cfg(any(
19                feature = "stm32f042",
20                feature = "stm32f048",
21                feature = "stm32f071",
22                feature = "stm32f072",
23                feature = "stm32f078",
24                feature = "stm32f091",
25                feature = "stm32f098",
26            ))]
27            crs: None,
28            #[cfg(any(
29                feature = "stm32f042",
30                feature = "stm32f048",
31                feature = "stm32f072",
32                feature = "stm32f078",
33            ))]
34            usb_src: USBClockSource::HSI48,
35            #[cfg(feature = "stm32f070")]
36            usb_src: USBClockSource::Disabled,
37            rcc: self,
38        }
39    }
40}
41
42/// Constrained RCC peripheral
43pub struct Rcc {
44    pub clocks: Clocks,
45    pub(crate) regs: RCC,
46}
47
48pub enum HSEBypassMode {
49    /// Not bypassed: for crystals
50    NotBypassed,
51    /// Bypassed: for external clock sources
52    Bypassed,
53}
54#[cfg(any(
55    feature = "stm32f042",
56    feature = "stm32f048",
57    feature = "stm32f070", // Doesn't have HSI48
58    feature = "stm32f072",
59    feature = "stm32f078",
60))]
61#[allow(clippy::upper_case_acronyms)]
62pub enum USBClockSource {
63    #[cfg(feature = "stm32f070")]
64    /// USB peripheral's tranceiver is disabled
65    Disabled,
66    #[cfg(not(feature = "stm32f070"))]
67    /// HSI48 is used as USB peripheral tranceiver clock
68    HSI48,
69    /// PLL output is used as USB peripheral tranceiver clock
70    PLL,
71}
72/// RCC for F0x0 devices
73#[cfg(any(feature = "stm32f030", feature = "stm32f070",))]
74mod inner {
75    use crate::pac::{rcc::cfgr::SW_A, RCC};
76
77    pub(super) const HSI: u32 = 8_000_000; // Hz
78
79    // Does PLLSRC have two bits?
80    #[cfg(any(
81        feature = "stm32f030x4",
82        feature = "stm32f030x6",
83        feature = "stm32f030x8",
84        // Reference Manual states HSI_PREDIV is not available on stm32f070/, but it actually
85        // seems to work, and also is referenced in its CMSIS header files stm32f070x6.h and stm32f070xb.h
86        // But, for now be conservative and mark it as not available.
87        feature = "stm32f070",
88        // It's also listed in the CMSIS headers for the f030xc,
89        feature = "stm32f030xc"
90    ))]
91    pub(super) const RCC_PLLSRC_PREDIV1_SUPPORT: bool = false;
92
93    #[allow(clippy::upper_case_acronyms)]
94    pub(super) enum SysClkSource {
95        HSI,
96        /// High-speed external clock(freq,bypassed)
97        HSE(u32, super::HSEBypassMode),
98    }
99
100    pub(super) fn get_freq(c_src: &SysClkSource) -> u32 {
101        // Select clock source based on user input and capability
102        // Highest selected frequency source available takes precedent.
103        match c_src {
104            SysClkSource::HSE(freq, _) => *freq,
105            _ => HSI,
106        }
107    }
108
109    pub(super) fn enable_clock(rcc: &mut RCC, c_src: &SysClkSource) {
110        // Enable the requested clock
111        match c_src {
112            SysClkSource::HSE(_, bypassed) => {
113                match bypassed {
114                    super::HSEBypassMode::NotBypassed => {
115                        rcc.cr
116                            .modify(|_, w| w.csson().on().hseon().on().hsebyp().not_bypassed());
117                    }
118                    super::HSEBypassMode::Bypassed => {
119                        rcc.cr
120                            .modify(|_, w| w.csson().on().hseon().on().hsebyp().bypassed());
121                    }
122                }
123                while !rcc.cr.read().hserdy().bit_is_set() {}
124            }
125            SysClkSource::HSI => {
126                rcc.cr.write(|w| w.hsion().set_bit());
127                while rcc.cr.read().hsirdy().bit_is_clear() {}
128            }
129        }
130    }
131
132    pub(super) fn enable_pll(
133        rcc: &mut RCC,
134        c_src: &SysClkSource,
135        pllmul_bits: u8,
136        ppre_bits: u8,
137        hpre_bits: u8,
138    ) {
139        let pllsrc_bit: bool = match c_src {
140            SysClkSource::HSI => false,
141            SysClkSource::HSE(_, _) => true,
142        };
143
144        // Set PLL source and multiplier
145        rcc.cfgr
146            .modify(|_, w| w.pllsrc().bit(pllsrc_bit).pllmul().bits(pllmul_bits));
147
148        rcc.cr.modify(|_, w| w.pllon().set_bit());
149        while rcc.cr.read().pllrdy().bit_is_clear() {}
150
151        rcc.cfgr
152            .modify(|_, w| unsafe { w.ppre().bits(ppre_bits).hpre().bits(hpre_bits).sw().pll() });
153    }
154
155    pub(super) fn get_sww(c_src: &SysClkSource) -> SW_A {
156        match c_src {
157            SysClkSource::HSI => SW_A::HSI,
158            SysClkSource::HSE(_, _) => SW_A::HSE,
159        }
160    }
161}
162/// RCC for F0x1, F0x2, F0x8 devices
163#[cfg(any(
164    feature = "stm32f031",
165    feature = "stm32f038",
166    feature = "stm32f042",
167    feature = "stm32f048",
168    feature = "stm32f051",
169    feature = "stm32f058",
170    feature = "stm32f071",
171    feature = "stm32f072",
172    feature = "stm32f078",
173    feature = "stm32f091",
174    feature = "stm32f098",
175))]
176mod inner {
177    use crate::pac::{rcc::cfgr::SW_A, RCC};
178
179    pub(super) const HSI: u32 = 8_000_000; // Hz
180    #[cfg(any(
181        feature = "stm32f042",
182        feature = "stm32f048",
183        feature = "stm32f071",
184        feature = "stm32f072",
185        feature = "stm32f078",
186        feature = "stm32f091",
187        feature = "stm32f098",
188    ))]
189    pub(super) const HSI48: u32 = 48_000_000; // Hz
190
191    // Does PLLSRC have two bits?
192    #[cfg(any(
193        feature = "stm32f042",
194        feature = "stm32f048",
195        feature = "stm32f071",
196        feature = "stm32f072",
197        feature = "stm32f078",
198        feature = "stm32f091",
199        feature = "stm32f098",
200    ))]
201    pub(super) const RCC_PLLSRC_PREDIV1_SUPPORT: bool = true;
202    #[cfg(any(
203        feature = "stm32f031",
204        feature = "stm32f038",
205        feature = "stm32f051",
206        feature = "stm32f058"
207    ))]
208    pub(super) const RCC_PLLSRC_PREDIV1_SUPPORT: bool = false;
209
210    #[allow(clippy::upper_case_acronyms)]
211    pub(super) enum SysClkSource {
212        HSI,
213        /// High-speed external clock(freq,bypassed)
214        HSE(u32, super::HSEBypassMode),
215        #[cfg(any(
216            feature = "stm32f042",
217            feature = "stm32f048",
218            feature = "stm32f071",
219            feature = "stm32f072",
220            feature = "stm32f078",
221            feature = "stm32f091",
222            feature = "stm32f098",
223        ))]
224        HSI48,
225    }
226
227    pub(super) fn get_freq(c_src: &SysClkSource) -> u32 {
228        // Select clock source based on user input and capability
229        // Highest selected frequency source available takes precedent.
230        match c_src {
231            SysClkSource::HSE(freq, _) => *freq,
232            #[cfg(any(
233                feature = "stm32f042",
234                feature = "stm32f048",
235                feature = "stm32f071",
236                feature = "stm32f072",
237                feature = "stm32f078",
238                feature = "stm32f091",
239                feature = "stm32f098",
240            ))]
241            SysClkSource::HSI48 => HSI48,
242            _ => HSI,
243        }
244    }
245
246    pub(super) fn enable_clock(rcc: &mut RCC, c_src: &SysClkSource) {
247        // Enable the requested clock
248        match c_src {
249            SysClkSource::HSE(_, bypassed) => {
250                match bypassed {
251                    super::HSEBypassMode::NotBypassed => {
252                        rcc.cr
253                            .modify(|_, w| w.csson().on().hseon().on().hsebyp().not_bypassed());
254                    }
255                    super::HSEBypassMode::Bypassed => {
256                        rcc.cr
257                            .modify(|_, w| w.csson().on().hseon().on().hsebyp().bypassed());
258                    }
259                }
260
261                while !rcc.cr.read().hserdy().bit_is_set() {}
262            }
263            #[cfg(any(
264                feature = "stm32f042",
265                feature = "stm32f048",
266                feature = "stm32f071",
267                feature = "stm32f072",
268                feature = "stm32f078",
269                feature = "stm32f091",
270                feature = "stm32f098",
271            ))]
272            SysClkSource::HSI48 => {
273                rcc.cr2.modify(|_, w| w.hsi48on().set_bit());
274                while rcc.cr2.read().hsi48rdy().bit_is_clear() {}
275            }
276            SysClkSource::HSI => {
277                rcc.cr.write(|w| w.hsion().set_bit());
278                while rcc.cr.read().hsirdy().bit_is_clear() {}
279            }
280        }
281    }
282
283    pub(super) fn enable_pll(
284        rcc: &mut RCC,
285        c_src: &SysClkSource,
286        pllmul_bits: u8,
287        ppre_bits: u8,
288        hpre_bits: u8,
289    ) {
290        let pllsrc_bit: u8 = match (c_src, RCC_PLLSRC_PREDIV1_SUPPORT) {
291            (SysClkSource::HSI, false) => 0b00, // HSI/2
292            (SysClkSource::HSI, true) => 0b01,  // HSI/PREDIV
293            #[cfg(any(
294                feature = "stm32f042",
295                feature = "stm32f048",
296                feature = "stm32f071",
297                feature = "stm32f072",
298                feature = "stm32f078",
299                feature = "stm32f091",
300                feature = "stm32f098",
301            ))]
302            (SysClkSource::HSI48, _) => 0b11,
303            (SysClkSource::HSE(_, _), _) => 0b10,
304        };
305
306        // Set PLL source and multiplier
307        rcc.cfgr
308            .modify(|_, w| w.pllsrc().bits(pllsrc_bit).pllmul().bits(pllmul_bits));
309
310        rcc.cr.modify(|_, w| w.pllon().set_bit());
311        while rcc.cr.read().pllrdy().bit_is_clear() {}
312
313        rcc.cfgr
314            .modify(|_, w| unsafe { w.ppre().bits(ppre_bits).hpre().bits(hpre_bits).sw().pll() });
315    }
316
317    pub(super) fn get_sww(c_src: &SysClkSource) -> SW_A {
318        match c_src {
319            SysClkSource::HSI => SW_A::HSI,
320            #[cfg(any(
321                feature = "stm32f042",
322                feature = "stm32f048",
323                feature = "stm32f071",
324                feature = "stm32f072",
325                feature = "stm32f078",
326                feature = "stm32f091",
327                feature = "stm32f098",
328            ))]
329            SysClkSource::HSI48 => SW_A::HSI48,
330            SysClkSource::HSE(_, _) => SW_A::HSE,
331        }
332    }
333}
334
335use self::inner::SysClkSource;
336
337pub struct CFGR {
338    hclk: Option<u32>,
339    pclk: Option<u32>,
340    sysclk: Option<u32>,
341    clock_src: SysClkSource,
342    #[cfg(any(
343        feature = "stm32f042",
344        feature = "stm32f048",
345        feature = "stm32f070",
346        feature = "stm32f072",
347        feature = "stm32f078",
348    ))]
349    usb_src: USBClockSource,
350    /// CRS is only available on devices with HSI48
351    #[cfg(any(
352        feature = "stm32f042",
353        feature = "stm32f048",
354        feature = "stm32f071",
355        feature = "stm32f072",
356        feature = "stm32f078",
357        feature = "stm32f091",
358        feature = "stm32f098",
359    ))]
360    crs: Option<crate::pac::CRS>,
361    rcc: RCC,
362}
363
364impl CFGR {
365    pub fn hse<F>(mut self, freq: F, bypass: HSEBypassMode) -> Self
366    where
367        F: Into<Hertz>,
368    {
369        self.clock_src = SysClkSource::HSE(freq.into().0, bypass);
370        self
371    }
372
373    #[cfg(any(
374        feature = "stm32f042",
375        feature = "stm32f048",
376        feature = "stm32f071",
377        feature = "stm32f072",
378        feature = "stm32f078",
379        feature = "stm32f091",
380        feature = "stm32f098",
381    ))]
382    pub fn hsi48(mut self) -> Self {
383        self.clock_src = SysClkSource::HSI48;
384        self
385    }
386
387    pub fn hclk<F>(mut self, freq: F) -> Self
388    where
389        F: Into<Hertz>,
390    {
391        self.hclk = Some(freq.into().0);
392        self
393    }
394
395    pub fn pclk<F>(mut self, freq: F) -> Self
396    where
397        F: Into<Hertz>,
398    {
399        self.pclk = Some(freq.into().0);
400        self
401    }
402
403    pub fn sysclk<F>(mut self, freq: F) -> Self
404    where
405        F: Into<Hertz>,
406    {
407        self.sysclk = Some(freq.into().0);
408        self
409    }
410    #[cfg(any(
411        feature = "stm32f042",
412        feature = "stm32f048",
413        feature = "stm32f070",
414        feature = "stm32f072",
415        feature = "stm32f078",
416    ))]
417    /// Set the USB clock source (only valid for STM32F0xx with USB)
418    pub fn usbsrc(mut self, src: USBClockSource) -> Self {
419        self.usb_src = src;
420        self
421    }
422
423    #[cfg(any(
424        feature = "stm32f042",
425        feature = "stm32f048",
426        feature = "stm32f071",
427        feature = "stm32f072",
428        feature = "stm32f078",
429        feature = "stm32f091",
430        feature = "stm32f098",
431    ))]
432    pub fn enable_crs(mut self, crs: crate::pac::CRS) -> Self {
433        self.crs = Some(crs);
434        self
435    }
436
437    pub fn freeze(mut self, flash: &mut crate::pac::FLASH) -> Rcc {
438        // Default to lowest frequency clock on all systems.
439        let sysclk = self.sysclk.unwrap_or(self::inner::HSI);
440
441        let r_sysclk; // The "real" sysclock value, calculated below
442        let pllmul_bits;
443
444        // Select clock source based on user input and capability
445        // Highest selected frequency source available takes precedent.
446        // For F04x, F07x, F09x parts, use HSI48 if requested.
447        let src_clk_freq = self::inner::get_freq(&self.clock_src);
448
449        // Pll check
450        if sysclk == src_clk_freq {
451            // Bypass pll if src clk and requested sysclk are the same, to save power.
452            // The only reason to override this behaviour is if the sysclk source were HSI, and you
453            // were running the USB off the PLL...
454            pllmul_bits = None;
455            r_sysclk = src_clk_freq;
456        } else {
457            // FIXME: This assumes reset value of prediv (/1).
458            //        There is no logic to set plldiv to any value other than 1.
459            // Note that for some models, HSI is fixed by hardware to divide by two.
460            let pllprediv = match (&self.clock_src, self::inner::RCC_PLLSRC_PREDIV1_SUPPORT) {
461                (self::inner::SysClkSource::HSI, false) => 2,
462                (_, _) => 1,
463            };
464            // Find PLL multiplier that creates freq closest to target
465            let pllmul = (2 * pllprediv * self.sysclk.unwrap_or(src_clk_freq) + src_clk_freq)
466                / src_clk_freq
467                / 2;
468            let pllmul = core::cmp::min(core::cmp::max(pllmul, 2), 16);
469            r_sysclk = pllmul * src_clk_freq / pllprediv;
470
471            pllmul_bits = Some(pllmul as u8 - 2)
472        }
473
474        let hpre_bits = self
475            .hclk
476            .map(|hclk| match r_sysclk / hclk {
477                0 => unreachable!(),
478                1 => 0b0111,
479                2 => 0b1000,
480                3..=5 => 0b1001,
481                6..=11 => 0b1010,
482                12..=39 => 0b1011,
483                40..=95 => 0b1100,
484                96..=191 => 0b1101,
485                192..=383 => 0b1110,
486                _ => 0b1111,
487            })
488            .unwrap_or(0b0111);
489
490        let hclk = r_sysclk / (1 << (hpre_bits - 0b0111));
491
492        let ppre_bits = self
493            .pclk
494            .map(|pclk| match hclk / pclk {
495                0 => unreachable!(),
496                1 => 0b011,
497                2 => 0b100,
498                3..=5 => 0b101,
499                6..=11 => 0b110,
500                _ => 0b111,
501            })
502            .unwrap_or(0b011);
503
504        let ppre: u8 = 1 << (ppre_bits - 0b011);
505        let pclk = hclk / cast::u32(ppre);
506
507        // adjust flash wait states
508        unsafe {
509            flash.acr.write(|w| {
510                w.latency().bits(if r_sysclk <= 24_000_000 {
511                    0b000
512                } else if r_sysclk <= 48_000_000 {
513                    0b001
514                } else {
515                    0b010
516                })
517            })
518        }
519
520        // Enable the requested clock
521        self::inner::enable_clock(&mut self.rcc, &self.clock_src);
522
523        // Only need to set USBSW if MCU has USB HW
524        #[cfg(feature = "stm32f070")]
525        {
526            match self.usb_src {
527                USBClockSource::Disabled => self.rcc.cfgr3.modify(|_, w| w.usbsw().clear_bit()),
528                USBClockSource::PLL => self.rcc.cfgr3.modify(|_, w| w.usbsw().set_bit()),
529            }
530        }
531        #[cfg(any(
532            feature = "stm32f042",
533            feature = "stm32f048",
534            feature = "stm32f072",
535            feature = "stm32f078",
536        ))]
537        match self.usb_src {
538            USBClockSource::HSI48 => self.rcc.cfgr3.modify(|_, w| w.usbsw().clear_bit()),
539            USBClockSource::PLL => self.rcc.cfgr3.modify(|_, w| w.usbsw().set_bit()),
540        }
541        // Set up rcc based on above calculated configuration.
542
543        // Enable PLL
544        if let Some(pllmul_bits) = pllmul_bits {
545            self::inner::enable_pll(
546                &mut self.rcc,
547                &self.clock_src,
548                pllmul_bits,
549                ppre_bits,
550                hpre_bits,
551            );
552        } else {
553            let sw_var = self::inner::get_sww(&self.clock_src);
554
555            // CRS is only available on devices with HSI48
556            #[cfg(any(
557                feature = "stm32f042",
558                feature = "stm32f048",
559                feature = "stm32f071",
560                feature = "stm32f072",
561                feature = "stm32f078",
562                feature = "stm32f091",
563                feature = "stm32f098",
564            ))]
565            match self.crs {
566                Some(crs) => {
567                    self.rcc.apb1enr.modify(|_, w| w.crsen().set_bit());
568
569                    // Initialize clock recovery
570                    // Set autotrim enabled.
571                    crs.cr.modify(|_, w| w.autotrimen().set_bit());
572                    // Enable CR
573                    crs.cr.modify(|_, w| w.cen().set_bit());
574                }
575                _ => {}
576            }
577
578            // use HSI as source
579            self.rcc.cfgr.modify(|_, w| unsafe {
580                w.ppre()
581                    .bits(ppre_bits)
582                    .hpre()
583                    .bits(hpre_bits)
584                    .sw()
585                    .variant(sw_var)
586            });
587        }
588        Rcc {
589            clocks: Clocks {
590                hclk: Hertz(hclk),
591                pclk: Hertz(pclk),
592                sysclk: Hertz(sysclk),
593            },
594            regs: self.rcc,
595        }
596    }
597}
598
599/// Frozen clock frequencies
600///
601/// The existence of this value indicates that the clock configuration can no longer be changed
602#[derive(Clone, Copy)]
603pub struct Clocks {
604    hclk: Hertz,
605    pclk: Hertz,
606    sysclk: Hertz,
607}
608
609impl Clocks {
610    /// Returns the frequency of the AHB
611    pub fn hclk(&self) -> Hertz {
612        self.hclk
613    }
614
615    /// Returns the frequency of the APB
616    pub fn pclk(&self) -> Hertz {
617        self.pclk
618    }
619
620    /// Returns the system (core) frequency
621    pub fn sysclk(&self) -> Hertz {
622        self.sysclk
623    }
624}