stm32f4xx_hal/rcc/
mod.rs

1//! Clock configuration.
2//!
3//! This module provides functionality to configure the RCC to generate the requested clocks.
4//!
5//! # Example
6//!
7//! ```
8//! let dp = pac::Peripherals::take().unwrap();
9//! let rcc = dp.RCC.constrain();
10//! let clocks = rcc
11//!     .cfgr
12//!     .use_hse(8.MHz())
13//!     .sysclk(168.MHz())
14//!     .pclk1(24.MHz())
15//!     .i2s_clk(86.MHz())
16//!     .require_pll48clk()
17//!     .freeze();
18//!     // Test that the I2S clock is suitable for 48000kHz audio.
19//!     assert!(clocks.i2s_clk().unwrap() == 48.MHz().into());
20//! ```
21//!
22//! # Limitations
23//!
24//! Unlike the clock configuration tool provided by ST, the code does not extensively search all
25//! possible configurations. Instead, it often relies on an iterative approach to reduce
26//! computational complexity. On most MCUs the code will first generate a configuration for the 48
27//! MHz clock and the system clock without taking other requested clocks into account, even if the
28//! accuracy of these clocks is affected. **If you specific accuracy requirements, you should
29//! always check the resulting frequencies!**
30//!
31//! Whereas the hardware often supports flexible clock source selection and many clocks can be
32//! sourced from multiple PLLs, the code implements a fixed mapping between PLLs and clocks. The 48
33//! MHz clock is always generated by the main PLL, the I2S clocks are always generated by the I2S
34//! PLL (unless a matching external clock input is provided), and similarly the SAI clocks are
35//! always generated by the SAI PLL. It is therefore not possible to, for example, specify two
36//! different I2S frequencies unless you also provide a matching I2S_CKIN signal for one of them.
37//!
38//! Some MCUs have limited clock generation hardware and do not provide either I2S or SAI PLLs even
39//! though I2S or SAI are available. On the STM32F410, the I2S clock is generated by the main PLL,
40//! and on the STM32F413/423 SAI clocks are generated by the I2S PLL. On these MCUs, the actual
41//! frequencies may substantially deviate from the requested frequencies.
42mod f4;
43pub use f4::*;
44
45use crate::pac::rcc::{self, RegisterBlock as RccRB};
46use crate::pac::RCC;
47use core::ops::{Deref, DerefMut};
48use fugit::HertzU32 as Hertz;
49
50/// Constrained RCC peripheral
51pub struct Rcc {
52    pub clocks: Clocks,
53    pub(crate) rb: RCC,
54}
55
56impl Deref for Rcc {
57    type Target = RCC;
58    fn deref(&self) -> &Self::Target {
59        &self.rb
60    }
61}
62
63impl DerefMut for Rcc {
64    fn deref_mut(&mut self) -> &mut Self::Target {
65        &mut self.rb
66    }
67}
68
69/// Extension trait that constrains the `RCC` peripheral
70pub trait RccExt {
71    /// Constrains the `RCC` peripheral so it plays nicely with the other abstractions
72    fn constrain(self) -> Rcc;
73
74    /// Constrains the `RCC` peripheral and apply clock configuration
75    fn freeze(self, rcc_cfg: Config) -> Rcc;
76}
77
78impl RccExt for RCC {
79    fn constrain(self) -> Rcc {
80        Rcc {
81            rb: self,
82            clocks: Clocks::default(),
83        }
84    }
85
86    fn freeze(self, rcc_cfg: Config) -> Rcc {
87        self.constrain().freeze(rcc_cfg)
88    }
89}
90
91/// Bus associated to peripheral
92pub trait RccBus: crate::Sealed {
93    /// Bus type;
94    type Bus;
95}
96
97/// Frequency on bus that peripheral is connected in
98pub trait BusClock {
99    /// Calculates frequency depending on `Clock` state
100    fn clock(clocks: &Clocks) -> Hertz;
101}
102
103/// Frequency on bus that timer is connected in
104pub trait BusTimerClock {
105    /// Calculates base frequency of timer depending on `Clock` state
106    fn timer_clock(clocks: &Clocks) -> Hertz;
107}
108
109impl<T> BusClock for T
110where
111    T: RccBus,
112    T::Bus: BusClock,
113{
114    fn clock(clocks: &Clocks) -> Hertz {
115        T::Bus::clock(clocks)
116    }
117}
118
119impl<T> BusTimerClock for T
120where
121    T: RccBus,
122    T::Bus: BusTimerClock,
123{
124    fn timer_clock(clocks: &Clocks) -> Hertz {
125        T::Bus::timer_clock(clocks)
126    }
127}
128
129/// Enable/disable peripheral
130pub trait Enable: RccBus {
131    /// Enables peripheral
132    fn enable(rcc: &mut RCC);
133
134    /// Disables peripheral
135    fn disable(rcc: &mut RCC);
136
137    /// Check if peripheral enabled
138    fn is_enabled() -> bool;
139
140    /// Check if peripheral disabled
141    #[inline]
142    fn is_disabled() -> bool {
143        !Self::is_enabled()
144    }
145
146    /// # Safety
147    ///
148    /// Enables peripheral. Takes access to RCC internally
149    unsafe fn enable_unchecked() {
150        let mut rcc = RCC::steal();
151        Self::enable(&mut rcc);
152    }
153
154    /// # Safety
155    ///
156    /// Disables peripheral. Takes access to RCC internally
157    unsafe fn disable_unchecked() {
158        let mut rcc = RCC::steal();
159        Self::disable(&mut rcc);
160    }
161}
162
163/// Low power enable/disable peripheral
164pub trait LPEnable: RccBus {
165    /// Enables peripheral in low power mode
166    fn enable_in_low_power(rcc: &mut RCC);
167
168    /// Disables peripheral in low power mode
169    fn disable_in_low_power(rcc: &mut RCC);
170
171    /// Check if peripheral enabled in low power mode
172    fn is_enabled_in_low_power() -> bool;
173
174    /// Check if peripheral disabled in low power mode
175    #[inline]
176    fn is_disabled_in_low_power() -> bool {
177        !Self::is_enabled_in_low_power()
178    }
179
180    /// # Safety
181    ///
182    /// Enables peripheral in low power mode. Takes access to RCC internally
183    unsafe fn enable_in_low_power_unchecked() {
184        let mut rcc = RCC::steal();
185        Self::enable_in_low_power(&mut rcc);
186    }
187
188    /// # Safety
189    ///
190    /// Disables peripheral in low power mode. Takes access to RCC internally
191    unsafe fn disable_in_low_power_unchecked() {
192        let mut rcc = RCC::steal();
193        Self::disable_in_low_power(&mut rcc);
194    }
195}
196
197/// Reset peripheral
198pub trait Reset: RccBus {
199    /// Resets peripheral
200    fn reset(rcc: &mut RCC);
201
202    /// # Safety
203    ///
204    /// Resets peripheral. Takes access to RCC internally
205    unsafe fn reset_unchecked() {
206        let mut rcc = RCC::steal();
207        Self::reset(&mut rcc);
208    }
209}
210
211macro_rules! bus_struct {
212    ($($busX:ident => ($EN:ident, $en:ident, $LPEN:ident, $lpen:ident, $RST:ident, $rst:ident, $doc:literal),)+) => {
213        $(
214            #[doc = $doc]
215            #[non_exhaustive]
216            pub struct $busX;
217
218            impl $busX {
219                pub(crate) fn enr(rcc: &RccRB) -> &rcc::$EN {
220                    rcc.$en()
221                }
222
223                #[allow(unused)]
224                pub(crate) fn lpenr(rcc: &RccRB) -> &rcc::$LPEN {
225                    rcc.$lpen()
226                }
227
228                pub(crate) fn rstr(rcc: &RccRB) -> &rcc::$RST {
229                    rcc.$rst()
230                }
231            }
232        )+
233    };
234}
235use bus_struct;
236
237bus_struct! {
238    APB1 => (APB1ENR, apb1enr, APB1LPENR, apb1lpenr, APB1RSTR, apb1rstr, "Advanced Peripheral Bus 1 (APB1) registers"),
239    APB2 => (APB2ENR, apb2enr, APB2LPENR, apb2lpenr, APB2RSTR, apb2rstr, "Advanced Peripheral Bus 2 (APB2) registers"),
240    AHB1 => (AHB1ENR, ahb1enr, AHB1LPENR, ahb1lpenr, AHB1RSTR, ahb1rstr, "Advanced High-performance Bus 1 (AHB1) registers"),
241}
242#[cfg(not(feature = "gpio-f410"))]
243bus_struct! {
244    AHB2 => (AHB2ENR, ahb2enr, AHB2LPENR, ahb2lpenr, AHB2RSTR, ahb2rstr, "Advanced High-performance Bus 2 (AHB2) registers"),
245}
246#[cfg(any(feature = "fsmc", feature = "fmc"))]
247bus_struct! {
248    AHB3 => (AHB3ENR, ahb3enr, AHB3LPENR, ahb3lpenr, AHB3RSTR, ahb3rstr, "Advanced High-performance Bus 3 (AHB3) registers"),
249}
250
251impl BusClock for AHB1 {
252    fn clock(clocks: &Clocks) -> Hertz {
253        clocks.hclk
254    }
255}
256
257#[cfg(not(feature = "gpio-f410"))]
258impl BusClock for AHB2 {
259    fn clock(clocks: &Clocks) -> Hertz {
260        clocks.hclk
261    }
262}
263
264#[cfg(any(feature = "fsmc", feature = "fmc"))]
265impl BusClock for AHB3 {
266    fn clock(clocks: &Clocks) -> Hertz {
267        clocks.hclk
268    }
269}
270
271impl BusClock for APB1 {
272    fn clock(clocks: &Clocks) -> Hertz {
273        clocks.pclk1
274    }
275}
276
277impl BusClock for APB2 {
278    fn clock(clocks: &Clocks) -> Hertz {
279        clocks.pclk2
280    }
281}
282
283impl BusTimerClock for APB1 {
284    fn timer_clock(clocks: &Clocks) -> Hertz {
285        clocks.timclk1
286    }
287}
288
289impl BusTimerClock for APB2 {
290    fn timer_clock(clocks: &Clocks) -> Hertz {
291        clocks.timclk2
292    }
293}