aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/rcc/g0.rs285
1 files changed, 280 insertions, 5 deletions
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index ad5a661d6..be0497290 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -1,5 +1,6 @@
1use crate::pac::rcc::vals::{Hpre, Hsidiv, Ppre, Sw}; 1use crate::pac::flash::vals::Latency;
2use crate::pac::{PWR, RCC}; 2use crate::pac::rcc::vals::{self, Hpre, Hsidiv, Ppre, Sw};
3use crate::pac::{FLASH, PWR, RCC};
3use crate::rcc::{set_freqs, Clocks}; 4use crate::rcc::{set_freqs, Clocks};
4use crate::time::Hertz; 5use crate::time::Hertz;
5use crate::time::U32Ext; 6use crate::time::U32Ext;
@@ -15,6 +16,7 @@ pub const LSI_FREQ: u32 = 32_000;
15pub enum ClockSrc { 16pub enum ClockSrc {
16 HSE(Hertz), 17 HSE(Hertz),
17 HSI16(HSI16Prescaler), 18 HSI16(HSI16Prescaler),
19 PLL(PllConfig),
18 LSI, 20 LSI,
19} 21}
20 22
@@ -45,6 +47,132 @@ impl Into<Hsidiv> for HSI16Prescaler {
45 } 47 }
46} 48}
47 49
50/// The PLL configuration.
51///
52/// * `VCOCLK = source / m * n`
53/// * `PLLRCLK = VCOCLK / r`
54/// * `PLLQCLK = VCOCLK / q`
55/// * `PLLPCLK = VCOCLK / p`
56#[derive(Clone, Copy)]
57pub struct PllConfig {
58 /// The source from which the PLL receives a clock signal
59 pub source: PllSrc,
60 /// The initial divisor of that clock signal
61 pub m: Pllm,
62 /// The PLL VCO multiplier, which must be in the range `8..=86`.
63 pub n: u8,
64 /// The final divisor for `PLLRCLK` output which drives the system clock
65 pub r: Pllr,
66
67 /// The divisor for the `PLLQCLK` output, if desired
68 pub q: Option<Pllr>,
69
70 /// The divisor for the `PLLPCLK` output, if desired
71 pub p: Option<Pllr>,
72}
73
74impl Default for PllConfig {
75 #[inline]
76 fn default() -> PllConfig {
77 // HSI16 / 1 * 8 / 2 = 64 MHz
78 PllConfig {
79 source: PllSrc::HSI16,
80 m: Pllm::Div1,
81 n: 8,
82 r: Pllr::Div2,
83 q: None,
84 p: None,
85 }
86 }
87}
88
89#[derive(Clone, Copy, Eq, PartialEq)]
90pub enum PllSrc {
91 HSI16,
92 HSE(Hertz),
93}
94
95#[derive(Clone, Copy)]
96pub enum Pllm {
97 Div1,
98 Div2,
99 Div3,
100 Div4,
101 Div5,
102 Div6,
103 Div7,
104 Div8,
105}
106
107impl From<Pllm> for u8 {
108 fn from(v: Pllm) -> Self {
109 match v {
110 Pllm::Div1 => 0b000,
111 Pllm::Div2 => 0b001,
112 Pllm::Div3 => 0b010,
113 Pllm::Div4 => 0b011,
114 Pllm::Div5 => 0b100,
115 Pllm::Div6 => 0b101,
116 Pllm::Div7 => 0b110,
117 Pllm::Div8 => 0b111,
118 }
119 }
120}
121
122impl From<Pllm> for u32 {
123 fn from(v: Pllm) -> Self {
124 match v {
125 Pllm::Div1 => 1,
126 Pllm::Div2 => 2,
127 Pllm::Div3 => 3,
128 Pllm::Div4 => 4,
129 Pllm::Div5 => 5,
130 Pllm::Div6 => 6,
131 Pllm::Div7 => 7,
132 Pllm::Div8 => 8,
133 }
134 }
135}
136
137#[derive(Clone, Copy)]
138pub enum Pllr {
139 Div2,
140 Div3,
141 Div4,
142 Div5,
143 Div6,
144 Div7,
145 Div8,
146}
147
148impl From<Pllr> for u8 {
149 fn from(v: Pllr) -> Self {
150 match v {
151 Pllr::Div2 => 0b000,
152 Pllr::Div3 => 0b001,
153 Pllr::Div4 => 0b010,
154 Pllr::Div5 => 0b011,
155 Pllr::Div6 => 0b101,
156 Pllr::Div7 => 0b110,
157 Pllr::Div8 => 0b111,
158 }
159 }
160}
161
162impl From<Pllr> for u32 {
163 fn from(v: Pllr) -> Self {
164 match v {
165 Pllr::Div2 => 2,
166 Pllr::Div3 => 3,
167 Pllr::Div4 => 4,
168 Pllr::Div5 => 5,
169 Pllr::Div6 => 6,
170 Pllr::Div7 => 7,
171 Pllr::Div8 => 8,
172 }
173 }
174}
175
48/// AHB prescaler 176/// AHB prescaler
49#[derive(Clone, Copy, PartialEq)] 177#[derive(Clone, Copy, PartialEq)]
50pub enum AHBPrescaler { 178pub enum AHBPrescaler {
@@ -117,6 +245,95 @@ impl Default for Config {
117 } 245 }
118} 246}
119 247
248impl PllConfig {
249 pub(crate) unsafe fn init(self) -> u32 {
250 assert!(self.n >= 8 && self.n <= 86);
251 let (src, input_freq) = match self.source {
252 PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ),
253 PllSrc::HSE(freq) => (vals::Pllsrc::HSE, freq.0),
254 };
255
256 let m_freq = input_freq / u32::from(self.m);
257 // RM0454 § 5.4.4:
258 // > Caution: The software must set these bits so that the PLL input frequency after the
259 // > /M divider is between 2.66 and 16 MHz.
260 debug_assert!(m_freq >= 2_660_000 && m_freq <= 16_000_000);
261
262 let n_freq = m_freq * self.n as u32;
263 // RM0454 § 5.4.4:
264 // > Caution: The software must set these bits so that the VCO output frequency is between
265 // > 64 and 344 MHz.
266 debug_assert!(n_freq >= 64_000_000 && n_freq <= 344_000_000);
267
268 let r_freq = n_freq / u32::from(self.r);
269 // RM0454 § 5.4.4:
270 // > Caution: The software must set this bitfield so as not to exceed 64 MHz on this clock.
271 debug_assert!(r_freq <= 64_000_000);
272
273 // RM0454 § 5.2.3:
274 // > To modify the PLL configuration, proceed as follows:
275 // > 1. Disable the PLL by setting PLLON to 0 in Clock control register (RCC_CR).
276 RCC.cr().modify(|w| w.set_pllon(false));
277
278 // > 2. Wait until PLLRDY is cleared. The PLL is now fully stopped.
279 while RCC.cr().read().pllrdy() {}
280
281 // > 3. Change the desired parameter.
282 // Enable whichever clock source we're using, and wait for it to become ready
283 match self.source {
284 PllSrc::HSI16 => {
285 RCC.cr().write(|w| w.set_hsion(true));
286 while !RCC.cr().read().hsirdy() {}
287 }
288 PllSrc::HSE(_) => {
289 RCC.cr().write(|w| w.set_hseon(true));
290 while !RCC.cr().read().hserdy() {}
291 }
292 }
293
294 // Configure PLLSYSCFGR
295 RCC.pllsyscfgr().modify(|w| {
296 w.set_pllr(u8::from(self.r));
297 w.set_pllren(false);
298
299 if let Some(q) = self.q {
300 w.set_pllq(u8::from(q));
301 }
302 w.set_pllqen(false);
303
304 if let Some(p) = self.p {
305 w.set_pllp(u8::from(p));
306 }
307 w.set_pllpen(false);
308
309 w.set_plln(self.n);
310
311 w.set_pllm(self.m as u8);
312
313 w.set_pllsrc(src)
314 });
315
316 // > 4. Enable the PLL again by setting PLLON to 1.
317 RCC.cr().modify(|w| w.set_pllon(true));
318
319 // Wait for the PLL to become ready
320 while !RCC.cr().read().pllrdy() {}
321
322 // > 5. Enable the desired PLL outputs by configuring PLLPEN, PLLQEN, and PLLREN in PLL
323 // > configuration register (RCC_PLLCFGR).
324 RCC.pllsyscfgr().modify(|w| {
325 // We'll use R for system clock, so enable that unconditionally
326 w.set_pllren(true);
327
328 // We may also use Q or P
329 w.set_pllqen(self.q.is_some());
330 w.set_pllpen(self.p.is_some());
331 });
332
333 r_freq
334 }
335}
336
120pub(crate) unsafe fn init(config: Config) { 337pub(crate) unsafe fn init(config: Config) {
121 let (sys_clk, sw) = match config.mux { 338 let (sys_clk, sw) = match config.mux {
122 ClockSrc::HSI16(div) => { 339 ClockSrc::HSI16(div) => {
@@ -137,6 +354,10 @@ pub(crate) unsafe fn init(config: Config) {
137 354
138 (freq.0, Sw::HSE) 355 (freq.0, Sw::HSE)
139 } 356 }
357 ClockSrc::PLL(pll) => {
358 let freq = pll.init();
359 (freq, Sw::PLLRCLK)
360 }
140 ClockSrc::LSI => { 361 ClockSrc::LSI => {
141 // Enable LSI 362 // Enable LSI
142 RCC.csr().write(|w| w.set_lsion(true)); 363 RCC.csr().write(|w| w.set_lsion(true));
@@ -145,12 +366,66 @@ pub(crate) unsafe fn init(config: Config) {
145 } 366 }
146 }; 367 };
147 368
369 // Determine the flash latency implied by the target clock speed
370 // RM0454 § 3.3.4:
371 let target_flash_latency = if sys_clk <= 24_000_000 {
372 Latency::WS0
373 } else if sys_clk <= 48_000_000 {
374 Latency::WS1
375 } else {
376 Latency::WS2
377 };
378
379 // Increase the number of cycles we wait for flash if the new value is higher
380 // There's no harm in waiting a little too much before the clock change, but we'll
381 // crash immediately if we don't wait enough after the clock change
382 let mut set_flash_latency_after = false;
383 FLASH.acr().modify(|w| {
384 // Is the current flash latency less than what we need at the new SYSCLK?
385 if w.latency().0 <= target_flash_latency.0 {
386 // We must increase the number of wait states now
387 w.set_latency(target_flash_latency)
388 } else {
389 // We may decrease the number of wait states later
390 set_flash_latency_after = true;
391 }
392
393 // RM0454 § 3.3.5:
394 // > Prefetch is enabled by setting the PRFTEN bit of the FLASH access control register
395 // > (FLASH_ACR). This feature is useful if at least one wait state is needed to access the
396 // > Flash memory.
397 //
398 // Enable flash prefetching if we have at least one wait state, and disable it otherwise.
399 w.set_prften(target_flash_latency.0 > 0);
400 });
401
402 if !set_flash_latency_after {
403 // Spin until the effective flash latency is compatible with the clock change
404 while FLASH.acr().read().latency().0 < target_flash_latency.0 {}
405 }
406
407 // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
408 let (sw, hpre, ppre) = (sw.into(), config.ahb_pre.into(), config.apb_pre.into());
148 RCC.cfgr().modify(|w| { 409 RCC.cfgr().modify(|w| {
149 w.set_sw(sw.into()); 410 w.set_sw(sw);
150 w.set_hpre(config.ahb_pre.into()); 411 w.set_hpre(hpre);
151 w.set_ppre(config.apb_pre.into()); 412 w.set_ppre(ppre);
152 }); 413 });
153 414
415 if set_flash_latency_after {
416 // We can make the flash require fewer wait states
417 // Spin until the SYSCLK changes have taken effect
418 loop {
419 let cfgr = RCC.cfgr().read();
420 if cfgr.sw() == sw && cfgr.hpre() == hpre && cfgr.ppre() == ppre {
421 break;
422 }
423 }
424
425 // Set the flash latency to require fewer wait states
426 FLASH.acr().modify(|w| w.set_latency(target_flash_latency));
427 }
428
154 let ahb_div = match config.ahb_pre { 429 let ahb_div = match config.ahb_pre {
155 AHBPrescaler::NotDivided => 1, 430 AHBPrescaler::NotDivided => 1,
156 AHBPrescaler::Div2 => 2, 431 AHBPrescaler::Div2 => 2,