1480: stm32: Async flash support for F4 r=rmja a=rmja

This PR depends on https://github.com/embassy-rs/embassy/pull/1478.

It adds async write/erase operations to the F4 series based on the work in https://github.com/embassy-rs/embassy/pull/870 but aligned to the new flash regions.

If one considers the entire `Flash` then nothing has changed other than the async operations have been added.



Co-authored-by: Rasmus Melchior Jacobsen <rmja@laesoe.org>
This commit is contained in:
bors[bot] 2023-05-26 08:21:57 +00:00 committed by GitHub
commit 31b364b9b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 854 additions and 288 deletions

View File

@ -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-hal-nb = { version = "=1.0.0-alpha.2", optional = true}
embedded-storage = "0.3.0" embedded-storage = "0.3.0"
embedded-storage-async = { version = "0.4.0", optional = true }
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true } log = { version = "0.4.14", optional = true }
@ -98,7 +99,7 @@ time-driver-tim12 = ["_time-driver"]
time-driver-tim15 = ["_time-driver"] time-driver-tim15 = ["_time-driver"]
# Enable nightly-only features # 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`. # 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. # This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version.

View File

@ -213,7 +213,7 @@ fn main() {
let region_type = format_ident!("{}", get_flash_region_type_name(region.name)); let region_type = format_ident!("{}", get_flash_region_type_name(region.name));
flash_regions.extend(quote! { flash_regions.extend(quote! {
#[cfg(flash)] #[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<MODE>);
}); });
} }
@ -224,11 +224,11 @@ fn main() {
let field_name = format_ident!("{}", region_name.to_lowercase()); let field_name = format_ident!("{}", region_name.to_lowercase());
let field_type = format_ident!("{}", get_flash_region_type_name(f.name)); let field_type = format_ident!("{}", get_flash_region_type_name(f.name));
let field = quote! { let field = quote! {
pub #field_name: #field_type<'d> pub #field_name: #field_type<'d, MODE>
}; };
let region_name = format_ident!("{}", region_name); let region_name = format_ident!("{}", region_name);
let init = quote! { 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)) (field, (init, region_name))
@ -238,15 +238,17 @@ fn main() {
let regions_len = flash_memory_regions.len(); let regions_len = flash_memory_regions.len();
flash_regions.extend(quote! { flash_regions.extend(quote! {
#[cfg(flash)] #[cfg(flash)]
pub struct FlashLayout<'d> { pub struct FlashLayout<'d, MODE = crate::flash::Async> {
#(#fields),* #(#fields),*,
_mode: core::marker::PhantomData<MODE>,
} }
#[cfg(flash)] #[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 { pub(crate) fn new(p: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>) -> Self {
Self { Self {
#(#inits),* #(#inits),*,
_mode: core::marker::PhantomData,
} }
} }
} }

View File

@ -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<CriticalSectionRawMutex, ()> = Mutex::new(());
impl<'d> Flash<'d, Async> {
pub fn new(
p: impl Peripheral<P = FLASH> + 'd,
_irq: impl interrupt::Binding<crate::interrupt::FLASH, InterruptHandler> + '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<crate::interrupt::FLASH> 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(&sector).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
}
}
};
}

View File

