From 44b6494ab7ec3e742aa9f82a8ca9ebdfc23ebbba Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 24 May 2023 17:24:28 +0200 Subject: [PATCH] Let FlashLayout and FlashRegion depends on a Blocking/Async mode generic --- embassy-stm32/Cargo.toml | 1 - embassy-stm32/build.rs | 16 ++- embassy-stm32/src/flash/asynch.rs | 35 ++++- embassy-stm32/src/flash/common.rs | 218 ++++++++++++------------------ embassy-stm32/src/flash/f4.rs | 112 +++++++-------- embassy-stm32/src/flash/mod.rs | 3 + 6 files changed, 179 insertions(+), 206 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 73841bdc..4e29bb32 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -69,7 +69,6 @@ cfg-if = "1.0.0" embedded-io = { version = "0.4.0", features = ["async"], optional = true } chrono = { version = "^0.4", default-features = false, optional = true} bit_field = "0.10.2" -paste = "1.0.12" [dev-dependencies] critical-section = { version = "1.1", features = ["std"] } diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 54098172..29af3c80 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -213,7 +213,7 @@ fn main() { let region_type = format_ident!("{}", get_flash_region_type_name(region.name)); flash_regions.extend(quote! { #[cfg(flash)] - pub struct #region_type<'d>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>,); + pub struct #region_type<'d, MODE>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>, pub(crate) core::marker::PhantomData); }); } @@ -224,11 +224,11 @@ fn main() { let field_name = format_ident!("{}", region_name.to_lowercase()); let field_type = format_ident!("{}", get_flash_region_type_name(f.name)); let field = quote! { - pub #field_name: #field_type<'d> + pub #field_name: #field_type<'d, MODE> }; let region_name = format_ident!("{}", region_name); let init = quote! { - #field_name: #field_type(&#region_name, unsafe { p.clone_unchecked()}) + #field_name: #field_type(&#region_name, unsafe { p.clone_unchecked()}, core::marker::PhantomData) }; (field, (init, region_name)) @@ -238,15 +238,17 @@ fn main() { let regions_len = flash_memory_regions.len(); flash_regions.extend(quote! { #[cfg(flash)] - pub struct FlashLayout<'d> { - #(#fields),* + pub struct FlashLayout<'d, MODE> { + #(#fields),*, + _mode: core::marker::PhantomData, } #[cfg(flash)] - impl<'d> FlashLayout<'d> { + impl<'d, MODE> FlashLayout<'d, MODE> { pub(crate) fn new(p: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>) -> Self { Self { - #(#inits),* + #(#inits),*, + _mode: core::marker::PhantomData, } } } diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs index 44e23d9c..3564bbff 100644 --- a/embassy-stm32/src/flash/asynch.rs +++ b/embassy-stm32/src/flash/asynch.rs @@ -1,12 +1,21 @@ use atomic_polyfill::{fence, Ordering}; use embassy_hal_common::drop::OnDrop; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::mutex::Mutex; use super::{ - ensure_sector_aligned, family, get_sector, Error, Flash, FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, - REGION_ACCESS, WRITE_SIZE, + ensure_sector_aligned, family, get_sector, read_blocking, Async, Error, Flash, FlashLayout, FLASH_BASE, FLASH_SIZE, + MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE, }; +pub(super) static REGION_ACCESS: Mutex = Mutex::new(()); + impl<'d> Flash<'d> { + pub fn into_regions(self) -> FlashLayout<'d, Async> { + family::set_default_layout(); + FlashLayout::new(self.inner) + } + pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { unsafe { write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes).await } } @@ -16,6 +25,18 @@ impl<'d> Flash<'d> { } } +impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_> { + const READ_SIZE: usize = READ_SIZE; + + async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { + self.read(offset, bytes) + } + + fn capacity(&self) -> usize { + FLASH_SIZE + } +} + impl embedded_storage_async::nor_flash::NorFlash for Flash<'_> { const WRITE_SIZE: usize = WRITE_SIZE; const ERASE_SIZE: usize = MAX_ERASE_SIZE; @@ -89,7 +110,11 @@ pub(super) async unsafe fn erase_sectored(base: u32, from: u32, to: u32) -> Resu foreach_flash_region! { ($type_name:ident, $write_size:literal, $erase_size:literal) => { - impl crate::_generated::flash_regions::$type_name<'_> { + impl crate::_generated::flash_regions::$type_name<'_, Async> { + pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + read_blocking(self.0.base, self.0.size, offset, bytes) + } + pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { let _guard = REGION_ACCESS.lock().await; unsafe { write_chunked(self.0.base, self.0.size, offset, bytes).await } @@ -101,7 +126,7 @@ foreach_flash_region! { } } - impl embedded_storage_async::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> { + impl embedded_storage_async::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_, Async> { const READ_SIZE: usize = READ_SIZE; async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { @@ -113,7 +138,7 @@ foreach_flash_region! { } } - impl embedded_storage_async::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_> { + impl embedded_storage_async::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_, Async> { const WRITE_SIZE: usize = $write_size; const ERASE_SIZE: usize = $erase_size; diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index e1fe7e9d..8b38745c 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -1,14 +1,12 @@ use atomic_polyfill::{fence, Ordering}; use embassy_cortex_m::interrupt::InterruptExt; -use embassy_futures::block_on; use embassy_hal_common::drop::OnDrop; use embassy_hal_common::{into_ref, PeripheralRef}; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::mutex::Mutex; use stm32_metapac::FLASH_BASE; use super::{ - family, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE, + family, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, + WRITE_SIZE, }; use crate::peripherals::FLASH; use crate::Peripheral; @@ -17,8 +15,6 @@ pub struct Flash<'d> { pub(crate) inner: PeripheralRef<'d, FLASH>, } -pub(crate) static REGION_ACCESS: Mutex = Mutex::new(()); - impl<'d> Flash<'d> { pub fn new(p: impl Peripheral

+ 'd, irq: impl Peripheral

+ 'd) -> Self { into_ref!(p, irq); @@ -30,7 +26,7 @@ impl<'d> Flash<'d> { Self { inner: p } } - pub fn into_regions(self) -> FlashLayout<'d> { + pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> { family::set_default_layout(); FlashLayout::new(self.inner) } @@ -40,11 +36,19 @@ impl<'d> Flash<'d> { } pub fn write_blocking(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - unsafe { write_chunked_blocking(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) } + unsafe { + write_blocking( + FLASH_BASE as u32, + FLASH_SIZE as u32, + offset, + bytes, + write_chunk_unlocked, + ) + } } pub fn erase_blocking(&mut self, from: u32, to: u32) -> Result<(), Error> { - unsafe { erase_sectored_blocking(FLASH_BASE as u32, from, to) } + unsafe { erase_blocking(FLASH_BASE as u32, from, to, erase_sector_unlocked) } } } @@ -59,7 +63,13 @@ pub(super) fn read_blocking(base: u32, size: u32, offset: u32, bytes: &mut [u8]) Ok(()) } -pub(super) unsafe fn write_chunked_blocking(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> { +pub(super) unsafe fn write_blocking( + base: u32, + size: u32, + offset: u32, + bytes: &[u8], + write_chunk: unsafe fn(u32, &[u8]) -> Result<(), Error>, +) -> Result<(), Error> { if offset + bytes.len() as u32 > size { return Err(Error::Size); } @@ -71,26 +81,39 @@ pub(super) unsafe fn write_chunked_blocking(base: u32, size: u32, offset: u32, b trace!("Writing {} bytes at 0x{:x}", bytes.len(), address); for chunk in bytes.chunks(WRITE_SIZE) { - family::clear_all_err(); - fence(Ordering::SeqCst); - family::unlock(); - fence(Ordering::SeqCst); - family::enable_blocking_write(); - fence(Ordering::SeqCst); - - let _on_drop = OnDrop::new(|| { - family::disable_blocking_write(); - fence(Ordering::SeqCst); - family::lock(); - }); - - family::write_blocking(address, chunk.try_into().unwrap())?; + write_chunk(address, chunk)?; address += WRITE_SIZE as u32; } Ok(()) } -pub(super) unsafe fn erase_sectored_blocking(base: u32, from: u32, to: u32) -> Result<(), Error> { +pub(super) unsafe fn write_chunk_unlocked(address: u32, chunk: &[u8]) -> Result<(), Error> { + family::clear_all_err(); + fence(Ordering::SeqCst); + family::unlock(); + fence(Ordering::SeqCst); + family::enable_blocking_write(); + fence(Ordering::SeqCst); + + let _on_drop = OnDrop::new(|| { + family::disable_blocking_write(); + fence(Ordering::SeqCst); + family::lock(); + }); + + family::write_blocking(address, chunk.try_into().unwrap()) +} + +pub(super) unsafe fn write_chunk_with_critical_section(address: u32, chunk: &[u8]) -> Result<(), Error> { + critical_section::with(|_| write_chunk_unlocked(address, chunk)) +} + +pub(super) unsafe fn erase_blocking( + base: u32, + from: u32, + to: u32, + erase_sector: unsafe fn(&FlashSector) -> Result<(), Error>, +) -> Result<(), Error> { let start_address = base + from; let end_address = base + to; let regions = family::get_flash_regions(); @@ -103,21 +126,28 @@ pub(super) unsafe fn erase_sectored_blocking(base: u32, from: u32, to: u32) -> R while address < end_address { let sector = get_sector(address, regions); trace!("Erasing sector: {:?}", sector); - - family::clear_all_err(); - fence(Ordering::SeqCst); - family::unlock(); - fence(Ordering::SeqCst); - - let _on_drop = OnDrop::new(|| family::lock()); - - family::erase_sector_blocking(§or)?; + erase_sector(§or)?; address += sector.size; } Ok(()) } -pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector { +pub(super) unsafe fn erase_sector_unlocked(sector: &FlashSector) -> Result<(), Error> { + family::clear_all_err(); + fence(Ordering::SeqCst); + family::unlock(); + fence(Ordering::SeqCst); + + let _on_drop = OnDrop::new(|| family::lock()); + + family::erase_sector_blocking(§or) +} + +pub(super) unsafe fn erase_sector_with_critical_section(sector: &FlashSector) -> Result<(), Error> { + critical_section::with(|_| erase_sector_unlocked(sector)) +} + +pub(super) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector { let mut current_bank = FlashBank::Bank1; let mut bank_offset = 0; for region in regions { @@ -142,7 +172,7 @@ pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector panic!("Flash sector not found"); } -pub(crate) fn ensure_sector_aligned( +pub(super) fn ensure_sector_aligned( start_address: u32, end_address: u32, regions: &[&FlashRegion], @@ -190,121 +220,49 @@ impl embedded_storage::nor_flash::NorFlash for Flash<'_> { } } -#[cfg(feature = "nightly")] -impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_> { - const READ_SIZE: usize = READ_SIZE; - - async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.read(offset, bytes) - } - - fn capacity(&self) -> usize { - FLASH_SIZE - } -} - -pub struct BlockingFlashRegion<'d, const WRITE_SIZE: u32, const ERASE_SIZE: u32>( - &'static FlashRegion, - PeripheralRef<'d, FLASH>, -); - -impl BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> { - pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - read_blocking(self.0.base, self.0.size, offset, bytes) - } - - pub fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - let _guard = block_on(REGION_ACCESS.lock()); - unsafe { write_chunked_blocking(self.0.base, self.0.size, offset, bytes) } - } - - pub fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - let _guard = block_on(REGION_ACCESS.lock()); - unsafe { erase_sectored_blocking(self.0.base, from, to) } - } -} - -impl embedded_storage::nor_flash::ErrorType - for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> -{ - type Error = Error; -} - -impl embedded_storage::nor_flash::ReadNorFlash - for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> -{ - const READ_SIZE: usize = READ_SIZE; - - fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.read(offset, bytes) - } - - fn capacity(&self) -> usize { - self.0.size as usize - } -} - -impl embedded_storage::nor_flash::NorFlash - for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> -{ - const WRITE_SIZE: usize = WRITE_SIZE as usize; - const ERASE_SIZE: usize = ERASE_SIZE as usize; - - fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { - self.write(offset, bytes) - } - - fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { - self.erase(from, to) - } -} - foreach_flash_region! { ($type_name:ident, $write_size:literal, $erase_size:literal) => { - paste::paste! { - pub type []<'d> = BlockingFlashRegion<'d, $write_size, $erase_size>; - } - - impl<'d> crate::_generated::flash_regions::$type_name<'d> { - /// Make this flash region work in a blocking context. - /// - /// SAFETY - /// - /// This function is unsafe as incorect usage of parallel blocking operations - /// on multiple regions may cause a deadlock because each region requires mutual access to the flash. - pub unsafe fn into_blocking(self) -> BlockingFlashRegion<'d, $write_size, $erase_size> { - BlockingFlashRegion(self.0, self.1) - } - - pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + impl<'d> crate::_generated::flash_regions::$type_name<'d, Blocking> { + pub fn read_blocking(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { read_blocking(self.0.base, self.0.size, offset, bytes) } - pub fn try_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?; - unsafe { write_chunked_blocking(self.0.base, self.0.size, offset, bytes) } + pub fn write_blocking(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { + unsafe { write_blocking(self.0.base, self.0.size, offset, bytes, write_chunk_with_critical_section) } } - pub fn try_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?; - unsafe { erase_sectored_blocking(self.0.base, from, to) } + pub fn erase_blocking(&mut self, from: u32, to: u32) -> Result<(), Error> { + unsafe { erase_blocking(self.0.base, from, to, erase_sector_with_critical_section) } } } - impl embedded_storage::nor_flash::ErrorType for crate::_generated::flash_regions::$type_name<'_> { + impl embedded_storage::nor_flash::ErrorType for crate::_generated::flash_regions::$type_name<'_, MODE> { type Error = Error; } - impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> { + impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_, Blocking> { const READ_SIZE: usize = READ_SIZE; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.read(offset, bytes) + self.read_blocking(offset, bytes) } fn capacity(&self) -> usize { self.0.size as usize } } + + impl embedded_storage::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_, Blocking> { + const WRITE_SIZE: usize = $write_size; + const ERASE_SIZE: usize = $erase_size; + + fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { + self.write_blocking(offset, bytes) + } + + fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { + self.erase_blocking(from, to) + } + } }; } diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 084bbdc6..d50a35b4 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -11,6 +11,8 @@ use crate::pac; #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] mod alt_regions { + use core::marker::PhantomData; + use embassy_hal_common::PeripheralRef; use stm32_metapac::FLASH_SIZE; @@ -18,8 +20,7 @@ mod alt_regions { #[cfg(feature = "nightly")] use crate::flash::asynch; use crate::flash::{ - common, Bank1Region1, Bank1Region2, BlockingFlashRegion, Error, Flash, FlashBank, FlashRegion, READ_SIZE, - REGION_ACCESS, + common, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion, READ_SIZE, }; use crate::peripherals::FLASH; @@ -53,101 +54,86 @@ mod alt_regions { &ALT_BANK2_REGION3, ]; - pub struct AltBank1Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); - pub struct AltBank2Region1<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); - pub struct AltBank2Region2<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); - pub struct AltBank2Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); + pub struct AltBank1Region3<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData); + pub struct AltBank2Region1<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData); + pub struct AltBank2Region2<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData); + pub struct AltBank2Region3<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData); - pub type BlockingAltBank1Region3<'d> = - BlockingFlashRegion<'d, { ALT_BANK1_REGION3.write_size }, { ALT_BANK1_REGION3.erase_size }>; - pub type BlockingAltBank2Region1<'d> = - BlockingFlashRegion<'d, { ALT_BANK2_REGION1.write_size }, { ALT_BANK2_REGION1.erase_size }>; - pub type BlockingAltBank2Region2<'d> = - BlockingFlashRegion<'d, { ALT_BANK2_REGION2.write_size }, { ALT_BANK2_REGION2.erase_size }>; - pub type BlockingAltBank2Region3<'d> = - BlockingFlashRegion<'d, { ALT_BANK2_REGION3.write_size }, { ALT_BANK2_REGION3.erase_size }>; - - pub struct AltFlashLayout<'d> { - pub bank1_region1: Bank1Region1<'d>, - pub bank1_region2: Bank1Region2<'d>, - pub bank1_region3: AltBank1Region3<'d>, - pub bank2_region1: AltBank2Region1<'d>, - pub bank2_region2: AltBank2Region2<'d>, - pub bank2_region3: AltBank2Region3<'d>, - pub otp_region: OTPRegion<'d>, + pub struct AltFlashLayout<'d, MODE> { + pub bank1_region1: Bank1Region1<'d, MODE>, + pub bank1_region2: Bank1Region2<'d, MODE>, + pub bank1_region3: AltBank1Region3<'d, MODE>, + pub bank2_region1: AltBank2Region1<'d, MODE>, + pub bank2_region2: AltBank2Region2<'d, MODE>, + pub bank2_region3: AltBank2Region3<'d, MODE>, + pub otp_region: OTPRegion<'d, MODE>, } impl<'d> Flash<'d> { - pub fn into_alt_regions(self) -> AltFlashLayout<'d> { + pub fn into_alt_regions(self) -> AltFlashLayout<'d, Async> { + unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) }; + + // SAFETY: We never expose the cloned peripheral references, and their instance is not public. + // Also, all async flash region operations are protected with a mutex. + let p = self.inner; + AltFlashLayout { + bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }, PhantomData), + bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }, PhantomData), + bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }, PhantomData), + bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData), + bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData), + bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData), + otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData), + } + } + + pub fn into_alt_blocking_regions(self) -> AltFlashLayout<'d, Blocking> { unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) }; // SAFETY: We never expose the cloned peripheral references, and their instance is not public. // Also, all blocking flash region operations are protected with a cs. let p = self.inner; AltFlashLayout { - bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }), - bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }), - bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }), - bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }), - bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }), - bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }), - otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }), + bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }, PhantomData), + bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }, PhantomData), + bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }, PhantomData), + bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData), + bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData), + bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData), + otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData), } } } macro_rules! foreach_altflash_region { ($type_name:ident, $region:ident) => { - impl $type_name<'_> { - pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + #[cfg(feature = "nightly")] + impl $type_name<'_, Async> { + pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { common::read_blocking(self.0.base, self.0.size, offset, bytes) } - #[cfg(feature = "nightly")] pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - let _guard = REGION_ACCESS.lock().await; + let _guard = asynch::REGION_ACCESS.lock().await; unsafe { asynch::write_chunked(self.0.base, self.0.size, offset, bytes).await } } - #[cfg(feature = "nightly")] pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - let _guard = REGION_ACCESS.lock().await; + let _guard = asynch::REGION_ACCESS.lock().await; unsafe { asynch::erase_sectored(self.0.base, from, to).await } } - - pub fn try_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?; - unsafe { common::write_chunked_blocking(self.0.base, self.0.size, offset, bytes) } - } - - pub fn try_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?; - unsafe { common::erase_sectored_blocking(self.0.base, from, to) } - } } - impl embedded_storage::nor_flash::ErrorType for $type_name<'_> { + impl embedded_storage::nor_flash::ErrorType for $type_name<'_, Async> { type Error = Error; } - impl embedded_storage::nor_flash::ReadNorFlash for $type_name<'_> { - const READ_SIZE: usize = READ_SIZE; - - fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.read(offset, bytes) - } - - fn capacity(&self) -> usize { - self.0.size as usize - } - } - #[cfg(feature = "nightly")] - impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_> { + impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_, Async> { const READ_SIZE: usize = READ_SIZE; async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.read(offset, bytes) + self.read(offset, bytes).await } fn capacity(&self) -> usize { @@ -156,7 +142,7 @@ mod alt_regions { } #[cfg(feature = "nightly")] - impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_> { + impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_, Async> { const WRITE_SIZE: usize = $region.write_size as usize; const ERASE_SIZE: usize = $region.erase_size as usize; diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 1ef04e56..56a680a8 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -14,6 +14,9 @@ pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; pub const READ_SIZE: usize = 1; +pub struct Blocking; +pub struct Async; + #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct FlashRegion {