From b2775fc90c3d7cc977f1ac3e15841462d7c8f1a4 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen <rmja@laesoe.org> Date: Wed, 24 May 2023 12:17:12 +0200 Subject: [PATCH 01/14] stm32: Add async flash write/erase to f4 --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/flash/asynch.rs | 129 +++++++++++++++ embassy-stm32/src/flash/common.rs | 267 ++++++++++++++++-------------- embassy-stm32/src/flash/f0.rs | 18 +- embassy-stm32/src/flash/f3.rs | 18 +- embassy-stm32/src/flash/f4.rs | 183 +++++++++++++++++--- embassy-stm32/src/flash/f7.rs | 21 +-- embassy-stm32/src/flash/h7.rs | 21 +-- embassy-stm32/src/flash/l.rs | 19 ++- embassy-stm32/src/flash/mod.rs | 49 ++++++ embassy-stm32/src/flash/other.rs | 12 +- 11 files changed, 547 insertions(+), 194 deletions(-) create mode 100644 embassy-stm32/src/flash/asynch.rs diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 21adb5ddf..440de85e8 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -47,6 +47,7 @@ embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true} embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true} embedded-storage = "0.3.0" +embedded-storage-async = { version = "0.4.0", optional = true } defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } @@ -68,6 +69,7 @@ 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"] } @@ -98,7 +100,7 @@ time-driver-tim12 = ["_time-driver"] time-driver-tim15 = ["_time-driver"] # Enable nightly-only features -nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"] +nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"] # Reexport stm32-metapac at `embassy_stm32::pac`. # This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version. diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs new file mode 100644 index 000000000..44e23d9c4 --- /dev/null +++ b/embassy-stm32/src/flash/asynch.rs @@ -0,0 +1,129 @@ +use atomic_polyfill::{fence, Ordering}; +use embassy_hal_common::drop::OnDrop; + +use super::{ + ensure_sector_aligned, family, get_sector, Error, Flash, FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, + REGION_ACCESS, WRITE_SIZE, +}; + +impl<'d> Flash<'d> { + 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 } + } + + pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { + unsafe { erase_sectored(FLASH_BASE as u32, from, to).await } + } +} + +impl embedded_storage_async::nor_flash::NorFlash for Flash<'_> { + const WRITE_SIZE: usize = WRITE_SIZE; + const ERASE_SIZE: usize = MAX_ERASE_SIZE; + + async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { + self.write(offset, bytes).await + } + + async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { + self.erase(from, to).await + } +} + +pub(super) async unsafe fn write_chunked(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> { + if offset + bytes.len() as u32 > size { + return Err(Error::Size); + } + if offset % WRITE_SIZE as u32 != 0 || bytes.len() % WRITE_SIZE != 0 { + return Err(Error::Unaligned); + } + + let mut address = base + offset; + 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_write(); + fence(Ordering::SeqCst); + + let _on_drop = OnDrop::new(|| { + family::disable_write(); + fence(Ordering::SeqCst); + family::lock(); + }); + + family::write(address, chunk.try_into().unwrap()).await?; + address += WRITE_SIZE as u32; + } + Ok(()) +} + +pub(super) async unsafe fn erase_sectored(base: u32, from: u32, to: u32) -> Result<(), Error> { + let start_address = base + from; + let end_address = base + to; + let regions = family::get_flash_regions(); + + ensure_sector_aligned(start_address, end_address, regions)?; + + trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); + + let mut address = start_address; + 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(§or).await?; + address += sector.size; + } + Ok(()) +} + +foreach_flash_region! { + ($type_name:ident, $write_size:literal, $erase_size:literal) => { + impl crate::_generated::flash_regions::$type_name<'_> { + 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 } + } + + pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { + let _guard = REGION_ACCESS.lock().await; + unsafe { erase_sectored(self.0.base, from, to).await } + } + } + + impl embedded_storage_async::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> { + 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 { + self.0.size as usize + } + } + + impl embedded_storage_async::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_> { + const WRITE_SIZE: usize = $write_size; + const ERASE_SIZE: usize = $erase_size; + + async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { + self.write(offset, bytes).await + } + + async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { + self.erase(from, to).await + } + } + }; +} diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 432c8a43b..990104a38 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -1,44 +1,55 @@ 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, FlashLayout, FlashRegion, FlashSector, FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, WRITE_SIZE}; -use crate::flash::FlashBank; +use super::{ + ensure_sector_aligned, family, get_sector, Error, FlashLayout, FlashRegion, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, + WRITE_SIZE, +}; +use crate::peripherals::FLASH; use crate::Peripheral; pub struct Flash<'d> { - inner: PeripheralRef<'d, crate::peripherals::FLASH>, + pub(crate) inner: PeripheralRef<'d, FLASH>, } +pub(crate) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(()); + impl<'d> Flash<'d> { - pub fn new(p: impl Peripheral<P = crate::peripherals::FLASH> + 'd) -> Self { - into_ref!(p); + pub fn new(p: impl Peripheral<P = FLASH> + 'd, irq: impl Peripheral<P = crate::interrupt::FLASH> + 'd) -> Self { + into_ref!(p, irq); + + irq.set_handler(family::on_interrupt); + irq.unpend(); + irq.enable(); + Self { inner: p } } pub fn into_regions(self) -> FlashLayout<'d> { family::set_default_layout(); - FlashLayout::new(self.release()) + FlashLayout::new(self.inner) } - pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - blocking_read(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) + pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + read_blocking(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) } - pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - unsafe { blocking_write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) } + 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) } } - pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - unsafe { blocking_erase_sectored(FLASH_BASE as u32, from, to) } - } - - pub(crate) fn release(self) -> PeripheralRef<'d, crate::peripherals::FLASH> { - unsafe { self.inner.clone_unchecked() } + pub fn erase_blocking(&mut self, from: u32, to: u32) -> Result<(), Error> { + unsafe { erase_sectored_blocking(FLASH_BASE as u32, from, to) } } } -pub(super) fn blocking_read(base: u32, size: u32, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { +pub(super) fn read_blocking(base: u32, size: u32, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { if offset + bytes.len() as u32 > size { return Err(Error::Size); } @@ -49,7 +60,7 @@ pub(super) fn blocking_read(base: u32, size: u32, offset: u32, bytes: &mut [u8]) Ok(()) } -pub(super) unsafe fn blocking_write_chunked(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> { +pub(super) unsafe fn write_chunked_blocking(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> { if offset + bytes.len() as u32 > size { return Err(Error::Size); } @@ -61,44 +72,31 @@ pub(super) unsafe fn blocking_write_chunked(base: u32, size: u32, offset: u32, b trace!("Writing {} bytes at 0x{:x}", bytes.len(), address); for chunk in bytes.chunks(WRITE_SIZE) { - critical_section::with(|_| { - family::clear_all_err(); - fence(Ordering::SeqCst); - family::unlock(); - fence(Ordering::SeqCst); - family::begin_write(); - fence(Ordering::SeqCst); + 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::end_write(); - fence(Ordering::SeqCst); - family::lock(); - }); + let _on_drop = OnDrop::new(|| { + family::disable_blocking_write(); + fence(Ordering::SeqCst); + family::lock(); + }); - family::blocking_write(address, chunk.try_into().unwrap()) - })?; + family::write_blocking(address, chunk.try_into().unwrap())?; address += WRITE_SIZE as u32; } Ok(()) } -pub(super) unsafe fn blocking_erase_sectored(base: u32, from: u32, to: u32) -> Result<(), Error> { +pub(super) unsafe fn erase_sectored_blocking(base: u32, from: u32, to: u32) -> Result<(), Error> { let start_address = base + from; let end_address = base + to; let regions = family::get_flash_regions(); - // Test if the address range is aligned at sector base addresses - let mut address = start_address; - while address < end_address { - let sector = get_sector(address, regions); - if sector.start != address { - return Err(Error::Unaligned); - } - address += sector.size; - } - if address != end_address { - return Err(Error::Unaligned); - } + ensure_sector_aligned(start_address, end_address, regions)?; trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); @@ -107,71 +105,28 @@ pub(super) unsafe fn blocking_erase_sectored(base: u32, from: u32, to: u32) -> R let sector = get_sector(address, regions); trace!("Erasing sector: {:?}", sector); - critical_section::with(|_| { - family::clear_all_err(); - fence(Ordering::SeqCst); - family::unlock(); - fence(Ordering::SeqCst); + family::clear_all_err(); + fence(Ordering::SeqCst); + family::unlock(); + fence(Ordering::SeqCst); - let _on_drop = OnDrop::new(|| { - family::lock(); - }); + let _on_drop = OnDrop::new(|| family::lock()); - family::blocking_erase_sector(§or) - })?; + family::erase_sector_blocking(§or)?; address += sector.size; } Ok(()) } -pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector { - let mut current_bank = FlashBank::Bank1; - let mut bank_offset = 0; - for region in regions { - if region.bank != current_bank { - current_bank = region.bank; - bank_offset = 0; - } - - if address < region.end() { - let index_in_region = (address - region.base) / region.erase_size; - return FlashSector { - bank: region.bank, - index_in_bank: bank_offset + index_in_region as u8, - start: region.base + index_in_region * region.erase_size, - size: region.erase_size, - }; - } - - bank_offset += region.sectors(); - } - - panic!("Flash sector not found"); -} - -impl FlashRegion { - pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - blocking_read(self.base, self.size, offset, bytes) - } - - pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - unsafe { blocking_write_chunked(self.base, self.size, offset, bytes) } - } - - pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - unsafe { blocking_erase_sectored(self.base, from, to) } - } -} - impl embedded_storage::nor_flash::ErrorType for Flash<'_> { type Error = Error; } impl embedded_storage::nor_flash::ReadNorFlash for Flash<'_> { - const READ_SIZE: usize = 1; + const READ_SIZE: usize = READ_SIZE; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(offset, bytes) + self.read(offset, bytes) } fn capacity(&self) -> usize { @@ -184,27 +139,112 @@ impl embedded_storage::nor_flash::NorFlash for Flash<'_> { const ERASE_SIZE: usize = MAX_ERASE_SIZE; fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(offset, bytes) + self.write_blocking(offset, bytes) } fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { - self.blocking_erase(from, to) + self.erase_blocking(from, to) + } +} + +#[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<const WRITE_SIZE: u32, const ERASE_SIZE: u32> 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<const WRITE_SIZE: u32, const ERASE_SIZE: u32> embedded_storage::nor_flash::ErrorType + for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> +{ + type Error = Error; +} + +impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> 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<const WRITE_SIZE: u32, const ERASE_SIZE: u32> 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) => { - impl crate::_generated::flash_regions::$type_name<'_> { - pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - blocking_read(self.0.base, self.0.size, offset, bytes) + paste::paste! { + pub type [<Blocking $type_name>]<'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 blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - unsafe { blocking_write_chunked(self.0.base, self.0.size, offset, bytes) } + pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + read_blocking(self.0.base, self.0.size, offset, bytes) } - pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - unsafe { blocking_erase_sectored(self.0.base, from, to) } + 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 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) } } } @@ -213,28 +253,15 @@ foreach_flash_region! { } impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> { - const READ_SIZE: usize = 1; + const READ_SIZE: usize = READ_SIZE; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(offset, bytes) + self.read(offset, bytes) } fn capacity(&self) -> usize { self.0.size as usize } } - - impl embedded_storage::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_> { - const WRITE_SIZE: usize = $write_size; - const ERASE_SIZE: usize = $erase_size; - - fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(offset, bytes) - } - - fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { - self.blocking_erase(from, to) - } - } }; } diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs index c6441ef16..ecf3a6981 100644 --- a/embassy-stm32/src/flash/f0.rs +++ b/embassy-stm32/src/flash/f0.rs @@ -13,6 +13,10 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } +pub(crate) unsafe fn on_interrupt(_: *mut ()) { + unimplemented!(); +} + pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } @@ -22,17 +26,17 @@ pub(crate) unsafe fn unlock() { pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); } -pub(crate) unsafe fn begin_write() { +pub(crate) unsafe fn enable_blocking_write() { assert_eq!(0, WRITE_SIZE % 2); pac::FLASH.cr().write(|w| w.set_pg(true)); } -pub(crate) unsafe fn end_write() { +pub(crate) unsafe fn disable_blocking_write() { pac::FLASH.cr().write(|w| w.set_pg(false)); } -pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { +pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { let mut address = start_address; for chunk in buf.chunks(2) { write_volatile(address as *mut u16, u16::from_le_bytes(chunk.try_into().unwrap())); @@ -42,10 +46,10 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) fence(Ordering::SeqCst); } - blocking_wait_ready() + wait_ready_blocking() } -pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { +pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> { pac::FLASH.cr().modify(|w| { w.set_per(true); }); @@ -56,7 +60,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E w.set_strt(true); }); - let mut ret: Result<(), Error> = blocking_wait_ready(); + let mut ret: Result<(), Error> = wait_ready_blocking(); if !pac::FLASH.sr().read().eop() { trace!("FLASH: EOP not set"); @@ -88,7 +92,7 @@ pub(crate) unsafe fn clear_all_err() { }); } -unsafe fn blocking_wait_ready() -> Result<(), Error> { +unsafe fn wait_ready_blocking() -> Result<(), Error> { loop { let sr = pac::FLASH.sr().read(); diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs index 4c8172203..fd778f2b1 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs @@ -13,6 +13,10 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } +pub(crate) unsafe fn on_interrupt(_: *mut ()) { + unimplemented!(); +} + pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } @@ -22,17 +26,17 @@ pub(crate) unsafe fn unlock() { pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); } -pub(crate) unsafe fn begin_write() { +pub(crate) unsafe fn enable_blocking_write() { assert_eq!(0, WRITE_SIZE % 2); pac::FLASH.cr().write(|w| w.set_pg(true)); } -pub(crate) unsafe fn end_write() { +pub(crate) unsafe fn disable_blocking_write() { pac::FLASH.cr().write(|w| w.set_pg(false)); } -pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { +pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { let mut address = start_address; for chunk in buf.chunks(2) { write_volatile(address as *mut u16, u16::from_le_bytes(chunk.try_into().unwrap())); @@ -42,10 +46,10 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) fence(Ordering::SeqCst); } - blocking_wait_ready() + wait_ready_blocking() } -pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { +pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> { pac::FLASH.cr().modify(|w| { w.set_per(true); }); @@ -56,7 +60,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E w.set_strt(true); }); - let mut ret: Result<(), Error> = blocking_wait_ready(); + let mut ret: Result<(), Error> = wait_ready_blocking(); if !pac::FLASH.sr().read().eop() { trace!("FLASH: EOP not set"); @@ -88,7 +92,7 @@ pub(crate) unsafe fn clear_all_err() { }); } -unsafe fn blocking_wait_ready() -> Result<(), Error> { +unsafe fn wait_ready_blocking() -> Result<(), Error> { loop { let sr = pac::FLASH.sr().read(); diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 7f1c5f671..3c8f81eb0 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -2,6 +2,8 @@ use core::convert::TryInto; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; +use embassy_sync::waitqueue::AtomicWaker; + use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; @@ -13,8 +15,8 @@ mod alt_regions { use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION}; use crate::flash::{ - blocking_erase_sectored, blocking_read, blocking_write_chunked, Bank1Region1, Bank1Region2, Error, Flash, - FlashBank, FlashRegion, + asynch, common, Bank1Region1, Bank1Region2, BlockingFlashRegion, Error, Flash, FlashBank, FlashRegion, + READ_SIZE, REGION_ACCESS, }; use crate::peripherals::FLASH; @@ -53,6 +55,15 @@ mod alt_regions { pub struct AltBank2Region2<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); pub struct AltBank2Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); + 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>, @@ -69,7 +80,7 @@ mod alt_regions { // 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.release(); + let p = self.inner; AltFlashLayout { bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }), bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }), @@ -85,16 +96,30 @@ mod alt_regions { macro_rules! foreach_altflash_region { ($type_name:ident, $region:ident) => { impl $type_name<'_> { - pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - blocking_read(self.0.base, self.0.size, offset, bytes) + pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + common::read_blocking(self.0.base, self.0.size, offset, bytes) } - pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - unsafe { blocking_write_chunked(self.0.base, self.0.size, offset, bytes) } + #[cfg(all(feature = "nightly"))] + pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { + let _guard = REGION_ACCESS.lock().await; + unsafe { asynch::write_chunked(self.0.base, self.0.size, offset, bytes).await } } - pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - unsafe { blocking_erase_sectored(self.0.base, from, to) } + #[cfg(all(feature = "nightly"))] + pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { + let _guard = 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) } } } @@ -103,10 +128,10 @@ mod alt_regions { } impl embedded_storage::nor_flash::ReadNorFlash for $type_name<'_> { - const READ_SIZE: usize = 1; + const READ_SIZE: usize = READ_SIZE; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(offset, bytes) + self.read(offset, bytes) } fn capacity(&self) -> usize { @@ -114,16 +139,28 @@ mod alt_regions { } } - impl embedded_storage::nor_flash::NorFlash for $type_name<'_> { + impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_> { + 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 { + self.0.size as usize + } + } + + impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_> { const WRITE_SIZE: usize = $region.write_size as usize; const ERASE_SIZE: usize = $region.erase_size as usize; - fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(offset, bytes) + async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { + self.write(offset, bytes).await } - fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { - self.blocking_erase(from, to) + async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { + self.erase(from, to).await } } }; @@ -138,6 +175,9 @@ mod alt_regions { #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] pub use alt_regions::*; +#[cfg(feature = "nightly")] +static WAKER: AtomicWaker = AtomicWaker::new(); + #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] pub fn set_default_layout() { unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(false)) }; @@ -160,6 +200,16 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } +pub(crate) unsafe fn on_interrupt(_: *mut ()) { + // Clear IRQ flags + pac::FLASH.sr().write(|w| { + w.set_operr(true); + w.set_eop(true); + }); + + WAKER.wake(); +} + pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } @@ -169,7 +219,28 @@ pub(crate) unsafe fn unlock() { pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); } -pub(crate) unsafe fn begin_write() { +#[cfg(feature = "nightly")] +pub(crate) unsafe fn enable_write() { + assert_eq!(0, WRITE_SIZE % 4); + + pac::FLASH.cr().write(|w| { + w.set_pg(true); + w.set_psize(pac::flash::vals::Psize::PSIZE32); + w.set_eopie(true); + w.set_errie(true); + }); +} + +#[cfg(feature = "nightly")] +pub(crate) unsafe fn disable_write() { + pac::FLASH.cr().write(|w| { + w.set_pg(false); + w.set_eopie(false); + w.set_errie(false); + }); +} + +pub(crate) unsafe fn enable_blocking_write() { assert_eq!(0, WRITE_SIZE % 4); pac::FLASH.cr().write(|w| { @@ -178,11 +249,22 @@ pub(crate) unsafe fn begin_write() { }); } -pub(crate) unsafe fn end_write() { +pub(crate) unsafe fn disable_blocking_write() { pac::FLASH.cr().write(|w| w.set_pg(false)); } -pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { +#[cfg(feature = "nightly")] +pub(crate) async unsafe fn write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + write_start(start_address, buf); + wait_ready().await +} + +pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + write_start(start_address, buf); + wait_ready_blocking() +} + +unsafe fn write_start(start_address: u32, buf: &[u8; WRITE_SIZE]) { let mut address = start_address; for val in buf.chunks(4) { write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); @@ -191,11 +273,32 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) // prevents parallelism errors fence(Ordering::SeqCst); } - - blocking_wait_ready() } -pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { +pub(crate) async unsafe fn erase_sector(sector: &FlashSector) -> Result<(), Error> { + let snb = ((sector.bank as u8) << 4) + sector.index_in_bank; + + pac::FLASH.cr().modify(|w| { + w.set_ser(true); + w.set_snb(snb); + w.set_eopie(true); + w.set_errie(true); + }); + + pac::FLASH.cr().modify(|w| { + w.set_strt(true); + }); + + let ret: Result<(), Error> = wait_ready().await; + pac::FLASH.cr().modify(|w| { + w.set_eopie(false); + w.set_errie(false); + }); + clear_all_err(); + ret +} + +pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> { let snb = ((sector.bank as u8) << 4) + sector.index_in_bank; pac::FLASH.cr().modify(|w| { @@ -207,10 +310,8 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E w.set_strt(true); }); - let ret: Result<(), Error> = blocking_wait_ready(); - + let ret: Result<(), Error> = wait_ready_blocking(); clear_all_err(); - ret } @@ -220,11 +321,39 @@ pub(crate) unsafe fn clear_all_err() { w.set_pgperr(true); w.set_pgaerr(true); w.set_wrperr(true); - w.set_eop(true); }); } -unsafe fn blocking_wait_ready() -> Result<(), Error> { +#[cfg(feature = "nightly")] +pub(crate) async unsafe fn wait_ready() -> Result<(), Error> { + use core::task::Poll; + + use futures::future::poll_fn; + + poll_fn(|cx| { + WAKER.register(cx.waker()); + + let sr = pac::FLASH.sr().read(); + if !sr.bsy() { + Poll::Ready(if sr.pgserr() { + Err(Error::Seq) + } else if sr.pgperr() { + Err(Error::Parallelism) + } else if sr.pgaerr() { + Err(Error::Unaligned) + } else if sr.wrperr() { + Err(Error::Protected) + } else { + Ok(()) + }) + } else { + return Poll::Pending; + } + }) + .await +} + +unsafe fn wait_ready_blocking() -> Result<(), Error> { loop { let sr = pac::FLASH.sr().read(); diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index ac2834a84..a0593b14b 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -12,6 +12,10 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } +pub(crate) unsafe fn on_interrupt(_: *mut ()) { + unimplemented!(); +} + pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } @@ -21,7 +25,7 @@ pub(crate) unsafe fn unlock() { pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); } -pub(crate) unsafe fn begin_write() { +pub(crate) unsafe fn enable_blocking_write() { assert_eq!(0, WRITE_SIZE % 4); pac::FLASH.cr().write(|w| { @@ -30,11 +34,11 @@ pub(crate) unsafe fn begin_write() { }); } -pub(crate) unsafe fn end_write() { +pub(crate) unsafe fn disable_blocking_write() { pac::FLASH.cr().write(|w| w.set_pg(false)); } -pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { +pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { let mut address = start_address; for val in buf.chunks(4) { write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); @@ -44,10 +48,10 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) fence(Ordering::SeqCst); } - blocking_wait_ready() + wait_ready_blocking() } -pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { +pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> { pac::FLASH.cr().modify(|w| { w.set_ser(true); w.set_snb(sector.index_in_bank) @@ -57,12 +61,9 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E w.set_strt(true); }); - let ret: Result<(), Error> = blocking_wait_ready(); - + let ret: Result<(), Error> = wait_ready_blocking(); pac::FLASH.cr().modify(|w| w.set_ser(false)); - clear_all_err(); - ret } @@ -86,7 +87,7 @@ pub(crate) unsafe fn clear_all_err() { }); } -unsafe fn blocking_wait_ready() -> Result<(), Error> { +unsafe fn wait_ready_blocking() -> Result<(), Error> { loop { let sr = pac::FLASH.sr().read(); diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 1b1631068..865f13283 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -17,6 +17,10 @@ pub fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } +pub(crate) unsafe fn on_interrupt(_: *mut ()) { + unimplemented!(); +} + pub(crate) unsafe fn lock() { pac::FLASH.bank(0).cr().modify(|w| w.set_lock(true)); if is_dual_bank() { @@ -33,13 +37,13 @@ pub(crate) unsafe fn unlock() { } } -pub(crate) unsafe fn begin_write() { +pub(crate) unsafe fn enable_blocking_write() { assert_eq!(0, WRITE_SIZE % 4); } -pub(crate) unsafe fn end_write() {} +pub(crate) unsafe fn disable_blocking_write() {} -pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { +pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { // We cannot have the write setup sequence in begin_write as it depends on the address let bank = if start_address < BANK1_REGION.end() { pac::FLASH.bank(0) @@ -60,7 +64,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); address += val.len() as u32; - res = Some(blocking_wait_ready(bank)); + res = Some(wait_ready_blocking(bank)); bank.sr().modify(|w| { if w.eop() { w.set_eop(true); @@ -80,7 +84,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) res.unwrap() } -pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { +pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> { let bank = pac::FLASH.bank(sector.bank as usize); bank.cr().modify(|w| { w.set_ser(true); @@ -91,12 +95,9 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E w.set_start(true); }); - let ret: Result<(), Error> = blocking_wait_ready(bank); - + let ret: Result<(), Error> = wait_ready_blocking(bank); bank.cr().modify(|w| w.set_ser(false)); - bank_clear_all_err(bank); - ret } @@ -141,7 +142,7 @@ unsafe fn bank_clear_all_err(bank: pac::flash::Bank) { }); } -unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> { +unsafe fn wait_ready_blocking(bank: pac::flash::Bank) -> Result<(), Error> { loop { let sr = bank.sr().read(); diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index c94f61900..f8a0dac4c 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -12,6 +12,10 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } +pub(crate) unsafe fn on_interrupt(_: *mut ()) { + unimplemented!(); +} + pub(crate) unsafe fn lock() { #[cfg(any(flash_wl, flash_wb, flash_l4))] pac::FLASH.cr().modify(|w| w.set_lock(true)); @@ -41,19 +45,19 @@ pub(crate) unsafe fn unlock() { } } -pub(crate) unsafe fn begin_write() { +pub(crate) unsafe fn enable_blocking_write() { assert_eq!(0, WRITE_SIZE % 4); #[cfg(any(flash_wl, flash_wb, flash_l4))] pac::FLASH.cr().write(|w| w.set_pg(true)); } -pub(crate) unsafe fn end_write() { +pub(crate) unsafe fn disable_blocking_write() { #[cfg(any(flash_wl, flash_wb, flash_l4))] pac::FLASH.cr().write(|w| w.set_pg(false)); } -pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { +pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { let mut address = start_address; for val in buf.chunks(4) { write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); @@ -63,10 +67,10 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) fence(Ordering::SeqCst); } - blocking_wait_ready() + wait_ready_blocking() } -pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { +pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> { #[cfg(any(flash_l0, flash_l1))] { pac::FLASH.pecr().modify(|w| { @@ -96,7 +100,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E }); } - let ret: Result<(), Error> = blocking_wait_ready(); + let ret: Result<(), Error> = wait_ready_blocking(); #[cfg(any(flash_wl, flash_wb, flash_l4))] pac::FLASH.cr().modify(|w| w.set_per(false)); @@ -108,7 +112,6 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E }); clear_all_err(); - ret } @@ -150,7 +153,7 @@ pub(crate) unsafe fn clear_all_err() { }); } -unsafe fn blocking_wait_ready() -> Result<(), Error> { +unsafe fn wait_ready_blocking() -> Result<(), Error> { loop { let sr = pac::FLASH.sr().read(); diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index b93270ae1..e781f1b86 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -1,5 +1,7 @@ use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; +#[cfg(all(feature = "nightly", flash_f4))] +pub mod asynch; #[cfg(flash)] mod common; @@ -10,6 +12,8 @@ pub use crate::_generated::flash_regions::*; pub use crate::_generated::MAX_ERASE_SIZE; pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; +pub const READ_SIZE: usize = 1; + #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct FlashRegion { @@ -76,6 +80,7 @@ pub enum Error { Protected, Unaligned, Parallelism, + TryLockError, } impl NorFlashError for Error { @@ -87,3 +92,47 @@ impl NorFlashError for Error { } } } + +pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector { + let mut current_bank = FlashBank::Bank1; + let mut bank_offset = 0; + for region in regions { + if region.bank != current_bank { + current_bank = region.bank; + bank_offset = 0; + } + + if address < region.end() { + let index_in_region = (address - region.base) / region.erase_size; + return FlashSector { + bank: region.bank, + index_in_bank: bank_offset + index_in_region as u8, + start: region.base + index_in_region * region.erase_size, + size: region.erase_size, + }; + } + + bank_offset += region.sectors(); + } + + panic!("Flash sector not found"); +} + +pub(crate) fn ensure_sector_aligned( + start_address: u32, + end_address: u32, + regions: &[&FlashRegion], +) -> Result<(), Error> { + let mut address = start_address; + while address < end_address { + let sector = get_sector(address, regions); + if sector.start != address { + return Err(Error::Unaligned); + } + address += sector.size; + } + if address != end_address { + return Err(Error::Unaligned); + } + Ok(()) +} diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs index 556034654..e21b0b241 100644 --- a/embassy-stm32/src/flash/other.rs +++ b/embassy-stm32/src/flash/other.rs @@ -8,22 +8,26 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } +pub(crate) unsafe fn on_interrupt(_: *mut ()) { + unimplemented!(); +} + pub(crate) unsafe fn lock() { unimplemented!(); } pub(crate) unsafe fn unlock() { unimplemented!(); } -pub(crate) unsafe fn begin_write() { +pub(crate) unsafe fn enable_blocking_write() { unimplemented!(); } -pub(crate) unsafe fn end_write() { +pub(crate) unsafe fn disable_blocking_write() { unimplemented!(); } -pub(crate) unsafe fn blocking_write(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { +pub(crate) unsafe fn write_blocking(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { unimplemented!(); } -pub(crate) unsafe fn blocking_erase_sector(_sector: &FlashSector) -> Result<(), Error> { +pub(crate) unsafe fn erase_sector_blocking(_sector: &FlashSector) -> Result<(), Error> { unimplemented!(); } pub(crate) unsafe fn clear_all_err() { From 0a26870d363022a7d09500b6ecb28c0b455e81e7 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen <rmja@laesoe.org> Date: Wed, 24 May 2023 12:41:52 +0200 Subject: [PATCH 02/14] Align examples --- examples/stm32f3/src/bin/flash.rs | 5 +- examples/stm32f4/src/bin/flash.rs | 14 ++--- examples/stm32f4/src/bin/flash_async.rs | 81 +++++++++++++++++++++++++ examples/stm32f7/src/bin/flash.rs | 5 +- examples/stm32h7/src/bin/flash.rs | 5 +- examples/stm32l0/src/bin/flash.rs | 5 +- examples/stm32l1/src/bin/flash.rs | 5 +- examples/stm32wl/src/bin/flash.rs | 5 +- 8 files changed, 100 insertions(+), 25 deletions(-) create mode 100644 examples/stm32f4/src/bin/flash_async.rs diff --git a/examples/stm32f3/src/bin/flash.rs b/examples/stm32f3/src/bin/flash.rs index e40ad4fc0..0e5fb0658 100644 --- a/examples/stm32f3/src/bin/flash.rs +++ b/examples/stm32f3/src/bin/flash.rs @@ -4,8 +4,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::flash::Flash; -use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; +use embassy_stm32::{flash::Flash, interrupt}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -15,7 +14,7 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x26000; - let mut f = Flash::new(p.FLASH).into_regions().bank1_region; + let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() }; info!("Reading..."); let mut buf = [0u8; 8]; diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs index bd3a7c95e..de4ecdb8f 100644 --- a/examples/stm32f4/src/bin/flash.rs +++ b/examples/stm32f4/src/bin/flash.rs @@ -4,7 +4,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::flash::Flash; +use embassy_stm32::{flash::Flash, interrupt}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { // Once can also call `into_regions()` to get access to NorFlash implementations // for each of the unique characteristics. - let mut f = Flash::new(p.FLASH); + let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)); // Sector 5 test_flash(&mut f, 128 * 1024, 128 * 1024); @@ -31,19 +31,19 @@ fn test_flash(f: &mut Flash, offset: u32, size: u32) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.blocking_read(offset, &mut buf)); + unwrap!(f.read(offset, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); - unwrap!(f.blocking_erase(offset, offset + size)); + unwrap!(f.erase_blocking(offset, offset + size)); info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.blocking_read(offset, &mut buf)); + unwrap!(f.read(offset, &mut buf)); info!("Read after erase: {=[u8]:x}", buf); info!("Writing..."); - unwrap!(f.blocking_write( + unwrap!(f.write_blocking( offset, &[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, @@ -53,7 +53,7 @@ fn test_flash(f: &mut Flash, offset: u32, size: u32) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.blocking_read(offset, &mut buf)); + unwrap!(f.read(offset, &mut buf)); info!("Read: {=[u8]:x}", buf); assert_eq!( &buf[..], diff --git a/examples/stm32f4/src/bin/flash_async.rs b/examples/stm32f4/src/bin/flash_async.rs new file mode 100644 index 000000000..c9d9df34b --- /dev/null +++ b/examples/stm32f4/src/bin/flash_async.rs @@ -0,0 +1,81 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::{info, unwrap}; +use embassy_executor::Spawner; +use embassy_time::{Timer, Duration}; +use embassy_stm32::flash::Flash; +use embassy_stm32::gpio::{AnyPin, Level, Output, Pin, Speed}; +use embassy_stm32::{interrupt}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello Flash!"); + + let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)); + + // Led should blink uninterrupted during ~2sec erase operation + spawner.spawn(blinky(p.PB7.degrade())).unwrap(); + + // Test on bank 2 in order not to stall CPU. + test_flash(&mut f, 1024 * 1024, 128 * 1024).await; +} + +#[embassy_executor::task] +async fn blinky(p: AnyPin) { + let mut led = Output::new(p, Level::High, Speed::Low); + + loop { + info!("high"); + led.set_high(); + Timer::after(Duration::from_millis(300)).await; + + info!("low"); + led.set_low(); + Timer::after(Duration::from_millis(300)).await; + } +} + +async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) { + info!("Testing offset: {=u32:#X}, size: {=u32:#X}", offset, size); + + info!("Reading..."); + let mut buf = [0u8; 32]; + unwrap!(f.read(offset, &mut buf)); + info!("Read: {=[u8]:x}", buf); + + info!("Erasing..."); + unwrap!(f.erase(offset, offset + size).await); + + info!("Reading..."); + let mut buf = [0u8; 32]; + unwrap!(f.read(offset, &mut buf)); + info!("Read after erase: {=[u8]:x}", buf); + + info!("Writing..."); + unwrap!( + f.write( + offset, + &[ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32 + ] + ) + .await + ); + + info!("Reading..."); + let mut buf = [0u8; 32]; + unwrap!(f.read(offset, &mut buf)); + info!("Read: {=[u8]:x}", buf); + assert_eq!( + &buf[..], + &[ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32 + ] + ); +} \ No newline at end of file diff --git a/examples/stm32f7/src/bin/flash.rs b/examples/stm32f7/src/bin/flash.rs index aabfe8557..717c82e86 100644 --- a/examples/stm32f7/src/bin/flash.rs +++ b/examples/stm32f7/src/bin/flash.rs @@ -4,9 +4,8 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::flash::Flash; +use embassy_stm32::{flash::Flash, interrupt}; use embassy_time::{Duration, Timer}; -use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -19,7 +18,7 @@ async fn main(_spawner: Spawner) { // wait a bit before accessing the flash Timer::after(Duration::from_millis(300)).await; - let mut f = Flash::new(p.FLASH).into_regions().bank1_region3; + let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region3.into_blocking() }; info!("Reading..."); let mut buf = [0u8; 32]; diff --git a/examples/stm32h7/src/bin/flash.rs b/examples/stm32h7/src/bin/flash.rs index 7ee9838c9..aab72cae8 100644 --- a/examples/stm32h7/src/bin/flash.rs +++ b/examples/stm32h7/src/bin/flash.rs @@ -4,9 +4,8 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::flash::Flash; +use embassy_stm32::{flash::Flash, interrupt}; use embassy_time::{Duration, Timer}; -use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -19,7 +18,7 @@ async fn main(_spawner: Spawner) { // wait a bit before accessing the flash Timer::after(Duration::from_millis(300)).await; - let mut f = Flash::new(p.FLASH).into_regions().bank2_region; + let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank2_region.into_blocking() }; info!("Reading..."); let mut buf = [0u8; 32]; diff --git a/examples/stm32l0/src/bin/flash.rs b/examples/stm32l0/src/bin/flash.rs index 337425028..0ed0d05fc 100644 --- a/examples/stm32l0/src/bin/flash.rs +++ b/examples/stm32l0/src/bin/flash.rs @@ -4,8 +4,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::flash::Flash; -use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; +use embassy_stm32::{flash::Flash, interrupt}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -15,7 +14,7 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x26000; - let mut f = Flash::new(p.FLASH).into_regions().bank1_region; + let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() }; info!("Reading..."); let mut buf = [0u8; 8]; diff --git a/examples/stm32l1/src/bin/flash.rs b/examples/stm32l1/src/bin/flash.rs index 38feb0d76..c4d7d029c 100644 --- a/examples/stm32l1/src/bin/flash.rs +++ b/examples/stm32l1/src/bin/flash.rs @@ -4,8 +4,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::flash::Flash; -use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; +use embassy_stm32::{flash::Flash, interrupt}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -15,7 +14,7 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x26000; - let mut f = Flash::new(p.FLASH).into_regions().bank1_region; + let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() }; info!("Reading..."); let mut buf = [0u8; 8]; diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs index e6bc2865c..df51ceb68 100644 --- a/examples/stm32wl/src/bin/flash.rs +++ b/examples/stm32wl/src/bin/flash.rs @@ -4,8 +4,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::flash::Flash; -use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; +use embassy_stm32::{flash::Flash, interrupt}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -15,7 +14,7 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x36000; - let mut f = Flash::new(p.FLASH).into_regions().bank1_region; + let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() }; info!("Reading..."); let mut buf = [0u8; 8]; From ff3a70ed9debd1ce4075c0a28c90bb0c6e693bce Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen <rmja@laesoe.org> Date: Wed, 24 May 2023 12:42:35 +0200 Subject: [PATCH 03/14] Add missing nightly guards --- embassy-stm32/src/flash/f4.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 3c8f81eb0..9698bcd58 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -139,6 +139,7 @@ mod alt_regions { } } + #[cfg(all(feature = "nightly"))] impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_> { const READ_SIZE: usize = READ_SIZE; @@ -151,6 +152,7 @@ mod alt_regions { } } + #[cfg(all(feature = "nightly"))] impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_> { const WRITE_SIZE: usize = $region.write_size as usize; const ERASE_SIZE: usize = $region.erase_size as usize; From 6804b6c0b49777489b132639290b5e977ec8ffd9 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen <rmja@laesoe.org> Date: Wed, 24 May 2023 12:45:59 +0200 Subject: [PATCH 04/14] Fix unused get_sector and ensure_sector_aligned --- embassy-stm32/src/flash/common.rs | 49 +++++++++++++++++++++++++++++-- embassy-stm32/src/flash/mod.rs | 44 --------------------------- 2 files changed, 47 insertions(+), 46 deletions(-) diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 990104a38..7cec5a3c9 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -8,8 +8,8 @@ use embassy_sync::mutex::Mutex; use stm32_metapac::FLASH_BASE; use super::{ - ensure_sector_aligned, family, get_sector, Error, FlashLayout, FlashRegion, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, - WRITE_SIZE, + family, Error, FlashLayout, FlashRegion, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, + WRITE_SIZE, FlashSector, FlashBank, }; use crate::peripherals::FLASH; use crate::Peripheral; @@ -118,6 +118,51 @@ pub(super) unsafe fn erase_sectored_blocking(base: u32, from: u32, to: u32) -> R Ok(()) } +pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector { + let mut current_bank = FlashBank::Bank1; + let mut bank_offset = 0; + for region in regions { + if region.bank != current_bank { + current_bank = region.bank; + bank_offset = 0; + } + + if address < region.end() { + let index_in_region = (address - region.base) / region.erase_size; + return FlashSector { + bank: region.bank, + index_in_bank: bank_offset + index_in_region as u8, + start: region.base + index_in_region * region.erase_size, + size: region.erase_size, + }; + } + + bank_offset += region.sectors(); + } + + panic!("Flash sector not found"); +} + +pub(crate) fn ensure_sector_aligned( + start_address: u32, + end_address: u32, + regions: &[&FlashRegion], +) -> Result<(), Error> { + let mut address = start_address; + while address < end_address { + let sector = get_sector(address, regions); + if sector.start != address { + return Err(Error::Unaligned); + } + address += sector.size; + } + if address != end_address { + return Err(Error::Unaligned); + } + Ok(()) +} + + impl embedded_storage::nor_flash::ErrorType for Flash<'_> { type Error = Error; } diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index e781f1b86..1ef04e56f 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -92,47 +92,3 @@ impl NorFlashError for Error { } } } - -pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector { - let mut current_bank = FlashBank::Bank1; - let mut bank_offset = 0; - for region in regions { - if region.bank != current_bank { - current_bank = region.bank; - bank_offset = 0; - } - - if address < region.end() { - let index_in_region = (address - region.base) / region.erase_size; - return FlashSector { - bank: region.bank, - index_in_bank: bank_offset + index_in_region as u8, - start: region.base + index_in_region * region.erase_size, - size: region.erase_size, - }; - } - - bank_offset += region.sectors(); - } - - panic!("Flash sector not found"); -} - -pub(crate) fn ensure_sector_aligned( - start_address: u32, - end_address: u32, - regions: &[&FlashRegion], -) -> Result<(), Error> { - let mut address = start_address; - while address < end_address { - let sector = get_sector(address, regions); - if sector.start != address { - return Err(Error::Unaligned); - } - address += sector.size; - } - if address != end_address { - return Err(Error::Unaligned); - } - Ok(()) -} From 1329a387e060d60ee2833d2eed6393f5dfc84d1a Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen <rmja@laesoe.org> Date: Wed, 24 May 2023 12:55:17 +0200 Subject: [PATCH 05/14] Add more missing nightly guards --- embassy-stm32/src/flash/f4.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 9698bcd58..0c008fd0d 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -2,12 +2,13 @@ use core::convert::TryInto; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; -use embassy_sync::waitqueue::AtomicWaker; - use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; +#[cfg(feature = "nightly")] +use embassy_sync::waitqueue::AtomicWaker; + #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] mod alt_regions { use embassy_hal_common::PeripheralRef; @@ -15,10 +16,12 @@ mod alt_regions { use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION}; use crate::flash::{ - asynch, common, Bank1Region1, Bank1Region2, BlockingFlashRegion, Error, Flash, FlashBank, FlashRegion, + common, Bank1Region1, Bank1Region2, BlockingFlashRegion, Error, Flash, FlashBank, FlashRegion, READ_SIZE, REGION_ACCESS, }; use crate::peripherals::FLASH; + #[cfg(feature = "nightly")] + use crate::flash::asynch; pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion { size: 3 * BANK1_REGION3.erase_size, @@ -100,13 +103,13 @@ mod alt_regions { common::read_blocking(self.0.base, self.0.size, offset, bytes) } - #[cfg(all(feature = "nightly"))] + #[cfg(feature = "nightly")] pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { let _guard = REGION_ACCESS.lock().await; unsafe { asynch::write_chunked(self.0.base, self.0.size, offset, bytes).await } } - #[cfg(all(feature = "nightly"))] + #[cfg(feature = "nightly")] pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { let _guard = REGION_ACCESS.lock().await; unsafe { asynch::erase_sectored(self.0.base, from, to).await } @@ -139,7 +142,7 @@ mod alt_regions { } } - #[cfg(all(feature = "nightly"))] + #[cfg(feature = "nightly")] impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_> { const READ_SIZE: usize = READ_SIZE; @@ -152,7 +155,7 @@ mod alt_regions { } } - #[cfg(all(feature = "nightly"))] + #[cfg(feature = "nightly")] impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_> { const WRITE_SIZE: usize = $region.write_size as usize; const ERASE_SIZE: usize = $region.erase_size as usize; @@ -209,6 +212,7 @@ pub(crate) unsafe fn on_interrupt(_: *mut ()) { w.set_eop(true); }); + #[cfg(feature = "nightly")] WAKER.wake(); } @@ -277,6 +281,7 @@ unsafe fn write_start(start_address: u32, buf: &[u8; WRITE_SIZE]) { } } +#[cfg(feature = "nightly")] pub(crate) async unsafe fn erase_sector(sector: &FlashSector) -> Result<(), Error> { let snb = ((sector.bank as u8) << 4) + sector.index_in_bank; From 966f0abf48cc143fc33e17a5fc9e138cf82ab05f Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen <rmja@laesoe.org> Date: Wed, 24 May 2023 13:11:03 +0200 Subject: [PATCH 06/14] Run format with nightly --- embassy-stm32/src/flash/common.rs | 4 +--- embassy-stm32/src/flash/f4.rs | 16 ++++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 7cec5a3c9..e1fe7e9da 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -8,8 +8,7 @@ use embassy_sync::mutex::Mutex; use stm32_metapac::FLASH_BASE; use super::{ - family, Error, FlashLayout, FlashRegion, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, - WRITE_SIZE, FlashSector, FlashBank, + family, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE, }; use crate::peripherals::FLASH; use crate::Peripheral; @@ -162,7 +161,6 @@ pub(crate) fn ensure_sector_aligned( Ok(()) } - impl embedded_storage::nor_flash::ErrorType for Flash<'_> { type Error = Error; } diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 0c008fd0d..084bbdc6e 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -2,26 +2,26 @@ use core::convert::TryInto; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; +#[cfg(feature = "nightly")] +use embassy_sync::waitqueue::AtomicWaker; + use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -#[cfg(feature = "nightly")] -use embassy_sync::waitqueue::AtomicWaker; - #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] mod alt_regions { use embassy_hal_common::PeripheralRef; use stm32_metapac::FLASH_SIZE; use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION}; - use crate::flash::{ - common, Bank1Region1, Bank1Region2, BlockingFlashRegion, Error, Flash, FlashBank, FlashRegion, - READ_SIZE, REGION_ACCESS, - }; - use crate::peripherals::FLASH; #[cfg(feature = "nightly")] use crate::flash::asynch; + use crate::flash::{ + common, Bank1Region1, Bank1Region2, BlockingFlashRegion, Error, Flash, FlashBank, FlashRegion, READ_SIZE, + REGION_ACCESS, + }; + use crate::peripherals::FLASH; pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion { size: 3 * BANK1_REGION3.erase_size, From dfd56031713aa04af682aa1b2b113a72831728f1 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen <rmja@laesoe.org> Date: Wed, 24 May 2023 17:24:28 +0200 Subject: [PATCH 07/14] 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 440de85e8..2572eafce 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 540981727..29af3c80d 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<MODE>); }); } @@ -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<MODE>, } #[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 44e23d9c4..3564bbff5 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<CriticalSectionRawMutex, ()> = 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 e1fe7e9da..8b38745cf 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<CriticalSectionRawMutex, ()> = Mutex::new(()); - impl<'d> Flash<'d> { pub fn new(p: impl Peripheral<P = FLASH> + 'd, irq: impl Peripheral<P = crate::interrupt::FLASH> + '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<const WRITE_SIZE: u32, const ERASE_SIZE: u32> 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<const WRITE_SIZE: u32, const ERASE_SIZE: u32> embedded_storage::nor_flash::ErrorType - for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> -{ - type Error = Error; -} - -impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> 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<const WRITE_SIZE: u32, const ERASE_SIZE: u32> 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 [<Blocking $type_name>]<'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<MODE> 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 084bbdc6e..d50a35b41 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<MODE>); + pub struct AltBank2Region1<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>); + pub struct AltBank2Region2<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>); + pub struct AltBank2Region3<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>); - 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 1ef04e56f..56a680a86 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 { From 8b13a7b33874483783cfd5be8fcbd73c888cd906 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen <rmja@laesoe.org> Date: Wed, 24 May 2023 17:31:35 +0200 Subject: [PATCH 08/14] Align examples --- examples/stm32f3/src/bin/flash.rs | 12 ++++++------ examples/stm32f7/src/bin/flash.rs | 12 ++++++------ examples/stm32h7/src/bin/flash.rs | 12 ++++++------ examples/stm32l0/src/bin/flash.rs | 12 ++++++------ examples/stm32l1/src/bin/flash.rs | 12 ++++++------ examples/stm32wl/src/bin/flash.rs | 12 ++++++------ 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/examples/stm32f3/src/bin/flash.rs b/examples/stm32f3/src/bin/flash.rs index 0e5fb0658..befae0a16 100644 --- a/examples/stm32f3/src/bin/flash.rs +++ b/examples/stm32f3/src/bin/flash.rs @@ -14,27 +14,27 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x26000; - let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() }; + let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); - unwrap!(f.erase(ADDR, ADDR + 2048)); + unwrap!(f.erase_blocking(ADDR, ADDR + 2048)); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read after erase: {=[u8]:x}", buf); info!("Writing..."); - unwrap!(f.write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); + unwrap!(f.write_blocking(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); } diff --git a/examples/stm32f7/src/bin/flash.rs b/examples/stm32f7/src/bin/flash.rs index 717c82e86..5507e7310 100644 --- a/examples/stm32f7/src/bin/flash.rs +++ b/examples/stm32f7/src/bin/flash.rs @@ -18,23 +18,23 @@ async fn main(_spawner: Spawner) { // wait a bit before accessing the flash Timer::after(Duration::from_millis(300)).await; - let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region3.into_blocking() }; + let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region3; info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); - unwrap!(f.erase(ADDR, ADDR + 256 * 1024)); + unwrap!(f.erase_blocking(ADDR, ADDR + 256 * 1024)); info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read after erase: {=[u8]:x}", buf); info!("Writing..."); - unwrap!(f.write( + unwrap!(f.write_blocking( ADDR, &[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, @@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); assert_eq!( &buf[..], diff --git a/examples/stm32h7/src/bin/flash.rs b/examples/stm32h7/src/bin/flash.rs index aab72cae8..fe6dad249 100644 --- a/examples/stm32h7/src/bin/flash.rs +++ b/examples/stm32h7/src/bin/flash.rs @@ -18,23 +18,23 @@ async fn main(_spawner: Spawner) { // wait a bit before accessing the flash Timer::after(Duration::from_millis(300)).await; - let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank2_region.into_blocking() }; + let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank2_region; info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); - unwrap!(f.erase(ADDR, ADDR + 128 * 1024)); + unwrap!(f.erase_blocking(ADDR, ADDR + 128 * 1024)); info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read after erase: {=[u8]:x}", buf); info!("Writing..."); - unwrap!(f.write( + unwrap!(f.write_blocking( ADDR, &[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, @@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); assert_eq!( &buf[..], diff --git a/examples/stm32l0/src/bin/flash.rs b/examples/stm32l0/src/bin/flash.rs index 0ed0d05fc..4182c87b1 100644 --- a/examples/stm32l0/src/bin/flash.rs +++ b/examples/stm32l0/src/bin/flash.rs @@ -14,27 +14,27 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x26000; - let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() }; + let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); - unwrap!(f.erase(ADDR, ADDR + 128)); + unwrap!(f.erase_blocking(ADDR, ADDR + 128)); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read after erase: {=[u8]:x}", buf); info!("Writing..."); - unwrap!(f.write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); + unwrap!(f.write_blocking(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); } diff --git a/examples/stm32l1/src/bin/flash.rs b/examples/stm32l1/src/bin/flash.rs index c4d7d029c..53052e7c5 100644 --- a/examples/stm32l1/src/bin/flash.rs +++ b/examples/stm32l1/src/bin/flash.rs @@ -14,27 +14,27 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x26000; - let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() }; + let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); - unwrap!(f.erase(ADDR, ADDR + 256)); + unwrap!(f.erase_blocking(ADDR, ADDR + 256)); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read after erase: {=[u8]:x}", buf); info!("Writing..."); - unwrap!(f.write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); + unwrap!(f.write_blocking(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); } diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs index df51ceb68..e03b69b82 100644 --- a/examples/stm32wl/src/bin/flash.rs +++ b/examples/stm32wl/src/bin/flash.rs @@ -14,27 +14,27 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x36000; - let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() }; + let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); - unwrap!(f.erase(ADDR, ADDR + 2048)); + unwrap!(f.erase_blocking(ADDR, ADDR + 2048)); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Writing..."); - unwrap!(f.write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); + unwrap!(f.write_blocking(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.read_blocking(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); } From 9370973846310d013f5be586a4e37031fcb21a16 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen <rmja@laesoe.org> Date: Wed, 24 May 2023 17:35:49 +0200 Subject: [PATCH 09/14] Remove TryLockError, --- embassy-stm32/src/flash/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 56a680a86..02f6c5320 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -83,7 +83,6 @@ pub enum Error { Protected, Unaligned, Parallelism, - TryLockError, } impl NorFlashError for Error { From e65ff85b88deef3e32cc437d28e36274b82ce03e Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen <rmja@laesoe.org> Date: Wed, 24 May 2023 23:51:48 +0200 Subject: [PATCH 10/14] Default to Async mode --- embassy-stm32/build.rs | 4 ++-- embassy-stm32/src/flash/f4.rs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 29af3c80d..b766f0739 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, MODE>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>, pub(crate) core::marker::PhantomData<MODE>); + pub struct #region_type<'d, MODE = crate::flash::Async>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>, pub(crate) core::marker::PhantomData<MODE>); }); } @@ -238,7 +238,7 @@ fn main() { let regions_len = flash_memory_regions.len(); flash_regions.extend(quote! { #[cfg(flash)] - pub struct FlashLayout<'d, MODE> { + pub struct FlashLayout<'d, MODE = crate::flash::Async> { #(#fields),*, _mode: core::marker::PhantomData<MODE>, } diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index d50a35b41..3d696223c 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -54,12 +54,12 @@ mod alt_regions { &ALT_BANK2_REGION3, ]; - pub struct AltBank1Region3<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>); - pub struct AltBank2Region1<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>); - pub struct AltBank2Region2<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>); - pub struct AltBank2Region3<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>); + pub struct AltBank1Region3<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>); + pub struct AltBank2Region1<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>); + pub struct AltBank2Region2<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>); + pub struct AltBank2Region3<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>); - pub struct AltFlashLayout<'d, MODE> { + pub struct AltFlashLayout<'d, MODE = Async> { pub bank1_region1: Bank1Region1<'d, MODE>, pub bank1_region2: Bank1Region2<'d, MODE>, pub bank1_region3: AltBank1Region3<'d, MODE>, From cd8198037fa37db9af7e9dde1e00122df9ed15a3 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen <rmja@laesoe.org> Date: Thu, 25 May 2023 13:08:40 +0200 Subject: [PATCH 11/14] Actually transition to dual bank mode - key was required --- embassy-stm32/src/flash/f4.rs | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 3d696223c..50ab446bd 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -71,7 +71,7 @@ mod alt_regions { impl<'d> Flash<'d> { pub fn into_alt_regions(self) -> AltFlashLayout<'d, Async> { - unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) }; + super::set_alt_layout(); // 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. @@ -88,7 +88,7 @@ mod alt_regions { } pub fn into_alt_blocking_regions(self) -> AltFlashLayout<'d, Blocking> { - unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) }; + super::set_alt_layout(); // 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. @@ -171,12 +171,31 @@ static WAKER: AtomicWaker = AtomicWaker::new(); #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] pub fn set_default_layout() { - unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(false)) }; + unsafe { + pac::FLASH.optkeyr().write(|w| w.set_optkey(0x08192A3B)); + pac::FLASH.optkeyr().write(|w| w.set_optkey(0x4C5D6E7F)); + pac::FLASH.optcr().modify(|r| { + r.set_db1m(false); + r.set_optlock(true) + }); + }; } #[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))] pub const fn set_default_layout() {} +#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] +fn set_alt_layout() { + unsafe { + pac::FLASH.optkeyr().write(|w| w.set_optkey(0x08192A3B)); + pac::FLASH.optkeyr().write(|w| w.set_optkey(0x4C5D6E7F)); + pac::FLASH.optcr().modify(|r| { + r.set_db1m(true); + r.set_optlock(true) + }); + }; +} + #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] pub fn get_flash_regions() -> &'static [&'static FlashRegion] { if unsafe { pac::FLASH.optcr().read().db1m() } { @@ -207,8 +226,8 @@ pub(crate) unsafe fn lock() { } pub(crate) unsafe fn unlock() { - pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123)); - pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); + pac::FLASH.keyr().write(|w| w.set_key(0x45670123)); + pac::FLASH.keyr().write(|w| w.set_key(0xCDEF89AB)); } #[cfg(feature = "nightly")] From baf1c2efbe0b218f86b491b88e48531fde691851 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen <rmja@laesoe.org> Date: Thu, 25 May 2023 13:42:42 +0200 Subject: [PATCH 12/14] Align with new bind_interrupt --- embassy-stm32/src/flash/asynch.rs | 3 ++ embassy-stm32/src/flash/common.rs | 41 +++++++++++++++---- embassy-stm32/src/flash/f0.rs | 2 +- embassy-stm32/src/flash/f3.rs | 2 +- embassy-stm32/src/flash/f4.rs | 2 +- embassy-stm32/src/flash/f7.rs | 2 +- embassy-stm32/src/flash/h7.rs | 2 +- embassy-stm32/src/flash/l.rs | 2 +- embassy-stm32/src/flash/other.rs | 2 +- examples/boot/application/rp/src/bin/a.rs | 2 +- .../boot/application/stm32f3/src/bin/a.rs | 2 +- .../boot/application/stm32f7/src/bin/a.rs | 2 +- .../boot/application/stm32h7/src/bin/a.rs | 2 +- .../boot/application/stm32l0/src/bin/a.rs | 2 +- .../boot/application/stm32l1/src/bin/a.rs | 2 +- .../boot/application/stm32l4/src/bin/a.rs | 2 +- .../boot/application/stm32wl/src/bin/a.rs | 2 +- examples/boot/bootloader/stm32/src/main.rs | 3 +- examples/stm32f3/src/bin/flash.rs | 4 +- examples/stm32f4/src/bin/flash.rs | 4 +- examples/stm32f4/src/bin/flash_async.rs | 10 +++-- examples/stm32h7/src/bin/flash.rs | 4 +- examples/stm32l0/src/bin/flash.rs | 4 +- examples/stm32l1/src/bin/flash.rs | 4 +- examples/stm32wl/src/bin/flash.rs | 4 +- 25 files changed, 71 insertions(+), 40 deletions(-) diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs index 3564bbff5..017fb17fa 100644 --- a/embassy-stm32/src/flash/asynch.rs +++ b/embassy-stm32/src/flash/asynch.rs @@ -12,15 +12,18 @@ pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new impl<'d> Flash<'d> { pub fn into_regions(self) -> FlashLayout<'d, Async> { + assert!(!self.blocking_only); family::set_default_layout(); FlashLayout::new(self.inner) } pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { + assert!(!self.blocking_only); unsafe { write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes).await } } pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { + assert!(!self.blocking_only); unsafe { erase_sectored(FLASH_BASE as u32, from, to).await } } } diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 8b38745cf..0a1ee5166 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -1,5 +1,5 @@ use atomic_polyfill::{fence, Ordering}; -use embassy_cortex_m::interrupt::InterruptExt; +use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; use embassy_hal_common::drop::OnDrop; use embassy_hal_common::{into_ref, PeripheralRef}; use stm32_metapac::FLASH_BASE; @@ -9,21 +9,37 @@ use super::{ WRITE_SIZE, }; use crate::peripherals::FLASH; -use crate::Peripheral; +use crate::{interrupt, Peripheral}; pub struct Flash<'d> { pub(crate) inner: PeripheralRef<'d, FLASH>, + pub(crate) blocking_only: bool, } impl<'d> Flash<'d> { - pub fn new(p: impl Peripheral<P = FLASH> + 'd, irq: impl Peripheral<P = crate::interrupt::FLASH> + 'd) -> Self { - into_ref!(p, irq); + pub fn new( + p: impl Peripheral<P = FLASH> + 'd, + _irq: impl interrupt::Binding<crate::interrupt::FLASH, InterruptHandler> + 'd, + ) -> Self { + into_ref!(p); - irq.set_handler(family::on_interrupt); - irq.unpend(); - irq.enable(); + let flash_irq = unsafe { crate::interrupt::FLASH::steal() }; + flash_irq.unpend(); + flash_irq.enable(); - Self { inner: p } + Self { + inner: p, + blocking_only: false, + } + } + + pub fn new_blocking_only(p: impl Peripheral<P = FLASH> + 'd) -> Self { + into_ref!(p); + + Self { + inner: p, + blocking_only: true, + } } pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> { @@ -52,6 +68,15 @@ impl<'d> Flash<'d> { } } +/// Interrupt handler +pub struct InterruptHandler; + +impl interrupt::Handler<crate::interrupt::FLASH> for InterruptHandler { + unsafe fn on_interrupt() { + family::on_interrupt(); + } +} + pub(super) fn read_blocking(base: u32, size: u32, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { if offset + bytes.len() as u32 > size { return Err(Error::Size); diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs index ecf3a6981..cd17486e6 100644 --- a/embassy-stm32/src/flash/f0.rs +++ b/embassy-stm32/src/flash/f0.rs @@ -13,7 +13,7 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } -pub(crate) unsafe fn on_interrupt(_: *mut ()) { +pub(crate) unsafe fn on_interrupt() { unimplemented!(); } diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs index fd778f2b1..4ce391288 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs @@ -13,7 +13,7 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } -pub(crate) unsafe fn on_interrupt(_: *mut ()) { +pub(crate) unsafe fn on_interrupt() { unimplemented!(); } diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 50ab446bd..2b0472640 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -210,7 +210,7 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } -pub(crate) unsafe fn on_interrupt(_: *mut ()) { +pub(crate) unsafe fn on_interrupt() { // Clear IRQ flags pac::FLASH.sr().write(|w| { w.set_operr(true); diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index a0593b14b..ab518bf89 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -12,7 +12,7 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } -pub(crate) unsafe fn on_interrupt(_: *mut ()) { +pub(crate) unsafe fn on_interrupt() { unimplemented!(); } diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 865f13283..d6818d594 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -17,7 +17,7 @@ pub fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } -pub(crate) unsafe fn on_interrupt(_: *mut ()) { +pub(crate) unsafe fn on_interrupt() { unimplemented!(); } diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index f8a0dac4c..c2394e0c9 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -12,7 +12,7 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } -pub(crate) unsafe fn on_interrupt(_: *mut ()) { +pub(crate) unsafe fn on_interrupt() { unimplemented!(); } diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs index e21b0b241..e569951f9 100644 --- a/embassy-stm32/src/flash/other.rs +++ b/embassy-stm32/src/flash/other.rs @@ -8,7 +8,7 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } -pub(crate) unsafe fn on_interrupt(_: *mut ()) { +pub(crate) unsafe fn on_interrupt() { unimplemented!(); } diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs index e3ac634c2..2b84ec614 100644 --- a/examples/boot/application/rp/src/bin/a.rs +++ b/examples/boot/application/rp/src/bin/a.rs @@ -26,7 +26,7 @@ async fn main(_s: Spawner) { let mut watchdog = Watchdog::new(p.WATCHDOG); watchdog.start(Duration::from_secs(8)); - let mut flash: Flash<_, FLASH_SIZE> = Flash::new(p.FLASH); + let mut flash: Flash<_, FLASH_SIZE> = Flash::new_blocking_only(p.FLASH); let mut updater = FirmwareUpdater::default(); diff --git a/examples/boot/application/stm32f3/src/bin/a.rs b/examples/boot/application/stm32f3/src/bin/a.rs index d92d59b29..a69b6327f 100644 --- a/examples/boot/application/stm32f3/src/bin/a.rs +++ b/examples/boot/application/stm32f3/src/bin/a.rs @@ -17,7 +17,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin"); #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let flash = Flash::new(p.FLASH); + let flash = Flash::new_blocking_only(p.FLASH); let mut flash = BlockingAsync::new(flash); let button = Input::new(p.PC13, Pull::Up); diff --git a/examples/boot/application/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs index 79ab80e09..1f55db932 100644 --- a/examples/boot/application/stm32f7/src/bin/a.rs +++ b/examples/boot/application/stm32f7/src/bin/a.rs @@ -16,7 +16,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin"); #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let mut flash = Flash::new(p.FLASH); + let mut flash = Flash::new_blocking_only(p.FLASH); let button = Input::new(p.PC13, Pull::Down); let mut button = ExtiInput::new(button, p.EXTI13); diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs index 8b452be34..b8617c3bd 100644 --- a/examples/boot/application/stm32h7/src/bin/a.rs +++ b/examples/boot/application/stm32h7/src/bin/a.rs @@ -16,7 +16,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin"); #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let mut flash = Flash::new(p.FLASH); + let mut flash = Flash::new_blocking_only(p.FLASH); let button = Input::new(p.PC13, Pull::Down); let mut button = ExtiInput::new(button, p.EXTI13); diff --git a/examples/boot/application/stm32l0/src/bin/a.rs b/examples/boot/application/stm32l0/src/bin/a.rs index 59ca34386..c66635639 100644 --- a/examples/boot/application/stm32l0/src/bin/a.rs +++ b/examples/boot/application/stm32l0/src/bin/a.rs @@ -18,7 +18,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin"); #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let flash = Flash::new(p.FLASH); + let flash = Flash::new_blocking_only(p.FLASH); let mut flash = BlockingAsync::new(flash); let button = Input::new(p.PB2, Pull::Up); diff --git a/examples/boot/application/stm32l1/src/bin/a.rs b/examples/boot/application/stm32l1/src/bin/a.rs index 59ca34386..c66635639 100644 --- a/examples/boot/application/stm32l1/src/bin/a.rs +++ b/examples/boot/application/stm32l1/src/bin/a.rs @@ -18,7 +18,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin"); #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let flash = Flash::new(p.FLASH); + let flash = Flash::new_blocking_only(p.FLASH); let mut flash = BlockingAsync::new(flash); let button = Input::new(p.PB2, Pull::Up); diff --git a/examples/boot/application/stm32l4/src/bin/a.rs b/examples/boot/application/stm32l4/src/bin/a.rs index 6cddc6cc8..86936222c 100644 --- a/examples/boot/application/stm32l4/src/bin/a.rs +++ b/examples/boot/application/stm32l4/src/bin/a.rs @@ -17,7 +17,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin"); #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let flash = Flash::new(p.FLASH); + let flash = Flash::new_blocking_only(p.FLASH); let mut flash = BlockingAsync::new(flash); let button = Input::new(p.PC13, Pull::Up); diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs index 1ff47eddd..2982e8df1 100644 --- a/examples/boot/application/stm32wl/src/bin/a.rs +++ b/examples/boot/application/stm32wl/src/bin/a.rs @@ -17,7 +17,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin"); #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let flash = Flash::new(p.FLASH); + let flash = Flash::new_blocking_only(p.FLASH); let mut flash = BlockingAsync::new(flash); let button = Input::new(p.PA0, Pull::Up); diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs index 49c21920b..5e8a4f2b3 100644 --- a/examples/boot/bootloader/stm32/src/main.rs +++ b/examples/boot/bootloader/stm32/src/main.rs @@ -20,8 +20,7 @@ fn main() -> ! { */ let mut bl: BootLoader<2048> = BootLoader::default(); - let flash = Flash::new(p.FLASH); - let layout = flash.into_regions(); + let layout = Flash::new_blocking_only(p.FLASH).into_blocking_regions(); let mut flash = BootFlash::new(layout.bank1_region); let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash)); core::mem::drop(flash); diff --git a/examples/stm32f3/src/bin/flash.rs b/examples/stm32f3/src/bin/flash.rs index befae0a16..9a31b548d 100644 --- a/examples/stm32f3/src/bin/flash.rs +++ b/examples/stm32f3/src/bin/flash.rs @@ -4,7 +4,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::{flash::Flash, interrupt}; +use embassy_stm32::flash::Flash; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x26000; - let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region; + let mut f = Flash::new_blocking_only(p.FLASH).into_blocking_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8]; diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs index de4ecdb8f..455af930b 100644 --- a/examples/stm32f4/src/bin/flash.rs +++ b/examples/stm32f4/src/bin/flash.rs @@ -4,7 +4,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::{flash::Flash, interrupt}; +use embassy_stm32::flash::Flash; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { // Once can also call `into_regions()` to get access to NorFlash implementations // for each of the unique characteristics. - let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)); + let mut f = Flash::new_blocking_only(p.FLASH); // Sector 5 test_flash(&mut f, 128 * 1024, 128 * 1024); diff --git a/examples/stm32f4/src/bin/flash_async.rs b/examples/stm32f4/src/bin/flash_async.rs index c9d9df34b..675337083 100644 --- a/examples/stm32f4/src/bin/flash_async.rs +++ b/examples/stm32f4/src/bin/flash_async.rs @@ -5,17 +5,21 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; use embassy_time::{Timer, Duration}; -use embassy_stm32::flash::Flash; +use embassy_stm32::flash::{Flash, InterruptHandler}; use embassy_stm32::gpio::{AnyPin, Level, Output, Pin, Speed}; -use embassy_stm32::{interrupt}; +use embassy_stm32::bind_interrupts; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + FLASH => InterruptHandler; +}); + #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello Flash!"); - let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)); + let mut f = Flash::new(p.FLASH, Irqs); // Led should blink uninterrupted during ~2sec erase operation spawner.spawn(blinky(p.PB7.degrade())).unwrap(); diff --git a/examples/stm32h7/src/bin/flash.rs b/examples/stm32h7/src/bin/flash.rs index fe6dad249..c0c332c34 100644 --- a/examples/stm32h7/src/bin/flash.rs +++ b/examples/stm32h7/src/bin/flash.rs @@ -4,7 +4,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::{flash::Flash, interrupt}; +use embassy_stm32::flash::Flash; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) { // wait a bit before accessing the flash Timer::after(Duration::from_millis(300)).await; - let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank2_region; + let mut f = Flash::new_blocking_only(p.FLASH).into_blocking_regions().bank2_region; info!("Reading..."); let mut buf = [0u8; 32]; diff --git a/examples/stm32l0/src/bin/flash.rs b/examples/stm32l0/src/bin/flash.rs index 4182c87b1..57ccf7f57 100644 --- a/examples/stm32l0/src/bin/flash.rs +++ b/examples/stm32l0/src/bin/flash.rs @@ -4,7 +4,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::{flash::Flash, interrupt}; +use embassy_stm32::flash::Flash; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x26000; - let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region; + let mut f = Flash::new_blocking_only(p.FLASH).into_blocking_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8]; diff --git a/examples/stm32l1/src/bin/flash.rs b/examples/stm32l1/src/bin/flash.rs index 53052e7c5..71174bfbc 100644 --- a/examples/stm32l1/src/bin/flash.rs +++ b/examples/stm32l1/src/bin/flash.rs @@ -4,7 +4,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::{flash::Flash, interrupt}; +use embassy_stm32::flash::Flash; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x26000; - let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region; + let mut f = Flash::new_blocking_only(p.FLASH).into_blocking_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8]; diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs index e03b69b82..51bd0db4e 100644 --- a/examples/stm32wl/src/bin/flash.rs +++ b/examples/stm32wl/src/bin/flash.rs @@ -4,7 +4,7 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::{flash::Flash, interrupt}; +use embassy_stm32::flash::Flash; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x36000; - let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region; + let mut f = Flash::new_blocking_only(p.FLASH).into_blocking_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8]; From 8b1eaf00a0fd24459407a70e76bdbc16983b9af6 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen <rmja@laesoe.org> Date: Thu, 25 May 2023 13:54:40 +0200 Subject: [PATCH 13/14] Simplify SR->Result --- embassy-stm32/src/flash/f4.rs | 45 +++++++++++++---------------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 2b0472640..53e58835e 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -4,6 +4,7 @@ use core::sync::atomic::{fence, Ordering}; #[cfg(feature = "nightly")] use embassy_sync::waitqueue::AtomicWaker; +use pac::flash::regs::Sr; use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; @@ -347,17 +348,7 @@ pub(crate) async unsafe fn wait_ready() -> Result<(), Error> { let sr = pac::FLASH.sr().read(); if !sr.bsy() { - Poll::Ready(if sr.pgserr() { - Err(Error::Seq) - } else if sr.pgperr() { - Err(Error::Parallelism) - } else if sr.pgaerr() { - Err(Error::Unaligned) - } else if sr.wrperr() { - Err(Error::Protected) - } else { - Ok(()) - }) + Poll::Ready(get_result(sr)) } else { return Poll::Pending; } @@ -370,27 +361,25 @@ unsafe fn wait_ready_blocking() -> Result<(), Error> { let sr = pac::FLASH.sr().read(); if !sr.bsy() { - if sr.pgserr() { - return Err(Error::Seq); - } - - if sr.pgperr() { - return Err(Error::Parallelism); - } - - if sr.pgaerr() { - return Err(Error::Unaligned); - } - - if sr.wrperr() { - return Err(Error::Protected); - } - - return Ok(()); + return get_result(sr); } } } +fn get_result(sr: Sr) -> Result<(), Error> { + if sr.pgserr() { + Err(Error::Seq) + } else if sr.pgperr() { + Err(Error::Parallelism) + } else if sr.pgaerr() { + Err(Error::Unaligned) + } else if sr.wrperr() { + Err(Error::Protected) + } else { + Ok(()) + } +} + #[cfg(test)] mod tests { use super::*; From c02759ad91994191944b4fd1a4b47cd310416c04 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen <rmja@laesoe.org> Date: Thu, 25 May 2023 13:59:32 +0200 Subject: [PATCH 14/14] Fix unused errors --- embassy-stm32/src/flash/common.rs | 3 +++ embassy-stm32/src/flash/f4.rs | 8 +++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 0a1ee5166..547e30312 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -13,6 +13,7 @@ use crate::{interrupt, Peripheral}; pub struct Flash<'d> { pub(crate) inner: PeripheralRef<'d, FLASH>, + #[cfg(all(feature = "nightly", flash_f4))] pub(crate) blocking_only: bool, } @@ -29,6 +30,7 @@ impl<'d> Flash<'d> { Self { inner: p, + #[cfg(all(feature = "nightly", flash_f4))] blocking_only: false, } } @@ -38,6 +40,7 @@ impl<'d> Flash<'d> { Self { inner: p, + #[cfg(all(feature = "nightly", flash_f4))] blocking_only: true, } } diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 53e58835e..aa3433b23 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -20,9 +20,7 @@ mod alt_regions { use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION}; #[cfg(feature = "nightly")] use crate::flash::asynch; - use crate::flash::{ - common, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion, READ_SIZE, - }; + use crate::flash::{Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion}; use crate::peripherals::FLASH; pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion { @@ -111,7 +109,7 @@ mod alt_regions { #[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) + crate::flash::common::read_blocking(self.0.base, self.0.size, offset, bytes) } pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { @@ -131,7 +129,7 @@ mod alt_regions { #[cfg(feature = "nightly")] impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_, Async> { - const READ_SIZE: usize = READ_SIZE; + const READ_SIZE: usize = crate::flash::READ_SIZE; async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { self.read(offset, bytes).await