diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 0d7e03bf..4e29bb32 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 } @@ -98,7 +99,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/build.rs b/embassy-stm32/build.rs index 54098172..b766f073 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 = crate::flash::Async>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>, pub(crate) core::marker::PhantomData); }); } @@ -224,11 +224,11 @@ fn main() { let field_name = format_ident!("{}", region_name.to_lowercase()); let field_type = format_ident!("{}", get_flash_region_type_name(f.name)); let field = quote! { - pub #field_name: #field_type<'d> + pub #field_name: #field_type<'d, MODE> }; let region_name = format_ident!("{}", region_name); let init = quote! { - #field_name: #field_type(&#region_name, unsafe { p.clone_unchecked()}) + #field_name: #field_type(&#region_name, unsafe { p.clone_unchecked()}, core::marker::PhantomData) }; (field, (init, region_name)) @@ -238,15 +238,17 @@ fn main() { let regions_len = flash_memory_regions.len(); flash_regions.extend(quote! { #[cfg(flash)] - pub struct FlashLayout<'d> { - #(#fields),* + pub struct FlashLayout<'d, MODE = crate::flash::Async> { + #(#fields),*, + _mode: core::marker::PhantomData, } #[cfg(flash)] - impl<'d> FlashLayout<'d> { + impl<'d, MODE> FlashLayout<'d, MODE> { pub(crate) fn new(p: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>) -> Self { Self { - #(#inits),* + #(#inits),*, + _mode: core::marker::PhantomData, } } } diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs new file mode 100644 index 00000000..a0d99495 --- /dev/null +++ b/embassy-stm32/src/flash/asynch.rs @@ -0,0 +1,189 @@ +use core::marker::PhantomData; + +use atomic_polyfill::{fence, Ordering}; +use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; +use embassy_hal_common::drop::OnDrop; +use embassy_hal_common::into_ref; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::mutex::Mutex; + +use super::{ + blocking_read, ensure_sector_aligned, family, get_sector, Async, Error, Flash, FlashLayout, FLASH_BASE, FLASH_SIZE, + WRITE_SIZE, +}; +use crate::peripherals::FLASH; +use crate::{interrupt, Peripheral}; + +pub(super) static REGION_ACCESS: Mutex = Mutex::new(()); + +impl<'d> Flash<'d, Async> { + pub fn new( + p: impl Peripheral

+ 'd, + _irq: impl interrupt::Binding + 'd, + ) -> Self { + into_ref!(p); + + let flash_irq = unsafe { crate::interrupt::FLASH::steal() }; + flash_irq.unpend(); + flash_irq.enable(); + + Self { + inner: p, + _mode: PhantomData, + } + } + + 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 } + } + + pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { + unsafe { erase_sectored(FLASH_BASE as u32, from, to).await } + } +} + +/// Interrupt handler +pub struct InterruptHandler; + +impl interrupt::Handler for InterruptHandler { + unsafe fn on_interrupt() { + family::on_interrupt(); + } +} + +#[cfg(feature = "nightly")] +impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_, Async> { + const READ_SIZE: usize = super::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 + } +} + +#[cfg(feature = "nightly")] +impl embedded_storage_async::nor_flash::NorFlash for Flash<'_, Async> { + const WRITE_SIZE: usize = WRITE_SIZE; + const ERASE_SIZE: usize = super::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<'_, Async> { + pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + blocking_read(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 } + } + + 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 } + } + } + + #[cfg(feature = "nightly")] + impl embedded_storage_async::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_, Async> { + const READ_SIZE: usize = super::READ_SIZE; + + async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { + self.read(offset, bytes).await + } + + fn capacity(&self) -> usize { + self.0.size as usize + } + } + + #[cfg(feature = "nightly")] + 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; + + 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 432c8a43..cc0e2572 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -1,40 +1,57 @@ +use core::marker::PhantomData; + use atomic_polyfill::{fence, Ordering}; use embassy_hal_common::drop::OnDrop; use embassy_hal_common::{into_ref, PeripheralRef}; +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::{ + family, Async, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, 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 struct Flash<'d, MODE = Async> { + pub(crate) inner: PeripheralRef<'d, FLASH>, + pub(crate) _mode: PhantomData, } -impl<'d> Flash<'d> { - pub fn new(p: impl Peripheral

