1use core::cmp;
2
3use cast::u32;
4use stm32::{FLASH, RCC};
5
6use time::Hertz;
7
8pub trait RccExt {
10 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
26pub struct Rcc {
28 pub cfgr: CFGR,
29}
30
31const HSI: u32 = 8_000_000; pub 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 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 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 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#[derive(Clone, Copy)]
153pub struct Clocks {
154 hclk: Hertz,
155 pclk: Hertz,
156 sysclk: Hertz,
157}
158
159impl Clocks {
160 pub fn hclk(&self) -> Hertz {
162 self.hclk
163 }
164
165 pub fn pclk(&self) -> Hertz {
167 self.pclk
168 }
169
170 pub fn sysclk(&self) -> Hertz {
172 self.sysclk
173 }
174}