diff options
Diffstat (limited to 'embassy-stm32/src/rcc/bd.rs')
| -rw-r--r-- | embassy-stm32/src/rcc/bd.rs | 140 |
1 files changed, 116 insertions, 24 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 @@ | |||
| 1 | use core::sync::atomic::{compiler_fence, Ordering}; | 1 | #[cfg(not(stm32n6))] |
| 2 | use core::sync::atomic::{Ordering, compiler_fence}; | ||
| 2 | 3 | ||
| 3 | use crate::pac::common::{Reg, RW}; | 4 | #[cfg(not(stm32n6))] |
| 5 | use crate::pac::common::{RW, Reg}; | ||
| 6 | #[cfg(backup_sram)] | ||
| 7 | use crate::pac::pwr::vals::Retention; | ||
| 4 | pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource; | 8 | pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource; |
| 5 | use crate::time::Hertz; | 9 | use 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)))] |
| 56 | type Bdcr = crate::pac::rcc::regs::Bdcr; | 60 | type Bdcr = crate::pac::rcc::regs::Bdcr; |
| 57 | #[cfg(any(rtc_v2_l0, rtc_v2_l1))] | 61 | #[cfg(any(rtc_v2_l0, rtc_v2_l1))] |
| 58 | type Bdcr = crate::pac::rcc::regs::Csr; | 62 | type 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))] |
| 63 | fn unlock() {} | 67 | fn unlock() {} |
| 64 | 68 | ||
| 65 | #[cfg(not(any(stm32c0)))] | 69 | #[cfg(not(any(stm32c0, stm32n6)))] |
| 66 | fn unlock() { | 70 | fn 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))] | ||
| 78 | fn bdcr() -> Reg<Bdcr, RW> { | 85 | fn 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 | ||
| 94 | impl LsConfig { | 103 | impl 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 | ||
| 142 | impl LsConfig { | 157 | impl 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); |