+ 'd) -> Self { +impl<'d> Flash<'d, Blocking> { + pub fn new_blocking(p: impl Peripheral

+ 'd) -> Self { into_ref!(p); - Self { inner: p } - } - pub fn into_regions(self) -> FlashLayout<'d> { + Self { + inner: p, + _mode: PhantomData, + } + } +} + +impl<'d, MODE> Flash<'d, MODE> { + pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> { 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> { + pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { blocking_read(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) } + unsafe { + blocking_write( + FLASH_BASE as u32, + FLASH_SIZE as u32, + offset, + bytes, + write_chunk_unlocked, + ) + } } 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() } + unsafe { blocking_erase(FLASH_BASE as u32, from, to, erase_sector_unlocked) } } } @@ -44,12 +61,22 @@ pub(super) fn blocking_read(base: u32, size: u32, offset: u32, bytes: &mut [u8]) } let start_address = base + offset; + + #[cfg(flash_f4)] + family::assert_not_corrupted_read(start_address + bytes.len() as u32); + let flash_data = unsafe { core::slice::from_raw_parts(start_address as *const u8, bytes.len()) }; bytes.copy_from_slice(flash_data); Ok(()) } -pub(super) unsafe fn blocking_write_chunked(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> { +pub(super) unsafe fn blocking_write( + 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); } @@ -61,44 +88,44 @@ 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); - - let _on_drop = OnDrop::new(|| { - family::end_write(); - fence(Ordering::SeqCst); - family::lock(); - }); - - family::blocking_write(address, chunk.try_into().unwrap()) - })?; + write_chunk(address, chunk)?; 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 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::blocking_write(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 blocking_erase( + 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(); - // 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); @@ -106,25 +133,28 @@ pub(super) unsafe fn blocking_erase_sectored(base: u32, from: u32, to: u32) -> R while address < end_address { 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); - - let _on_drop = OnDrop::new(|| { - family::lock(); - }); - - family::blocking_erase_sector(§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::blocking_erase_sector(§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 { @@ -149,29 +179,34 @@ pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector 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(super) 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; } - - 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) } + if address != end_address { + return Err(Error::Unaligned); } + Ok(()) } -impl embedded_storage::nor_flash::ErrorType for Flash<'_> { +impl embedded_storage::nor_flash::ErrorType for Flash<'_, MODE> { type Error = Error; } -impl embedded_storage::nor_flash::ReadNorFlash for Flash<'_> { - const READ_SIZE: usize = 1; +impl embedded_storage::nor_flash::ReadNorFlash for Flash<'_, MODE> { + 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 { @@ -179,7 +214,7 @@ impl embedded_storage::nor_flash::ReadNorFlash for Flash<'_> { } } -impl embedded_storage::nor_flash::NorFlash for Flash<'_> { +impl embedded_storage::nor_flash::NorFlash for Flash<'_, MODE> { const WRITE_SIZE: usize = WRITE_SIZE; const ERASE_SIZE: usize = MAX_ERASE_SIZE; @@ -194,26 +229,28 @@ impl embedded_storage::nor_flash::NorFlash for Flash<'_> { 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<'_, MODE> { pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { blocking_read(self.0.base, self.0.size, offset, bytes) } + } + impl crate::_generated::flash_regions::$type_name<'_, Blocking> { pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - unsafe { blocking_write_chunked(self.0.base, self.0.size, offset, bytes) } + unsafe { blocking_write(self.0.base, self.0.size, offset, bytes, write_chunk_with_critical_section) } } pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - unsafe { blocking_erase_sectored(self.0.base, from, to) } + unsafe { blocking_erase(self.0.base, from, to, erase_sector_with_critical_section) } } } - impl embedded_storage::nor_flash::ErrorType for crate::_generated::flash_regions::$type_name<'_> { + impl embedded_storage::nor_flash::ErrorType for crate::_generated::flash_regions::$type_name<'_, MODE> { type Error = Error; } - impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> { - const READ_SIZE: usize = 1; + impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_, MODE> { + const READ_SIZE: usize = READ_SIZE; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { self.blocking_read(offset, bytes) @@ -224,7 +261,7 @@ foreach_flash_region! { } } - impl embedded_storage::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_> { + 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; diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs index c6441ef1..e9916d14 100644 --- a/embassy-stm32/src/flash/f0.rs +++ b/embassy-stm32/src/flash/f0.rs @@ -22,13 +22,13 @@ 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)); } @@ -42,7 +42,7 @@ 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> { @@ -56,7 +56,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 +88,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 4c817220..4e65f558 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs @@ -22,13 +22,13 @@ 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)); } @@ -42,7 +42,7 @@ 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> { @@ -56,7 +56,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 +88,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 7f1c5f67..25d96ca1 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -2,20 +2,24 @@ use core::convert::TryInto; use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; -use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use atomic_polyfill::AtomicBool; +use embassy_sync::waitqueue::AtomicWaker; +use pac::flash::regs::Sr; +use pac::FLASH_SIZE; + +use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; 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; 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, - }; + use crate::flash::{asynch, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion}; use crate::peripherals::FLASH; pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion { @@ -48,62 +52,87 @@ 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 = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData); + pub struct AltBank2Region1<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData); + pub struct AltBank2Region2<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData); + pub struct AltBank2Region3<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData); - 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 = Async> { + 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> { - unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) }; + pub fn into_alt_regions(self) -> AltFlashLayout<'d, Async> { + 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. + 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> { + 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. - 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() }), - 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<'_> { + impl $type_name<'_, MODE> { 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 blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - unsafe { blocking_write_chunked(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) } + crate::flash::common::blocking_read(self.0.base, self.0.size, offset, bytes) } } - impl embedded_storage::nor_flash::ErrorType for $type_name<'_> { + impl $type_name<'_, Async> { + pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { + self.blocking_read(offset, bytes) + } + + pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { + let _guard = asynch::REGION_ACCESS.lock().await; + unsafe { asynch::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 = asynch::REGION_ACCESS.lock().await; + unsafe { asynch::erase_sectored(self.0.base, from, to).await } + } + } + + impl embedded_storage::nor_flash::ErrorType for $type_name<'_, MODE> { type Error = Error; } - impl embedded_storage::nor_flash::ReadNorFlash for $type_name<'_> { - const READ_SIZE: usize = 1; + impl embedded_storage::nor_flash::ReadNorFlash for $type_name<'_, MODE> { + const READ_SIZE: usize = crate::flash::READ_SIZE; fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { self.blocking_read(offset, bytes) @@ -114,16 +143,30 @@ mod alt_regions { } } - impl embedded_storage::nor_flash::NorFlash for $type_name<'_> { + #[cfg(feature = "nightly")] + impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_, Async> { + 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 + } + + fn capacity(&self) -> usize { + self.0.size as usize + } + } + + #[cfg(feature = "nightly")] + 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; - 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,14 +181,42 @@ mod alt_regions { #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] pub use alt_regions::*; +static WAKER: AtomicWaker = AtomicWaker::new(); +static DATA_CACHE_WAS_ENABLED: AtomicBool = AtomicBool::new(false); + +impl FlashSector { + const fn snb(&self) -> u8 { + ((self.bank as u8) << 4) + self.index_in_bank + } +} + #[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() } { @@ -160,17 +231,49 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } +pub(crate) unsafe fn on_interrupt() { + // 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)); } 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)); } -pub(crate) unsafe fn begin_write() { +pub(crate) unsafe fn enable_write() { assert_eq!(0, WRITE_SIZE % 4); + save_data_cache_state(); + + 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); + }); +} + +pub(crate) unsafe fn disable_write() { + pac::FLASH.cr().write(|w| { + w.set_pg(false); + w.set_eopie(false); + w.set_errie(false); + }); + restore_data_cache_state(); +} + +pub(crate) unsafe fn enable_blocking_write() { + assert_eq!(0, WRITE_SIZE % 4); + save_data_cache_state(); pac::FLASH.cr().write(|w| { w.set_pg(true); @@ -178,11 +281,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)); + restore_data_cache_state(); +} + +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 blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + write_start(start_address, buf); + blocking_wait_ready() +} + +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,16 +305,42 @@ 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> { - let snb = ((sector.bank as u8) << 4) + sector.index_in_bank; +pub(crate) async unsafe fn erase_sector(sector: &FlashSector) -> Result<(), Error> { + save_data_cache_state(); + + trace!("Erasing sector number {}", sector.snb()); pac::FLASH.cr().modify(|w| { w.set_ser(true); - w.set_snb(snb) + w.set_snb(sector.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(); + restore_data_cache_state(); + ret +} + +pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { + save_data_cache_state(); + + trace!("Blocking erasing sector number {}", sector.snb()); + + pac::FLASH.cr().modify(|w| { + w.set_ser(true); + w.set_snb(sector.snb()) }); pac::FLASH.cr().modify(|w| { @@ -208,9 +348,8 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E }); let ret: Result<(), Error> = blocking_wait_ready(); - clear_all_err(); - + restore_data_cache_state(); ret } @@ -220,36 +359,150 @@ pub(crate) unsafe fn clear_all_err() { w.set_pgperr(true); w.set_pgaerr(true); w.set_wrperr(true); - w.set_eop(true); }); } +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(get_result(sr)) + } else { + return Poll::Pending; + } + }) + .await +} + unsafe fn blocking_wait_ready() -> Result<(), Error> { loop { 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(()) + } +} + +fn save_data_cache_state() { + let dual_bank = get_flash_regions().last().unwrap().bank == FlashBank::Bank2; + if dual_bank { + // Disable data cache during write/erase if there are two banks, see errata 2.2.12 + let dcen = unsafe { pac::FLASH.acr().read().dcen() }; + DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed); + if dcen { + unsafe { pac::FLASH.acr().modify(|w| w.set_dcen(false)) }; + } + } +} + +fn restore_data_cache_state() { + let dual_bank = get_flash_regions().last().unwrap().bank == FlashBank::Bank2; + if dual_bank { + // Restore data cache if it was enabled + let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed); + if dcen { + unsafe { + // Reset data cache before we enable it again + pac::FLASH.acr().modify(|w| w.set_dcrst(true)); + pac::FLASH.acr().modify(|w| w.set_dcrst(false)); + pac::FLASH.acr().modify(|w| w.set_dcen(true)) + }; + } + } +} + +pub(crate) fn assert_not_corrupted_read(end_address: u32) { + #[allow(unused)] + const REVISION_3: u16 = 0x2001; + + #[allow(unused)] + let second_bank_read = + get_flash_regions().last().unwrap().bank == FlashBank::Bank2 && end_address > (FLASH_SIZE / 2) as u32; + + #[cfg(any( + feature = "stm32f427ai", + feature = "stm32f427ii", + feature = "stm32f427vi", + feature = "stm32f427zi", + feature = "stm32f429ai", + feature = "stm32f429bi", + feature = "stm32f429ii", + feature = "stm32f429ni", + feature = "stm32f429vi", + feature = "stm32f429zi", + feature = "stm32f437ai", + feature = "stm32f437ii", + feature = "stm32f437vi", + feature = "stm32f437zi", + feature = "stm32f439ai", + feature = "stm32f439bi", + feature = "stm32f439ii", + feature = "stm32f439ni", + feature = "stm32f439vi", + feature = "stm32f439zi", + ))] + if second_bank_read && unsafe { pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() } { + panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11"); + } + + #[cfg(any( + feature = "stm32f427ag", + feature = "stm32f427ig", + feature = "stm32f427vg", + feature = "stm32f427zg", + feature = "stm32f429ag", + feature = "stm32f429bg", + feature = "stm32f429ig", + feature = "stm32f429ng", + feature = "stm32f429vg", + feature = "stm32f429zg", + feature = "stm32f437ig", + feature = "stm32f437vg", + feature = "stm32f437zg", + feature = "stm32f439bg", + feature = "stm32f439ig", + feature = "stm32f439ng", + feature = "stm32f439vg", + feature = "stm32f439zg", + ))] + if second_bank_read && unsafe { pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() } { + panic!("Read corruption for stm32f42xxG and stm32f43xxG in dual bank mode when PA12 is in use for chips below revision 3, see errata 2.2.11"); + } +} + +#[allow(unused)] +fn pa12_is_output_pull_low() -> bool { + use pac::gpio::vals; + use pac::GPIOA; + const PIN: usize = 12; + unsafe { + GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT + && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN + && GPIOA.odr().read().odr(PIN) == vals::Odr::LOW + } +} + #[cfg(test)] mod tests { use super::*; @@ -257,12 +510,14 @@ mod tests { #[test] #[cfg(stm32f429)] - fn can_get_sector_single_bank() { + fn can_get_sector() { const SMALL_SECTOR_SIZE: u32 = 16 * 1024; const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024; const LARGE_SECTOR_SIZE: u32 = 128 * 1024; - let assert_sector = |index_in_bank: u8, start: u32, size: u32, address: u32| { + let assert_sector = |snb: u8, index_in_bank: u8, start: u32, size: u32, address: u32| { + let sector = get_sector(address, &FLASH_REGIONS); + assert_eq!(snb, sector.snb()); assert_eq!( FlashSector { bank: FlashBank::Bank1, @@ -270,24 +525,26 @@ mod tests { start, size }, - get_sector(address, &FLASH_REGIONS) - ) + sector + ); }; - assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); - assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); - assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); - assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); + assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); + assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); + assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); + assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); - assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); - assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); + assert_sector(0x04, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); + assert_sector(0x04, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); - assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); - assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); - assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); - assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); + assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); + assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); + assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); + assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); - let assert_sector = |bank: FlashBank, index_in_bank: u8, start: u32, size: u32, address: u32| { + let assert_sector = |snb: u8, bank: FlashBank, index_in_bank: u8, start: u32, size: u32, address: u32| { + let sector = get_sector(address, &ALT_FLASH_REGIONS); + assert_eq!(snb, sector.snb()); assert_eq!( FlashSector { bank, @@ -295,34 +552,34 @@ mod tests { start, size }, - get_sector(address, &ALT_FLASH_REGIONS) + sector ) }; - assert_sector(FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); - assert_sector(FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); - assert_sector(FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); - assert_sector(FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); + assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); + assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); + assert_sector(0x03, FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); + assert_sector(0x03, FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); - assert_sector(FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); - assert_sector(FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); + assert_sector(0x04, FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); + assert_sector(0x04, FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); - assert_sector(FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); - assert_sector(FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); - assert_sector(FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000); - assert_sector(FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); + assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); + assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); + assert_sector(0x07, FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000); + assert_sector(0x07, FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); - assert_sector(FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000); - assert_sector(FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF); - assert_sector(FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000); - assert_sector(FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF); + assert_sector(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000); + assert_sector(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF); + assert_sector(0x13, FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000); + assert_sector(0x13, FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF); - assert_sector(FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_0000); - assert_sector(FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_FFFF); + assert_sector(0x14, FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_0000); + assert_sector(0x14, FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_FFFF); - assert_sector(FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000); - assert_sector(FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF); - assert_sector(FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); - assert_sector(FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); + assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000); + assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF); + assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); + assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); } } diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index ac2834a8..e6267e17 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -21,7 +21,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,7 +30,7 @@ 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)); } @@ -58,11 +58,8 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E }); let ret: Result<(), Error> = blocking_wait_ready(); - pac::FLASH.cr().modify(|w| w.set_ser(false)); - clear_all_err(); - ret } diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 1b163106..d09ebc0d 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -33,11 +33,11 @@ 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> { // We cannot have the write setup sequence in begin_write as it depends on the address @@ -92,11 +92,8 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E }); let ret: Result<(), Error> = blocking_wait_ready(bank); - bank.cr().modify(|w| w.set_ser(false)); - bank_clear_all_err(bank); - ret } diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index c94f6190..c4bbd547 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -41,14 +41,14 @@ 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)); } @@ -63,7 +63,7 @@ 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> { @@ -96,7 +96,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 +108,6 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E }); clear_all_err(); - ret } @@ -150,7 +149,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 b93270ae..f44ef2c1 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -1,8 +1,12 @@ use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; +#[cfg(flash_f4)] +mod asynch; #[cfg(flash)] mod common; +#[cfg(flash_f4)] +pub use asynch::InterruptHandler; #[cfg(flash)] pub use common::*; @@ -10,6 +14,11 @@ 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; + +pub struct Blocking; +pub struct Async; + #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct FlashRegion { diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs index 55603465..ccdcfeb7 100644 --- a/embassy-stm32/src/flash/other.rs +++ b/embassy-stm32/src/flash/other.rs @@ -14,10 +14,10 @@ pub(crate) unsafe fn lock() { 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> { diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs index e3ac634c..47f1d16d 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(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 d92d59b2..5db1dbb5 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(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 79ab80e0..5d586445 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(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 8b452be3..20222022 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(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 59ca3438..4033ac59 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(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 59ca3438..4033ac59 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(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 6cddc6cc..141d82af 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(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 1ff47edd..5f48dbe5 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(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 49c21920..f81fdbc5 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(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 e40ad4fc..236fb36c 100644 --- a/examples/stm32f3/src/bin/flash.rs +++ b/examples/stm32f3/src/bin/flash.rs @@ -5,7 +5,6 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; use embassy_stm32::flash::Flash; -use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -15,27 +14,27 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x26000; - let mut f = Flash::new(p.FLASH).into_regions().bank1_region; + let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); - unwrap!(f.erase(ADDR, ADDR + 2048)); + unwrap!(f.blocking_erase(ADDR, ADDR + 2048)); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(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.blocking_write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); } diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs index bd3a7c95..93c54e94 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::{Blocking, 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); + let mut f = Flash::new_blocking(p.FLASH); // Sector 5 test_flash(&mut f, 128 * 1024, 128 * 1024); @@ -26,12 +26,12 @@ async fn main(_spawner: Spawner) { test_flash(&mut f, (2048 - 128) * 1024, 128 * 1024); } -fn test_flash(f: &mut Flash, offset: u32, size: u32) { +fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) { info!("Testing offset: {=u32:#X}, size: {=u32:#X}", offset, size); 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..."); @@ -39,7 +39,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 after erase: {=[u8]:x}", buf); info!("Writing..."); @@ -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 00000000..6c9689d9 --- /dev/null +++ b/examples/stm32f4/src/bin/flash_async.rs @@ -0,0 +1,85 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::{info, unwrap}; +use embassy_executor::Spawner; +use embassy_stm32::bind_interrupts; +use embassy_stm32::flash::{Flash, InterruptHandler}; +use embassy_stm32::gpio::{AnyPin, Level, Output, Pin, Speed}; +use embassy_time::{Duration, Timer}; +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, Irqs); + + // 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 + ] + ); +} diff --git a/examples/stm32f7/src/bin/flash.rs b/examples/stm32f7/src/bin/flash.rs index aabfe855..35d3059b 100644 --- a/examples/stm32f7/src/bin/flash.rs +++ b/examples/stm32f7/src/bin/flash.rs @@ -6,7 +6,6 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; use embassy_stm32::flash::Flash; use embassy_time::{Duration, Timer}; -use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -19,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 = Flash::new(p.FLASH).into_regions().bank1_region3; + let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region3; info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); - unwrap!(f.erase(ADDR, ADDR + 256 * 1024)); + unwrap!(f.blocking_erase(ADDR, ADDR + 256 * 1024)); info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(ADDR, &mut buf)); info!("Read after erase: {=[u8]:x}", buf); info!("Writing..."); - unwrap!(f.write( + unwrap!(f.blocking_write( 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, @@ -45,7 +44,7 @@ async fn main(_spawner: Spawner) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(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 7ee9838c..f66df770 100644 --- a/examples/stm32h7/src/bin/flash.rs +++ b/examples/stm32h7/src/bin/flash.rs @@ -6,7 +6,6 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; use embassy_stm32::flash::Flash; use embassy_time::{Duration, Timer}; -use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -19,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 = Flash::new(p.FLASH).into_regions().bank2_region; + let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank2_region; info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); - unwrap!(f.erase(ADDR, ADDR + 128 * 1024)); + unwrap!(f.blocking_erase(ADDR, ADDR + 128 * 1024)); info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(ADDR, &mut buf)); info!("Read after erase: {=[u8]:x}", buf); info!("Writing..."); - unwrap!(f.write( + unwrap!(f.blocking_write( 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, @@ -45,7 +44,7 @@ async fn main(_spawner: Spawner) { info!("Reading..."); let mut buf = [0u8; 32]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(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 33742502..86f6c70b 100644 --- a/examples/stm32l0/src/bin/flash.rs +++ b/examples/stm32l0/src/bin/flash.rs @@ -5,7 +5,6 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; use embassy_stm32::flash::Flash; -use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -15,27 +14,27 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x26000; - let mut f = Flash::new(p.FLASH).into_regions().bank1_region; + let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); - unwrap!(f.erase(ADDR, ADDR + 128)); + unwrap!(f.blocking_erase(ADDR, ADDR + 128)); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(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.blocking_write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(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 38feb0d7..aeb535cc 100644 --- a/examples/stm32l1/src/bin/flash.rs +++ b/examples/stm32l1/src/bin/flash.rs @@ -5,7 +5,6 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; use embassy_stm32::flash::Flash; -use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -15,27 +14,27 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x26000; - let mut f = Flash::new(p.FLASH).into_regions().bank1_region; + let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); - unwrap!(f.erase(ADDR, ADDR + 256)); + unwrap!(f.blocking_erase(ADDR, ADDR + 256)); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(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.blocking_write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(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 e6bc2865..5e52d49e 100644 --- a/examples/stm32wl/src/bin/flash.rs +++ b/examples/stm32wl/src/bin/flash.rs @@ -5,7 +5,6 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; use embassy_stm32::flash::Flash; -use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -15,27 +14,27 @@ async fn main(_spawner: Spawner) { const ADDR: u32 = 0x36000; - let mut f = Flash::new(p.FLASH).into_regions().bank1_region; + let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region; info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Erasing..."); - unwrap!(f.erase(ADDR, ADDR + 2048)); + unwrap!(f.blocking_erase(ADDR, ADDR + 2048)); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); info!("Writing..."); - unwrap!(f.write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); + unwrap!(f.blocking_write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); info!("Reading..."); let mut buf = [0u8; 8]; - unwrap!(f.read(ADDR, &mut buf)); + unwrap!(f.blocking_read(ADDR, &mut buf)); info!("Read: {=[u8]:x}", buf); assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); }