aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-03-03 23:18:29 +0100
committerDario Nieuwenhuis <[email protected]>2024-03-04 00:04:06 +0100
commitb4567bb8c56dced1c64177d727ebb32ee4680ea3 (patch)
tree65d711269e363415b41c2229610d96025f00e359
parent20760ff4f7dcbca8b1654957462df4551883932d (diff)
stm32/rcc: g4: consistent PllSource, add pll pqr limits, simplify a bit.
-rw-r--r--embassy-stm32/src/rcc/g4.rs218
-rw-r--r--examples/stm32g4/src/bin/adc.rs2
-rw-r--r--examples/stm32g4/src/bin/can.rs2
-rw-r--r--examples/stm32g4/src/bin/pll.rs29
-rw-r--r--examples/stm32g4/src/bin/usb_serial.rs2
-rw-r--r--tests/stm32/src/common.rs2
6 files changed, 129 insertions, 126 deletions
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index 79bdbeb77..cd2d2a8a2 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -1,12 +1,9 @@
1use stm32_metapac::flash::vals::Latency; 1use crate::pac::flash::vals::Latency;
2use stm32_metapac::rcc::vals::Sw;
3use stm32_metapac::FLASH;
4
5pub use crate::pac::rcc::vals::{ 2pub use crate::pac::rcc::vals::{
6 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, 3 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv,
7 Ppre as APBPrescaler, Sw as Sysclk, 4 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
8}; 5};
9use crate::pac::{PWR, RCC}; 6use crate::pac::{FLASH, PWR, RCC};
10use crate::time::Hertz; 7use crate::time::Hertz;
11 8
12/// HSI speed 9/// HSI speed
@@ -37,7 +34,7 @@ pub struct Hse {
37/// frequency ranges for each of these settings. 34/// frequency ranges for each of these settings.
38pub struct Pll { 35pub struct Pll {
39 /// PLL Source clock selection. 36 /// PLL Source clock selection.
40 pub source: Pllsrc, 37 pub source: PllSource,
41 38
42 /// PLL pre-divider 39 /// PLL pre-divider
43 pub prediv: PllPreDiv, 40 pub prediv: PllPreDiv,
@@ -73,7 +70,7 @@ pub struct Config {
73 /// PLL Configuration 70 /// PLL Configuration
74 pub pll: Option<Pll>, 71 pub pll: Option<Pll>,
75 72
76 /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration 73 /// If PLL is requested as the main clock source in the `sys` field then the PLL configuration
77 /// MUST turn on the PLLR output. 74 /// MUST turn on the PLLR output.
78 pub ahb_pre: AHBPrescaler, 75 pub ahb_pre: AHBPrescaler,
79 pub apb1_pre: APBPrescaler, 76 pub apb1_pre: APBPrescaler,
@@ -112,6 +109,7 @@ impl Default for Config {
112 } 109 }
113} 110}
114 111
112#[derive(Default)]
115pub struct PllFreq { 113pub struct PllFreq {
116 pub pll_p: Option<Hertz>, 114 pub pll_p: Option<Hertz>,
117 pub pll_q: Option<Hertz>, 115 pub pll_q: Option<Hertz>,
@@ -154,91 +152,91 @@ pub(crate) unsafe fn init(config: Config) {
154 // Configure HSI48 if required 152 // Configure HSI48 if required
155 let hsi48 = config.hsi48.map(super::init_hsi48); 153 let hsi48 = config.hsi48.map(super::init_hsi48);
156 154
157 let pll_freq = config.pll.map(|pll_config| { 155 let pll = config
158 let src_freq = match pll_config.source { 156 .pll
159 Pllsrc::HSI => unwrap!(hsi), 157 .map(|pll_config| {
160 Pllsrc::HSE => unwrap!(hse), 158 let src_freq = match pll_config.source {
161 _ => unreachable!(), 159 PllSource::HSI => unwrap!(hsi),
162 }; 160 PllSource::HSE => unwrap!(hse),
163 161 _ => unreachable!(),
164 // Disable PLL before configuration 162 };
165 RCC.cr().modify(|w| w.set_pllon(false)); 163
166 while RCC.cr().read().pllrdy() {} 164 // Disable PLL before configuration
167 165 RCC.cr().modify(|w| w.set_pllon(false));
168 let in_freq = src_freq / pll_config.prediv; 166 while RCC.cr().read().pllrdy() {}
169 assert!(max::PLL_IN.contains(&in_freq)); 167
170 let internal_freq = in_freq * pll_config.mul; 168 let in_freq = src_freq / pll_config.prediv;
171 169 assert!(max::PLL_IN.contains(&in_freq));
172 assert!(max::PLL_VCO.contains(&internal_freq)); 170 let internal_freq = in_freq * pll_config.mul;
173 171
174 RCC.pllcfgr().write(|w| { 172 assert!(max::PLL_VCO.contains(&internal_freq));
175 w.set_plln(pll_config.mul); 173
176 w.set_pllm(pll_config.prediv); 174 RCC.pllcfgr().write(|w| {
177 w.set_pllsrc(pll_config.source.into()); 175 w.set_plln(pll_config.mul);
178 }); 176 w.set_pllm(pll_config.prediv);
179 177 w.set_pllsrc(pll_config.source.into());
180 let pll_p_freq = pll_config.divp.map(|div_p| {
181 RCC.pllcfgr().modify(|w| {
182 w.set_pllp(div_p);
183 w.set_pllpen(true);
184 }); 178 });
185 let freq = internal_freq / div_p; 179
186 assert!(max::PCLK.contains(&freq)); 180 let pll_p_freq = pll_config.divp.map(|div_p| {
187 freq 181 RCC.pllcfgr().modify(|w| {
188 }); 182 w.set_pllp(div_p);
189 183 w.set_pllpen(true);
190 let pll_q_freq = pll_config.divq.map(|div_q| { 184 });
191 RCC.pllcfgr().modify(|w| { 185 let freq = internal_freq / div_p;
192 w.set_pllq(div_q); 186 assert!(max::PLL_P.contains(&freq));
193 w.set_pllqen(true); 187 freq
194 }); 188 });
195 let freq = internal_freq / div_q; 189
196 assert!(max::PCLK.contains(&freq)); 190 let pll_q_freq = pll_config.divq.map(|div_q| {
197 freq 191 RCC.pllcfgr().modify(|w| {
198 }); 192 w.set_pllq(div_q);
199 193 w.set_pllqen(true);
200 let pll_r_freq = pll_config.divr.map(|div_r| { 194 });
201 RCC.pllcfgr().modify(|w| { 195 let freq = internal_freq / div_q;
202 w.set_pllr(div_r); 196 assert!(max::PLL_Q.contains(&freq));
203 w.set_pllren(true); 197 freq
204 }); 198 });
205 let freq = internal_freq / div_r;
206 assert!(max::PCLK.contains(&freq));
207 freq
208 });
209
210 // Enable the PLL
211 RCC.cr().modify(|w| w.set_pllon(true));
212 while !RCC.cr().read().pllrdy() {}
213
214 PllFreq {
215 pll_p: pll_p_freq,
216 pll_q: pll_q_freq,
217 pll_r: pll_r_freq,
218 }
219 });
220 199
221 let (sys_clk, sw) = match config.sys { 200 let pll_r_freq = pll_config.divr.map(|div_r| {
222 Sysclk::HSI => (HSI_FREQ, Sw::HSI), 201 RCC.pllcfgr().modify(|w| {
223 Sysclk::HSE => (unwrap!(hse), Sw::HSE), 202 w.set_pllr(div_r);
224 Sysclk::PLL1_R => { 203 w.set_pllren(true);
225 assert!(pll_freq.is_some()); 204 });
226 assert!(pll_freq.as_ref().unwrap().pll_r.is_some()); 205 let freq = internal_freq / div_r;
206 assert!(max::PLL_R.contains(&freq));
207 freq
208 });
227 209
228 let freq = pll_freq.as_ref().unwrap().pll_r.unwrap().0; 210 // Enable the PLL
211 RCC.cr().modify(|w| w.set_pllon(true));
212 while !RCC.cr().read().pllrdy() {}
229 213
230 assert!(max::SYSCLK.contains(&Hertz(freq))); 214 PllFreq {
215 pll_p: pll_p_freq,
216 pll_q: pll_q_freq,
217 pll_r: pll_r_freq,
218 }
219 })
220 .unwrap_or_default();
231 221
232 (Hertz(freq), Sw::PLL1_R) 222 let sys = match config.sys {
233 } 223 Sysclk::HSI => unwrap!(hsi),
224 Sysclk::HSE => unwrap!(hse),
225 Sysclk::PLL1_R => unwrap!(pll.pll_r),
234 _ => unreachable!(), 226 _ => unreachable!(),
235 }; 227 };
236 228
237 // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. 229 assert!(max::SYSCLK.contains(&sys));
238 let hclk = sys_clk / config.ahb_pre;
239 230
231 // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency.
232 let hclk = sys / config.ahb_pre;
240 assert!(max::HCLK.contains(&hclk)); 233 assert!(max::HCLK.contains(&hclk));
241 234
235 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
236 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre);
237 assert!(max::PCLK.contains(&pclk2));
238 assert!(max::PCLK.contains(&pclk2));
239
242 // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!) 240 // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!)
243 if config.boost { 241 if config.boost {
244 // RM0440 p235 242 // RM0440 p235
@@ -253,23 +251,28 @@ pub(crate) unsafe fn init(config: Config) {
253 // 4. Configure and switch to new frequency 251 // 4. Configure and switch to new frequency
254 } 252 }
255 253
254 let latency = match (config.boost, hclk.0) {
255 (true, ..=34_000_000) => Latency::WS0,
256 (true, ..=68_000_000) => Latency::WS1,
257 (true, ..=102_000_000) => Latency::WS2,
258 (true, ..=136_000_000) => Latency::WS3,
259 (true, _) => Latency::WS4,
260
261 (false, ..=36_000_000) => Latency::WS0,
262 (false, ..=60_000_000) => Latency::WS1,
263 (false, ..=90_000_000) => Latency::WS2,
264 (false, ..=120_000_000) => Latency::WS3,
265 (false, _) => Latency::WS4,
266 };
267
256 // Configure flash read access latency based on boost mode and frequency (RM0440 p98) 268 // Configure flash read access latency based on boost mode and frequency (RM0440 p98)
257 FLASH.acr().modify(|w| { 269 FLASH.acr().modify(|w| {
258 w.set_latency(match (config.boost, hclk.0) { 270 w.set_latency(latency);
259 (true, ..=34_000_000) => Latency::WS0,
260 (true, ..=68_000_000) => Latency::WS1,
261 (true, ..=102_000_000) => Latency::WS2,
262 (true, ..=136_000_000) => Latency::WS3,
263 (true, _) => Latency::WS4,
264
265 (false, ..=36_000_000) => Latency::WS0,
266 (false, ..=60_000_000) => Latency::WS1,
267 (false, ..=90_000_000) => Latency::WS2,
268 (false, ..=120_000_000) => Latency::WS3,
269 (false, _) => Latency::WS4,
270 })
271 }); 271 });
272 272
273 // Spin until the effective flash latency is set.
274 while FLASH.acr().read().latency() != latency {}
275
273 if config.boost { 276 if config.boost {
274 // 5. Wait for at least 1us and then reconfigure the AHB prescaler to get the needed HCLK clock frequency. 277 // 5. Wait for at least 1us and then reconfigure the AHB prescaler to get the needed HCLK clock frequency.
275 cortex_m::asm::delay(16); 278 cortex_m::asm::delay(16);
@@ -277,17 +280,14 @@ pub(crate) unsafe fn init(config: Config) {
277 280
278 // Now that boost mode and flash read access latency are configured, set up SYSCLK 281 // Now that boost mode and flash read access latency are configured, set up SYSCLK
279 RCC.cfgr().modify(|w| { 282 RCC.cfgr().modify(|w| {
280 w.set_sw(sw); 283 w.set_sw(config.sys);
281 w.set_hpre(config.ahb_pre); 284 w.set_hpre(config.ahb_pre);
282 w.set_ppre1(config.apb1_pre); 285 w.set_ppre1(config.apb1_pre);
283 w.set_ppre2(config.apb2_pre); 286 w.set_ppre2(config.apb2_pre);
284 }); 287 });
285 288
286 let (apb1_freq, apb1_tim_freq) = super::util::calc_pclk(hclk, config.apb1_pre);
287 let (apb2_freq, apb2_tim_freq) = super::util::calc_pclk(hclk, config.apb2_pre);
288
289 if config.low_power_run { 289 if config.low_power_run {
290 assert!(sys_clk <= Hertz(2_000_000)); 290 assert!(sys <= Hertz(2_000_000));
291 PWR.cr1().modify(|w| w.set_lpr(true)); 291 PWR.cr1().modify(|w| w.set_lpr(true));
292 } 292 }
293 293
@@ -296,17 +296,18 @@ pub(crate) unsafe fn init(config: Config) {
296 config.mux.init(); 296 config.mux.init();
297 297
298 set_clocks!( 298 set_clocks!(
299 sys: Some(sys_clk), 299 sys: Some(sys),
300 hclk1: Some(hclk), 300 hclk1: Some(hclk),
301 hclk2: Some(hclk), 301 hclk2: Some(hclk),
302 hclk3: Some(hclk), 302 hclk3: Some(hclk),
303 pclk1: Some(apb1_freq), 303 pclk1: Some(pclk1),
304 pclk1_tim: Some(apb1_tim_freq), 304 pclk1_tim: Some(pclk1_tim),
305 pclk2: Some(apb2_freq), 305 pclk2: Some(pclk2),
306 pclk2_tim: Some(apb2_tim_freq), 306 pclk2_tim: Some(pclk2_tim),
307 pll1_p: pll_freq.as_ref().and_then(|pll| pll.pll_p), 307 pll1_p: pll.pll_p,
308 pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_q), 308 pll1_q: pll.pll_q,
309 pll1_r: pll_freq.as_ref().and_then(|pll| pll.pll_r), 309 pll1_r: pll.pll_r,
310 hsi: hsi,
310 hse: hse, 311 hse: hse,
311 hsi48: hsi48, 312 hsi48: hsi48,
312 rtc: rtc, 313 rtc: rtc,
@@ -342,4 +343,7 @@ mod max {
342 343
343 /// PLL VCO (internal) Frequency Range (STM32G474 Datasheet p123, Table 46) 344 /// PLL VCO (internal) Frequency Range (STM32G474 Datasheet p123, Table 46)
344 pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(96_000_000)..=Hertz(344_000_000); 345 pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(96_000_000)..=Hertz(344_000_000);
346 pub(crate) const PLL_P: RangeInclusive<Hertz> = Hertz(2_064_500)..=Hertz(170_000_000);
347 pub(crate) const PLL_Q: RangeInclusive<Hertz> = Hertz(8_000_000)..=Hertz(170_000_000);
348 pub(crate) const PLL_R: RangeInclusive<Hertz> = Hertz(8_000_000)..=Hertz(170_000_000);
345} 349}
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
index f81335f93..ae64bc8e4 100644
--- a/examples/stm32g4/src/bin/adc.rs
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
14 { 14 {
15 use embassy_stm32::rcc::*; 15 use embassy_stm32::rcc::*;
16 config.rcc.pll = Some(Pll { 16 config.rcc.pll = Some(Pll {
17 source: Pllsrc::HSI, 17 source: PllSource::HSI,
18 prediv: PllPreDiv::DIV4, 18 prediv: PllPreDiv::DIV4,
19 mul: PllMul::MUL85, 19 mul: PllMul::MUL85,
20 divp: None, 20 divp: None,
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs
index 93b206de8..4373a89a8 100644
--- a/examples/stm32g4/src/bin/can.rs
+++ b/examples/stm32g4/src/bin/can.rs
@@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
24 mode: HseMode::Oscillator, 24 mode: HseMode::Oscillator,
25 }); 25 });
26 config.rcc.pll = Some(Pll { 26 config.rcc.pll = Some(Pll {
27 source: Pllsrc::HSE, 27 source: PllSource::HSE,
28 prediv: PllPreDiv::DIV6, 28 prediv: PllPreDiv::DIV6,
29 mul: PllMul::MUL85, 29 mul: PllMul::MUL85,
30 divp: None, 30 divp: None,
diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs
index 2609abfa2..08ed95b34 100644
--- a/examples/stm32g4/src/bin/pll.rs
+++ b/examples/stm32g4/src/bin/pll.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllRDiv, Pllsrc, Sysclk};
7use embassy_stm32::Config; 6use embassy_stm32::Config;
8use embassy_time::Timer; 7use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
@@ -11,20 +10,20 @@ use {defmt_rtt as _, panic_probe as _};
11#[embassy_executor::main] 10#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 11async fn main(_spawner: Spawner) {
13 let mut config = Config::default(); 12 let mut config = Config::default();
14 13 {
15 config.rcc.hsi = true; 14 use embassy_stm32::rcc::*;
16 config.rcc.pll = Some(Pll { 15 config.rcc.hsi = true;
17 source: Pllsrc::HSI, 16 config.rcc.pll = Some(Pll {
18 prediv: PllPreDiv::DIV4, 17 source: PllSource::HSI,
19 mul: PllMul::MUL85, 18 prediv: PllPreDiv::DIV4,
20 divp: None, 19 mul: PllMul::MUL85,
21 divq: None, 20 divp: None,
22 // Main system clock at 170 MHz 21 divq: None,
23 divr: Some(PllRDiv::DIV2), 22 // Main system clock at 170 MHz
24 }); 23 divr: Some(PllRDiv::DIV2),
25 24 });
26 config.rcc.sys = Sysclk::PLL1_R; 25 config.rcc.sys = Sysclk::PLL1_R;
27 26 }
28 let _p = embassy_stm32::init(config); 27 let _p = embassy_stm32::init(config);
29 info!("Hello World!"); 28 info!("Hello World!");
30 29
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index 90caaae14..dc95aa6e5 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
28 mode: HseMode::Oscillator, 28 mode: HseMode::Oscillator,
29 }); 29 });
30 config.rcc.pll = Some(Pll { 30 config.rcc.pll = Some(Pll {
31 source: Pllsrc::HSE, 31 source: PllSource::HSE,
32 prediv: PllPreDiv::DIV2, 32 prediv: PllPreDiv::DIV2,
33 mul: PllMul::MUL72, 33 mul: PllMul::MUL72,
34 divp: None, 34 divp: None,
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index cf3e04a4b..c3f39c04f 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -456,7 +456,7 @@ pub fn config() -> Config {
456 mode: HseMode::Oscillator, 456 mode: HseMode::Oscillator,
457 }); 457 });
458 config.rcc.pll = Some(Pll { 458 config.rcc.pll = Some(Pll {
459 source: Pllsrc::HSE, 459 source: PllSource::HSE,
460 prediv: PllPreDiv::DIV6, 460 prediv: PllPreDiv::DIV6,
461 mul: PllMul::MUL85, 461 mul: PllMul::MUL85,
462 divp: None, 462 divp: None,