diff options
| author | Rasmus Melchior Jacobsen <[email protected]> | 2023-05-25 21:14:35 +0200 |
|---|---|---|
| committer | Rasmus Melchior Jacobsen <[email protected]> | 2023-05-25 21:14:35 +0200 |
| commit | 18d14dff48d1fd49cfd43fb94304bf932a74a6ca (patch) | |
| tree | 8d870c031b0b444d324ff3665be676411df23c2f /embassy-stm32 | |
| parent | b412784a7aea102ef53744fbb11d473fa3c0c984 (diff) | |
Handle errata 2.2.12
Diffstat (limited to 'embassy-stm32')
| -rw-r--r-- | embassy-stm32/src/flash/f4.rs | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 488584212..d67e6d0a1 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs | |||
| @@ -2,11 +2,12 @@ use core::convert::TryInto; | |||
| 2 | use core::ptr::write_volatile; | 2 | use core::ptr::write_volatile; |
| 3 | use core::sync::atomic::{fence, Ordering}; | 3 | use core::sync::atomic::{fence, Ordering}; |
| 4 | 4 | ||
| 5 | use atomic_polyfill::AtomicBool; | ||
| 5 | #[cfg(feature = "nightly")] | 6 | #[cfg(feature = "nightly")] |
| 6 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 7 | use pac::flash::regs::Sr; | 8 | use pac::flash::regs::Sr; |
| 8 | 9 | ||
| 9 | use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | 10 | use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; |
| 10 | use crate::flash::Error; | 11 | use crate::flash::Error; |
| 11 | use crate::pac; | 12 | use crate::pac; |
| 12 | 13 | ||
| @@ -167,6 +168,7 @@ pub use alt_regions::*; | |||
| 167 | 168 | ||
| 168 | #[cfg(feature = "nightly")] | 169 | #[cfg(feature = "nightly")] |
| 169 | static WAKER: AtomicWaker = AtomicWaker::new(); | 170 | static WAKER: AtomicWaker = AtomicWaker::new(); |
| 171 | static DATA_CACHE_WAS_ENABLED: AtomicBool = AtomicBool::new(false); | ||
| 170 | 172 | ||
| 171 | impl FlashSector { | 173 | impl FlashSector { |
| 172 | const fn snb(&self) -> u8 { | 174 | const fn snb(&self) -> u8 { |
| @@ -238,6 +240,7 @@ pub(crate) unsafe fn unlock() { | |||
| 238 | #[cfg(feature = "nightly")] | 240 | #[cfg(feature = "nightly")] |
| 239 | pub(crate) unsafe fn enable_write() { | 241 | pub(crate) unsafe fn enable_write() { |
| 240 | assert_eq!(0, WRITE_SIZE % 4); | 242 | assert_eq!(0, WRITE_SIZE % 4); |
| 243 | save_data_cache_state(); | ||
| 241 | 244 | ||
| 242 | pac::FLASH.cr().write(|w| { | 245 | pac::FLASH.cr().write(|w| { |
| 243 | w.set_pg(true); | 246 | w.set_pg(true); |
| @@ -254,10 +257,12 @@ pub(crate) unsafe fn disable_write() { | |||
| 254 | w.set_eopie(false); | 257 | w.set_eopie(false); |
| 255 | w.set_errie(false); | 258 | w.set_errie(false); |
| 256 | }); | 259 | }); |
| 260 | restore_data_cache_state(); | ||
| 257 | } | 261 | } |
| 258 | 262 | ||
| 259 | pub(crate) unsafe fn enable_blocking_write() { | 263 | pub(crate) unsafe fn enable_blocking_write() { |
| 260 | assert_eq!(0, WRITE_SIZE % 4); | 264 | assert_eq!(0, WRITE_SIZE % 4); |
| 265 | save_data_cache_state(); | ||
| 261 | 266 | ||
| 262 | pac::FLASH.cr().write(|w| { | 267 | pac::FLASH.cr().write(|w| { |
| 263 | w.set_pg(true); | 268 | w.set_pg(true); |
| @@ -267,6 +272,7 @@ pub(crate) unsafe fn enable_blocking_write() { | |||
| 267 | 272 | ||
| 268 | pub(crate) unsafe fn disable_blocking_write() { | 273 | pub(crate) unsafe fn disable_blocking_write() { |
| 269 | pac::FLASH.cr().write(|w| w.set_pg(false)); | 274 | pac::FLASH.cr().write(|w| w.set_pg(false)); |
| 275 | restore_data_cache_state(); | ||
| 270 | } | 276 | } |
| 271 | 277 | ||
| 272 | #[cfg(feature = "nightly")] | 278 | #[cfg(feature = "nightly")] |
| @@ -293,6 +299,8 @@ unsafe fn write_start(start_address: u32, buf: &[u8; WRITE_SIZE]) { | |||
| 293 | 299 | ||
| 294 | #[cfg(feature = "nightly")] | 300 | #[cfg(feature = "nightly")] |
| 295 | pub(crate) async unsafe fn erase_sector(sector: &FlashSector) -> Result<(), Error> { | 301 | pub(crate) async unsafe fn erase_sector(sector: &FlashSector) -> Result<(), Error> { |
| 302 | save_data_cache_state(); | ||
| 303 | |||
| 296 | pac::FLASH.cr().modify(|w| { | 304 | pac::FLASH.cr().modify(|w| { |
| 297 | w.set_ser(true); | 305 | w.set_ser(true); |
| 298 | w.set_snb(sector.snb()); | 306 | w.set_snb(sector.snb()); |
| @@ -310,10 +318,13 @@ pub(crate) async unsafe fn erase_sector(sector: &FlashSector) -> Result<(), Erro | |||
| 310 | w.set_errie(false); | 318 | w.set_errie(false); |
| 311 | }); | 319 | }); |
| 312 | clear_all_err(); | 320 | clear_all_err(); |
| 321 | restore_data_cache_state(); | ||
| 313 | ret | 322 | ret |
| 314 | } | 323 | } |
| 315 | 324 | ||
| 316 | pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> { | 325 | pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> { |
| 326 | save_data_cache_state(); | ||
| 327 | |||
| 317 | pac::FLASH.cr().modify(|w| { | 328 | pac::FLASH.cr().modify(|w| { |
| 318 | w.set_ser(true); | 329 | w.set_ser(true); |
| 319 | w.set_snb(sector.snb()) | 330 | w.set_snb(sector.snb()) |
| @@ -325,6 +336,7 @@ pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), E | |||
| 325 | 336 | ||
| 326 | let ret: Result<(), Error> = wait_ready_blocking(); | 337 | let ret: Result<(), Error> = wait_ready_blocking(); |
| 327 | clear_all_err(); | 338 | clear_all_err(); |
| 339 | restore_data_cache_state(); | ||
| 328 | ret | 340 | ret |
| 329 | } | 341 | } |
| 330 | 342 | ||
| @@ -380,6 +392,33 @@ fn get_result(sr: Sr) -> Result<(), Error> { | |||
| 380 | } | 392 | } |
| 381 | } | 393 | } |
| 382 | 394 | ||
| 395 | fn save_data_cache_state() { | ||
| 396 | let dual_bank = get_flash_regions().last().unwrap().bank == FlashBank::Bank2; | ||
| 397 | if dual_bank { | ||
| 398 | // Disable data cache during write/erase if there are two banks, see errata 2.2.12 | ||
| 399 | let dcen = unsafe { pac::FLASH.acr().read().dcen() }; | ||
| 400 | DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed); | ||
| 401 | if dcen { | ||
| 402 | unsafe { pac::FLASH.acr().modify(|w| w.set_dcen(false)) }; | ||
| 403 | } | ||
| 404 | } | ||
| 405 | } | ||
| 406 | |||
| 407 | fn restore_data_cache_state() { | ||
| 408 | let dual_bank = get_flash_regions().last().unwrap().bank == FlashBank::Bank2; | ||
| 409 | if dual_bank { | ||
| 410 | // Restore data cache if it was enabled | ||
| 411 | let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed); | ||
| 412 | if dcen { | ||
| 413 | unsafe { | ||
| 414 | // Reset data cache before we enable it again | ||
| 415 | pac::FLASH.acr().modify(|w| w.set_dcrst(true)); | ||
| 416 | pac::FLASH.acr().modify(|w| w.set_dcen(true)) | ||
| 417 | }; | ||
| 418 | } | ||
| 419 | } | ||
| 420 | } | ||
| 421 | |||
| 383 | pub(crate) fn assert_not_corrupted_read() { | 422 | pub(crate) fn assert_not_corrupted_read() { |
| 384 | #[allow(unused)] | 423 | #[allow(unused)] |
| 385 | const REVISION_3: u16 = 0x2001; | 424 | const REVISION_3: u16 = 0x2001; |
