stm32f30x_hal/
rcc.rs

1//! Reset and Clock Control
2
3use core::cmp;
4
5use cast::u32;
6use stm32f30x::{rcc, RCC};
7
8use flash::ACR;
9use time::Hertz;
10
11/// Extension trait that constrains the `RCC` peripheral
12pub trait RccExt {
13    /// Constrains the `RCC` peripheral so it plays nicely with the other abstractions
14    fn constrain(self) -> Rcc;
15}
16
17impl RccExt for RCC {
18    fn constrain(self) -> Rcc {
19        Rcc {
20            ahb: AHB { _0: () },
21            apb1: APB1 { _0: () },
22            apb2: APB2 { _0: () },
23            cfgr: CFGR {
24                hclk: None,
25                pclk1: None,
26                pclk2: None,
27                sysclk: None,
28            },
29        }
30    }
31}
32
33/// Constrained RCC peripheral
34pub struct Rcc {
35    /// AMBA High-performance Bus (AHB) registers
36    pub ahb: AHB,
37    /// Advanced Peripheral Bus 1 (APB1) registers
38    pub apb1: APB1,
39    /// Advanced Peripheral Bus 2 (APB2) registers
40    pub apb2: APB2,
41    /// Clock configuration
42    pub cfgr: CFGR,
43}
44
45/// AMBA High-performance Bus (AHB) registers
46pub struct AHB {
47    _0: (),
48}
49
50impl AHB {
51    pub(crate) fn enr(&mut self) -> &rcc::AHBENR {
52        // NOTE(unsafe) this proxy grants exclusive access to this register
53        unsafe { &(*RCC::ptr()).ahbenr }
54    }
55
56    pub(crate) fn rstr(&mut self) -> &rcc::AHBRSTR {
57        // NOTE(unsafe) this proxy grants exclusive access to this register
58        unsafe { &(*RCC::ptr()).ahbrstr }
59    }
60}
61
62/// Advanced Peripheral Bus 1 (APB1) registers
63pub struct APB1 {
64    _0: (),
65}
66
67impl APB1 {
68    pub(crate) fn enr(&mut self) -> &rcc::APB1ENR {
69        // NOTE(unsafe) this proxy grants exclusive access to this register
70        unsafe { &(*RCC::ptr()).apb1enr }
71    }
72
73    pub(crate) fn rstr(&mut self) -> &rcc::APB1RSTR {
74        // NOTE(unsafe) this proxy grants exclusive access to this register
75        unsafe { &(*RCC::ptr()).apb1rstr }
76    }
77}
78
79/// Advanced Peripheral Bus 2 (APB2) registers
80pub struct APB2 {
81    _0: (),
82}
83
84impl APB2 {
85    pub(crate) fn enr(&mut self) -> &rcc::APB2ENR {
86        // NOTE(unsafe) this proxy grants exclusive access to this register
87        unsafe { &(*RCC::ptr()).apb2enr }
88    }
89
90    pub(crate) fn rstr(&mut self) -> &rcc::APB2RSTR {
91        // NOTE(unsafe) this proxy grants exclusive access to this register
92        unsafe { &(*RCC::ptr()).apb2rstr }
93    }
94}
95
96const HSI: u32 = 8_000_000; // Hz
97
98/// Clock configuration
99pub struct CFGR {
100    hclk: Option<u32>,
101    pclk1: Option<u32>,
102    pclk2: Option<u32>,
103    sysclk: Option<u32>,
104}
105
106impl CFGR {
107    /// Sets a frequency for the AHB bus
108    pub fn hclk<F>(mut self, freq: F) -> Self
109    where
110        F: Into<Hertz>,
111    {
112        self.hclk = Some(freq.into().0);
113        self
114    }
115
116    /// Sets a frequency for the APB1 bus
117    pub fn pclk1<F>(mut self, freq: F) -> Self
118    where
119        F: Into<Hertz>,
120    {
121        self.pclk1 = Some(freq.into().0);
122        self
123    }
124
125    /// Sets a frequency for the APB2 bus
126    pub fn pclk2<F>(mut self, freq: F) -> Self
127    where
128        F: Into<Hertz>,
129    {
130        self.pclk2 = Some(freq.into().0);
131        self
132    }
133
134    /// Sets the system (core) frequency
135    pub fn sysclk<F>(mut self, freq: F) -> Self
136    where
137        F: Into<Hertz>,
138    {
139        self.sysclk = Some(freq.into().0);
140        self
141    }
142
143    /// Freezes the clock configuration, making it effective
144    pub fn freeze(self, acr: &mut ACR) -> Clocks {
145        let pllmul = (2 * self.sysclk.unwrap_or(HSI)) / HSI;
146        let pllmul = cmp::min(cmp::max(pllmul, 2), 16);
147        let pllmul_bits = if pllmul == 2 {
148            None
149        } else {
150            Some(pllmul as u8 - 2)
151        };
152
153        let sysclk = pllmul * HSI / 2;
154
155        assert!(sysclk <= 72_000_000);
156
157        let hpre_bits = self.hclk
158            .map(|hclk| match sysclk / hclk {
159                0 => unreachable!(),
160                1 => 0b0111,
161                2 => 0b1000,
162                3...5 => 0b1001,
163                6...11 => 0b1010,
164                12...39 => 0b1011,
165                40...95 => 0b1100,
166                96...191 => 0b1101,
167                192...383 => 0b1110,
168                _ => 0b1111,
169            })
170            .unwrap_or(0b0111);
171
172        let hclk = sysclk / (1 << (hpre_bits - 0b0111));
173
174        assert!(hclk <= 72_000_000);
175
176        let ppre1_bits = self.pclk1
177            .map(|pclk1| match hclk / pclk1 {
178                0 => unreachable!(),
179                1 => 0b011,
180                2 => 0b100,
181                3...5 => 0b101,
182                6...11 => 0b110,
183                _ => 0b111,
184            })
185            .unwrap_or(0b011);
186
187        let ppre1 = 1 << (ppre1_bits - 0b011);
188        let pclk1 = hclk / u32(ppre1);
189
190        assert!(pclk1 <= 36_000_000);
191
192        let ppre2_bits = self.pclk2
193            .map(|pclk2| match hclk / pclk2 {
194                0 => unreachable!(),
195                1 => 0b011,
196                2 => 0b100,
197                3...5 => 0b101,
198                6...11 => 0b110,
199                _ => 0b111,
200            })
201            .unwrap_or(0b011);
202
203        let ppre2 = 1 << (ppre2_bits - 0b011);
204        let pclk2 = hclk / u32(ppre2);
205
206        assert!(pclk2 <= 72_000_000);
207
208        // adjust flash wait states
209        unsafe {
210            acr.acr().write(|w| {
211                w.latency().bits(if sysclk <= 24_000_000 {
212                    0b000
213                } else if sysclk <= 48_000_000 {
214                    0b001
215                } else {
216                    0b010
217                })
218            })
219        }
220
221        let rcc = unsafe { &*RCC::ptr() };
222        if let Some(pllmul_bits) = pllmul_bits {
223            // use PLL as source
224
225            rcc.cfgr.write(|w| unsafe { w.pllmul().bits(pllmul_bits) });
226
227            rcc.cr.write(|w| w.pllon().set_bit());
228
229            while rcc.cr.read().pllrdy().bit_is_clear() {}
230
231            // SW: PLL selected as system clock
232            rcc.cfgr.modify(|_, w| unsafe {
233                w.ppre2()
234                    .bits(ppre2_bits)
235                    .ppre1()
236                    .bits(ppre1_bits)
237                    .hpre()
238                    .bits(hpre_bits)
239                    .sw()
240                    .bits(0b10)
241            });
242        } else {
243            // use HSI as source
244
245            // SW: HSI selected as system clock
246            rcc.cfgr.write(|w| unsafe {
247                w.ppre2()
248                    .bits(ppre2_bits)
249                    .ppre1()
250                    .bits(ppre1_bits)
251                    .hpre()
252                    .bits(hpre_bits)
253                    .sw()
254                    .bits(0b00)
255            });
256        }
257
258        Clocks {
259            hclk: Hertz(hclk),
260            pclk1: Hertz(pclk1),
261            pclk2: Hertz(pclk2),
262            ppre1,
263            ppre2,
264            sysclk: Hertz(sysclk),
265        }
266    }
267}
268
269/// Frozen clock frequencies
270///
271/// The existence of this value indicates that the clock configuration can no longer be changed
272#[derive(Clone, Copy)]
273pub struct Clocks {
274    hclk: Hertz,
275    pclk1: Hertz,
276    pclk2: Hertz,
277    ppre1: u8,
278    // TODO remove `allow`
279    #[allow(dead_code)]
280    ppre2: u8,
281    sysclk: Hertz,
282}
283
284impl Clocks {
285    /// Returns the frequency of the AHB
286    pub fn hclk(&self) -> Hertz {
287        self.hclk
288    }
289
290    /// Returns the frequency of the APB1
291    pub fn pclk1(&self) -> Hertz {
292        self.pclk1
293    }
294
295    /// Returns the frequency of the APB2
296    pub fn pclk2(&self) -> Hertz {
297        self.pclk2
298    }
299
300    pub(crate) fn ppre1(&self) -> u8 {
301        self.ppre1
302    }
303
304    // TODO remove `allow`
305    #[allow(dead_code)]
306    pub(crate) fn ppre2(&self) -> u8 {
307        self.ppre2
308    }
309
310    /// Returns the system (core) frequency
311    pub fn sysclk(&self) -> Hertz {
312        self.sysclk
313    }
314}