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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user