Merge #1480
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:
commit
31b364b9b0
@ -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.
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
189
embassy-stm32/src/flash/asynch.rs
Normal file
189
embassy-stm32/src/flash/asynch.rs
Normal 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(§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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -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(§or)?;
|
||||||
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)
|
|
||||||
})?;
|
|
||||||
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(§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 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;
|
||||||
pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
|
|
||||||
unsafe { blocking_write_chunked(self.base, self.size, offset, bytes) }
|
|
||||||
}
|
}
|
||||||
|
if address != end_address {
|
||||||
pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
|
return Err(Error::Unaligned);
|
||||||
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;
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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,33 +359,147 @@ 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() {
|
||||||
|
return get_result(sr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_result(sr: Sr) -> Result<(), Error> {
|
||||||
if sr.pgserr() {
|
if sr.pgserr() {
|
||||||
return Err(Error::Seq);
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
if sr.pgperr() {
|
#[cfg(any(
|
||||||
return Err(Error::Parallelism);
|
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");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if sr.pgaerr() {
|
#[allow(unused)]
|
||||||
return Err(Error::Unaligned);
|
fn pa12_is_output_pull_low() -> bool {
|
||||||
}
|
use pac::gpio::vals;
|
||||||
|
use pac::GPIOA;
|
||||||
if sr.wrperr() {
|
const PIN: usize = 12;
|
||||||
return Err(Error::Protected);
|
unsafe {
|
||||||
}
|
GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT
|
||||||
|
&& GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN
|
||||||
return Ok(());
|
&& GPIOA.odr().read().odr(PIN) == vals::Odr::LOW
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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> {
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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]);
|
||||||
}
|
}
|
||||||
|
@ -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[..],
|
||||||
|
85
examples/stm32f4/src/bin/flash_async.rs
Normal file
85
examples/stm32f4/src/bin/flash_async.rs
Normal 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
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
@ -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[..],
|
||||||
|
@ -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[..],
|
||||||
|
@ -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]);
|
||||||
}
|
}
|
||||||
|
@ -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]);
|
||||||
}
|
}
|
||||||
|
@ -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]);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user