stm32f042_hal/
rcc.rs

1use core::cmp;
2
3use cast::u32;
4use stm32::{FLASH, RCC};
5
6use time::Hertz;
7
8/// Extension trait that constrains the `RCC` peripheral
9pub trait RccExt {
10    /// Constrains the `RCC` peripheral so it plays nicely with the other abstractions
11    fn constrain(self) -> Rcc;
12}
13
14impl RccExt for RCC {
15    fn constrain(self) -> Rcc {
16        Rcc {
17            cfgr: CFGR {
18                hclk: None,
19                pclk: None,
20                sysclk: None,
21            },
22        }
23    }
24}
25
26/// Constrained RCC peripheral
27pub struct Rcc {
28    pub cfgr: CFGR,
29}
30
31const HSI: u32 = 8_000_000; // Hz
32
33pub struct CFGR {
34    hclk: Option<u32>,
35    pclk: Option<u32>,
36    sysclk: Option<u32>,
37}
38
39impl CFGR {
40    pub fn hclk<F>(mut self, freq: F) -> Self
41    where
42        F: Into<Hertz>,
43    {
44        self.hclk = Some(freq.into().0);
45        self
46    }
47
48    pub fn pclk<F>(mut self, freq: F) -> Self
49    where
50        F: Into<Hertz>,
51    {
52        self.pclk = Some(freq.into().0);
53        self
54    }
55
56    pub fn sysclk<F>(mut self, freq: F) -> Self
57    where
58        F: Into<Hertz>,
59    {
60        self.sysclk = Some(freq.into().0);
61        self
62    }
63
64    pub fn freeze(self) -> Clocks {
65        let pllmul = (4 * self.sysclk.unwrap_or(HSI) + HSI) / HSI / 2;
66        let pllmul = cmp::min(cmp::max(pllmul, 2), 16);
67        let sysclk = pllmul * HSI / 2;
68
69        let pllmul_bits = if pllmul == 2 {
70            None
71        } else {
72            Some(pllmul as u8 - 2)
73        };
74
75        let hpre_bits = self
76            .hclk
77            .map(|hclk| match sysclk / hclk {
78                0 => unreachable!(),
79                1 => 0b0111,
80                2 => 0b1000,
81                3...5 => 0b1001,
82                6...11 => 0b1010,
83                12...39 => 0b1011,
84                40...95 => 0b1100,
85                96...191 => 0b1101,
86                192...383 => 0b1110,
87                _ => 0b1111,
88            })
89            .unwrap_or(0b0111);
90
91        let hclk = sysclk / (1 << (hpre_bits - 0b0111));
92
93        let ppre_bits = self
94            .pclk
95            .map(|pclk| match hclk / pclk {
96                0 => unreachable!(),
97                1 => 0b011,
98                2 => 0b100,
99                3...5 => 0b101,
100                6...11 => 0b110,
101                _ => 0b111,
102            })
103            .unwrap_or(0b011);
104
105        let ppre: u8 = 1 << (ppre_bits - 0b011);
106        let pclk = hclk / u32(ppre);
107
108        // adjust flash wait states
109        unsafe {
110            let flash = &*FLASH::ptr();
111            flash.acr.write(|w| {
112                w.latency().bits(if sysclk <= 24_000_000 {
113                    0b000
114                } else if sysclk <= 48_000_000 {
115                    0b001
116                } else {
117                    0b010
118                })
119            })
120        }
121
122        let rcc = unsafe { &*RCC::ptr() };
123        if let Some(pllmul_bits) = pllmul_bits {
124            // use PLL as source
125
126            rcc.cfgr.write(|w| unsafe { w.pllmul().bits(pllmul_bits) });
127
128            rcc.cr.write(|w| w.pllon().set_bit());
129
130            while rcc.cr.read().pllrdy().bit_is_clear() {}
131
132            rcc.cfgr.modify(|_, w| unsafe {
133                w.ppre().bits(ppre_bits).hpre().bits(hpre_bits).sw().bits(2)
134            });
135        } else {
136            // use HSI as source
137            rcc.cfgr
138                .write(|w| unsafe { w.ppre().bits(ppre_bits).hpre().bits(hpre_bits).sw().bits(0) });
139        }
140
141        Clocks {
142            hclk: Hertz(hclk),
143            pclk: Hertz(pclk),
144            sysclk: Hertz(sysclk),
145        }
146    }
147}
148
149/// Frozen clock frequencies
150///
151/// The existence of this value indicates that the clock configuration can no longer be changed
152#[derive(Clone, Copy)]
153pub struct Clocks {
154    hclk: Hertz,
155    pclk: Hertz,
156    sysclk: Hertz,
157}
158
159impl Clocks {
160    /// Returns the frequency of the AHB
161    pub fn hclk(&self) -> Hertz {
162        self.hclk
163    }
164
165    /// Returns the frequency of the APB
166    pub fn pclk(&self) -> Hertz {
167        self.pclk
168    }
169
170    /// Returns the system (core) frequency
171    pub fn sysclk(&self) -> Hertz {
172        self.sysclk
173    }
174}