aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-02-23 00:37:20 +0000
committerGitHub <[email protected]>2024-02-23 00:37:20 +0000
commit2855bb69680a42a721fe88168657ea1e634e8766 (patch)
treebf0fb98be948566b5c3064a1e5392299f889d11e
parent4481c5f3ccf29da071538ef4f1e48fc5372a72a5 (diff)
parentd24349f57ce7435e70fcf1cd9aac20d1740995d4 (diff)
Merge pull request #2617 from embassy-rs/u5-rcc
stm32/rcc: port U5 to new API, add all PLLs, all HSE modes.
-rw-r--r--embassy-stm32/src/rcc/u5.rs627
-rw-r--r--examples/stm32u5/src/bin/usb_serial.rs27
-rw-r--r--tests/stm32/Cargo.toml2
-rw-r--r--tests/stm32/build.rs1
-rw-r--r--tests/stm32/src/common.rs13
5 files changed, 311 insertions, 359 deletions
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index 20cc3112a..72613f0f3 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -1,134 +1,83 @@
1pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange, Plldiv, Pllm, Plln, Ppre as APBPrescaler}; 1pub use crate::pac::pwr::vals::Vos as VoltageScale;
2use crate::pac::rcc::vals::{Msirgsel, Pllmboost, Pllrge, Pllsrc, Sw}; 2pub use crate::pac::rcc::vals::{
3 Hpre as AHBPrescaler, Msirange, Msirange as MSIRange, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul,
4 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as ClockSrc,
5};
6use crate::pac::rcc::vals::{Hseext, Msirgsel, Pllmboost, Pllrge};
3use crate::pac::{FLASH, PWR, RCC}; 7use crate::pac::{FLASH, PWR, RCC};
4use crate::time::Hertz; 8use crate::time::Hertz;
5 9
6/// HSI speed 10/// HSI speed
7pub const HSI_FREQ: Hertz = Hertz(16_000_000); 11pub const HSI_FREQ: Hertz = Hertz(16_000_000);
8 12
9pub use crate::pac::pwr::vals::Vos as VoltageScale; 13#[derive(Clone, Copy, Eq, PartialEq)]
10 14pub enum HseMode {
11#[derive(Copy, Clone)] 15 /// crystal/ceramic oscillator (HSEBYP=0)
12#[allow(non_camel_case_types)] 16 Oscillator,
13pub enum ClockSrc { 17 /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
14 /// Use an internal medium speed oscillator (MSIS) as the system clock. 18 Bypass,
15 MSI(Msirange), 19 /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
16 /// Use the external high speed clock as the system clock. 20 BypassDigital,
17 ///
18 /// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must
19 /// never exceed 50 MHz.
20 HSE(Hertz),
21 /// Use the 16 MHz internal high speed oscillator as the system clock.
22 HSI,
23 /// Use PLL1 as the system clock.
24 PLL1_R(PllConfig),
25} 21}
26 22
27impl Default for ClockSrc { 23#[derive(Clone, Copy, Eq, PartialEq)]
28 fn default() -> Self { 24pub struct Hse {
29 // The default system clock source is MSIS @ 4 MHz, per RM0456 § 11.4.9 25 /// HSE frequency.
30 ClockSrc::MSI(Msirange::RANGE_4MHZ) 26 pub freq: Hertz,
31 } 27 /// HSE mode.
28 pub mode: HseMode,
32} 29}
33 30
34#[derive(Clone, Copy)] 31#[derive(Clone, Copy)]
35pub struct PllConfig { 32pub struct Pll {
36 /// The clock source for the PLL. 33 /// The clock source for the PLL.
37 pub source: PllSource, 34 pub source: PllSource,
38 /// The PLL prescaler. 35 /// The PLL pre-divider.
39 /// 36 ///
40 /// The clock speed of the `source` divided by `m` must be between 4 and 16 MHz. 37 /// The clock speed of the `source` divided by `m` must be between 4 and 16 MHz.
41 pub m: Pllm, 38 pub prediv: PllPreDiv,
42 /// The PLL multiplier. 39 /// The PLL multiplier.
43 /// 40 ///
44 /// The multiplied clock – `source` divided by `m` times `n` – must be between 128 and 544 41 /// The multiplied clock – `source` divided by `m` times `n` – must be between 128 and 544
45 /// MHz. The upper limit may be lower depending on the `Config { voltage_range }`. 42 /// MHz. The upper limit may be lower depending on the `Config { voltage_range }`.
46 pub n: Plln, 43 pub mul: PllMul,
47 /// The divider for the P output. 44 /// The divider for the P output.
48 /// 45 ///
49 /// The P output is one of several options 46 /// The P output is one of several options
50 /// that can be used to feed the SAI/MDF/ADF Clock mux's. 47 /// that can be used to feed the SAI/MDF/ADF Clock mux's.
51 pub p: Plldiv, 48 pub divp: Option<PllDiv>,
52 /// The divider for the Q output. 49 /// The divider for the Q output.
53 /// 50 ///
54 /// The Q ouput is one of severals options that can be used to feed the 48MHz clocks 51 /// The Q ouput is one of severals options that can be used to feed the 48MHz clocks
55 /// and the OCTOSPI clock. It may also be used on the MDF/ADF clock mux's. 52 /// and the OCTOSPI clock. It may also be used on the MDF/ADF clock mux's.
56 pub q: Plldiv, 53 pub divq: Option<PllDiv>,
57 /// The divider for the R output. 54 /// The divider for the R output.
58 /// 55 ///
59 /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r` 56 /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r`
60 /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default 57 /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default
61 /// `Config { voltage_range }`. 58 /// `Config { voltage_range }`.
62 pub r: Plldiv, 59 pub divr: Option<PllDiv>,
63}
64
65impl PllConfig {
66 /// A configuration for HSI / 1 * 10 / 1 = 160 MHz
67 pub const fn hsi_160mhz() -> Self {
68 PllConfig {
69 source: PllSource::HSI,
70 m: Pllm::DIV1,
71 n: Plln::MUL10,
72 p: Plldiv::DIV3,
73 q: Plldiv::DIV2,
74 r: Plldiv::DIV1,
75 }
76 }
77
78 /// A configuration for MSIS @ 48 MHz / 3 * 10 / 1 = 160 MHz
79 pub const fn msis_160mhz() -> Self {
80 PllConfig {
81 source: PllSource::MSIS(Msirange::RANGE_48MHZ),
82 m: Pllm::DIV3,
83 n: Plln::MUL10,
84 p: Plldiv::DIV3,
85 q: Plldiv::DIV2,
86 r: Plldiv::DIV1,
87 }
88 }
89}
90
91#[derive(Clone, Copy)]
92pub enum PllSource {
93 /// Use an internal medium speed oscillator as the PLL source.
94 MSIS(Msirange),
95 /// Use the external high speed clock as the system PLL source.
96 ///
97 /// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must
98 /// never exceed 50 MHz.
99 HSE(Hertz),
100 /// Use the 16 MHz internal high speed oscillator as the PLL source.
101 HSI,
102} 60}
103 61
104impl Into<Pllsrc> for PllSource { 62pub struct Config {
105 fn into(self) -> Pllsrc { 63 // base clock sources
106 match self { 64 pub msi: Option<MSIRange>,
107 PllSource::MSIS(..) => Pllsrc::MSIS, 65 pub hsi: bool,
108 PllSource::HSE(..) => Pllsrc::HSE, 66 pub hse: Option<Hse>,
109 PllSource::HSI => Pllsrc::HSI, 67 pub hsi48: Option<super::Hsi48Config>,
110 }
111 }
112}
113 68
114impl Into<Sw> for ClockSrc { 69 // pll
115 fn into(self) -> Sw { 70 pub pll1: Option<Pll>,
116 match self { 71 pub pll2: Option<Pll>,
117 ClockSrc::MSI(..) => Sw::MSIS, 72 pub pll3: Option<Pll>,
118 ClockSrc::HSE(..) => Sw::HSE,
119 ClockSrc::HSI => Sw::HSI,
120 ClockSrc::PLL1_R(..) => Sw::PLL1_R,
121 }
122 }
123}
124 73
125pub struct Config { 74 // sysclk, buses.
126 pub mux: ClockSrc, 75 pub mux: ClockSrc,
127 pub ahb_pre: AHBPrescaler, 76 pub ahb_pre: AHBPrescaler,
128 pub apb1_pre: APBPrescaler, 77 pub apb1_pre: APBPrescaler,
129 pub apb2_pre: APBPrescaler, 78 pub apb2_pre: APBPrescaler,
130 pub apb3_pre: APBPrescaler, 79 pub apb3_pre: APBPrescaler,
131 pub hsi48: Option<super::Hsi48Config>, 80
132 /// The voltage range influences the maximum clock frequencies for different parts of the 81 /// The voltage range influences the maximum clock frequencies for different parts of the
133 /// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks 82 /// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks
134 /// exceeding 55 MHz require at least `RANGE2`. 83 /// exceeding 55 MHz require at least `RANGE2`.
@@ -138,35 +87,35 @@ pub struct Config {
138 pub ls: super::LsConfig, 87 pub ls: super::LsConfig,
139} 88}
140 89
141impl Config { 90impl Default for Config {
142 unsafe fn init_hsi(&self) -> Hertz { 91 fn default() -> Self {
143 RCC.cr().write(|w| w.set_hsion(true)); 92 Self {
144 while !RCC.cr().read().hsirdy() {} 93 msi: Some(Msirange::RANGE_4MHZ),
145 94 hse: None,
146 HSI_FREQ 95 hsi: false,
147 } 96 hsi48: Some(Default::default()),
148 97 pll1: None,
149 unsafe fn init_hse(&self, frequency: Hertz) -> Hertz { 98 pll2: None,
150 // Check frequency limits per RM456 § 11.4.10 99 pll3: None,
151 match self.voltage_range { 100 mux: ClockSrc::MSIS,
152 VoltageScale::RANGE1 | VoltageScale::RANGE2 | VoltageScale::RANGE3 => { 101 ahb_pre: AHBPrescaler::DIV1,
153 assert!(frequency.0 <= 50_000_000); 102 apb1_pre: APBPrescaler::DIV1,
154 } 103 apb2_pre: APBPrescaler::DIV1,
155 VoltageScale::RANGE4 => { 104 apb3_pre: APBPrescaler::DIV1,
156 assert!(frequency.0 <= 25_000_000); 105 voltage_range: VoltageScale::RANGE1,
157 } 106 ls: Default::default(),
158 } 107 }
159
160 // Enable HSE, and wait for it to stabilize
161 RCC.cr().write(|w| w.set_hseon(true));
162 while !RCC.cr().read().hserdy() {}
163
164 frequency
165 } 108 }
109}
110
111pub(crate) unsafe fn init(config: Config) {
112 // Set the requested power mode
113 PWR.vosr().modify(|w| w.set_vos(config.voltage_range));
114 while !PWR.vosr().read().vosrdy() {}
166 115
167 unsafe fn init_msis(&self, range: Msirange) -> Hertz { 116 let msi = config.msi.map(|range| {
168 // Check MSI output per RM0456 § 11.4.10 117 // Check MSI output per RM0456 § 11.4.10
169 match self.voltage_range { 118 match config.voltage_range {
170 VoltageScale::RANGE4 => { 119 VoltageScale::RANGE4 => {
171 assert!(msirange_to_hertz(range).0 <= 24_000_000); 120 assert!(msirange_to_hertz(range).0 <= 24_000_000);
172 } 121 }
@@ -191,223 +140,98 @@ impl Config {
191 }); 140 });
192 while !RCC.cr().read().msisrdy() {} 141 while !RCC.cr().read().msisrdy() {}
193 msirange_to_hertz(range) 142 msirange_to_hertz(range)
194 }
195}
196
197impl Default for Config {
198 fn default() -> Self {
199 Self {
200 mux: ClockSrc::default(),
201 ahb_pre: AHBPrescaler::DIV1,
202 apb1_pre: APBPrescaler::DIV1,
203 apb2_pre: APBPrescaler::DIV1,
204 apb3_pre: APBPrescaler::DIV1,
205 hsi48: Some(Default::default()),
206 voltage_range: VoltageScale::RANGE3,
207 ls: Default::default(),
208 }
209 }
210}
211
212pub(crate) unsafe fn init(config: Config) {
213 // Ensure PWR peripheral clock is enabled
214 RCC.ahb3enr().modify(|w| {
215 w.set_pwren(true);
216 }); 143 });
217 RCC.ahb3enr().read(); // synchronize
218 144
219 // Set the requested power mode 145 let hsi = config.hsi.then(|| {
220 PWR.vosr().modify(|w| { 146 RCC.cr().write(|w| w.set_hsion(true));
221 w.set_vos(config.voltage_range); 147 while !RCC.cr().read().hsirdy() {}
148
149 HSI_FREQ
222 }); 150 });
223 while !PWR.vosr().read().vosrdy() {}
224 151
225 let sys_clk = match config.mux { 152 let hse = config.hse.map(|hse| {
226 ClockSrc::MSI(range) => config.init_msis(range), 153 // Check frequency limits per RM456 § 11.4.10
227 ClockSrc::HSE(freq) => config.init_hse(freq), 154 match config.voltage_range {
228 ClockSrc::HSI => config.init_hsi(), 155 VoltageScale::RANGE1 | VoltageScale::RANGE2 | VoltageScale::RANGE3 => {
229 ClockSrc::PLL1_R(pll) => { 156 assert!(hse.freq.0 <= 50_000_000);
230 // Configure the PLL source
231 let source_clk = match pll.source {
232 PllSource::MSIS(range) => config.init_msis(range),
233 PllSource::HSE(hertz) => config.init_hse(hertz),
234 PllSource::HSI => config.init_hsi(),
235 };
236
237 // Calculate the reference clock, which is the source divided by m
238 let reference_clk = source_clk / pll.m;
239
240 // Check limits per RM0456 § 11.4.6
241 assert!(Hertz::mhz(4) <= reference_clk && reference_clk <= Hertz::mhz(16));
242
243 // Calculate the PLL1 VCO clock and PLL1 R output clock
244 let pll1_clk = reference_clk * pll.n;
245 let pll1r_clk = pll1_clk / pll.r;
246
247 // Check system clock per RM0456 § 11.4.9
248 assert!(pll1r_clk <= Hertz::mhz(160));
249
250 // Check PLL clocks per RM0456 § 11.4.10
251 match config.voltage_range {
252 VoltageScale::RANGE1 => {
253 assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544));
254 assert!(pll1r_clk <= Hertz::mhz(208));
255 }
256 VoltageScale::RANGE2 => {
257 assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544));
258 assert!(pll1r_clk <= Hertz::mhz(110));
259 }
260 VoltageScale::RANGE3 => {
261 assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(330));
262 assert!(pll1r_clk <= Hertz::mhz(55));
263 }
264 VoltageScale::RANGE4 => {
265 panic!("PLL is unavailable in voltage range 4");
266 }
267 } 157 }
158 VoltageScale::RANGE4 => {
159 assert!(hse.freq.0 <= 25_000_000);
160 }
161 }
268 162
269 // § 10.5.4: if we're targeting >= 55 MHz, we must configure PLL1MBOOST to a prescaler 163 // Enable HSE, and wait for it to stabilize
270 // value that results in an output between 4 and 16 MHz for the PWR EPOD boost 164 RCC.cr().write(|w| {
271 let mboost = if pll1r_clk >= Hertz::mhz(55) { 165 w.set_hseon(true);
272 // source_clk can be up to 50 MHz, so there's just a few cases: 166 w.set_hsebyp(hse.mode != HseMode::Oscillator);
273 if source_clk > Hertz::mhz(32) { 167 w.set_hseext(match hse.mode {
274 // Divide by 4, giving EPOD 8-12.5 MHz 168 HseMode::Oscillator | HseMode::Bypass => Hseext::ANALOG,
275 Pllmboost::DIV4 169 HseMode::BypassDigital => Hseext::DIGITAL,
276 } else if source_clk > Hertz::mhz(16) {
277 // Divide by 2, giving EPOD 8-16 MHz
278 Pllmboost::DIV2
279 } else {
280 // Bypass, giving EPOD 4-16 MHz
281 Pllmboost::DIV1
282 }
283 } else {
284 // Nothing to do
285 Pllmboost::DIV1
286 };
287
288 // Disable the PLL, and wait for it to disable
289 RCC.cr().modify(|w| w.set_pllon(0, false));
290 while RCC.cr().read().pllrdy(0) {}
291
292 // Configure the PLL
293 RCC.pll1cfgr().write(|w| {
294 // Configure PLL1 source and prescaler
295 w.set_pllsrc(pll.source.into());
296 w.set_pllm(pll.m);
297
298 // Configure PLL1 input frequncy range
299 let input_range = if reference_clk <= Hertz::mhz(8) {
300 Pllrge::FREQ_4TO8MHZ
301 } else {
302 Pllrge::FREQ_8TO16MHZ
303 };
304 w.set_pllrge(input_range);
305
306 // Set the prescaler for PWR EPOD
307 w.set_pllmboost(mboost);
308
309 // Enable PLL1_R output
310 w.set_pllren(true);
311 }); 170 });
171 });
172 while !RCC.cr().read().hserdy() {}
312 173
313 // Configure the PLL divisors 174 hse.freq
314 RCC.pll1divr().modify(|w| { 175 });
315 // Set the VCO multiplier
316 w.set_plln(pll.n);
317 w.set_pllp(pll.p);
318 w.set_pllq(pll.q);
319 // Set the R output divisor
320 w.set_pllr(pll.r);
321 });
322 176
323 // Do we need the EPOD booster to reach the target clock speed per § 10.5.4? 177 let hsi48 = config.hsi48.map(super::init_hsi48);
324 if pll1r_clk >= Hertz::mhz(55) {
325 // Enable the booster
326 PWR.vosr().modify(|w| {
327 w.set_boosten(true);
328 });
329 while !PWR.vosr().read().boostrdy() {}
330 }
331 178
332 // Enable the PLL 179 let pll_input = PllInput { hse, hsi, msi };
333 RCC.cr().modify(|w| w.set_pllon(0, true)); 180 let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range);
334 while !RCC.cr().read().pllrdy(0) {} 181 let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range);
182 let pll3 = init_pll(PllInstance::Pll3, config.pll3, &pll_input, config.voltage_range);
335 183
336 pll1r_clk 184 let sys_clk = match config.mux {
337 } 185 ClockSrc::HSE => hse.unwrap(),
186 ClockSrc::HSI => hsi.unwrap(),
187 ClockSrc::MSIS => msi.unwrap(),
188 ClockSrc::PLL1_R => pll1.r.unwrap(),
338 }; 189 };
339 190
340 let hsi48 = config.hsi48.map(super::init_hsi48); 191 // Do we need the EPOD booster to reach the target clock speed per § 10.5.4?
192 if sys_clk >= Hertz::mhz(55) {
193 // Enable the booster
194 PWR.vosr().modify(|w| w.set_boosten(true));
195 while !PWR.vosr().read().boostrdy() {}
196 }
341 197
342 // The clock source is ready 198 // The clock source is ready
343 // Calculate and set the flash wait states 199 // Calculate and set the flash wait states
344 let wait_states = match config.voltage_range { 200 let wait_states = match config.voltage_range {
345 // VOS 1 range VCORE 1.26V - 1.40V 201 // VOS 1 range VCORE 1.26V - 1.40V
346 VoltageScale::RANGE1 => { 202 VoltageScale::RANGE1 => match sys_clk.0 {
347 if sys_clk.0 < 32_000_000 { 203 ..=32_000_000 => 0,
348 0 204 ..=64_000_000 => 1,
349 } else if sys_clk.0 < 64_000_000 { 205 ..=96_000_000 => 2,
350 1 206 ..=128_000_000 => 3,
351 } else if sys_clk.0 < 96_000_000 { 207 _ => 4,
352 2 208 },
353 } else if sys_clk.0 < 128_000_000 {
354 3
355 } else {
356 4
357 }
358 }
359 // VOS 2 range VCORE 1.15V - 1.26V 209 // VOS 2 range VCORE 1.15V - 1.26V
360 VoltageScale::RANGE2 => { 210 VoltageScale::RANGE2 => match sys_clk.0 {
361 if sys_clk.0 < 30_000_000 { 211 ..=30_000_000 => 0,
362 0 212 ..=60_000_000 => 1,
363 } else if sys_clk.0 < 60_000_000 { 213 ..=90_000_000 => 2,
364 1 214 _ => 3,
365 } else if sys_clk.0 < 90_000_000 { 215 },
366 2
367 } else {
368 3
369 }
370 }
371 // VOS 3 range VCORE 1.05V - 1.15V 216 // VOS 3 range VCORE 1.05V - 1.15V
372 VoltageScale::RANGE3 => { 217 VoltageScale::RANGE3 => match sys_clk.0 {
373 if sys_clk.0 < 24_000_000 { 218 ..=24_000_000 => 0,
374 0 219 ..=48_000_000 => 1,
375 } else if sys_clk.0 < 48_000_000 { 220 _ => 2,
376 1 221 },
377 } else {
378 2
379 }
380 }
381 // VOS 4 range VCORE 0.95V - 1.05V 222 // VOS 4 range VCORE 0.95V - 1.05V
382 VoltageScale::RANGE4 => { 223 VoltageScale::RANGE4 => match sys_clk.0 {
383 if sys_clk.0 < 12_000_000 { 224 ..=12_000_000 => 0,
384 0 225 _ => 1,
385 } else { 226 },
386 1
387 }
388 }
389 }; 227 };
390 FLASH.acr().modify(|w| { 228 FLASH.acr().modify(|w| {
391 w.set_latency(wait_states); 229 w.set_latency(wait_states);
392 }); 230 });
393 231
394 // Switch the system clock source 232 // Switch the system clock source
395 RCC.cfgr1().modify(|w| { 233 RCC.cfgr1().modify(|w| w.set_sw(config.mux));
396 w.set_sw(config.mux.into()); 234 while RCC.cfgr1().read().sws() != config.mux {}
397 });
398
399 // RM0456 § 11.4.9 specifies maximum bus frequencies per voltage range, but the maximum bus
400 // frequency for each voltage range exactly matches the maximum permitted PLL output frequency.
401 // Given that:
402 //
403 // 1. Any bus frequency can never exceed the system clock frequency;
404 // 2. We checked the PLL output frequency if we're using it as a system clock;
405 // 3. The maximum HSE frequencies at each voltage range are lower than the bus limits, and
406 // we checked the HSE frequency if configured as a system clock; and
407 // 4. The maximum frequencies from the other clock sources are lower than the lowest bus
408 // frequency limit
409 //
410 // ...then we do not need to perform additional bus-related frequency checks.
411 235
412 // Configure the bus prescalers 236 // Configure the bus prescalers
413 RCC.cfgr2().modify(|w| { 237 RCC.cfgr2().modify(|w| {
@@ -419,64 +243,52 @@ pub(crate) unsafe fn init(config: Config) {
419 w.set_ppre3(config.apb3_pre); 243 w.set_ppre3(config.apb3_pre);
420 }); 244 });
421 245
422 let ahb_freq = sys_clk / config.ahb_pre; 246 let hclk = sys_clk / config.ahb_pre;
423
424 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
425 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
426 pre => {
427 let freq = ahb_freq / pre;
428 (freq, freq * 2u32)
429 }
430 };
431 247
432 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { 248 let hclk_max = match config.voltage_range {
433 APBPrescaler::DIV1 => (ahb_freq, ahb_freq), 249 VoltageScale::RANGE1 => Hertz::mhz(160),
434 pre => { 250 VoltageScale::RANGE2 => Hertz::mhz(110),
435 let freq = ahb_freq / pre; 251 VoltageScale::RANGE3 => Hertz::mhz(55),
436 (freq, freq * 2u32) 252 VoltageScale::RANGE4 => Hertz::mhz(25),
437 }
438 }; 253 };
254 assert!(hclk <= hclk_max);
439 255
440 let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre { 256 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
441 APBPrescaler::DIV1 => (ahb_freq, ahb_freq), 257 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre);
442 pre => { 258 let (pclk3, _) = super::util::calc_pclk(hclk, config.apb3_pre);
443 let freq = ahb_freq / pre;
444 (freq, freq * 2u32)
445 }
446 };
447 259
448 let rtc = config.ls.init(); 260 let rtc = config.ls.init();
449 261
450 set_clocks!( 262 set_clocks!(
451 sys: Some(sys_clk), 263 sys: Some(sys_clk),
452 hclk1: Some(ahb_freq), 264 hclk1: Some(hclk),
453 hclk2: Some(ahb_freq), 265 hclk2: Some(hclk),
454 hclk3: Some(ahb_freq), 266 hclk3: Some(hclk),
455 pclk1: Some(apb1_freq), 267 pclk1: Some(pclk1),
456 pclk2: Some(apb2_freq), 268 pclk2: Some(pclk2),
457 pclk3: Some(apb3_freq), 269 pclk3: Some(pclk3),
458 pclk1_tim: Some(apb1_tim_freq), 270 pclk1_tim: Some(pclk1_tim),
459 pclk2_tim: Some(apb2_tim_freq), 271 pclk2_tim: Some(pclk2_tim),
460 hsi48: hsi48, 272 hsi48: hsi48,
461 rtc: rtc, 273 rtc: rtc,
274 hse: hse,
275 hsi: hsi,
276 pll1_p: pll1.p,
277 pll1_q: pll1.q,
278 pll1_r: pll1.r,
279 pll2_p: pll2.p,
280 pll2_q: pll2.q,
281 pll2_r: pll2.r,
282 pll3_p: pll3.p,
283 pll3_q: pll3.q,
284 pll3_r: pll3.r,
462 285
463 // TODO 286 // TODO
464 hse: None,
465 hsi: None,
466 audioclk: None, 287 audioclk: None,
467 hsi48_div_2: None, 288 hsi48_div_2: None,
468 lse: None, 289 lse: None,
469 lsi: None, 290 lsi: None,
470 msik: None, 291 msik: None,
471 pll1_p: None,
472 pll1_q: None,
473 pll1_r: None,
474 pll2_p: None,
475 pll2_q: None,
476 pll2_r: None,
477 pll3_p: None,
478 pll3_q: None,
479 pll3_r: None,
480 iclk: None, 292 iclk: None,
481 ); 293 );
482} 294}
@@ -501,3 +313,126 @@ fn msirange_to_hertz(range: Msirange) -> Hertz {
501 Msirange::RANGE_100KHZ => Hertz(100_000), 313 Msirange::RANGE_100KHZ => Hertz(100_000),
502 } 314 }
503} 315}
316
317pub(super) struct PllInput {
318 pub hsi: Option<Hertz>,
319 pub hse: Option<Hertz>,
320 pub msi: Option<Hertz>,
321}
322
323#[allow(unused)]
324#[derive(Default)]
325pub(super) struct PllOutput {
326 pub p: Option<Hertz>,
327 pub q: Option<Hertz>,
328 pub r: Option<Hertz>,
329}
330
331#[derive(PartialEq, Eq, Clone, Copy)]
332enum PllInstance {
333 Pll1 = 0,
334 Pll2 = 1,
335 Pll3 = 2,
336}
337
338fn pll_enable(instance: PllInstance, enabled: bool) {
339 RCC.cr().modify(|w| w.set_pllon(instance as _, enabled));
340 while RCC.cr().read().pllrdy(instance as _) != enabled {}
341}
342
343fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput, voltage_range: VoltageScale) -> PllOutput {
344 // Disable PLL
345 pll_enable(instance, false);
346
347 let Some(pll) = config else { return PllOutput::default() };
348
349 let src_freq = match pll.source {
350 PllSource::DISABLE => panic!("must not select PLL source as DISABLE"),
351 PllSource::HSE => unwrap!(input.hse),
352 PllSource::HSI => unwrap!(input.hsi),
353 PllSource::MSIS => unwrap!(input.msi),
354 };
355
356 // Calculate the reference clock, which is the source divided by m
357 let ref_freq = src_freq / pll.prediv;
358 // Check limits per RM0456 § 11.4.6
359 assert!(Hertz::mhz(4) <= ref_freq && ref_freq <= Hertz::mhz(16));
360
361 // Check PLL clocks per RM0456 § 11.4.10
362 let (vco_min, vco_max, out_max) = match voltage_range {
363 VoltageScale::RANGE1 => (Hertz::mhz(128), Hertz::mhz(544), Hertz::mhz(208)),
364 VoltageScale::RANGE2 => (Hertz::mhz(128), Hertz::mhz(544), Hertz::mhz(110)),
365 VoltageScale::RANGE3 => (Hertz::mhz(128), Hertz::mhz(330), Hertz::mhz(55)),
366 VoltageScale::RANGE4 => panic!("PLL is unavailable in voltage range 4"),
367 };
368
369 // Calculate the PLL VCO clock
370 let vco_freq = ref_freq * pll.mul;
371 assert!(vco_freq >= vco_min && vco_freq <= vco_max);
372
373 // Calculate output clocks.
374 let p = pll.divp.map(|div| vco_freq / div);
375 let q = pll.divq.map(|div| vco_freq / div);
376 let r = pll.divr.map(|div| vco_freq / div);
377 for freq in [p, q, r] {
378 if let Some(freq) = freq {
379 assert!(freq <= out_max);
380 }
381 }
382
383 let divr = match instance {
384 PllInstance::Pll1 => RCC.pll1divr(),
385 PllInstance::Pll2 => RCC.pll2divr(),
386 PllInstance::Pll3 => RCC.pll3divr(),
387 };
388 divr.write(|w| {
389 w.set_plln(pll.mul);
390 w.set_pllp(pll.divp.unwrap_or(PllDiv::DIV1));
391 w.set_pllq(pll.divq.unwrap_or(PllDiv::DIV1));
392 w.set_pllr(pll.divr.unwrap_or(PllDiv::DIV1));
393 });
394
395 let input_range = match ref_freq.0 {
396 ..=8_000_000 => Pllrge::FREQ_4TO8MHZ,
397 _ => Pllrge::FREQ_8TO16MHZ,
398 };
399
400 macro_rules! write_fields {
401 ($w:ident) => {
402 $w.set_pllpen(pll.divp.is_some());
403 $w.set_pllqen(pll.divq.is_some());
404 $w.set_pllren(pll.divr.is_some());
405 $w.set_pllm(pll.prediv);
406 $w.set_pllsrc(pll.source);
407 $w.set_pllrge(input_range);
408 };
409 }
410
411 match instance {
412 PllInstance::Pll1 => RCC.pll1cfgr().write(|w| {
413 // § 10.5.4: if we're targeting >= 55 MHz, we must configure PLL1MBOOST to a prescaler
414 // value that results in an output between 4 and 16 MHz for the PWR EPOD boost
415 if r.unwrap() >= Hertz::mhz(55) {
416 // source_clk can be up to 50 MHz, so there's just a few cases:
417 let mboost = match src_freq.0 {
418 ..=16_000_000 => Pllmboost::DIV1, // Bypass, giving EPOD 4-16 MHz
419 ..=32_000_000 => Pllmboost::DIV2, // Divide by 2, giving EPOD 8-16 MHz
420 _ => Pllmboost::DIV4, // Divide by 4, giving EPOD 8-12.5 MHz
421 };
422 w.set_pllmboost(mboost);
423 }
424 write_fields!(w);
425 }),
426 PllInstance::Pll2 => RCC.pll2cfgr().write(|w| {
427 write_fields!(w);
428 }),
429 PllInstance::Pll3 => RCC.pll3cfgr().write(|w| {
430 write_fields!(w);
431 }),
432 }
433
434 // Enable PLL
435 pll_enable(instance, true);
436
437 PllOutput { p, q, r }
438}
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
index dca34fd0e..99cdeacc9 100644
--- a/examples/stm32u5/src/bin/usb_serial.rs
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -4,7 +4,6 @@
4use defmt::{panic, *}; 4use defmt::{panic, *};
5use defmt_rtt as _; // global logger 5use defmt_rtt as _; // global logger
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::rcc::*;
8use embassy_stm32::usb_otg::{Driver, Instance}; 7use embassy_stm32::usb_otg::{Driver, Instance};
9use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; 8use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@@ -22,22 +21,28 @@ async fn main(_spawner: Spawner) {
22 info!("Hello World!"); 21 info!("Hello World!");
23 22
24 let mut config = Config::default(); 23 let mut config = Config::default();
25 config.rcc.mux = ClockSrc::PLL1_R(PllConfig { 24 {
26 source: PllSource::HSI, 25 use embassy_stm32::rcc::*;
27 m: Pllm::DIV2, 26 config.rcc.hsi = true;
28 n: Plln::MUL10, 27 config.rcc.pll1 = Some(Pll {
29 p: Plldiv::DIV1, 28 source: PllSource::HSI, // 16 MHz
30 q: Plldiv::DIV1, 29 prediv: PllPreDiv::DIV1,
31 r: Plldiv::DIV1, 30 mul: PllMul::MUL10,
32 }); 31 divp: None,
33 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB 32 divq: None,
33 divr: Some(PllDiv::DIV1), // 160 MHz
34 });
35 config.rcc.mux = ClockSrc::PLL1_R;
36 config.rcc.voltage_range = VoltageScale::RANGE1;
37 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
38 }
34 39
35 let p = embassy_stm32::init(config); 40 let p = embassy_stm32::init(config);
36 41
37 // Create the driver, from the HAL. 42 // Create the driver, from the HAL.
38 let mut ep_out_buffer = [0u8; 256]; 43 let mut ep_out_buffer = [0u8; 256];
39 let mut config = embassy_stm32::usb_otg::Config::default(); 44 let mut config = embassy_stm32::usb_otg::Config::default();
40 config.vbus_detection = true; 45 config.vbus_detection = false;
41 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 46 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
42 47
43 // Create embassy-usb Config 48 // Create embassy-usb Config
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 5b28b5849..828a28e2c 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -26,7 +26,7 @@ stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"
26stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] 26stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"]
27stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"] 27stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"]
28stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng", "hash"] 28stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng", "hash"]
29stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng"] 29stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng", "hash"]
30stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] 30stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"]
31stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"] 31stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"]
32stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] 32stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"]
diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs
index bc5589164..176adff62 100644
--- a/tests/stm32/build.rs
+++ b/tests/stm32/build.rs
@@ -16,6 +16,7 @@ fn main() -> Result<(), Box<dyn Error>> {
16 feature = "stm32l073rz", 16 feature = "stm32l073rz",
17 // wrong ram size in stm32-data 17 // wrong ram size in stm32-data
18 feature = "stm32wl55jc", 18 feature = "stm32wl55jc",
19 feature = "stm32u5a5zj",
19 // no VTOR, so interrupts can't work when running from RAM 20 // no VTOR, so interrupts can't work when running from RAM
20 feature = "stm32f091rc", 21 feature = "stm32f091rc",
21 )) { 22 )) {
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index 50a7f9bae..1e6b1cce9 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -577,7 +577,18 @@ pub fn config() -> Config {
577 #[cfg(any(feature = "stm32u585ai", feature = "stm32u5a5zj"))] 577 #[cfg(any(feature = "stm32u585ai", feature = "stm32u5a5zj"))]
578 { 578 {
579 use embassy_stm32::rcc::*; 579 use embassy_stm32::rcc::*;
580 config.rcc.mux = ClockSrc::MSI(Msirange::RANGE_48MHZ); 580 config.rcc.hsi = true;
581 config.rcc.pll1 = Some(Pll {
582 source: PllSource::HSI, // 16 MHz
583 prediv: PllPreDiv::DIV1,
584 mul: PllMul::MUL10,
585 divp: None,
586 divq: None,
587 divr: Some(PllDiv::DIV1), // 160 MHz
588 });
589 config.rcc.mux = ClockSrc::PLL1_R;
590 config.rcc.voltage_range = VoltageScale::RANGE1;
591 config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
581 } 592 }
582 593
583 #[cfg(feature = "stm32wba52cg")] 594 #[cfg(feature = "stm32wba52cg")]