aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/rcc
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/rcc')
-rw-r--r--embassy-stm32/src/rcc/bd.rs140
-rw-r--r--embassy-stm32/src/rcc/f247.rs4
-rw-r--r--embassy-stm32/src/rcc/h.rs5
-rw-r--r--embassy-stm32/src/rcc/l.rs17
-rw-r--r--embassy-stm32/src/rcc/mco.rs37
-rw-r--r--embassy-stm32/src/rcc/mod.rs250
-rw-r--r--embassy-stm32/src/rcc/n6.rs1066
-rw-r--r--embassy-stm32/src/rcc/u5.rs19
-rw-r--r--embassy-stm32/src/rcc/wba.rs9
9 files changed, 1472 insertions, 75 deletions
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs
index 63fc195dd..219be208f 100644
--- a/embassy-stm32/src/rcc/bd.rs
+++ b/embassy-stm32/src/rcc/bd.rs
@@ -1,6 +1,10 @@
1use core::sync::atomic::{compiler_fence, Ordering}; 1#[cfg(not(stm32n6))]
2use core::sync::atomic::{Ordering, compiler_fence};
2 3
3use crate::pac::common::{Reg, RW}; 4#[cfg(not(stm32n6))]
5use crate::pac::common::{RW, Reg};
6#[cfg(backup_sram)]
7use crate::pac::pwr::vals::Retention;
4pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource; 8pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource;
5use crate::time::Hertz; 9use crate::time::Hertz;
6 10
@@ -52,7 +56,7 @@ impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
52 } 56 }
53} 57}
54 58
55#[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0)))] 59#[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0, stm32n6)))]
56type Bdcr = crate::pac::rcc::regs::Bdcr; 60type Bdcr = crate::pac::rcc::regs::Bdcr;
57#[cfg(any(rtc_v2_l0, rtc_v2_l1))] 61#[cfg(any(rtc_v2_l0, rtc_v2_l1))]
58type Bdcr = crate::pac::rcc::regs::Csr; 62type Bdcr = crate::pac::rcc::regs::Csr;
@@ -62,19 +66,22 @@ type Bdcr = crate::pac::rcc::regs::Csr1;
62#[cfg(any(stm32c0))] 66#[cfg(any(stm32c0))]
63fn unlock() {} 67fn unlock() {}
64 68
65#[cfg(not(any(stm32c0)))] 69#[cfg(not(any(stm32c0, stm32n6)))]
66fn unlock() { 70fn unlock() {
67 #[cfg(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1))] 71 #[cfg(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1))]
68 let cr = crate::pac::PWR.cr(); 72 let cr = crate::pac::PWR.cr();
69 #[cfg(not(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba)))] 73 #[cfg(not(any(
74 stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba, stm32n6
75 )))]
70 let cr = crate::pac::PWR.cr1(); 76 let cr = crate::pac::PWR.cr1();
71 #[cfg(any(stm32u5, stm32h5, stm32wba))] 77 #[cfg(any(stm32u5, stm32h5, stm32wba, stm32n6))]
72 let cr = crate::pac::PWR.dbpcr(); 78 let cr = crate::pac::PWR.dbpcr();
73 79
74 cr.modify(|w| w.set_dbp(true)); 80 cr.modify(|w| w.set_dbp(true));
75 while !cr.read().dbp() {} 81 while !cr.read().dbp() {}
76} 82}
77 83
84#[cfg(not(stm32n6))]
78fn bdcr() -> Reg<Bdcr, RW> { 85fn bdcr() -> Reg<Bdcr, RW> {
79 #[cfg(any(rtc_v2_l0, rtc_v2_l1))] 86 #[cfg(any(rtc_v2_l0, rtc_v2_l1))]
80 return crate::pac::RCC.csr(); 87 return crate::pac::RCC.csr();
@@ -89,6 +96,8 @@ pub struct LsConfig {
89 pub rtc: RtcClockSource, 96 pub rtc: RtcClockSource,
90 pub lsi: bool, 97 pub lsi: bool,
91 pub lse: Option<LseConfig>, 98 pub lse: Option<LseConfig>,
99 #[cfg(backup_sram)]
100 pub enable_backup_sram: bool,
92} 101}
93 102
94impl LsConfig { 103impl LsConfig {
@@ -113,6 +122,8 @@ impl LsConfig {
113 peripherals_clocked: false, 122 peripherals_clocked: false,
114 }), 123 }),
115 lsi: false, 124 lsi: false,
125 #[cfg(backup_sram)]
126 enable_backup_sram: false,
116 } 127 }
117 } 128 }
118 129
@@ -121,6 +132,8 @@ impl LsConfig {
121 rtc: RtcClockSource::LSI, 132 rtc: RtcClockSource::LSI,
122 lsi: true, 133 lsi: true,
123 lse: None, 134 lse: None,
135 #[cfg(backup_sram)]
136 enable_backup_sram: false,
124 } 137 }
125 } 138 }
126 139
@@ -129,6 +142,8 @@ impl LsConfig {
129 rtc: RtcClockSource::DISABLE, 142 rtc: RtcClockSource::DISABLE,
130 lsi: false, 143 lsi: false,
131 lse: None, 144 lse: None,
145 #[cfg(backup_sram)]
146 enable_backup_sram: false,
132 } 147 }
133 } 148 }
134} 149}
@@ -140,6 +155,7 @@ impl Default for LsConfig {
140} 155}
141 156
142impl LsConfig { 157impl LsConfig {
158 #[cfg(not(stm32n6))]
143 pub(crate) fn init(&self) -> Option<Hertz> { 159 pub(crate) fn init(&self) -> Option<Hertz> {
144 let rtc_clk = match self.rtc { 160 let rtc_clk = match self.rtc {
145 RtcClockSource::LSI => { 161 RtcClockSource::LSI => {
@@ -175,14 +191,19 @@ impl LsConfig {
175 if self.lsi { 191 if self.lsi {
176 #[cfg(any(stm32u5, stm32h5, stm32wba))] 192 #[cfg(any(stm32u5, stm32h5, stm32wba))]
177 let csr = crate::pac::RCC.bdcr(); 193 let csr = crate::pac::RCC.bdcr();
178 #[cfg(not(any(stm32u5, stm32h5, stm32wba, stm32c0)))] 194 #[cfg(stm32n6)]
195 let csr = crate::pac::RCC.sr();
196 #[cfg(not(any(stm32u5, stm32h5, stm32wba, stm32c0, stm32n6)))]
179 let csr = crate::pac::RCC.csr(); 197 let csr = crate::pac::RCC.csr();
180 #[cfg(any(stm32c0))] 198 #[cfg(stm32c0)]
181 let csr = crate::pac::RCC.csr2(); 199 let csr = crate::pac::RCC.csr2();
182 200
183 #[cfg(not(any(rcc_wb, rcc_wba)))] 201 #[cfg(not(any(rcc_wb, rcc_wba, rcc_n6)))]
184 csr.modify(|w| w.set_lsion(true)); 202 csr.modify(|w| w.set_lsion(true));
185 203
204 #[cfg(rcc_n6)]
205 crate::pac::RCC.cr().modify(|w| w.set_lsion(true));
206
186 #[cfg(any(rcc_wb, rcc_wba))] 207 #[cfg(any(rcc_wb, rcc_wba))]
187 csr.modify(|w| w.set_lsi1on(true)); 208 csr.modify(|w| w.set_lsi1on(true));
188 209
@@ -193,28 +214,77 @@ impl LsConfig {
193 while !csr.read().lsi1rdy() {} 214 while !csr.read().lsi1rdy() {}
194 } 215 }
195 216
217 // Enable backup regulator for peristent battery backed sram
218 #[cfg(backup_sram)]
219 {
220 unsafe { super::BKSRAM_RETAINED = crate::pac::PWR.bdcr().read().bren() == Retention::PRESERVED };
221
222 crate::pac::PWR.bdcr().modify(|w| {
223 w.set_bren(match self.enable_backup_sram {
224 true => Retention::PRESERVED,
225 false => Retention::LOST,
226 });
227 });
228
229 // Wait for backup regulator voltage to stabilize
230 while self.enable_backup_sram && !crate::pac::PWR.bdsr().read().brrdy() {}
231 }
232
196 // backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets. 233 // backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets.
197 // once set, changing it requires a backup domain reset. 234 // once set, changing it requires a backup domain reset.
198 // first check if the configuration matches what we want. 235 // first check if the configuration matches what we want.
236 // N6 has all the fields spread across multiple registers under RCC.
199 237
200 // check if it's already enabled and in the source we want. 238 // check if it's already enabled and in the source we want.
239 #[cfg(not(rcc_n6))]
201 let reg = bdcr().read(); 240 let reg = bdcr().read();
241 #[cfg(rcc_n6)]
242 let reg = crate::pac::RCC.cr().read();
243 #[cfg(rcc_n6)]
244 let apb4lenr = crate::pac::RCC.apb4lenr().read();
245 #[cfg(rcc_n6)]
246 let ccipr7 = crate::pac::RCC.ccipr7().read();
247 #[cfg(rcc_n6)]
248 let lsecfgr = crate::pac::RCC.lsecfgr().read();
249
202 let mut ok = true; 250 let mut ok = true;
203 ok &= reg.rtcsel() == self.rtc; 251 #[cfg(not(rcc_n6))]
204 #[cfg(not(rcc_wba))] 252 {
253 ok &= reg.rtcsel() == self.rtc;
254 }
255 #[cfg(rcc_n6)]
256 {
257 ok &= ccipr7.rtcsel() == self.rtc;
258 }
259 #[cfg(not(any(rcc_wba, rcc_n6)))]
205 { 260 {
206 ok &= reg.rtcen() == (self.rtc != RtcClockSource::DISABLE); 261 ok &= reg.rtcen() == (self.rtc != RtcClockSource::DISABLE);
207 } 262 }
263 #[cfg(rcc_n6)]
264 {
265 ok &= apb4lenr.rtcen() == (self.rtc != RtcClockSource::DISABLE);
266 }
208 ok &= reg.lseon() == lse_en; 267 ok &= reg.lseon() == lse_en;
209 ok &= reg.lsebyp() == lse_byp; 268 #[cfg(not(rcc_n6))]
269 {
270 ok &= reg.lsebyp() == lse_byp;
271 }
272 #[cfg(rcc_n6)]
273 {
274 ok &= lsecfgr.lsebyp() == lse_byp;
275 }
210 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))] 276 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))]
211 if let Some(lse_sysen) = lse_sysen { 277 if let Some(lse_sysen) = lse_sysen {
212 ok &= reg.lsesysen() == lse_sysen; 278 ok &= reg.lsesysen() == lse_sysen;
213 } 279 }
214 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))] 280 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1, rcc_n6)))]
215 if let Some(lse_drv) = lse_drv { 281 if let Some(lse_drv) = lse_drv {
216 ok &= reg.lsedrv() == lse_drv.into(); 282 ok &= reg.lsedrv() == lse_drv.into();
217 } 283 }
284 #[cfg(rcc_n6)]
285 if let Some(lse_drv) = lse_drv {
286 ok &= lsecfgr.lsedrv() == lse_drv.into();
287 }
218 288
219 // if configuration is OK, we're done. 289 // if configuration is OK, we're done.
220 if ok { 290 if ok {
@@ -223,7 +293,7 @@ impl LsConfig {
223 } 293 }
224 294
225 // If not OK, reset backup domain and configure it. 295 // If not OK, reset backup domain and configure it.
226 #[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32h7rs, stm32c0)))] 296 #[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32h7rs, stm32c0, stm32n6)))]
227 { 297 {
228 bdcr().modify(|w| w.set_bdrst(true)); 298 bdcr().modify(|w| w.set_bdrst(true));
229 bdcr().modify(|w| w.set_bdrst(false)); 299 bdcr().modify(|w| w.set_bdrst(false));
@@ -236,7 +306,7 @@ impl LsConfig {
236 // STM32H503CB/EB/KB/RB device errata - 2.2.8 SRAM2 unduly erased upon a backup domain reset 306 // STM32H503CB/EB/KB/RB device errata - 2.2.8 SRAM2 unduly erased upon a backup domain reset
237 // STM32H562xx/563xx/573xx device errata - 2.2.14 SRAM2 is erased when the backup domain is reset 307 // STM32H562xx/563xx/573xx device errata - 2.2.14 SRAM2 is erased when the backup domain is reset
238 //#[cfg(any(stm32h5, stm32h7rs))] 308 //#[cfg(any(stm32h5, stm32h7rs))]
239 #[cfg(any(stm32h7rs))] 309 #[cfg(any(stm32h7rs, stm32n6))]
240 { 310 {
241 bdcr().modify(|w| w.set_vswrst(true)); 311 bdcr().modify(|w| w.set_vswrst(true));
242 bdcr().modify(|w| w.set_vswrst(false)); 312 bdcr().modify(|w| w.set_vswrst(false));
@@ -248,16 +318,31 @@ impl LsConfig {
248 } 318 }
249 319
250 if lse_en { 320 if lse_en {
251 bdcr().modify(|w| { 321 #[cfg(not(rcc_n6))]
252 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))] 322 {
253 if let Some(lse_drv) = lse_drv { 323 bdcr().modify(|w| {
254 w.set_lsedrv(lse_drv.into()); 324 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))]
255 } 325 if let Some(lse_drv) = lse_drv {
256 w.set_lsebyp(lse_byp); 326 w.set_lsedrv(lse_drv.into());
257 w.set_lseon(true); 327 }
258 }); 328 w.set_lsebyp(lse_byp);
329 w.set_lseon(true);
330 });
331
332 while !bdcr().read().lserdy() {}
333 }
334 #[cfg(rcc_n6)]
335 {
336 crate::pac::RCC.lsecfgr().modify(|w| {
337 if let Some(lse_drv) = lse_drv {
338 w.set_lsedrv(lse_drv.into());
339 }
340 w.set_lsebyp(lse_byp);
341 });
342 crate::pac::RCC.cr().modify(|w| w.set_lseon(true));
259 343
260 while !bdcr().read().lserdy() {} 344 while !crate::pac::RCC.sr().read().lserdy() {}
345 }
261 346
262 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))] 347 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))]
263 if let Some(lse_sysen) = lse_sysen { 348 if let Some(lse_sysen) = lse_sysen {
@@ -272,6 +357,7 @@ impl LsConfig {
272 } 357 }
273 358
274 if self.rtc != RtcClockSource::DISABLE { 359 if self.rtc != RtcClockSource::DISABLE {
360 #[cfg(not(rcc_n6))]
275 bdcr().modify(|w| { 361 bdcr().modify(|w| {
276 #[cfg(any(rtc_v2_h7, rtc_v2_l4, rtc_v2_wb, rtc_v3_base, rtc_v3_u5))] 362 #[cfg(any(rtc_v2_h7, rtc_v2_l4, rtc_v2_wb, rtc_v3_base, rtc_v3_u5))]
277 assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet."); 363 assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
@@ -280,6 +366,12 @@ impl LsConfig {
280 w.set_rtcen(true); 366 w.set_rtcen(true);
281 w.set_rtcsel(self.rtc); 367 w.set_rtcsel(self.rtc);
282 }); 368 });
369
370 #[cfg(rcc_n6)]
371 {
372 crate::pac::RCC.ccipr7().modify(|w| w.set_rtcsel(self.rtc));
373 crate::pac::RCC.apb4lenr().modify(|w| w.set_rtcen(true))
374 }
283 } 375 }
284 376
285 trace!("BDCR configured: {:08x}", bdcr().read().0); 377 trace!("BDCR configured: {:08x}", bdcr().read().0);
diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs
index 8f2e8db5f..d941054cd 100644
--- a/embassy-stm32/src/rcc/f247.rs
+++ b/embassy-stm32/src/rcc/f247.rs
@@ -1,13 +1,13 @@
1use stm32_metapac::flash::vals::Latency; 1use stm32_metapac::flash::vals::Latency;
2 2
3#[cfg(any(stm32f4, stm32f7))]
4use crate::pac::PWR;
3#[cfg(any(stm32f413, stm32f423, stm32f412))] 5#[cfg(any(stm32f413, stm32f423, stm32f412))]
4pub use crate::pac::rcc::vals::Plli2ssrc as Plli2sSource; 6pub use crate::pac::rcc::vals::Plli2ssrc as Plli2sSource;
5pub use crate::pac::rcc::vals::{ 7pub use crate::pac::rcc::vals::{
6 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, 8 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv,
7 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, 9 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
8}; 10};
9#[cfg(any(stm32f4, stm32f7))]
10use crate::pac::PWR;
11use crate::pac::{FLASH, RCC}; 11use crate::pac::{FLASH, RCC};
12use crate::time::Hertz; 12use crate::time::Hertz;
13 13
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 331bab7a0..485edd390 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -597,7 +597,10 @@ pub(crate) unsafe fn init(config: Config) {
597 Hertz(24_000_000) => Usbrefcksel::MHZ24, 597 Hertz(24_000_000) => Usbrefcksel::MHZ24,
598 Hertz(26_000_000) => Usbrefcksel::MHZ26, 598 Hertz(26_000_000) => Usbrefcksel::MHZ26,
599 Hertz(32_000_000) => Usbrefcksel::MHZ32, 599 Hertz(32_000_000) => Usbrefcksel::MHZ32,
600 _ => panic!("cannot select USBPHYC reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), 600 _ => panic!(
601 "cannot select USBPHYC reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz",
602 clk_val
603 ),
601 }, 604 },
602 None => Usbrefcksel::MHZ24, 605 None => Usbrefcksel::MHZ24,
603 }; 606 };
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index 81b89046e..0d668103c 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -135,7 +135,14 @@ pub const WPAN_DEFAULT: Config = Config {
135 apb1_pre: APBPrescaler::DIV1, 135 apb1_pre: APBPrescaler::DIV1,
136 apb2_pre: APBPrescaler::DIV1, 136 apb2_pre: APBPrescaler::DIV1,
137 137
138 mux: super::mux::ClockMux::default(), 138 mux: {
139 use crate::pac::rcc::vals::Rfwkpsel;
140
141 let mut mux = super::mux::ClockMux::default();
142
143 mux.rfwkpsel = Rfwkpsel::LSE;
144 mux
145 },
139}; 146};
140 147
141fn msi_enable(range: MSIRange) { 148fn msi_enable(range: MSIRange) {
@@ -499,9 +506,9 @@ pub use pll::*;
499 506
500#[cfg(any(stm32l0, stm32l1))] 507#[cfg(any(stm32l0, stm32l1))]
501mod pll { 508mod pll {
502 use super::{pll_enable, PllInstance}; 509 use super::{PllInstance, pll_enable};
503 pub use crate::pac::rcc::vals::{Plldiv as PllDiv, Pllmul as PllMul, Pllsrc as PllSource};
504 use crate::pac::RCC; 510 use crate::pac::RCC;
511 pub use crate::pac::rcc::vals::{Plldiv as PllDiv, Pllmul as PllMul, Pllsrc as PllSource};
505 use crate::time::Hertz; 512 use crate::time::Hertz;
506 513
507 #[derive(Clone, Copy)] 514 #[derive(Clone, Copy)]
@@ -563,11 +570,11 @@ mod pll {
563 570
564#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))] 571#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
565mod pll { 572mod pll {
566 use super::{pll_enable, PllInstance}; 573 use super::{PllInstance, pll_enable};
574 use crate::pac::RCC;
567 pub use crate::pac::rcc::vals::{ 575 pub use crate::pac::rcc::vals::{
568 Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PllSource, 576 Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PllSource,
569 }; 577 };
570 use crate::pac::RCC;
571 use crate::time::Hertz; 578 use crate::time::Hertz;
572 579
573 #[derive(Clone, Copy)] 580 #[derive(Clone, Copy)]
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs
index 59ccc8cb5..0624fdf26 100644
--- a/embassy-stm32/src/rcc/mco.rs
+++ b/embassy-stm32/src/rcc/mco.rs
@@ -3,6 +3,7 @@ use core::marker::PhantomData;
3use embassy_hal_internal::PeripheralType; 3use embassy_hal_internal::PeripheralType;
4 4
5use crate::gpio::{AfType, OutputType, Speed}; 5use crate::gpio::{AfType, OutputType, Speed};
6use crate::pac::RCC;
6#[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] 7#[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))]
7pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; 8pub use crate::pac::rcc::vals::Mcopre as McoPrescaler;
8#[cfg(not(any( 9#[cfg(not(any(
@@ -15,7 +16,8 @@ pub use crate::pac::rcc::vals::Mcopre as McoPrescaler;
15 rcc_h7ab, 16 rcc_h7ab,
16 rcc_h7rm0433, 17 rcc_h7rm0433,
17 rcc_h7, 18 rcc_h7,
18 rcc_h7rs 19 rcc_h7rs,
20 rcc_n6
19)))] 21)))]
20pub use crate::pac::rcc::vals::Mcosel as McoSource; 22pub use crate::pac::rcc::vals::Mcosel as McoSource;
21#[cfg(any( 23#[cfg(any(
@@ -28,11 +30,11 @@ pub use crate::pac::rcc::vals::Mcosel as McoSource;
28 rcc_h7ab, 30 rcc_h7ab,
29 rcc_h7rm0433, 31 rcc_h7rm0433,
30 rcc_h7, 32 rcc_h7,
31 rcc_h7rs 33 rcc_h7rs,
34 rcc_n6
32))] 35))]
33pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; 36pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source};
34use crate::pac::RCC; 37use crate::{Peri, peripherals};
35use crate::{peripherals, Peri};
36 38
37#[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))] 39#[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))]
38#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] 40#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
@@ -59,10 +61,12 @@ macro_rules! impl_peri {
59 type Source = $source; 61 type Source = $source;
60 62
61 unsafe fn _apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) { 63 unsafe fn _apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) {
62 #[cfg(not(any(stm32u5, stm32wba)))] 64 #[cfg(not(any(stm32u5, stm32wba, stm32n6)))]
63 let r = RCC.cfgr(); 65 let r = RCC.cfgr();
64 #[cfg(any(stm32u5, stm32wba))] 66 #[cfg(any(stm32u5, stm32wba))]
65 let r = RCC.cfgr1(); 67 let r = RCC.cfgr1();
68 #[cfg(any(stm32n6))]
69 let r = RCC.ccipr5();
66 70
67 r.modify(|w| { 71 r.modify(|w| {
68 w.$set_source(source); 72 w.$set_source(source);
@@ -91,12 +95,29 @@ pub struct Mco<'d, T: McoInstance> {
91 95
92impl<'d, T: McoInstance> Mco<'d, T> { 96impl<'d, T: McoInstance> Mco<'d, T> {
93 /// Create a new MCO instance. 97 /// Create a new MCO instance.
94 pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin<T>>, source: T::Source, prescaler: McoPrescaler) -> Self { 98 pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin<T>>, source: T::Source, config: McoConfig) -> Self {
95 critical_section::with(|_| unsafe { 99 critical_section::with(|_| unsafe {
96 T::_apply_clock_settings(source, prescaler); 100 T::_apply_clock_settings(source, config.prescaler);
97 set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::VeryHigh)); 101 set_as_af!(pin, AfType::output(OutputType::PushPull, config.speed));
98 }); 102 });
99 103
100 Self { phantom: PhantomData } 104 Self { phantom: PhantomData }
101 } 105 }
102} 106}
107
108#[non_exhaustive]
109pub struct McoConfig {
110 /// Master Clock Out prescaler
111 pub prescaler: McoPrescaler,
112 /// IO Drive Strength
113 pub speed: Speed,
114}
115
116impl Default for McoConfig {
117 fn default() -> Self {
118 Self {
119 prescaler: McoPrescaler::DIV1,
120 speed: Speed::VeryHigh,
121 }
122 }
123}
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index c41f81816..d25c922d8 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -4,6 +4,7 @@
4#![allow(missing_docs)] // TODO 4#![allow(missing_docs)] // TODO
5 5
6use core::mem::MaybeUninit; 6use core::mem::MaybeUninit;
7use core::ops;
7 8
8mod bd; 9mod bd;
9pub use bd::*; 10pub use bd::*;
@@ -11,6 +12,7 @@ pub use bd::*;
11#[cfg(any(mco, mco1, mco2))] 12#[cfg(any(mco, mco1, mco2))]
12mod mco; 13mod mco;
13use critical_section::CriticalSection; 14use critical_section::CriticalSection;
15use embassy_hal_internal::{Peri, PeripheralType};
14#[cfg(any(mco, mco1, mco2))] 16#[cfg(any(mco, mco1, mco2))]
15pub use mco::*; 17pub use mco::*;
16 18
@@ -28,12 +30,13 @@ pub use hsi48::*;
28#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl, stm32u0), path = "l.rs")] 30#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl, stm32u0), path = "l.rs")]
29#[cfg_attr(stm32u5, path = "u5.rs")] 31#[cfg_attr(stm32u5, path = "u5.rs")]
30#[cfg_attr(stm32wba, path = "wba.rs")] 32#[cfg_attr(stm32wba, path = "wba.rs")]
33#[cfg_attr(stm32n6, path = "n6.rs")]
31mod _version; 34mod _version;
32 35
33pub use _version::*; 36pub use _version::*;
34use stm32_metapac::RCC; 37use stm32_metapac::RCC;
35 38
36pub use crate::_generated::{mux, Clocks}; 39pub use crate::_generated::{Clocks, mux};
37use crate::time::Hertz; 40use crate::time::Hertz;
38 41
39#[cfg(feature = "low-power")] 42#[cfg(feature = "low-power")]
@@ -48,6 +51,12 @@ pub(crate) static mut REFCOUNT_STOP1: u32 = 0;
48/// May be read without a critical section 51/// May be read without a critical section
49pub(crate) static mut REFCOUNT_STOP2: u32 = 0; 52pub(crate) static mut REFCOUNT_STOP2: u32 = 0;
50 53
54#[cfg(feature = "low-power")]
55pub(crate) static mut RCC_CONFIG: Option<Config> = None;
56
57#[cfg(backup_sram)]
58pub(crate) static mut BKSRAM_RETAINED: bool = false;
59
51#[cfg(not(feature = "_dual-core"))] 60#[cfg(not(feature = "_dual-core"))]
52/// Frozen clock frequencies 61/// Frozen clock frequencies
53/// 62///
@@ -104,6 +113,32 @@ pub fn clocks<'a>(_rcc: &'a crate::Peri<'a, crate::peripherals::RCC>) -> &'a Clo
104 unsafe { get_freqs() } 113 unsafe { get_freqs() }
105} 114}
106 115
116#[cfg(feature = "low-power")]
117fn increment_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) {
118 match stop_mode {
119 StopMode::Standby => {}
120 StopMode::Stop2 => unsafe {
121 REFCOUNT_STOP2 += 1;
122 },
123 StopMode::Stop1 => unsafe {
124 REFCOUNT_STOP1 += 1;
125 },
126 }
127}
128
129#[cfg(feature = "low-power")]
130fn decrement_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) {
131 match stop_mode {
132 StopMode::Standby => {}
133 StopMode::Stop2 => unsafe {
134 REFCOUNT_STOP2 -= 1;
135 },
136 StopMode::Stop1 => unsafe {
137 REFCOUNT_STOP1 -= 1;
138 },
139 }
140}
141
107pub(crate) trait SealedRccPeripheral { 142pub(crate) trait SealedRccPeripheral {
108 fn frequency() -> Hertz; 143 fn frequency() -> Hertz;
109 #[allow(dead_code)] 144 #[allow(dead_code)]
@@ -134,14 +169,27 @@ pub(crate) struct RccInfo {
134 stop_mode: StopMode, 169 stop_mode: StopMode,
135} 170}
136 171
172/// Specifies a limit for the stop mode of the peripheral or the stop mode to be entered.
173/// E.g. if `StopMode::Stop1` is selected, the peripheral prevents the chip from entering Stop1 mode.
137#[cfg(feature = "low-power")] 174#[cfg(feature = "low-power")]
138#[allow(dead_code)] 175#[allow(dead_code)]
139pub(crate) enum StopMode { 176#[derive(Debug, Clone, Copy, PartialEq, Default, defmt::Format)]
140 Standby, 177pub enum StopMode {
141 Stop2, 178 #[default]
179 /// Peripheral prevents chip from entering Stop1 or executor will enter Stop1
142 Stop1, 180 Stop1,
181 /// Peripheral prevents chip from entering Stop2 or executor will enter Stop2
182 Stop2,
183 /// Peripheral does not prevent chip from entering Stop
184 Standby,
143} 185}
144 186
187#[cfg(feature = "low-power")]
188type BusyRccPeripheral = BusyPeripheral<StopMode>;
189
190#[cfg(not(feature = "low-power"))]
191type BusyRccPeripheral = ();
192
145impl RccInfo { 193impl RccInfo {
146 /// Safety: 194 /// Safety:
147 /// - `reset_offset_and_bit`, if set, must correspond to valid xxxRST bit 195 /// - `reset_offset_and_bit`, if set, must correspond to valid xxxRST bit
@@ -194,17 +242,6 @@ impl RccInfo {
194 } 242 }
195 } 243 }
196 244
197 #[cfg(feature = "low-power")]
198 match self.stop_mode {
199 StopMode::Standby => {}
200 StopMode::Stop2 => unsafe {
201 REFCOUNT_STOP2 += 1;
202 },
203 StopMode::Stop1 => unsafe {
204 REFCOUNT_STOP1 += 1;
205 },
206 }
207
208 // set the xxxRST bit 245 // set the xxxRST bit
209 let reset_ptr = self.reset_ptr(); 246 let reset_ptr = self.reset_ptr();
210 if let Some(reset_ptr) = reset_ptr { 247 if let Some(reset_ptr) = reset_ptr {
@@ -260,17 +297,6 @@ impl RccInfo {
260 } 297 }
261 } 298 }
262 299
263 #[cfg(feature = "low-power")]
264 match self.stop_mode {
265 StopMode::Standby => {}
266 StopMode::Stop2 => unsafe {
267 REFCOUNT_STOP2 -= 1;
268 },
269 StopMode::Stop1 => unsafe {
270 REFCOUNT_STOP1 -= 1;
271 },
272 }
273
274 // clear the xxxEN bit 300 // clear the xxxEN bit
275 let enable_ptr = self.enable_ptr(); 301 let enable_ptr = self.enable_ptr();
276 unsafe { 302 unsafe {
@@ -279,14 +305,85 @@ impl RccInfo {
279 } 305 }
280 } 306 }
281 307
308 #[allow(dead_code)]
309 pub(crate) fn increment_stop_refcount_with_cs(&self, _cs: CriticalSection) {
310 #[cfg(feature = "low-power")]
311 increment_stop_refcount(_cs, self.stop_mode);
312 }
313
314 #[allow(dead_code)]
315 fn increment_minimum_stop_refcount_with_cs(&self, _cs: CriticalSection) {
316 #[cfg(all(stm32wlex, feature = "low-power"))]
317 match self.stop_mode {
318 StopMode::Stop1 | StopMode::Stop2 => increment_stop_refcount(_cs, StopMode::Stop2),
319 _ => {}
320 }
321 }
322
323 #[allow(dead_code)]
324 pub(crate) fn increment_stop_refcount(&self) {
325 #[cfg(feature = "low-power")]
326 critical_section::with(|cs| self.increment_stop_refcount_with_cs(cs))
327 }
328
329 #[allow(dead_code)]
330 pub(crate) fn decrement_stop_refcount_with_cs(&self, _cs: CriticalSection) {
331 #[cfg(feature = "low-power")]
332 decrement_stop_refcount(_cs, self.stop_mode);
333 }
334
335 #[allow(dead_code)]
336 fn decrement_minimum_stop_refcount_with_cs(&self, _cs: CriticalSection) {
337 #[cfg(all(stm32wlex, feature = "low-power"))]
338 match self.stop_mode {
339 StopMode::Stop1 | StopMode::Stop2 => decrement_stop_refcount(_cs, StopMode::Stop2),
340 _ => {}
341 }
342 }
343
344 #[allow(dead_code)]
345 pub(crate) fn decrement_stop_refcount(&self) {
346 #[cfg(feature = "low-power")]
347 critical_section::with(|cs| self.decrement_stop_refcount_with_cs(cs))
348 }
349
282 // TODO: should this be `unsafe`? 350 // TODO: should this be `unsafe`?
283 pub(crate) fn enable_and_reset(&self) { 351 pub(crate) fn enable_and_reset(&self) {
284 critical_section::with(|cs| self.enable_and_reset_with_cs(cs)) 352 critical_section::with(|cs| {
353 self.enable_and_reset_with_cs(cs);
354 self.increment_stop_refcount_with_cs(cs);
355 })
356 }
357
358 #[allow(dead_code)]
359 pub(crate) fn enable_and_reset_without_stop(&self) {
360 critical_section::with(|cs| {
361 self.enable_and_reset_with_cs(cs);
362 self.increment_minimum_stop_refcount_with_cs(cs);
363 })
285 } 364 }
286 365
287 // TODO: should this be `unsafe`? 366 // TODO: should this be `unsafe`?
288 pub(crate) fn disable(&self) { 367 pub(crate) fn disable(&self) {
289 critical_section::with(|cs| self.disable_with_cs(cs)) 368 critical_section::with(|cs| {
369 self.disable_with_cs(cs);
370 self.decrement_stop_refcount_with_cs(cs);
371 })
372 }
373
374 // TODO: should this be `unsafe`?
375 #[allow(dead_code)]
376 pub(crate) fn disable_without_stop(&self) {
377 critical_section::with(|cs| {
378 self.disable_with_cs(cs);
379 self.decrement_minimum_stop_refcount_with_cs(cs);
380 })
381 }
382
383 #[allow(dead_code)]
384 pub(crate) fn block_stop(&self) -> BusyRccPeripheral {
385 #[cfg(feature = "low-power")]
386 BusyPeripheral::new(self.stop_mode)
290 } 387 }
291 388
292 fn reset_ptr(&self) -> Option<*mut u32> { 389 fn reset_ptr(&self) -> Option<*mut u32> {
@@ -302,6 +399,60 @@ impl RccInfo {
302 } 399 }
303} 400}
304 401
402pub(crate) trait StoppablePeripheral {
403 #[cfg(feature = "low-power")]
404 #[allow(dead_code)]
405 fn stop_mode(&self) -> StopMode;
406}
407
408#[cfg(feature = "low-power")]
409impl StoppablePeripheral for StopMode {
410 fn stop_mode(&self) -> StopMode {
411 *self
412 }
413}
414
415impl<'a, T: StoppablePeripheral + PeripheralType> StoppablePeripheral for Peri<'a, T> {
416 #[cfg(feature = "low-power")]
417 fn stop_mode(&self) -> StopMode {
418 T::stop_mode(&self)
419 }
420}
421
422pub(crate) struct BusyPeripheral<T: StoppablePeripheral> {
423 peripheral: T,
424}
425
426impl<T: StoppablePeripheral> BusyPeripheral<T> {
427 pub fn new(peripheral: T) -> Self {
428 #[cfg(feature = "low-power")]
429 critical_section::with(|cs| increment_stop_refcount(cs, peripheral.stop_mode()));
430
431 Self { peripheral }
432 }
433}
434
435impl<T: StoppablePeripheral> Drop for BusyPeripheral<T> {
436 fn drop(&mut self) {
437 #[cfg(feature = "low-power")]
438 critical_section::with(|cs| decrement_stop_refcount(cs, self.peripheral.stop_mode()));
439 }
440}
441
442impl<T: StoppablePeripheral> ops::Deref for BusyPeripheral<T> {
443 type Target = T;
444
445 fn deref(&self) -> &Self::Target {
446 &self.peripheral
447 }
448}
449
450impl<T: StoppablePeripheral> ops::DerefMut for BusyPeripheral<T> {
451 fn deref_mut(&mut self) -> &mut Self::Target {
452 &mut self.peripheral
453 }
454}
455
305#[allow(unused)] 456#[allow(unused)]
306mod util { 457mod util {
307 use crate::time::Hertz; 458 use crate::time::Hertz;
@@ -371,6 +522,16 @@ pub fn enable_and_reset<T: RccPeripheral>() {
371 T::RCC_INFO.enable_and_reset(); 522 T::RCC_INFO.enable_and_reset();
372} 523}
373 524
525/// Enables and resets peripheral `T` without incrementing the stop refcount.
526///
527/// # Safety
528///
529/// Peripheral must not be in use.
530// TODO: should this be `unsafe`?
531pub fn enable_and_reset_without_stop<T: RccPeripheral>() {
532 T::RCC_INFO.enable_and_reset_without_stop();
533}
534
374/// Disables peripheral `T`. 535/// Disables peripheral `T`.
375/// 536///
376/// # Safety 537/// # Safety
@@ -390,7 +551,7 @@ pub fn disable<T: RccPeripheral>() {
390/// 551///
391/// This should only be called after `init`. 552/// This should only be called after `init`.
392#[cfg(not(feature = "_dual-core"))] 553#[cfg(not(feature = "_dual-core"))]
393pub fn reinit<'a>(config: Config, _rcc: &'a mut crate::Peri<'a, crate::peripherals::RCC>) { 554pub fn reinit(config: Config, _rcc: &'_ mut crate::Peri<'_, crate::peripherals::RCC>) {
394 critical_section::with(|cs| init_rcc(cs, config)) 555 critical_section::with(|cs| init_rcc(cs, config))
395} 556}
396 557
@@ -404,8 +565,39 @@ pub(crate) fn init_rcc(_cs: CriticalSection, config: Config) {
404 565
405 #[cfg(feature = "low-power")] 566 #[cfg(feature = "low-power")]
406 { 567 {
568 RCC_CONFIG = Some(config);
407 REFCOUNT_STOP2 = 0; 569 REFCOUNT_STOP2 = 0;
408 REFCOUNT_STOP1 = 0; 570 REFCOUNT_STOP1 = 0;
409 } 571 }
410 } 572 }
411} 573}
574
575/// Calculate intermediate prescaler number used to calculate peripheral prescalers
576///
577/// This function is intended to calculate a number indicating a minimum division
578/// necessary to result in a frequency lower than the provided `freq_max`.
579///
580/// The returned value indicates the `val + 1` divider is necessary to result in
581/// the output frequency that is below the maximum provided.
582///
583/// For example:
584/// 0 = divider of 1 => no division necessary as the input frequency is below max
585/// 1 = divider of 2 => division by 2 necessary
586/// ...
587///
588/// The provided max frequency is inclusive. So if `freq_in == freq_max` the result
589/// will be 0, indicating that no division is necessary. To accomplish that we subtract
590/// 1 from the input frequency so that the integer rounding plays in our favor.
591///
592/// For example:
593/// Let the input frequency be 110 and the max frequency be 55.
594/// If we naiively do `110/55 = 2` the renult will indicate that we need a divider by 3
595/// which in reality will be rounded up to 4 as usually a 3 division is not available.
596/// In either case the resulting frequency will be either 36 or 27 which is lower than
597/// what we would want. The result should be 1.
598/// If we do the following instead `109/55 = 1` indicating that we need a divide by 2
599/// which will result in the correct 55.
600#[allow(unused)]
601pub(crate) fn raw_prescaler(freq_in: u32, freq_max: u32) -> u32 {
602 freq_in.saturating_sub(1) / freq_max
603}
diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs
new file mode 100644
index 000000000..178ec57d4
--- /dev/null
+++ b/embassy-stm32/src/rcc/n6.rs
@@ -0,0 +1,1066 @@
1use stm32_metapac::rcc::vals::{
2 Cpusw, Cpusws, Hseext, Hsitrim, Icint, Icsel, Msifreqsel, Plldivm, Pllmodssdis, Pllpdiv, Pllsel, Syssw, Syssws,
3 Timpre,
4};
5pub use stm32_metapac::rcc::vals::{
6 Hpre as AhbPrescaler, Hsidiv as HsiPrescaler, Hsitrim as HsiCalibration, Ppre as ApbPrescaler,
7};
8
9use crate::pac::{PWR, RCC, SYSCFG};
10use crate::time::Hertz;
11
12pub const HSI_FREQ: Hertz = Hertz(64_000_000);
13pub const LSE_FREQ: Hertz = Hertz(32_768);
14
15#[derive(Clone, Copy, Eq, PartialEq)]
16pub enum HseMode {
17 /// crystal/ceramic oscillator
18 Oscillator,
19 /// oscillator bypassed with external clock (analog)
20 Bypass,
21 /// oscillator bypassed with external digital clock
22 BypassDigital,
23}
24
25#[derive(Clone, Copy, Eq, PartialEq)]
26pub struct Hse {
27 /// HSE frequency.
28 pub freq: Hertz,
29 /// HSE oscillator mode.
30 pub mode: HseMode,
31}
32
33#[derive(Clone, Copy, Eq, PartialEq)]
34pub struct Hsi {
35 pub pre: HsiPrescaler,
36 pub trim: Hsitrim,
37}
38
39#[derive(Clone, Copy, PartialEq)]
40pub enum SupplyConfig {
41 Smps,
42 External,
43}
44
45#[derive(Clone, Copy, PartialEq)]
46pub enum CpuClk {
47 Hse,
48 Ic1 { source: Icsel, divider: Icint },
49 Msi,
50 Hsi,
51}
52
53impl CpuClk {
54 const fn to_bits(self) -> u8 {
55 match self {
56 Self::Hsi => 0x0,
57 Self::Msi => 0x1,
58 Self::Hse => 0x2,
59 Self::Ic1 { .. } => 0x3,
60 }
61 }
62}
63
64#[derive(Clone, Copy, PartialEq)]
65pub struct IcConfig {
66 source: Icsel,
67 divider: Icint,
68}
69
70#[derive(Clone, Copy, PartialEq)]
71pub enum SysClk {
72 Hse,
73 Ic2 {
74 ic2: IcConfig,
75 ic6: IcConfig,
76 ic11: IcConfig,
77 },
78 Msi,
79 Hsi,
80}
81
82impl SysClk {
83 const fn to_bits(self) -> u8 {
84 match self {
85 Self::Hsi => 0x0,
86 Self::Msi => 0x1,
87 Self::Hse => 0x2,
88 Self::Ic2 { .. } => 0x3,
89 }
90 }
91}
92
93#[derive(Clone, Copy, PartialEq)]
94pub struct Msi {
95 pub freq: Msifreqsel,
96 pub trim: u8,
97}
98
99#[derive(Clone, Copy, PartialEq)]
100pub enum Pll {
101 Oscillator {
102 source: Pllsel,
103 divm: Plldivm,
104 fractional: u32,
105 divn: u16,
106 divp1: Pllpdiv,
107 divp2: Pllpdiv,
108 },
109 Bypass {
110 source: Pllsel,
111 },
112}
113
114/// Configuration of the core clocks
115#[non_exhaustive]
116#[derive(Clone, Copy)]
117pub struct Config {
118 pub hsi: Option<Hsi>,
119 pub hse: Option<Hse>,
120 pub msi: Option<Msi>,
121 pub lsi: bool,
122 pub lse: bool,
123
124 pub sys: SysClk,
125 pub cpu: CpuClk,
126
127 pub pll1: Option<Pll>,
128 pub pll2: Option<Pll>,
129 pub pll3: Option<Pll>,
130 pub pll4: Option<Pll>,
131
132 pub ahb: AhbPrescaler,
133 pub apb1: ApbPrescaler,
134 pub apb2: ApbPrescaler,
135 pub apb4: ApbPrescaler,
136 pub apb5: ApbPrescaler,
137
138 pub supply_config: SupplyConfig,
139}
140
141impl Config {
142 pub const fn new() -> Self {
143 Self {
144 hsi: Some(Hsi {
145 pre: HsiPrescaler::DIV1,
146 trim: HsiCalibration::from_bits(32),
147 }),
148 hse: None,
149 msi: None,
150 lsi: true,
151 lse: false,
152 sys: SysClk::Hsi,
153 cpu: CpuClk::Hsi,
154 pll1: Some(Pll::Bypass { source: Pllsel::HSI }),
155 pll2: Some(Pll::Bypass { source: Pllsel::HSI }),
156 pll3: Some(Pll::Bypass { source: Pllsel::HSI }),
157 pll4: Some(Pll::Bypass { source: Pllsel::HSI }),
158
159 ahb: AhbPrescaler::DIV2,
160 apb1: ApbPrescaler::DIV1,
161 apb2: ApbPrescaler::DIV1,
162 apb4: ApbPrescaler::DIV1,
163 apb5: ApbPrescaler::DIV1,
164
165 supply_config: SupplyConfig::Smps,
166 }
167 }
168}
169
170#[allow(dead_code)]
171struct ClocksOutput {
172 cpuclk: Hertz,
173 sysclk: Hertz,
174 pclk_tim: Hertz,
175 ahb: Hertz,
176 apb1: Hertz,
177 apb2: Hertz,
178 apb4: Hertz,
179 apb5: Hertz,
180}
181
182struct ClocksInput {
183 hsi: Option<Hertz>,
184 msi: Option<Hertz>,
185 hse: Option<Hertz>,
186}
187
188fn init_clocks(config: Config, input: &ClocksInput) -> ClocksOutput {
189 // handle increasing dividers
190 debug!("configuring increasing pclk dividers");
191 RCC.cfgr2().modify(|w| {
192 if config.apb1 > w.ppre1() {
193 debug!(" - APB1");
194 w.set_ppre1(config.apb1);
195 }
196 if config.apb2 > w.ppre2() {
197 debug!(" - APB2");
198 w.set_ppre2(config.apb2);
199 }
200 if config.apb4 > w.ppre4() {
201 debug!(" - APB4");
202 w.set_ppre4(config.apb4);
203 }
204 if config.apb5 > w.ppre5() {
205 debug!(" - APB5");
206 w.set_ppre5(config.apb5);
207 }
208 if config.ahb > w.hpre() {
209 debug!(" - AHB");
210 w.set_hpre(config.ahb);
211 }
212 });
213 // cpuclk
214 debug!("configuring cpuclk");
215 match config.cpu {
216 CpuClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"),
217 CpuClk::Ic1 { source, divider } => {
218 if !pll_sources_ready(RCC.iccfgr(0).read().icsel().to_bits(), source.to_bits()) {
219 panic!("ICx clock switch requires both origin and destination clock source to be active")
220 }
221
222 RCC.iccfgr(0).write(|w| {
223 w.set_icsel(source);
224 w.set_icint(divider);
225 });
226 RCC.divensr().modify(|w| w.set_ic1ens(true));
227 }
228 CpuClk::Msi if !RCC.sr().read().msirdy() => panic!("MSI is not ready to be selected as CPU clock source"),
229 CpuClk::Hsi if !RCC.sr().read().hsirdy() => panic!("HSI is not ready to be selected as CPU clock source"),
230 _ => {}
231 }
232 // set source
233 let cpusw = Cpusw::from_bits(config.cpu.to_bits());
234 RCC.cfgr().modify(|w| w.set_cpusw(cpusw));
235 // wait for changes to take effect
236 while RCC.cfgr().read().cpusws() != Cpusws::from_bits(config.cpu.to_bits()) {}
237
238 // sysclk
239 debug!("configuring sysclk");
240 match config.sys {
241 SysClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"),
242 SysClk::Ic2 { ic2, ic6, ic11 } => {
243 if !pll_sources_ready(RCC.iccfgr(1).read().icsel().to_bits(), ic2.source.to_bits()) {
244 panic!("IC2 clock switch requires both origin and destination clock source to be active")
245 }
246 if !pll_sources_ready(RCC.iccfgr(5).read().icsel().to_bits(), ic6.source.to_bits()) {
247 panic!("IC6 clock switch requires both origin and destination clock source to be active")
248 }
249 if !pll_sources_ready(RCC.iccfgr(10).read().icsel().to_bits(), ic11.source.to_bits()) {
250 panic!("IC11 clock switch requires both origin and destination clock source to be active")
251 }
252
253 RCC.iccfgr(1).write(|w| {
254 w.set_icsel(ic2.source);
255 w.set_icint(ic2.divider);
256 });
257 RCC.iccfgr(5).write(|w| {
258 w.set_icsel(ic6.source);
259 w.set_icint(ic6.divider);
260 });
261 RCC.iccfgr(10).write(|w| {
262 w.set_icsel(ic11.source);
263 w.set_icint(ic11.divider);
264 });
265 RCC.divensr().modify(|w| {
266 w.set_ic2ens(true);
267 w.set_ic6ens(true);
268 w.set_ic11ens(true);
269 });
270 }
271 SysClk::Msi if !RCC.sr().read().msirdy() => panic!("MSI is not ready to be selected as CPU clock source"),
272 SysClk::Hsi if !RCC.sr().read().hsirdy() => panic!("HSI is not ready to be selected as CPU clock source"),
273 _ => {}
274 }
275 // switch the system bus clock
276 let syssw = Syssw::from_bits(config.sys.to_bits());
277 RCC.cfgr().modify(|w| w.set_syssw(syssw));
278 // wait for changes to be applied
279 while RCC.cfgr().read().syssws() != Syssws::from_bits(config.sys.to_bits()) {}
280
281 // decreasing dividers
282 debug!("configuring decreasing pclk dividers");
283 RCC.cfgr2().modify(|w| {
284 if config.ahb < w.hpre() {
285 debug!(" - AHB");
286 w.set_hpre(config.ahb);
287 }
288 if config.apb1 < w.ppre1() {
289 debug!(" - APB1");
290 w.set_ppre1(config.apb1);
291 }
292 if config.apb2 < w.ppre2() {
293 debug!(" - APB2");
294 w.set_ppre2(config.apb2);
295 }
296 if config.apb4 < w.ppre4() {
297 debug!(" - APB4");
298 w.set_ppre4(config.apb4);
299 }
300 if config.apb5 < w.ppre5() {
301 debug!(" - APB5");
302 w.set_ppre5(config.apb5);
303 }
304 });
305
306 let cpuclk = match config.cpu {
307 CpuClk::Hsi => unwrap!(input.hsi),
308 CpuClk::Msi => unwrap!(input.msi),
309 CpuClk::Hse => unwrap!(input.hse),
310 CpuClk::Ic1 { .. } => todo!(),
311 };
312
313 let sysclk = match config.sys {
314 SysClk::Hsi => unwrap!(input.hsi),
315 SysClk::Msi => unwrap!(input.msi),
316 SysClk::Hse => unwrap!(input.hse),
317 SysClk::Ic2 { .. } => todo!(),
318 };
319
320 let timpre: u32 = match RCC.cfgr2().read().timpre() {
321 Timpre::DIV1 => 1,
322 Timpre::DIV2 => 2,
323 Timpre::DIV4 => 4,
324 Timpre::_RESERVED_3 => 8,
325 };
326
327 let hpre = periph_prescaler_to_value(config.ahb.to_bits());
328 let ppre1 = periph_prescaler_to_value(config.apb1.to_bits());
329 let ppre2 = periph_prescaler_to_value(config.apb2.to_bits());
330 let ppre4 = periph_prescaler_to_value(config.apb4.to_bits());
331 let ppre5 = periph_prescaler_to_value(config.apb5.to_bits());
332
333 // enable all peripherals in sleep mode
334 enable_low_power_peripherals();
335
336 // enable interrupts
337 unsafe {
338 core::arch::asm!("cpsie i");
339 }
340
341 ClocksOutput {
342 sysclk,
343 cpuclk,
344 pclk_tim: sysclk / timpre,
345 ahb: Hertz(sysclk.0 / hpre as u32),
346 apb1: sysclk / hpre / ppre1,
347 apb2: sysclk / hpre / ppre2,
348 apb4: sysclk / hpre / ppre4,
349 apb5: sysclk / hpre / ppre5,
350 }
351}
352
353fn enable_low_power_peripherals() {
354 // AHB1-5
355 RCC.ahb1lpenr().modify(|w| {
356 w.set_adc12lpen(true);
357 w.set_gpdma1lpen(true);
358 });
359 RCC.ahb2lpenr().modify(|w| {
360 w.set_adf1lpen(true);
361 w.set_mdf1lpen(true);
362 w.set_ramcfglpen(true);
363 });
364 RCC.ahb3lpenr().modify(|w| {
365 w.set_risaflpen(true);
366 w.set_iaclpen(true);
367 w.set_rifsclpen(true);
368 w.set_pkalpen(true);
369 w.set_saeslpen(true);
370 w.set_cryplpen(true);
371 w.set_hashlpen(true);
372 w.set_rnglpen(true);
373 });
374 RCC.ahb4lpenr().modify(|w| {
375 w.set_crclpen(true);
376 w.set_pwrlpen(true);
377 w.set_gpioqlpen(true);
378 w.set_gpioplpen(true);
379 w.set_gpioolpen(true);
380 w.set_gpionlpen(true);
381 w.set_gpiohlpen(true);
382 w.set_gpioglpen(true);
383 w.set_gpioflpen(true);
384 w.set_gpioelpen(true);
385 w.set_gpiodlpen(true);
386 w.set_gpioclpen(true);
387 w.set_gpioblpen(true);
388 w.set_gpioalpen(true);
389 });
390 RCC.ahb5lpenr().modify(|w| {
391 w.set_npulpen(true);
392 w.set_npucachelpen(true);
393 w.set_otg2lpen(true);
394 w.set_otgphy2lpen(true);
395 w.set_otgphy1lpen(true);
396 w.set_otg1lpen(true);
397 w.set_eth1lpen(true);
398 w.set_eth1rxlpen(true);
399 w.set_eth1txlpen(true);
400 w.set_eth1maclpen(true);
401 w.set_gpulpen(true);
402 w.set_gfxmmulpen(true);
403 w.set_mce4lpen(true);
404 w.set_xspi3lpen(true);
405 w.set_mce3lpen(true);
406 w.set_mce2lpen(true);
407 w.set_mce1lpen(true);
408 w.set_xspimlpen(true);
409 w.set_xspi2lpen(true);
410 w.set_sdmmc1lpen(true);
411 w.set_sdmmc2lpen(true);
412 w.set_pssilpen(true);
413 w.set_xspi1lpen(true);
414 w.set_fmclpen(true);
415 w.set_jpeglpen(true);
416 w.set_dma2dlpen(true);
417 w.set_hpdma1lpen(true);
418 });
419
420 // APB1-5
421 RCC.apb1llpenr().modify(|w| {
422 w.set_uart8lpen(true);
423 w.set_uart7lpen(true);
424 w.set_i3c2lpen(true);
425 w.set_i3c1lpen(true);
426 w.set_i2c3lpen(true);
427 w.set_i2c2lpen(true);
428 w.set_i2c1lpen(true);
429 w.set_uart5lpen(true);
430 w.set_uart4lpen(true);
431 w.set_usart3lpen(true);
432 w.set_usart2lpen(true);
433 w.set_spdifrx1lpen(true);
434 w.set_spi3lpen(true);
435 w.set_spi2lpen(true);
436 w.set_tim11lpen(true);
437 w.set_tim10lpen(true);
438 w.set_wwdglpen(true);
439 w.set_lptim1lpen(true);
440 w.set_tim14lpen(true);
441 w.set_tim13lpen(true);
442 w.set_tim12lpen(true);
443 w.set_tim7lpen(true);
444 w.set_tim6lpen(true);
445 w.set_tim5lpen(true);
446 w.set_tim4lpen(true);
447 w.set_tim3lpen(true);
448 w.set_tim2lpen(true);
449 });
450 RCC.apb1hlpenr().modify(|w| {
451 w.set_ucpd1lpen(true);
452 w.set_fdcanlpen(true);
453 w.set_mdioslpen(true);
454 });
455 RCC.apb2lpenr().modify(|w| {
456 w.set_sai2lpen(true);
457 w.set_sai1lpen(true);
458 w.set_spi5lpen(true);
459 w.set_tim9lpen(true);
460 w.set_tim17lpen(true);
461 w.set_tim16lpen(true);
462 w.set_tim15lpen(true);
463 w.set_tim18lpen(true);
464 w.set_spi4lpen(true);
465 w.set_spi1lpen(true);
466 w.set_usart10lpen(true);
467 w.set_uart9lpen(true);
468 w.set_usart6lpen(true);
469 w.set_usart1lpen(true);
470 w.set_tim8lpen(true);
471 w.set_tim1lpen(true);
472 });
473 RCC.apb3lpenr().modify(|w| {
474 w.set_dftlpen(true);
475 });
476 RCC.apb4llpenr().modify(|w| {
477 w.set_rtcapblpen(true);
478 w.set_rtclpen(true);
479 w.set_vrefbuflpen(true);
480 w.set_lptim5lpen(true);
481 w.set_lptim4lpen(true);
482 w.set_lptim3lpen(true);
483 w.set_lptim2lpen(true);
484 w.set_i2c4lpen(true);
485 w.set_spi6lpen(true);
486 w.set_lpuart1lpen(true);
487 w.set_hdplpen(true);
488 });
489 RCC.apb4hlpenr().modify(|w| {
490 w.set_dtslpen(true);
491 w.set_bseclpen(true);
492 w.set_syscfglpen(true);
493 });
494 RCC.apb5lpenr().modify(|w| {
495 w.set_csilpen(true);
496 w.set_venclpen(true);
497 w.set_gfxtimlpen(true);
498 w.set_dcmilpen(true);
499 w.set_ltdclpen(true);
500 });
501
502 RCC.buslpenr().modify(|w| {
503 w.set_aclknclpen(true);
504 w.set_aclknlpen(true);
505 });
506
507 RCC.memlpenr().modify(|w| {
508 w.set_bootromlpen(true);
509 w.set_vencramlpen(true);
510 w.set_npucacheramlpen(true);
511 w.set_flexramlpen(true);
512 w.set_axisram2lpen(true);
513 w.set_axisram1lpen(true);
514 w.set_bkpsramlpen(true);
515 w.set_ahbsram2lpen(true);
516 w.set_ahbsram1lpen(true);
517 w.set_axisram6lpen(true);
518 w.set_axisram5lpen(true);
519 w.set_axisram4lpen(true);
520 w.set_axisram3lpen(true);
521 });
522
523 RCC.misclpenr().modify(|w| {
524 w.set_perlpen(true);
525 w.set_xspiphycomplpen(true);
526 w.set_dbglpen(true);
527 });
528}
529
530const fn periph_prescaler_to_value(bits: u8) -> u8 {
531 match bits {
532 0 => 1,
533 1 => 2,
534 2 => 4,
535 3 => 8,
536 4 => 16,
537 5 => 32,
538 6 => 64,
539 7.. => 128,
540 }
541}
542
543fn pll_source_ready(source: u8) -> bool {
544 match source {
545 0x0 if !RCC.sr().read().pllrdy(0) && !RCC.pllcfgr1(0).read().pllbyp() => false,
546 0x1 if !RCC.sr().read().pllrdy(1) && !RCC.pllcfgr1(1).read().pllbyp() => false,
547 0x2 if !RCC.sr().read().pllrdy(2) && !RCC.pllcfgr1(2).read().pllbyp() => false,
548 0x3 if !RCC.sr().read().pllrdy(3) && !RCC.pllcfgr1(3).read().pllbyp() => false,
549 _ => true,
550 }
551}
552
553fn pll_sources_ready(source1: u8, source2: u8) -> bool {
554 pll_source_ready(source1) && pll_source_ready(source2)
555}
556
557impl Default for Config {
558 fn default() -> Self {
559 Self::new()
560 }
561}
562
563fn power_supply_config(supply_config: SupplyConfig) {
564 // power supply config
565 PWR.cr1().modify(|w| {
566 w.set_sden(match supply_config {
567 SupplyConfig::External => false,
568 SupplyConfig::Smps => true,
569 });
570 });
571
572 // Validate supply configuration
573 while !PWR.voscr().read().actvosrdy() {}
574}
575
576struct PllInput {
577 hsi: Option<Hertz>,
578 msi: Option<Hertz>,
579 hse: Option<Hertz>,
580 i2s_ckin: Option<Hertz>,
581}
582
583#[derive(Clone, Copy, Default)]
584#[allow(dead_code)]
585struct PllOutput {
586 divm: Option<Hertz>,
587 divn: Option<Hertz>,
588 divp1: Option<Hertz>,
589 divp2: Option<Hertz>,
590 output: Option<Hertz>,
591}
592
593fn init_pll(pll_config: Option<Pll>, pll_index: usize, input: &PllInput) -> PllOutput {
594 let cfgr1 = RCC.pllcfgr1(pll_index);
595 let cfgr2 = RCC.pllcfgr2(pll_index);
596 let cfgr3 = RCC.pllcfgr3(pll_index);
597
598 match pll_config {
599 Some(Pll::Oscillator {
600 source,
601 divm,
602 fractional,
603 divn,
604 divp1,
605 divp2,
606 }) => {
607 // ensure pll is disabled
608 RCC.ccr().write(|w| w.set_pllonc(pll_index, true));
609 while RCC.sr().read().pllrdy(pll_index) {}
610
611 // ensure PLLxMODSSDIS=1 to work in fractional mode
612 cfgr3.modify(|w| w.set_pllmodssdis(Pllmodssdis::FRACTIONAL_DIVIDE));
613 // clear bypass mode
614 cfgr1.modify(|w| w.set_pllbyp(false));
615 // configure the pll clock source, mul and div factors
616 cfgr1.modify(|w| {
617 w.set_pllsel(source);
618 w.set_plldivm(divm);
619 w.set_plldivn(divn);
620 });
621
622 let in_clk = match source {
623 Pllsel::HSI => unwrap!(input.hsi),
624 Pllsel::MSI => unwrap!(input.msi),
625 Pllsel::HSE => unwrap!(input.hse),
626 Pllsel::I2S_CKIN => unwrap!(input.i2s_ckin),
627 _ => panic!("reserved PLL source not allowed"),
628 };
629
630 let m = divm.to_bits() as u32;
631 let n = divn as u32;
632
633 cfgr3.modify(|w| {
634 w.set_pllpdiv1(divp1);
635 w.set_pllpdiv2(divp2);
636 });
637
638 let p1 = divp1.to_bits() as u32;
639 let p2 = divp2.to_bits() as u32;
640
641 // configure pll divnfrac
642 cfgr2.modify(|w| w.set_plldivnfrac(fractional));
643 // clear pllxmoddsen
644 cfgr3.modify(|w| w.set_pllmoddsen(false));
645 // fractional mode
646 if fractional != 0 {
647 cfgr3.modify(|w| {
648 w.set_pllmoddsen(true);
649 w.set_plldacen(true);
650 })
651 }
652 // enable pll post divider output
653 cfgr3.modify(|w| {
654 w.set_pllmodssrst(true);
655 w.set_pllpdiven(true);
656 });
657 // enable the pll
658 RCC.csr().write(|w| w.pllons(pll_index));
659 // wait until ready
660 while RCC.sr().read().pllrdy(pll_index) {}
661
662 PllOutput {
663 divm: Some(Hertz(m)),
664 divn: Some(Hertz(n)),
665 divp1: Some(Hertz(p1)),
666 divp2: Some(Hertz(p2)),
667 output: Some(Hertz(in_clk.0 / m / n / p1 / p2)),
668 }
669 }
670 Some(Pll::Bypass { source }) => {
671 // check if source is ready
672 if !pll_source_ready(source.to_bits()) {
673 panic!("PLL source is not ready")
674 }
675
676 // ensure pll is disabled
677 RCC.ccr().write(|w| w.set_pllonc(pll_index, true));
678 while RCC.sr().read().pllrdy(pll_index) {}
679
680 cfgr1.modify(|w| {
681 w.set_pllbyp(true);
682 w.set_pllsel(source);
683 });
684
685 let in_clk = match source {
686 Pllsel::HSI => unwrap!(input.hsi),
687 Pllsel::MSI => unwrap!(input.msi),
688 Pllsel::HSE => unwrap!(input.hse),
689 Pllsel::I2S_CKIN => unwrap!(input.i2s_ckin),
690 _ => panic!("reserved PLL source not allowed"),
691 };
692
693 PllOutput {
694 output: Some(in_clk),
695 ..Default::default()
696 }
697 }
698 None => {
699 cfgr3.modify(|w| w.set_pllpdiven(false));
700 RCC.ccr().write(|w| w.set_pllonc(pll_index, true));
701 // wait till disabled
702 while RCC.sr().read().pllrdy(pll_index) {}
703
704 // clear bypass mode
705 cfgr1.modify(|w| w.set_pllbyp(false));
706
707 PllOutput::default()
708 }
709 }
710}
711
712#[allow(dead_code)]
713struct OscOutput {
714 hsi: Option<Hertz>,
715 hse: Option<Hertz>,
716 msi: Option<Hertz>,
717 lsi: Option<Hertz>,
718 lse: Option<Hertz>,
719 pll1: Option<Hertz>,
720 pll2: Option<Hertz>,
721 pll3: Option<Hertz>,
722 pll4: Option<Hertz>,
723 ic1sel: Icsel,
724 ic2sel: Icsel,
725 ic6sel: Icsel,
726 ic11sel: Icsel,
727}
728
729fn init_osc(config: Config) -> OscOutput {
730 let (cpu_src, sys_src) = {
731 let reg = RCC.cfgr().read();
732 (reg.cpusws(), reg.syssws())
733 };
734 let pll1_src = RCC.pllcfgr1(0).read().pllsel();
735 let pll2_src = RCC.pllcfgr1(1).read().pllsel();
736 let pll3_src = RCC.pllcfgr1(2).read().pllsel();
737 let pll4_src = RCC.pllcfgr1(3).read().pllsel();
738 let rcc_sr = RCC.sr().read();
739
740 debug!("configuring HSE");
741
742 // hse configuration
743 let hse = if let Some(hse) = config.hse {
744 match hse.mode {
745 HseMode::Oscillator => {
746 debug!("HSE in oscillator mode");
747 }
748 HseMode::Bypass => {
749 debug!("HSE in bypass mode");
750 RCC.hsecfgr().modify(|w| {
751 w.set_hsebyp(true);
752 w.set_hseext(Hseext::ANALOG);
753 });
754 }
755 HseMode::BypassDigital => {
756 debug!("HSE in bypass digital mode");
757 RCC.hsecfgr().modify(|w| {
758 w.set_hsebyp(true);
759 w.set_hseext(Hseext::DIGITAL);
760 });
761 }
762 }
763 RCC.csr().write(|w| w.set_hseons(true));
764
765 // wait until the hse is ready
766 while !RCC.sr().read().hserdy() {}
767
768 Some(hse.freq)
769 } else if cpu_src == Cpusws::HSE
770 || sys_src == Syssws::HSE
771 || (pll1_src == Pllsel::HSE && rcc_sr.pllrdy(0))
772 || (pll2_src == Pllsel::HSE && rcc_sr.pllrdy(1))
773 || (pll3_src == Pllsel::HSE && rcc_sr.pllrdy(2))
774 || (pll4_src == Pllsel::HSE && rcc_sr.pllrdy(3))
775 {
776 panic!(
777 "When the HSE is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"
778 );
779 } else {
780 debug!("HSE off");
781
782 RCC.ccr().write(|w| w.set_hseonc(true));
783 RCC.hsecfgr().modify(|w| {
784 w.set_hseext(Hseext::ANALOG);
785 w.set_hsebyp(false);
786 });
787
788 // wait until the hse is disabled
789 while RCC.sr().read().hserdy() {}
790
791 None
792 };
793
794 // hsi configuration
795 debug!("configuring HSI");
796 let hsi = if let Some(hsi) = config.hsi {
797 RCC.csr().write(|w| w.set_hsions(true));
798 while !RCC.sr().read().hsirdy() {}
799
800 // set divider and calibration
801 RCC.hsicfgr().modify(|w| {
802 w.set_hsidiv(hsi.pre);
803 w.set_hsitrim(hsi.trim);
804 });
805
806 Some(HSI_FREQ / hsi.pre)
807 } else if cpu_src == Cpusws::HSI
808 || sys_src == Syssws::HSI
809 || (pll1_src == Pllsel::HSI && rcc_sr.pllrdy(0))
810 || (pll2_src == Pllsel::HSI && rcc_sr.pllrdy(1))
811 || (pll3_src == Pllsel::HSI && rcc_sr.pllrdy(2))
812 || (pll4_src == Pllsel::HSI && rcc_sr.pllrdy(3))
813 {
814 panic!(
815 "When the HSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"
816 );
817 } else {
818 debug!("HSI off");
819
820 RCC.ccr().write(|w| w.set_hsionc(true));
821 while RCC.sr().read().hsirdy() {}
822
823 None
824 };
825
826 // msi configuration
827 debug!("configuring MSI");
828 let msi = if let Some(msi) = config.msi {
829 RCC.msicfgr().modify(|w| w.set_msifreqsel(msi.freq));
830 RCC.csr().write(|w| w.set_msions(true));
831 while !RCC.sr().read().msirdy() {}
832 RCC.msicfgr().modify(|w| w.set_msitrim(msi.trim));
833
834 Some(match msi.freq {
835 Msifreqsel::_4MHZ => Hertz::mhz(4),
836 Msifreqsel::_16MHZ => Hertz::mhz(16),
837 })
838 } else if cpu_src == Cpusws::MSI
839 || sys_src == Syssws::MSI
840 || (pll1_src == Pllsel::MSI && rcc_sr.pllrdy(0))
841 || (pll2_src == Pllsel::MSI && rcc_sr.pllrdy(1))
842 || (pll3_src == Pllsel::MSI && rcc_sr.pllrdy(2))
843 || (pll4_src == Pllsel::MSI && rcc_sr.pllrdy(3))
844 {
845 panic!(
846 "When the MSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"
847 );
848 } else {
849 RCC.ccr().write(|w| w.set_msionc(true));
850 while RCC.sr().read().msirdy() {}
851
852 None
853 };
854
855 // lsi configuration
856 debug!("configuring LSI");
857 let lsi = if config.lsi {
858 RCC.csr().write(|w| w.set_lsions(true));
859 while !RCC.sr().read().lsirdy() {}
860 Some(super::LSI_FREQ)
861 } else {
862 RCC.ccr().write(|w| w.set_lsionc(true));
863 while RCC.sr().read().lsirdy() {}
864 None
865 };
866
867 // lse configuration
868 debug!("configuring LSE");
869 let lse = if config.lse {
870 RCC.csr().write(|w| w.set_lseons(true));
871 while !RCC.sr().read().lserdy() {}
872 Some(LSE_FREQ)
873 } else {
874 RCC.ccr().write(|w| w.set_lseonc(true));
875 while RCC.sr().read().lserdy() {}
876 None
877 };
878
879 let pll_input = PllInput {
880 hse,
881 msi,
882 hsi,
883 i2s_ckin: None,
884 };
885
886 // pll1,2,3,4 config
887 let pll_configs = [config.pll1, config.pll2, config.pll3, config.pll4];
888 let mut pll_outputs: [PllOutput; 4] = [PllOutput::default(); 4];
889
890 let ic1_src = RCC.iccfgr(0).read().icsel();
891 let ic2_src = RCC.iccfgr(1).read().icsel();
892 let ic6_src = RCC.iccfgr(5).read().icsel();
893 let ic11_src = RCC.iccfgr(10).read().icsel();
894
895 for (n, (&pll, out)) in pll_configs.iter().zip(pll_outputs.iter_mut()).enumerate() {
896 debug!("configuring PLL{}", n + 1);
897 let pll_ready = RCC.sr().read().pllrdy(n);
898
899 if is_new_pll_config(pll, 0) {
900 let this_pll = Icsel::from_bits(n as u8);
901
902 if cpu_src == Cpusws::IC1 && ic1_src == this_pll {
903 panic!("PLL should not be disabled / reconfigured if used for IC1 (cpuclksrc)")
904 }
905
906 if sys_src == Syssws::IC2 && (ic2_src == this_pll || ic6_src == this_pll || ic11_src == this_pll) {
907 panic!("PLL should not be disabled / reconfigured if used for IC2, IC6 or IC11 (sysclksrc)")
908 }
909
910 *out = init_pll(pll, 0, &pll_input);
911 } else if pll.is_some() && !pll_ready {
912 RCC.csr().write(|w| w.pllons(n));
913 while !RCC.sr().read().pllrdy(n) {}
914 }
915 }
916
917 OscOutput {
918 hsi,
919 hse,
920 msi,
921 lsi,
922 lse,
923 pll1: pll_outputs[0].output,
924 pll2: pll_outputs[1].output,
925 pll3: pll_outputs[2].output,
926 pll4: pll_outputs[3].output,
927 ic1sel: ic1_src,
928 ic2sel: ic2_src,
929 ic6sel: ic6_src,
930 ic11sel: ic11_src,
931 }
932}
933
934fn is_new_pll_config(pll: Option<Pll>, pll_index: usize) -> bool {
935 let cfgr1 = RCC.pllcfgr1(pll_index).read();
936 let cfgr2 = RCC.pllcfgr2(pll_index).read();
937 let cfgr3 = RCC.pllcfgr3(pll_index).read();
938
939 let ready = RCC.sr().read().pllrdy(pll_index);
940 let bypass = cfgr1.pllbyp();
941
942 match (pll, ready, bypass) {
943 (None, true, _) => return true,
944 (Some(_), false, _) => return true,
945 (Some(conf), true, bypass) => match (conf, bypass) {
946 (Pll::Bypass { .. }, false) => return true,
947 (Pll::Oscillator { .. }, true) => return true,
948 _ => {}
949 },
950 _ => {}
951 }
952
953 match pll {
954 Some(Pll::Bypass { source }) => cfgr1.pllsel() != source,
955 Some(Pll::Oscillator {
956 source,
957 divm: m,
958 fractional,
959 divn: n,
960 divp1: p1,
961 divp2: p2,
962 }) => {
963 cfgr1.pllsel() != source
964 || cfgr1.plldivm() != m
965 || cfgr1.plldivn() != n
966 || cfgr2.plldivnfrac() != fractional
967 || cfgr3.pllpdiv1() != p1
968 || cfgr3.pllpdiv2() != p2
969 }
970 None => false,
971 }
972}
973
974pub(crate) unsafe fn init(config: Config) {
975 debug!("enabling SYSCFG");
976 // system configuration setup
977 RCC.apb4hensr().write(|w| w.set_syscfgens(true));
978 // delay after RCC peripheral clock enabling
979 RCC.apb4hensr().read();
980
981 debug!("setting VTOR");
982
983 let vtor = unsafe {
984 let p = cortex_m::Peripherals::steal();
985 p.SCB.vtor.read()
986 };
987
988 // set default vector table location after reset or standby
989 SYSCFG.initsvtorcr().write(|w| w.set_svtor_addr(vtor));
990 // read back the value to ensure it is written before deactivating SYSCFG
991 SYSCFG.initsvtorcr().read();
992
993 debug!("deactivating SYSCFG");
994
995 // deactivate SYSCFG
996 RCC.apb4hensr().write(|w| w.set_syscfgens(false));
997
998 debug!("enabling FPU");
999
1000 // enable fpu
1001 unsafe {
1002 let p = cortex_m::Peripherals::steal();
1003 p.SCB.cpacr.modify(|w| w | (3 << 20) | (3 << 22));
1004 }
1005
1006 // TODO: ugly workaround for DMA accesses until RIF is properly implemented
1007 debug!("deactivating RIF");
1008 const RISAF3_BASE_NS: *mut u32 = stm32_metapac::RNG.wrapping_byte_offset(0x8000) as _; // AHB3PERIPH_BASE_NS + 0x8000UL
1009 const RISAF3_REG0_CFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x40);
1010 const RISAF3_REG0_ENDR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x48);
1011 const RISAF3_REG0_CIDCFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x4C);
1012 const RISAF3_REG1_CFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x80);
1013 const RISAF3_REG1_ENDR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x88);
1014 const RISAF3_REG1_CIDCFGR: *mut u32 = RISAF3_BASE_NS.wrapping_byte_offset(0x8C);
1015 unsafe {
1016 *RISAF3_REG0_CIDCFGR = 0x000F000F; /* RW for everyone */
1017 *RISAF3_REG0_ENDR = 0xFFFFFFFF; /* all-encompassing */
1018 *RISAF3_REG0_CFGR = 0x00000101; /* enabled, secure, unprivileged for everyone */
1019 *RISAF3_REG1_CIDCFGR = 0x00FF00FF; /* RW for everyone */
1020 *RISAF3_REG1_ENDR = 0xFFFFFFFF; /* all-encompassing */
1021 *RISAF3_REG1_CFGR = 0x00000001; /* enabled, non-secure, unprivileged*/
1022 }
1023
1024 debug!("setting power supply config");
1025
1026 power_supply_config(config.supply_config);
1027
1028 let osc = init_osc(config);
1029 let clock_inputs = ClocksInput {
1030 hsi: osc.hsi,
1031 msi: osc.msi,
1032 hse: osc.hse,
1033 };
1034 let clocks = init_clocks(config, &clock_inputs);
1035
1036 // TODO: sysb, sysc, sysd must have the same clock source
1037
1038 set_clocks!(
1039 sys: Some(clocks.sysclk),
1040 hsi: osc.hsi,
1041 hsi_div: None,
1042 hse: osc.hse,
1043 msi: osc.msi,
1044 hclk1: Some(clocks.ahb),
1045 hclk2: Some(clocks.ahb),
1046 hclk3: Some(clocks.ahb),
1047 hclk4: Some(clocks.ahb),
1048 hclk5: Some(clocks.ahb),
1049 pclk1: Some(clocks.apb1),
1050 pclk2: Some(clocks.apb2),
1051 pclk1_tim: Some(clocks.pclk_tim),
1052 pclk2_tim: Some(clocks.pclk_tim),
1053 pclk4: Some(clocks.apb4),
1054 pclk5: Some(clocks.apb5),
1055 per: None,
1056 rtc: None,
1057 i2s_ckin: None,
1058 ic8: None,
1059 ic9: None,
1060 ic10: None,
1061 ic14: None,
1062 ic15: None,
1063 ic17: None,
1064 ic20: None,
1065 );
1066}
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index 06895a99a..47cc29c6f 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -6,9 +6,9 @@ pub use crate::pac::rcc::vals::{
6 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, 6 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
7}; 7};
8use crate::pac::rcc::vals::{Hseext, Msipllfast, Msipllsel, Msirgsel, Pllmboost, Pllrge}; 8use crate::pac::rcc::vals::{Hseext, Msipllfast, Msipllsel, Msirgsel, Pllmboost, Pllrge};
9#[cfg(all(peri_usb_otg_hs))]
10pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG};
11use crate::pac::{FLASH, PWR, RCC}; 9use crate::pac::{FLASH, PWR, RCC};
10#[cfg(all(peri_usb_otg_hs))]
11pub use crate::pac::{SYSCFG, syscfg::vals::Usbrefcksel};
12use crate::rcc::LSI_FREQ; 12use crate::rcc::LSI_FREQ;
13use crate::time::Hertz; 13use crate::time::Hertz;
14 14
@@ -343,6 +343,16 @@ pub(crate) unsafe fn init(config: Config) {
343 343
344 let hsi48 = config.hsi48.map(super::init_hsi48); 344 let hsi48 = config.hsi48.map(super::init_hsi48);
345 345
346 // There's a possibility that a bootloader that ran before us has configured the system clock
347 // source to be PLL1_R. In that case we'd get forever stuck on (de)configuring PLL1 as the chip
348 // prohibits disabling PLL1 when it's used as a source for system clock. Change the system
349 // clock source to MSIS which doesn't suffer from this conflict. The correct source per the
350 // provided config is then set further down.
351 // See https://github.com/embassy-rs/embassy/issues/5072
352 let default_system_clock_source = Config::default().sys;
353 RCC.cfgr1().modify(|w| w.set_sw(default_system_clock_source));
354 while RCC.cfgr1().read().sws() != default_system_clock_source {}
355
346 let pll_input = PllInput { hse, hsi, msi: msis }; 356 let pll_input = PllInput { hse, hsi, msi: msis };
347 let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range); 357 let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range);
348 let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range); 358 let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range);
@@ -442,7 +452,10 @@ pub(crate) unsafe fn init(config: Config) {
442 Hertz(24_000_000) => Usbrefcksel::MHZ24, 452 Hertz(24_000_000) => Usbrefcksel::MHZ24,
443 Hertz(26_000_000) => Usbrefcksel::MHZ26, 453 Hertz(26_000_000) => Usbrefcksel::MHZ26,
444 Hertz(32_000_000) => Usbrefcksel::MHZ32, 454 Hertz(32_000_000) => Usbrefcksel::MHZ32,
445 _ => panic!("cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), 455 _ => panic!(
456 "cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz",
457 clk_val
458 ),
446 }, 459 },
447 None => Usbrefcksel::MHZ24, 460 None => Usbrefcksel::MHZ24,
448 }; 461 };
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs
index 481437939..2528996d5 100644
--- a/embassy-stm32/src/rcc/wba.rs
+++ b/embassy-stm32/src/rcc/wba.rs
@@ -7,9 +7,9 @@ pub use crate::pac::rcc::vals::{
7 Hdiv5, Hpre as AHBPrescaler, Hpre5 as AHB5Prescaler, Hsepre as HsePrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, 7 Hdiv5, Hpre as AHBPrescaler, Hpre5 as AHB5Prescaler, Hsepre as HsePrescaler, Plldiv as PllDiv, Pllm as PllPreDiv,
8 Plln as PllMul, Pllsrc as PllSource, Ppre as APBPrescaler, Sai1sel, Sw as Sysclk, 8 Plln as PllMul, Pllsrc as PllSource, Ppre as APBPrescaler, Sai1sel, Sw as Sysclk,
9}; 9};
10#[cfg(all(peri_usb_otg_hs))]
11pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG};
12use crate::pac::{FLASH, RCC}; 10use crate::pac::{FLASH, RCC};
11#[cfg(all(peri_usb_otg_hs))]
12pub use crate::pac::{SYSCFG, syscfg::vals::Usbrefcksel};
13use crate::rcc::LSI_FREQ; 13use crate::rcc::LSI_FREQ;
14use crate::time::Hertz; 14use crate::time::Hertz;
15 15
@@ -245,7 +245,10 @@ pub(crate) unsafe fn init(config: Config) {
245 Hertz(24_000_000) => Usbrefcksel::MHZ24, 245 Hertz(24_000_000) => Usbrefcksel::MHZ24,
246 Hertz(26_000_000) => Usbrefcksel::MHZ26, 246 Hertz(26_000_000) => Usbrefcksel::MHZ26,
247 Hertz(32_000_000) => Usbrefcksel::MHZ32, 247 Hertz(32_000_000) => Usbrefcksel::MHZ32,
248 _ => panic!("cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), 248 _ => panic!(
249 "cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz",
250 clk_val
251 ),
249 }, 252 },
250 None => Usbrefcksel::MHZ24, 253 None => Usbrefcksel::MHZ24,
251 }; 254 };