@ -1,40 +1,57 @@
use core::marker::PhantomData;
use atomic_polyfill::{fence, Ordering}; use atomic_polyfill::{fence, Ordering};
use embassy_hal_common::drop::OnDrop; use embassy_hal_common::drop::OnDrop;
use embassy_hal_common::{into_ref, PeripheralRef}; 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 super::{
use crate::flash::FlashBank; family, Async, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, MAX_ERASE_SIZE,
READ_SIZE, WRITE_SIZE,
};
use crate::peripherals::FLASH;
use crate::Peripheral; use crate::Peripheral;
pub struct Flash<'d> { pub struct Flash<'d, MODE = Async> {
inner: PeripheralRef<'d, crate::peripherals::FLASH>, pub(crate) inner: PeripheralRef<'d, FLASH>,
pub(crate) _mode: PhantomData<MODE>,
} }
impl<'d> Flash<'d> { impl<'d> Flash<'d, Blocking> {
pub fn new(p: impl Peripheral<P = crate::peripherals::FLASH> + 'd) -> Self { pub fn new_blocking(p: impl Peripheral<P = FLASH> + 'd) -> Self {
into_ref!(p); 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(); 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) blocking_read(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes)
} }
pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { 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> { pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
unsafe { blocking_erase_sectored(FLASH_BASE as u32, from, to) } unsafe { blocking_erase(FLASH_BASE as u32, from, to, erase_sector_unlocked) }
}
pub(crate) fn release(self) -> PeripheralRef<'d, crate::peripherals::FLASH> {
unsafe { self.inner.clone_unchecked() }
} }
} }
@ -44,12 +61,22 @@ pub(super) fn blocking_read(base: u32, size: u32, offset: u32, bytes: &mut [u8])
} }
let start_address = base + offset; 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()) }; let flash_data = unsafe { core::slice::from_raw_parts(start_address as *const u8, bytes.len()) };
bytes.copy_from_slice(flash_data); bytes.copy_from_slice(flash_data);
Ok(()) 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 { if offset + bytes.len() as u32 > size {
return Err(Error::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); trace!("Writing {} bytes at 0x{:x}", bytes.len(), address);
for chunk in bytes.chunks(WRITE_SIZE) { for chunk in bytes.chunks(WRITE_SIZE) {
critical_section::with(|_| { write_chunk(address, chunk)?;
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())
})?;
address += WRITE_SIZE as u32; address += WRITE_SIZE as u32;
} }
Ok(()) 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 start_address = base + from;
let end_address = base + to; let end_address = base + to;
let regions = family::get_flash_regions(); let regions = family::get_flash_regions();
// Test if the address range is aligned at sector base addresses ensure_sector_aligned(start_address, end_address, regions)?;
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);
}
trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); 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 { while address < end_address {
let sector = get_sector(address, regions); let sector = get_sector(address, regions);
trace!("Erasing sector: {:?}", sector); trace!("Erasing sector: {:?}", sector);
erase_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(&sector)
})?;
address += sector.size; address += sector.size;
} }
Ok(()) 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(&sector)
}
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 current_bank = FlashBank::Bank1;
let mut bank_offset = 0; let mut bank_offset = 0;
for region in regions { for region in regions {
@ -149,29 +179,34 @@ pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector
panic!("Flash sector not found"); panic!("Flash sector not found");
} }
impl FlashRegion { pub(super) fn ensure_sector_aligned(
pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { start_address: u32,
blocking_read(self.base, self.size, offset, bytes) 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 {
pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { return Err(Error::Unaligned);
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) }
} }
Ok(())
} }
impl embedded_storage::nor_flash::ErrorType for Flash<'_> { impl<MODE> embedded_storage::nor_flash::ErrorType for Flash<'_, MODE> {
type Error = Error; type Error = Error;
} }
impl embedded_storage::nor_flash::ReadNorFlash for Flash<'_> { impl<MODE> embedded_storage::nor_flash::ReadNorFlash for Flash<'_, MODE> {
const READ_SIZE: usize = 1; const READ_SIZE: usize = READ_SIZE;
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { 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 { 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<MODE> embedded_storage::nor_flash::NorFlash for Flash<'_, MODE> {
const WRITE_SIZE: usize = WRITE_SIZE; const WRITE_SIZE: usize = WRITE_SIZE;
const ERASE_SIZE: usize = MAX_ERASE_SIZE; const ERASE_SIZE: usize = MAX_ERASE_SIZE;
@ -194,26 +229,28 @@ impl embedded_storage::nor_flash::NorFlash for Flash<'_> {
foreach_flash_region! { foreach_flash_region! {
($type_name:ident, $write_size:literal, $erase_size:literal) => { ($type_name:ident, $write_size:literal, $erase_size:literal) => {
impl crate::_generated::flash_regions::$type_name<'_> { impl<MODE> crate::_generated::flash_regions::$type_name<'_, MODE> {
pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
blocking_read(self.0.base, self.0.size, offset, bytes) 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> { 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> { 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<MODE> embedded_storage::nor_flash::ErrorType for crate::_generated::flash_regions::$type_name<'_, MODE> {
type Error = Error; type Error = Error;
} }
impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> { impl<MODE> embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_, MODE> {
const READ_SIZE: usize = 1; const READ_SIZE: usize = READ_SIZE;
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_read(offset, bytes) 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 WRITE_SIZE: usize = $write_size;
const ERASE_SIZE: usize = $erase_size; const ERASE_SIZE: usize = $erase_size;

View File

@ -22,13 +22,13 @@ pub(crate) unsafe fn unlock() {
pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); 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); assert_eq!(0, WRITE_SIZE % 2);
pac::FLASH.cr().write(|w| w.set_pg(true)); 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)); 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); fence(Ordering::SeqCst);
} }
blocking_wait_ready() wait_ready_blocking()
} }
pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 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); 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() { if !pac::FLASH.sr().read().eop() {
trace!("FLASH: EOP not set"); 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 { loop {
let sr = pac::FLASH.sr().read(); let sr = pac::FLASH.sr().read();

View File

@ -22,13 +22,13 @@ pub(crate) unsafe fn unlock() {
pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); 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); assert_eq!(0, WRITE_SIZE % 2);
pac::FLASH.cr().write(|w| w.set_pg(true)); 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)); 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); fence(Ordering::SeqCst);
} }
blocking_wait_ready() wait_ready_blocking()
} }
pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 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); 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() { if !pac::FLASH.sr().read().eop() {
trace!("FLASH: EOP not set"); 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 { loop {
let sr = pac::FLASH.sr().read(); let sr = pac::FLASH.sr().read();

View File

@ -2,20 +2,24 @@ use core::convert::TryInto;
use core::ptr::write_volatile; use core::ptr::write_volatile;
use core::sync::atomic::{fence, Ordering}; 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::flash::Error;
use crate::pac; use crate::pac;
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
mod alt_regions { mod alt_regions {
use core::marker::PhantomData;
use embassy_hal_common::PeripheralRef; use embassy_hal_common::PeripheralRef;
use stm32_metapac::FLASH_SIZE; use stm32_metapac::FLASH_SIZE;
use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION}; use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION};
use crate::flash::{ use crate::flash::{asynch, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion};
blocking_erase_sectored, blocking_read, blocking_write_chunked, Bank1Region1, Bank1Region2, Error, Flash,
FlashBank, FlashRegion,
};
use crate::peripherals::FLASH; use crate::peripherals::FLASH;
pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion { pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion {
@ -48,62 +52,87 @@ mod alt_regions {
&ALT_BANK2_REGION3, &ALT_BANK2_REGION3,
]; ];
pub struct AltBank1Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); pub struct AltBank1Region3<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
pub struct AltBank2Region1<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); pub struct AltBank2Region1<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
pub struct AltBank2Region2<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); pub struct AltBank2Region2<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
pub struct AltBank2Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); pub struct AltBank2Region3<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
pub struct AltFlashLayout<'d> { pub struct AltFlashLayout<'d, MODE = Async> {
pub bank1_region1: Bank1Region1<'d>, pub bank1_region1: Bank1Region1<'d, MODE>,
pub bank1_region2: Bank1Region2<'d>, pub bank1_region2: Bank1Region2<'d, MODE>,
pub bank1_region3: AltBank1Region3<'d>, pub bank1_region3: AltBank1Region3<'d, MODE>,
pub bank2_region1: AltBank2Region1<'d>, pub bank2_region1: AltBank2Region1<'d, MODE>,
pub bank2_region2: AltBank2Region2<'d>, pub bank2_region2: AltBank2Region2<'d, MODE>,
pub bank2_region3: AltBank2Region3<'d>, pub bank2_region3: AltBank2Region3<'d, MODE>,
pub otp_region: OTPRegion<'d>, pub otp_region: OTPRegion<'d, MODE>,
} }
impl<'d> Flash<'d> { 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)) }; 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. // 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. // Also, all blocking flash region operations are protected with a cs.
let p = self.release(); let p = self.inner;
AltFlashLayout { AltFlashLayout {
bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }), bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }), bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }), bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }), bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }), bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }), bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }), otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData),
} }
} }
} }
macro_rules! foreach_altflash_region { macro_rules! foreach_altflash_region {
($type_name:ident, $region:ident) => { ($type_name:ident, $region:ident) => {
impl $type_name<'_> { impl<MODE> $type_name<'_, MODE> {
pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
blocking_read(self.0.base, self.0.size, offset, bytes) crate::flash::common::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) }
} }
} }
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<MODE> embedded_storage::nor_flash::ErrorType for $type_name<'_, MODE> {
type Error = Error; type Error = Error;
} }
impl embedded_storage::nor_flash::ReadNorFlash for $type_name<'_> { impl<MODE> embedded_storage::nor_flash::ReadNorFlash for $type_name<'_, MODE> {
const READ_SIZE: usize = 1; const READ_SIZE: usize = crate::flash::READ_SIZE;
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_read(offset, bytes) 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 WRITE_SIZE: usize = $region.write_size as usize;
const ERASE_SIZE: usize = $region.erase_size as usize; const ERASE_SIZE: usize = $region.erase_size as usize;
fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(offset, bytes) self.write(offset, bytes).await
} }
fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
self.blocking_erase(from, to) self.erase(from, to).await
} }
} }
}; };
@ -138,14 +181,42 @@ mod alt_regions {
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
pub use alt_regions::*; 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))] #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
pub fn set_default_layout() { 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)))] #[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))]
pub const fn set_default_layout() {} 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))] #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
pub fn get_flash_regions() -> &'static [&'static FlashRegion] { pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
if unsafe { pac::FLASH.optcr().read().db1m() } { if unsafe { pac::FLASH.optcr().read().db1m() } {
@ -160,17 +231,49 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
&FLASH_REGIONS &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() { pub(crate) unsafe fn lock() {
pac::FLASH.cr().modify(|w| w.set_lock(true)); pac::FLASH.cr().modify(|w| w.set_lock(true));
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123)); pac::FLASH.keyr().write(|w| w.set_key(0x45670123));
pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); 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); 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| { pac::FLASH.cr().write(|w| {
w.set_pg(true); 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)); 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> { 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; let mut address = start_address;
for val in buf.chunks(4) { for val in buf.chunks(4) {
write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); 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 // prevents parallelism errors
fence(Ordering::SeqCst); 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; save_data_cache_state();
trace!("Erasing sector number {}", sector.snb());
pac::FLASH.cr().modify(|w| { pac::FLASH.cr().modify(|w| {
w.set_ser(true); 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| { 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(); let ret: Result<(), Error> = blocking_wait_ready();
clear_all_err(); clear_all_err();
restore_data_cache_state();
ret ret
} }
@ -220,36 +359,150 @@ pub(crate) unsafe fn clear_all_err() {
w.set_pgperr(true); w.set_pgperr(true);
w.set_pgaerr(true); w.set_pgaerr(true);
w.set_wrperr(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> { unsafe fn blocking_wait_ready() -> Result<(), Error> {
loop { loop {
let sr = pac::FLASH.sr().read(); let sr = pac::FLASH.sr().read();
if !sr.bsy() { if !sr.bsy() {
if sr.pgserr() { return get_result(sr);
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(());
} }
} }
} }
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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -257,12 +510,14 @@ mod tests {
#[test] #[test]
#[cfg(stm32f429)] #[cfg(stm32f429)]
fn can_get_sector_single_bank() { fn can_get_sector() {
const SMALL_SECTOR_SIZE: u32 = 16 * 1024; const SMALL_SECTOR_SIZE: u32 = 16 * 1024;
const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024; const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024;
const LARGE_SECTOR_SIZE: u32 = 128 * 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!( assert_eq!(
FlashSector { FlashSector {
bank: FlashBank::Bank1, bank: FlashBank::Bank1,
@ -270,24 +525,26 @@ mod tests {
start, start,
size size
}, },
get_sector(address, &FLASH_REGIONS) sector
) );
}; };
assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000);
assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF);
assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000);
assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF);
assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); assert_sector(0x04, 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_FFFF);
assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000);
assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF);
assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000);
assert_sector(11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); 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!( assert_eq!(
FlashSector { FlashSector {
bank, bank,
@ -295,34 +552,34 @@ mod tests {
start, start,
size size
}, },
get_sector(address, &ALT_FLASH_REGIONS) sector
) )
}; };
assert_sector(FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000);
assert_sector(FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF);
assert_sector(FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); assert_sector(0x03, FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000);
assert_sector(FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); 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(0x04, 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_FFFF);
assert_sector(FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000);
assert_sector(FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF);
assert_sector(FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000); assert_sector(0x07, FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000);
assert_sector(FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); 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(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000);
assert_sector(FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF); assert_sector(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF);
assert_sector(FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000); assert_sector(0x13, FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000);
assert_sector(FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF); 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(0x14, 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_FFFF);
assert_sector(FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000); assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000);
assert_sector(FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF); assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF);
assert_sector(FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000);
assert_sector(FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF);
} }
} }

