aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-07-23 17:01:34 -0500
committerxoviat <[email protected]>2023-07-23 17:01:34 -0500
commitbd60f003e0ef367e1678d549973ba9b4ae753652 (patch)
tree16488e78c9380e082833546dd0b100e2e29a0170
parent4db63677f6e56c52ea3d432542513967f5d93c69 (diff)
stm32/rcc: move rcc logic from ipcc
-rw-r--r--embassy-stm32/src/ipcc.rs56
-rw-r--r--embassy-stm32/src/rcc/mod.rs8
-rw-r--r--embassy-stm32/src/rcc/wb.rs326
3 files changed, 287 insertions, 103 deletions
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index a24cba9f0..e100ca5cc 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -265,63 +265,9 @@ pub(crate) mod sealed {
265} 265}
266 266
267fn _configure_pwr() { 267fn _configure_pwr() {
268 // TODO: move this to RCC 268 // TODO: move the rest of this to rcc
269
270 let pwr = crate::pac::PWR;
271 let rcc = crate::pac::RCC; 269 let rcc = crate::pac::RCC;
272 270
273 rcc.cfgr().modify(|w| w.set_stopwuck(true));
274
275 pwr.cr1().modify(|w| w.set_dbp(true));
276 pwr.cr1().modify(|w| w.set_dbp(true));
277
278 // configure LSE
279 rcc.bdcr().modify(|w| w.set_lseon(true));
280
281 // select system clock source = PLL
282 // set PLL coefficients
283 // m: 2,
284 // n: 12,
285 // r: 3,
286 // q: 4,
287 // p: 3,
288 let src_bits = 0b11;
289 let pllp = (3 - 1) & 0b11111;
290 let pllq = (4 - 1) & 0b111;
291 let pllr = (3 - 1) & 0b111;
292 let plln = 12 & 0b1111111;
293 let pllm = (2 - 1) & 0b111;
294 rcc.pllcfgr().modify(|w| {
295 w.set_pllsrc(src_bits);
296 w.set_pllm(pllm);
297 w.set_plln(plln);
298 w.set_pllr(pllr);
299 w.set_pllp(pllp);
300 w.set_pllpen(true);
301 w.set_pllq(pllq);
302 w.set_pllqen(true);
303 });
304 // enable PLL
305 rcc.cr().modify(|w| w.set_pllon(true));
306 rcc.cr().write(|w| w.set_hsion(false));
307 // while !rcc.cr().read().pllrdy() {}
308
309 // configure SYSCLK mux to use PLL clocl
310 rcc.cfgr().modify(|w| w.set_sw(0b11));
311
312 // configure CPU1 & CPU2 dividers
313 rcc.cfgr().modify(|w| w.set_hpre(0)); // not divided
314 rcc.extcfgr().modify(|w| {
315 w.set_c2hpre(0b1000); // div2
316 w.set_shdhpre(0); // not divided
317 });
318
319 // apply APB1 / APB2 values
320 rcc.cfgr().modify(|w| {
321 w.set_ppre1(0b000); // not divided
322 w.set_ppre2(0b000); // not divided
323 });
324
325 // TODO: required 271 // TODO: required
326 // set RF wake-up clock = LSE 272 // set RF wake-up clock = LSE
327 rcc.csr().modify(|w| w.set_rfwkpsel(0b01)); 273 rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 886fc0b93..4ae65d3e6 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -78,6 +78,14 @@ pub struct Clocks {
78/// The existence of this value indicates that the clock configuration can no longer be changed 78/// The existence of this value indicates that the clock configuration can no longer be changed
79static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit(); 79static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
80 80
81#[cfg(stm32wb)]
82/// RCC initialization function
83pub(crate) unsafe fn init(config: Config) {
84 set_freqs(compute_clocks(&config));
85
86 configure_clocks(&config);
87}
88
81/// Sets the clock frequencies 89/// Sets the clock frequencies
82/// 90///
83/// Safety: Sets a mutable global. 91/// Safety: Sets a mutable global.
diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs
index e6123821a..41f602c02 100644
--- a/embassy-stm32/src/rcc/wb.rs
+++ b/embassy-stm32/src/rcc/wb.rs
@@ -1,6 +1,5 @@
1use crate::pac::RCC; 1use crate::rcc::Clocks;
2use crate::rcc::{set_freqs, Clocks}; 2use crate::time::{khz, mhz, Hertz};
3use crate::time::Hertz;
4 3
5/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, 4/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
6/// and with the addition of the init function to configure a system clock. 5/// and with the addition of the init function to configure a system clock.
@@ -13,11 +12,94 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
13/// LSI speed 12/// LSI speed
14pub const LSI_FREQ: Hertz = Hertz(32_000); 13pub const LSI_FREQ: Hertz = Hertz(32_000);
15 14
16/// System clock mux source
17#[derive(Clone, Copy)] 15#[derive(Clone, Copy)]
18pub enum ClockSrc { 16pub enum HsePrescaler {
19 HSE(Hertz), 17 NotDivided,
20 HSI16, 18 Div2,
19}
20
21impl From<HsePrescaler> for bool {
22 fn from(value: HsePrescaler) -> Self {
23 match value {
24 HsePrescaler::NotDivided => false,
25 HsePrescaler::Div2 => true,
26 }
27 }
28}
29
30pub struct Hse {
31 pub prediv: HsePrescaler,
32
33 pub frequency: Hertz,
34}
35
36/// System clock mux source
37#[derive(Clone, Copy, PartialEq)]
38pub enum Sysclk {
39 /// MSI selected as sysclk
40 MSI,
41 /// HSI selected as sysclk
42 HSI,
43 /// HSE selected as sysclk
44 HSE,
45 /// PLL selected as sysclk
46 Pll,
47}
48
49impl From<Sysclk> for u8 {
50 fn from(value: Sysclk) -> Self {
51 match value {
52 Sysclk::MSI => 0b00,
53 Sysclk::HSI => 0b01,
54 Sysclk::HSE => 0b10,
55 Sysclk::Pll => 0b11,
56 }
57 }
58}
59
60#[derive(Clone, Copy, PartialEq)]
61pub enum PllSource {
62 Hsi,
63 Msi,
64 Hse,
65}
66
67impl From<PllSource> for u8 {
68 fn from(value: PllSource) -> Self {
69 match value {
70 PllSource::Msi => 0b01,
71 PllSource::Hsi => 0b10,
72 PllSource::Hse => 0b11,
73 }
74 }
75}
76
77pub enum Pll48Source {
78 PllSai,
79 Pll,
80 Msi,
81 Hsi48,
82}
83
84pub struct PllMux {
85 /// Source clock selection.
86 pub source: PllSource,
87
88 /// PLL pre-divider (DIVM). Must be between 1 and 63.
89 pub prediv: u8,
90}
91
92pub struct Pll {
93 /// PLL multiplication factor. Must be between 4 and 512.
94 pub mul: u16,
95
96 /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128.
97 /// On PLL1, it must be even (in particular, it cannot be 1.)
98 pub divp: Option<u16>,
99 /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128.
100 pub divq: Option<u16>,
101 /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128.
102 pub divr: Option<u16>,
21} 103}
22 104
23/// AHB prescaler 105/// AHB prescaler
@@ -84,8 +166,18 @@ impl Into<u8> for AHBPrescaler {
84 166
85/// Clocks configutation 167/// Clocks configutation
86pub struct Config { 168pub struct Config {
87 pub mux: ClockSrc, 169 pub hse: Option<Hse>,
88 pub ahb_pre: AHBPrescaler, 170 pub lse: Option<Hertz>,
171 pub sys: Sysclk,
172 pub mux: Option<PllMux>,
173 pub pll48: Option<Pll48Source>,
174
175 pub pll: Option<Pll>,
176 pub pllsai: Option<Pll>,
177
178 pub ahb1_pre: AHBPrescaler,
179 pub ahb2_pre: AHBPrescaler,
180 pub ahb3_pre: AHBPrescaler,
89 pub apb1_pre: APBPrescaler, 181 pub apb1_pre: APBPrescaler,
90 pub apb2_pre: APBPrescaler, 182 pub apb2_pre: APBPrescaler,
91} 183}
@@ -94,76 +186,214 @@ impl Default for Config {
94 #[inline] 186 #[inline]
95 fn default() -> Config { 187 fn default() -> Config {
96 Config { 188 Config {
97 mux: ClockSrc::HSI16, 189 hse: Some(Hse {
98 ahb_pre: AHBPrescaler::NotDivided, 190 frequency: mhz(32),
191 prediv: HsePrescaler::NotDivided,
192 }),
193 lse: Some(khz(32)),
194 sys: Sysclk::HSI,
195 mux: Some(PllMux {
196 source: PllSource::Hse,
197 prediv: 2,
198 }),
199 pll48: None,
200
201 pll: Some(Pll {
202 mul: 12,
203 divp: Some(3),
204 divq: Some(4),
205 divr: Some(3),
206 }),
207 pllsai: None,
208
209 ahb1_pre: AHBPrescaler::NotDivided,
210 ahb2_pre: AHBPrescaler::Div2,
211 ahb3_pre: AHBPrescaler::NotDivided,
99 apb1_pre: APBPrescaler::NotDivided, 212 apb1_pre: APBPrescaler::NotDivided,
100 apb2_pre: APBPrescaler::NotDivided, 213 apb2_pre: APBPrescaler::NotDivided,
101 } 214 }
102 } 215 }
103} 216}
104 217
105pub(crate) unsafe fn init(config: Config) { 218pub(crate) fn compute_clocks(config: &Config) -> Clocks {
106 let (sys_clk, sw) = match config.mux { 219 let hse_clk = config.hse.as_ref().map(|hse| match hse.prediv {
107 ClockSrc::HSI16 => { 220 HsePrescaler::NotDivided => hse.frequency,
108 // Enable HSI16 221 HsePrescaler::Div2 => hse.frequency / 2u32,
109 RCC.cr().write(|w| w.set_hsion(true)); 222 });
110 while !RCC.cr().read().hsirdy() {} 223
224 let mux_clk = config.mux.as_ref().map(|pll_mux| {
225 (match pll_mux.source {
226 PllSource::Hse => hse_clk.unwrap(),
227 PllSource::Hsi => HSI_FREQ,
228 _ => unreachable!(),
229 } / pll_mux.prediv)
230 });
111 231
112 (HSI_FREQ.0, 0x01) 232 let (pll_r, _pll_q, _pll_p) = match &config.pll {
233 Some(pll) => {
234 let pll_vco = mux_clk.unwrap() * pll.mul as u32;
235
236 (
237 pll.divr.map(|divr| pll_vco / divr),
238 pll.divq.map(|divq| pll_vco / divq),
239 pll.divp.map(|divp| pll_vco / divp),
240 )
113 } 241 }
114 ClockSrc::HSE(freq) => { 242 None => (None, None, None),
115 // Enable HSE 243 };
116 RCC.cr().write(|w| w.set_hseon(true));
117 while !RCC.cr().read().hserdy() {}
118 244
119 (freq.0, 0x02) 245 let sys_clk = match config.sys {
246 Sysclk::HSE => hse_clk.unwrap(),
247 Sysclk::HSI => HSI_FREQ,
248 Sysclk::Pll => pll_r.unwrap(),
249 _ => unreachable!(),
250 };
251
252 let ahb1_clk = match config.ahb1_pre {
253 AHBPrescaler::NotDivided => sys_clk,
254 pre => {
255 let pre: u8 = pre.into();
256 let pre = 1u32 << (pre as u32 - 7);
257 sys_clk / pre
120 } 258 }
121 }; 259 };
122 260
123 RCC.cfgr().modify(|w| { 261 let ahb2_clk = match config.ahb2_pre {
124 w.set_sw(sw.into()); 262 AHBPrescaler::NotDivided => sys_clk,
125 w.set_hpre(config.ahb_pre.into()); 263 pre => {
126 w.set_ppre1(config.apb1_pre.into()); 264 let pre: u8 = pre.into();
127 w.set_ppre2(config.apb2_pre.into()); 265 let pre = 1u32 << (pre as u32 - 7);
128 }); 266 sys_clk / pre
267 }
268 };
129 269
130 let ahb_freq: u32 = match config.ahb_pre { 270 let ahb3_clk = match config.ahb3_pre {
131 AHBPrescaler::NotDivided => sys_clk, 271 AHBPrescaler::NotDivided => sys_clk,
132 pre => { 272 pre => {
133 let pre: u8 = pre.into(); 273 let pre: u8 = pre.into();
134 let pre = 1 << (pre as u32 - 7); 274 let pre = 1u32 << (pre as u32 - 7);
135 sys_clk / pre 275 sys_clk / pre
136 } 276 }
137 }; 277 };
138 278
139 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { 279 let (apb1_clk, apb1_tim_clk) = match config.apb1_pre {
140 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 280 APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk),
141 pre => { 281 pre => {
142 let pre: u8 = pre.into(); 282 let pre: u8 = pre.into();
143 let pre: u8 = 1 << (pre - 3); 283 let pre: u8 = 1 << (pre - 3);
144 let freq = ahb_freq / pre as u32; 284 let freq = ahb1_clk / pre as u32;
145 (freq, freq * 2) 285 (freq, freq * 2u32)
146 } 286 }
147 }; 287 };
148 288
149 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { 289 let (apb2_clk, apb2_tim_clk) = match config.apb2_pre {
150 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 290 APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk),
151 pre => { 291 pre => {
152 let pre: u8 = pre.into(); 292 let pre: u8 = pre.into();
153 let pre: u8 = 1 << (pre - 3); 293 let pre: u8 = 1 << (pre - 3);
154 let freq = ahb_freq / pre as u32; 294 let freq = ahb1_clk / pre as u32;
155 (freq, freq * 2) 295 (freq, freq * 2u32)
156 } 296 }
157 }; 297 };
158 298
159 set_freqs(Clocks { 299 Clocks {
160 sys: Hertz(sys_clk), 300 sys: sys_clk,
161 ahb1: Hertz(ahb_freq), 301 ahb1: ahb1_clk,
162 ahb2: Hertz(ahb_freq), 302 ahb2: ahb2_clk,
163 ahb3: Hertz(ahb_freq), 303 ahb3: ahb3_clk,
164 apb1: Hertz(apb1_freq), 304 apb1: apb1_clk,
165 apb2: Hertz(apb2_freq), 305 apb2: apb2_clk,
166 apb1_tim: Hertz(apb1_tim_freq), 306 apb1_tim: apb1_tim_clk,
167 apb2_tim: Hertz(apb2_tim_freq), 307 apb2_tim: apb2_tim_clk,
308 }
309}
310
311pub(crate) fn configure_clocks(config: &Config) {
312 let pwr = crate::pac::PWR;
313 let rcc = crate::pac::RCC;
314
315 let needs_hsi = if let Some(pll_mux) = &config.mux {
316 pll_mux.source == PllSource::Hsi
317 } else {
318 false
319 };
320
321 if needs_hsi || config.sys == Sysclk::HSI {
322 rcc.cr().modify(|w| {
323 w.set_hsion(true);
324 });
325
326 while !rcc.cr().read().hsirdy() {}
327 }
328
329 match &config.lse {
330 Some(_) => {
331 rcc.cfgr().modify(|w| w.set_stopwuck(true));
332
333 pwr.cr1().modify(|w| w.set_dbp(true));
334 pwr.cr1().modify(|w| w.set_dbp(true));
335
336 rcc.bdcr().modify(|w| w.set_lseon(true));
337 }
338 _ => {}
339 }
340
341 match &config.hse {
342 Some(hse) => {
343 rcc.cr().modify(|w| {
344 w.set_hsepre(hse.prediv.into());
345 w.set_hseon(true);
346 });
347
348 while !rcc.cr().read().hserdy() {}
349 }
350 _ => {}
351 }
352
353 match &config.mux {
354 Some(pll_mux) => {
355 rcc.pllcfgr().modify(|w| {
356 w.set_pllm(pll_mux.prediv);
357 w.set_pllsrc(pll_mux.source.into());
358 });
359 }
360 _ => {}
361 };
362
363 match &config.pll {
364 Some(pll) => {
365 rcc.pllcfgr().modify(|w| {
366 w.set_plln((pll.mul - 1) as u8);
367 pll.divp.map(|divp| {
368 w.set_pllpen(true);
369 w.set_pllp((divp - 1) as u8)
370 });
371 pll.divq.map(|divq| {
372 w.set_pllqen(true);
373 w.set_pllq((divq - 1) as u8)
374 });
375 pll.divr.map(|divr| w.set_pllr((divr - 1) as u8));
376 });
377
378 rcc.cr().modify(|w| w.set_pllon(true));
379
380 while !rcc.cr().read().pllrdy() {}
381 }
382 _ => {}
383 }
384
385 rcc.cfgr().modify(|w| {
386 w.set_sw(config.sys.into());
387 w.set_hpre(config.ahb1_pre.into());
388 w.set_ppre1(config.apb1_pre.into());
389 w.set_ppre2(config.apb2_pre.into());
390
391 w.set_ppre1(config.apb1_pre.into());
392 w.set_ppre2(config.apb2_pre.into());
393 });
394
395 rcc.extcfgr().modify(|w| {
396 w.set_c2hpre(config.ahb2_pre.into());
397 w.set_shdhpre(config.ahb3_pre.into());
168 }); 398 });
169} 399}