stm32l4_hal/
rcc.rs

1//! Reset and Clock Control
2
3use core::cmp;
4
5use cast::u32;
6use crate::stm32::{rcc, RCC};
7
8use crate::flash::ACR;
9use crate::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            ahb1: AHB1 { _0: () },
21            ahb2: AHB2 { _0: () },
22            ahb3: AHB3 { _0: () },
23            apb1r1: APB1R1 { _0: () },
24            apb1r2: APB1R2 { _0: () },
25            apb2: APB2 { _0: () },
26            bdcr: BDCR { _0: () },
27            csr: CSR { _0: () },
28            cfgr: CFGR {
29                hclk: None,
30                pclk1: None,
31                pclk2: None,
32                sysclk: None,
33                pllcfg: None,
34            },
35        }
36    }
37}
38
39/// Constrained RCC peripheral
40pub struct Rcc {
41    /// AMBA High-performance Bus (AHB1) registers
42    pub ahb1: AHB1,
43    /// AMBA High-performance Bus (AHB2) registers
44    pub ahb2: AHB2,
45    /// AMBA High-performance Bus (AHB3) registers
46    pub ahb3: AHB3,
47    /// Advanced Peripheral Bus 1 (APB1) registers
48    pub apb1r1: APB1R1,
49    /// Advanced Peripheral Bus 1 (APB2) registers
50    pub apb1r2: APB1R2,
51    /// Advanced Peripheral Bus 2 (APB2) registers
52    pub apb2: APB2,
53    /// Clock configuration register
54    pub cfgr: CFGR,
55    /// Backup domain control register
56    pub bdcr: BDCR,
57    /// Control/Status Register
58    pub csr: CSR,
59}
60
61/// CSR Control/Status Register
62pub struct CSR {
63    _0: (),
64}
65
66impl CSR {
67    // TODO remove `allow`
68    #[allow(dead_code)]
69    pub(crate) fn csr(&mut self) -> &rcc::CSR {
70        // NOTE(unsafe) this proxy grants exclusive access to this register
71        unsafe { &(*RCC::ptr()).csr }
72    }
73}
74
75/// BDCR Backup domain control register registers
76pub struct BDCR {
77    _0: (),
78}
79
80impl BDCR {
81    // TODO remove `allow`
82    #[allow(dead_code)]
83    pub(crate) fn enr(&mut self) -> &rcc::BDCR {
84        // NOTE(unsafe) this proxy grants exclusive access to this register
85        unsafe { &(*RCC::ptr()).bdcr }
86    }
87}
88
89/// AMBA High-performance Bus 1 (AHB1) registers
90pub struct AHB1 {
91    _0: (),
92}
93
94impl AHB1 {
95    // TODO remove `allow`
96    #[allow(dead_code)]
97    pub(crate) fn enr(&mut self) -> &rcc::AHB1ENR {
98        // NOTE(unsafe) this proxy grants exclusive access to this register
99        unsafe { &(*RCC::ptr()).ahb1enr }
100    }
101    // TODO remove `allow`
102    #[allow(dead_code)]
103    pub(crate) fn rstr(&mut self) -> &rcc::AHB1RSTR {
104        // NOTE(unsafe) this proxy grants exclusive access to this register
105        unsafe { &(*RCC::ptr()).ahb1rstr }
106    }
107}
108
109/// AMBA High-performance Bus 2 (AHB2) registers
110pub struct AHB2 {
111    _0: (),
112}
113
114impl AHB2 {
115    pub(crate) fn enr(&mut self) -> &rcc::AHB2ENR {
116        // NOTE(unsafe) this proxy grants exclusive access to this register
117        unsafe { &(*RCC::ptr()).ahb2enr }
118    }
119
120    pub(crate) fn rstr(&mut self) -> &rcc::AHB2RSTR {
121        // NOTE(unsafe) this proxy grants exclusive access to this register
122        unsafe { &(*RCC::ptr()).ahb2rstr }
123    }
124}
125
126/// AMBA High-performance Bus (AHB3) registers
127pub struct AHB3 {
128    _0: (),
129}
130
131impl AHB3 {
132    // TODO remove `allow`
133    #[allow(dead_code)]
134    pub(crate) fn enr(&mut self) -> &rcc::AHB3ENR {
135        // NOTE(unsafe) this proxy grants exclusive access to this register
136        unsafe { &(*RCC::ptr()).ahb3enr }
137    }
138    // TODO remove `allow`
139    #[allow(dead_code)]
140    pub(crate) fn rstr(&mut self) -> &rcc::AHB3RSTR {
141        // NOTE(unsafe) this proxy grants exclusive access to this register
142        unsafe { &(*RCC::ptr()).ahb3rstr }
143    }
144}
145
146/// Advanced Peripheral Bus 1 (APB1) register 1 registers
147pub struct APB1R1 {
148    _0: (),
149}
150
151impl APB1R1 {
152    pub(crate) fn enr(&mut self) -> &rcc::APB1ENR1 {
153        // NOTE(unsafe) this proxy grants exclusive access to this register
154        unsafe { &(*RCC::ptr()).apb1enr1 }
155    }
156
157    pub(crate) fn rstr(&mut self) -> &rcc::APB1RSTR1 {
158        // NOTE(unsafe) this proxy grants exclusive access to this register
159        unsafe { &(*RCC::ptr()).apb1rstr1 }
160    }
161}
162
163/// Advanced Peripheral Bus 1 (APB1) register 2 registers
164pub struct APB1R2 {
165    _0: (),
166}
167
168impl APB1R2 {
169    // TODO remove `allow`
170    #[allow(dead_code)]
171    pub(crate) fn enr(&mut self) -> &rcc::APB1ENR2 {
172        // NOTE(unsafe) this proxy grants exclusive access to this register
173        unsafe { &(*RCC::ptr()).apb1enr2 }
174    }
175    // TODO remove `allow`
176    #[allow(dead_code)]
177    pub(crate) fn rstr(&mut self) -> &rcc::APB1RSTR2 {
178        // NOTE(unsafe) this proxy grants exclusive access to this register
179        unsafe { &(*RCC::ptr()).apb1rstr2 }
180    }
181}
182
183/// Advanced Peripheral Bus 2 (APB2) registers
184pub struct APB2 {
185    _0: (),
186}
187
188impl APB2 {
189    pub(crate) fn enr(&mut self) -> &rcc::APB2ENR {
190        // NOTE(unsafe) this proxy grants exclusive access to this register
191        unsafe { &(*RCC::ptr()).apb2enr }
192    }
193
194    pub(crate) fn rstr(&mut self) -> &rcc::APB2RSTR {
195        // NOTE(unsafe) this proxy grants exclusive access to this register
196        unsafe { &(*RCC::ptr()).apb2rstr }
197    }
198}
199
200const HSI: u32 = 16_000_000; // Hz
201
202/// Clock configuration
203pub struct CFGR {
204    hclk: Option<u32>,
205    pclk1: Option<u32>,
206    pclk2: Option<u32>,
207    sysclk: Option<u32>,
208    pllcfg: Option<PllConfig>
209}
210
211impl CFGR {
212    /// Sets a frequency for the AHB bus
213    pub fn hclk<F>(mut self, freq: F) -> Self
214    where
215        F: Into<Hertz>,
216    {
217        self.hclk = Some(freq.into().0);
218        self
219    }
220
221    /// Sets a frequency for the APB1 bus
222    pub fn pclk1<F>(mut self, freq: F) -> Self
223    where
224        F: Into<Hertz>,
225    {
226        self.pclk1 = Some(freq.into().0);
227        self
228    }
229
230    /// Sets a frequency for the APB2 bus
231    pub fn pclk2<F>(mut self, freq: F) -> Self
232    where
233        F: Into<Hertz>,
234    {
235        self.pclk2 = Some(freq.into().0);
236        self
237    }
238
239    /// Sets the system (core) frequency
240    pub fn sysclk<F>(mut self, freq: F) -> Self
241    where
242        F: Into<Hertz>,
243    {
244        self.sysclk = Some(freq.into().0);
245        self
246    }
247
248    /// Sets the system (core) frequency with some pll configuration
249    pub fn sysclk_with_pll<F>(mut self, freq: F, cfg: PllConfig) -> Self
250    where
251        F: Into<Hertz>,
252    {
253        self.pllcfg = Some(cfg);
254        self.sysclk = Some(freq.into().0);
255        self
256    }
257
258    /// Freezes the clock configuration, making it effective
259    pub fn freeze(self, acr: &mut ACR) -> Clocks {
260
261        let pllconf = if self.pllcfg.is_none() {
262            let plln = (2 * self.sysclk.unwrap_or(HSI)) / HSI;
263            let plln = cmp::min(cmp::max(plln, 2), 16);
264            if plln == 2 {
265                None
266            } else {
267                // create a best effort pll config, just multiply n
268                // TODO should we reject this configuration as the clocks stored in RCC could cause timing issues?
269                let conf = PllConfig {
270                    m: 0b0,
271                    r: 0b0,
272                    n: plln as u8
273                };
274                Some(conf)
275            }
276
277        } else {
278            let conf = self.pllcfg.unwrap();
279            Some(conf)
280        };
281
282        let sysclk = self.sysclk.unwrap_or(HSI);
283
284        assert!(sysclk <= 80_000_000);
285
286        let hpre_bits = self.hclk
287            .map(|hclk| match sysclk / hclk {
288                0 => unreachable!(),
289                1 => 0b0000,
290                2 => 0b1000,
291                3...5 => 0b1001,
292                6...11 => 0b1010,
293                12...39 => 0b1011,
294                40...95 => 0b1100,
295                96...191 => 0b1101,
296                192...383 => 0b1110,
297                _ => 0b1111,
298            })
299            .unwrap_or(0b0000);
300
301        let hclk = sysclk / (1 << (hpre_bits));
302
303        assert!(hclk <= sysclk);
304
305        let ppre1_bits = self.pclk1
306            .map(|pclk1| match hclk / pclk1 {
307                0 => unreachable!(),
308                1 => 0b000,
309                2 => 0b100,
310                3...5 => 0b101,
311                6...11 => 0b110,
312                _ => 0b111,
313            })
314            .unwrap_or(0b000);
315
316        let ppre1 = 1 << (ppre1_bits);
317        let pclk1 = hclk / u32(ppre1);
318
319        assert!(pclk1 <= sysclk);
320
321        let ppre2_bits = self.pclk2
322            .map(|pclk2| match hclk / pclk2 {
323                0 => unreachable!(),
324                1 => 0b000,
325                2 => 0b100,
326                3...5 => 0b101,
327                6...11 => 0b110,
328                _ => 0b111,
329            })
330            .unwrap_or(0b000);
331
332        let ppre2 = 1 << (ppre2_bits);
333        let pclk2 = hclk / u32(ppre2);
334
335        assert!(pclk2 <= sysclk);
336
337        // adjust flash wait states
338        unsafe {
339            acr.acr().write(|w| {
340                w.latency().bits(if sysclk <= 24_000_000 {
341                    0b000
342                } else if sysclk <= 48_000_000 {
343                    0b001
344                } else {
345                    0b010
346                })
347            })
348        }
349
350        let rcc = unsafe { &*RCC::ptr() };
351        let sysclk_src_bits;
352        if let Some(pllconf) = pllconf {
353            // use PLL as source
354            sysclk_src_bits = 0b11;
355            rcc.cr.modify(|_, w| w.pllon().clear_bit());
356            while rcc.cr.read().pllrdy().bit_is_set() {}
357
358            let pllsrc_bits = 0b10; // use HSI16 as PLL source
359            rcc.cr.write(|w| w.hsion().set_bit());
360            while rcc.cr.read().hsirdy().bit_is_clear() {}
361
362            rcc.pllcfgr
363            .modify(|_, w| unsafe {
364                w.pllsrc()
365                    .bits(pllsrc_bits)
366                    .pllm().bits(pllconf.m)
367                    .pllr().bits(pllconf.r)
368                    .plln().bits(pllconf.n)
369            });
370
371            rcc.cr.modify(|_, w| w.pllon().set_bit());
372
373            while rcc.cr.read().pllrdy().bit_is_clear() {}
374
375            rcc.pllcfgr.modify(|_, w| w.pllren().set_bit());
376
377            // SW: PLL selected as system clock
378            rcc.cfgr.modify(|_, w| unsafe {
379                w.ppre2()
380                    .bits(ppre2_bits)
381                    .ppre1()
382                    .bits(ppre1_bits)
383                    .hpre()
384                    .bits(hpre_bits)
385                    .sw()
386                    .bits(sysclk_src_bits)
387            });
388        } else {
389            // use HSI as source
390            sysclk_src_bits = 0b01;
391
392            rcc.cr.write(|w| w.hsion().set_bit());
393            while rcc.cr.read().hsirdy().bit_is_clear() {}
394
395            // SW: HSI selected as system clock
396            rcc.cfgr.write(|w| unsafe {
397                w.ppre2()
398                    .bits(ppre2_bits)
399                    .ppre1()
400                    .bits(ppre1_bits)
401                    .hpre()
402                    .bits(hpre_bits)
403                    .sw()
404                    .bits(sysclk_src_bits)
405            });
406        }
407
408        while rcc.cfgr.read().sws().bits() != sysclk_src_bits {}
409
410        // Turn on the internal 32khz lsi oscillator
411        rcc.csr.modify(|_, w| {
412            w.lsion().set_bit()
413        });
414        // Wait until LSI is running
415        while rcc.csr.read().lsirdy().bit_is_clear() {}
416
417
418        Clocks {
419            hclk: Hertz(hclk),
420            pclk1: Hertz(pclk1),
421            pclk2: Hertz(pclk2),
422            ppre1,
423            ppre2,
424            sysclk: Hertz(sysclk),
425        }
426    }
427}
428
429#[derive(Clone, Copy)]
430/// Pll Configuration - Calculation = ((SourceClk / m) * n) / r
431pub struct PllConfig {
432    /// Main PLL Division factor
433    pub m: u8,
434    /// Main Pll Multiplication factor
435    pub n: u8,
436    /// Main PLL division factor for PLLCLK (system clock)
437    pub r: u8,
438}
439
440/// Frozen clock frequencies
441///
442/// The existence of this value indicates that the clock configuration can no longer be changed
443#[derive(Clone, Copy)]
444pub struct Clocks {
445    hclk: Hertz,
446    pclk1: Hertz,
447    pclk2: Hertz,
448    // TODO remove `allow`
449    #[allow(dead_code)]
450    ppre1: u8,
451    ppre2: u8,
452    sysclk: Hertz,
453}
454
455impl Clocks {
456    /// Returns the frequency of the AHB
457    pub fn hclk(&self) -> Hertz {
458        self.hclk
459    }
460
461    /// Returns the frequency of the APB1
462    pub fn pclk1(&self) -> Hertz {
463        self.pclk1
464    }
465
466    /// Returns the frequency of the APB2
467    pub fn pclk2(&self) -> Hertz {
468        self.pclk2
469    }
470
471    // TODO remove `allow`
472    #[allow(dead_code)]
473    pub(crate) fn ppre1(&self) -> u8 {
474        self.ppre1
475    }
476    // TODO remove `allow`
477    #[allow(dead_code)]
478    pub(crate) fn ppre2(&self) -> u8 {
479        self.ppre2
480    }
481
482    /// Returns the system (core) frequency
483    pub fn sysclk(&self) -> Hertz {
484        self.sysclk
485    }
486}