View File

@ -21,7 +21,7 @@ pub(crate) unsafe fn unlock() {
pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); 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); assert_eq!(0, WRITE_SIZE % 4);
pac::FLASH.cr().write(|w| { 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)); 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(); let ret: Result<(), Error> = blocking_wait_ready();
pac::FLASH.cr().modify(|w| w.set_ser(false)); pac::FLASH.cr().modify(|w| w.set_ser(false));
clear_all_err(); clear_all_err();
ret ret
} }

View File

@ -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); 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 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 // 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); let ret: Result<(), Error> = blocking_wait_ready(bank);
bank.cr().modify(|w| w.set_ser(false)); bank.cr().modify(|w| w.set_ser(false));
bank_clear_all_err(bank); bank_clear_all_err(bank);
ret ret
} }

View File

@ -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); assert_eq!(0, WRITE_SIZE % 4);
#[cfg(any(flash_wl, flash_wb, flash_l4))] #[cfg(any(flash_wl, flash_wb, flash_l4))]
pac::FLASH.cr().write(|w| w.set_pg(true)); 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))] #[cfg(any(flash_wl, flash_wb, flash_l4))]
pac::FLASH.cr().write(|w| w.set_pg(false)); 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); fence(Ordering::SeqCst);
} }
blocking_wait_ready() wait_ready_blocking()
} }
pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 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))] #[cfg(any(flash_wl, flash_wb, flash_l4))]
pac::FLASH.cr().modify(|w| w.set_per(false)); 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(); clear_all_err();
ret 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 { loop {
let sr = pac::FLASH.sr().read(); let sr = pac::FLASH.sr().read();

View File

@ -1,8 +1,12 @@
use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind};
#[cfg(flash_f4)]
mod asynch;
#[cfg(flash)] #[cfg(flash)]
mod common; mod common;
#[cfg(flash_f4)]
pub use asynch::InterruptHandler;
#[cfg(flash)] #[cfg(flash)]
pub use common::*; pub use common::*;
@ -10,6 +14,11 @@ pub use crate::_generated::flash_regions::*;
pub use crate::_generated::MAX_ERASE_SIZE; pub use crate::_generated::MAX_ERASE_SIZE;
pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_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)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FlashRegion { pub struct FlashRegion {

View File

@ -14,10 +14,10 @@ pub(crate) unsafe fn lock() {
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
unimplemented!(); unimplemented!();
} }
pub(crate) unsafe fn begin_write() { pub(crate) unsafe fn enable_blocking_write() {
unimplemented!(); unimplemented!();
} }
pub(crate) unsafe fn end_write() { pub(crate) unsafe fn disable_blocking_write() {
unimplemented!(); unimplemented!();
} }
pub(crate) unsafe fn blocking_write(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { pub(crate) unsafe fn blocking_write(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {

View File

@ -26,7 +26,7 @@ async fn main(_s: Spawner) {
let mut watchdog = Watchdog::new(p.WATCHDOG); let mut watchdog = Watchdog::new(p.WATCHDOG);
watchdog.start(Duration::from_secs(8)); 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(); let mut updater = FirmwareUpdater::default();

View File

@ -17,7 +17,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default()); 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 mut flash = BlockingAsync::new(flash);
let button = Input::new(p.PC13, Pull::Up); let button = Input::new(p.PC13, Pull::Up);

View File

@ -16,7 +16,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default()); 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 button = Input::new(p.PC13, Pull::Down);
let mut button = ExtiInput::new(button, p.EXTI13); let mut button = ExtiInput::new(button, p.EXTI13);

View File

@ -16,7 +16,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default()); 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 button = Input::new(p.PC13, Pull::Down);
let mut button = ExtiInput::new(button, p.EXTI13); let mut button = ExtiInput::new(button, p.EXTI13);

View File

@ -18,7 +18,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default()); 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 mut flash = BlockingAsync::new(flash);
let button = Input::new(p.PB2, Pull::Up); let button = Input::new(p.PB2, Pull::Up);

View File

@ -18,7 +18,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default()); 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 mut flash = BlockingAsync::new(flash);
let button = Input::new(p.PB2, Pull::Up); let button = Input::new(p.PB2, Pull::Up);

View File

@ -17,7 +17,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default()); 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 mut flash = BlockingAsync::new(flash);
let button = Input::new(p.PC13, Pull::Up); let button = Input::new(p.PC13, Pull::Up);

View File

@ -17,7 +17,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default()); 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 mut flash = BlockingAsync::new(flash);
let button = Input::new(p.PA0, Pull::Up); let button = Input::new(p.PA0, Pull::Up);

View File

@ -20,8 +20,7 @@ fn main() -> ! {
*/ */
let mut bl: BootLoader<2048> = BootLoader::default(); let mut bl: BootLoader<2048> = BootLoader::default();
let flash = Flash::new(p.FLASH); let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
let layout = flash.into_regions();
let mut flash = BootFlash::new(layout.bank1_region); let mut flash = BootFlash::new(layout.bank1_region);
let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash)); let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash));
core::mem::drop(flash); core::mem::drop(flash);

View File

@ -5,7 +5,6 @@
use defmt::{info, unwrap}; use defmt::{info, unwrap};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::flash::Flash; use embassy_stm32::flash::Flash;
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main] #[embassy_executor::main]
@ -15,27 +14,27 @@ async fn main(_spawner: Spawner) {
const ADDR: u32 = 0x26000; 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..."); info!("Reading...");
let mut buf = [0u8; 8]; let mut buf = [0u8; 8];
unwrap!(f.read(ADDR, &mut buf)); unwrap!(f.blocking_read(ADDR, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
info!("Erasing..."); info!("Erasing...");
unwrap!(f.erase(ADDR, ADDR + 2048)); unwrap!(f.blocking_erase(ADDR, ADDR + 2048));
info!("Reading..."); info!("Reading...");
let mut buf = [0u8; 8]; 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!("Read after erase: {=[u8]:x}", buf);
info!("Writing..."); 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..."); info!("Reading...");
let mut buf = [0u8; 8]; let mut buf = [0u8; 8];
unwrap!(f.read(ADDR, &mut buf)); unwrap!(f.blocking_read(ADDR, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
} }

View File

@ -4,7 +4,7 @@
use defmt::{info, unwrap}; use defmt::{info, unwrap};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::flash::Flash; use embassy_stm32::flash::{Blocking, Flash};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main] #[embassy_executor::main]
@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
// Once can also call `into_regions()` to get access to NorFlash implementations // Once can also call `into_regions()` to get access to NorFlash implementations
// for each of the unique characteristics. // for each of the unique characteristics.
let mut f = Flash::new(p.FLASH); let mut f = Flash::new_blocking(p.FLASH);
// Sector 5 // Sector 5
test_flash(&mut f, 128 * 1024, 128 * 1024); 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); 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!("Testing offset: {=u32:#X}, size: {=u32:#X}", offset, size);
info!("Reading..."); info!("Reading...");
let mut buf = [0u8; 32]; let mut buf = [0u8; 32];
unwrap!(f.blocking_read(offset, &mut buf)); unwrap!(f.read(offset, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
info!("Erasing..."); info!("Erasing...");
@ -39,7 +39,7 @@ fn test_flash(f: &mut Flash, offset: u32, size: u32) {
info!("Reading..."); info!("Reading...");
let mut buf = [0u8; 32]; 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!("Read after erase: {=[u8]:x}", buf);
info!("Writing..."); info!("Writing...");
@ -53,7 +53,7 @@ fn test_flash(f: &mut Flash, offset: u32, size: u32) {
info!("Reading..."); info!("Reading...");
let mut buf = [0u8; 32]; let mut buf = [0u8; 32];
unwrap!(f.blocking_read(offset, &mut buf)); unwrap!(f.read(offset, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
assert_eq!( assert_eq!(
&buf[..], &buf[..],

View File

@ -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
]
);
}

View File

@ -6,7 +6,6 @@ use defmt::{info, unwrap};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::flash::Flash; use embassy_stm32::flash::Flash;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main] #[embassy_executor::main]
@ -19,23 +18,23 @@ async fn main(_spawner: Spawner) {
// wait a bit before accessing the flash // wait a bit before accessing the flash
Timer::after(Duration::from_millis(300)).await; 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..."); info!("Reading...");
let mut buf = [0u8; 32]; let mut buf = [0u8; 32];
unwrap!(f.read(ADDR, &mut buf)); unwrap!(f.blocking_read(ADDR, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
info!("Erasing..."); info!("Erasing...");
unwrap!(f.erase(ADDR, ADDR + 256 * 1024)); unwrap!(f.blocking_erase(ADDR, ADDR + 256 * 1024));
info!("Reading..."); info!("Reading...");
let mut buf = [0u8; 32]; 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!("Read after erase: {=[u8]:x}", buf);
info!("Writing..."); info!("Writing...");
unwrap!(f.write( unwrap!(f.blocking_write(
ADDR, 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, 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..."); info!("Reading...");
let mut buf = [0u8; 32]; let mut buf = [0u8; 32];
unwrap!(f.read(ADDR, &mut buf)); unwrap!(f.blocking_read(ADDR, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
assert_eq!( assert_eq!(
&buf[..], &buf[..],

View File

@ -6,7 +6,6 @@ use defmt::{info, unwrap};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::flash::Flash; use embassy_stm32::flash::Flash;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main] #[embassy_executor::main]
@ -19,23 +18,23 @@ async fn main(_spawner: Spawner) {
// wait a bit before accessing the flash // wait a bit before accessing the flash
Timer::after(Duration::from_millis(300)).await; 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..."); info!("Reading...");
let mut buf = [0u8; 32]; let mut buf = [0u8; 32];
unwrap!(f.read(ADDR, &mut buf)); unwrap!(f.blocking_read(ADDR, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
info!("Erasing..."); info!("Erasing...");
unwrap!(f.erase(ADDR, ADDR + 128 * 1024)); unwrap!(f.blocking_erase(ADDR, ADDR + 128 * 1024));
info!("Reading..."); info!("Reading...");
let mut buf = [0u8; 32]; 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!("Read after erase: {=[u8]:x}", buf);
info!("Writing..."); info!("Writing...");
unwrap!(f.write( unwrap!(f.blocking_write(
ADDR, 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, 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..."); info!("Reading...");
let mut buf = [0u8; 32]; let mut buf = [0u8; 32];
unwrap!(f.read(ADDR, &mut buf)); unwrap!(f.blocking_read(ADDR, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
assert_eq!( assert_eq!(
&buf[..], &buf[..],

View File

@ -5,7 +5,6 @@
use defmt::{info, unwrap}; use defmt::{info, unwrap};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::flash::Flash; use embassy_stm32::flash::Flash;
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main] #[embassy_executor::main]
@ -15,27 +14,27 @@ async fn main(_spawner: Spawner) {
const ADDR: u32 = 0x26000; 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..."); info!("Reading...");
let mut buf = [0u8; 8]; let mut buf = [0u8; 8];
unwrap!(f.read(ADDR, &mut buf)); unwrap!(f.blocking_read(ADDR, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
info!("Erasing..."); info!("Erasing...");
unwrap!(f.erase(ADDR, ADDR + 128)); unwrap!(f.blocking_erase(ADDR, ADDR + 128));
info!("Reading..."); info!("Reading...");
let mut buf = [0u8; 8]; 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!("Read after erase: {=[u8]:x}", buf);
info!("Writing..."); 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..."); info!("Reading...");
let mut buf = [0u8; 8]; let mut buf = [0u8; 8];
unwrap!(f.read(ADDR, &mut buf)); unwrap!(f.blocking_read(ADDR, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
} }

View File

@ -5,7 +5,6 @@
use defmt::{info, unwrap}; use defmt::{info, unwrap};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::flash::Flash; use embassy_stm32::flash::Flash;
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main] #[embassy_executor::main]
@ -15,27 +14,27 @@ async fn main(_spawner: Spawner) {
const ADDR: u32 = 0x26000; 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..."); info!("Reading...");
let mut buf = [0u8; 8]; let mut buf = [0u8; 8];
unwrap!(f.read(ADDR, &mut buf)); unwrap!(f.blocking_read(ADDR, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
info!("Erasing..."); info!("Erasing...");
unwrap!(f.erase(ADDR, ADDR + 256)); unwrap!(f.blocking_erase(ADDR, ADDR + 256));
info!("Reading..."); info!("Reading...");
let mut buf = [0u8; 8]; 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!("Read after erase: {=[u8]:x}", buf);
info!("Writing..."); 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..."); info!("Reading...");
let mut buf = [0u8; 8]; let mut buf = [0u8; 8];
unwrap!(f.read(ADDR, &mut buf)); unwrap!(f.blocking_read(ADDR, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
} }

View File

@ -5,7 +5,6 @@
use defmt::{info, unwrap}; use defmt::{info, unwrap};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::flash::Flash; use embassy_stm32::flash::Flash;
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main] #[embassy_executor::main]
@ -15,27 +14,27 @@ async fn main(_spawner: Spawner) {
const ADDR: u32 = 0x36000; 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..."); info!("Reading...");
let mut buf = [0u8; 8]; let mut buf = [0u8; 8];
unwrap!(f.read(ADDR, &mut buf)); unwrap!(f.blocking_read(ADDR, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
info!("Erasing..."); info!("Erasing...");
unwrap!(f.erase(ADDR, ADDR + 2048)); unwrap!(f.blocking_erase(ADDR, ADDR + 2048));
info!("Reading..."); info!("Reading...");
let mut buf = [0u8; 8]; let mut buf = [0u8; 8];
unwrap!(f.read(ADDR, &mut buf)); unwrap!(f.blocking_read(ADDR, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
info!("Writing..."); 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..."); info!("Reading...");
let mut buf = [0u8; 8]; let mut buf = [0u8; 8];
unwrap!(f.read(ADDR, &mut buf)); unwrap!(f.blocking_read(ADDR, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
} }