From b2775fc90c3d7cc977f1ac3e15841462d7c8f1a4 Mon Sep 17 00:00:00 2001
From: Rasmus Melchior Jacobsen <rmja@laesoe.org>
Date: Wed, 24 May 2023 12:17:12 +0200
Subject: [PATCH 01/14] stm32: Add async flash write/erase to f4

---
 embassy-stm32/Cargo.toml          |   4 +-
 embassy-stm32/src/flash/asynch.rs | 129 +++++++++++++++
 embassy-stm32/src/flash/common.rs | 267 ++++++++++++++++--------------
 embassy-stm32/src/flash/f0.rs     |  18 +-
 embassy-stm32/src/flash/f3.rs     |  18 +-
 embassy-stm32/src/flash/f4.rs     | 183 +++++++++++++++++---
 embassy-stm32/src/flash/f7.rs     |  21 +--
 embassy-stm32/src/flash/h7.rs     |  21 +--
 embassy-stm32/src/flash/l.rs      |  19 ++-
 embassy-stm32/src/flash/mod.rs    |  49 ++++++
 embassy-stm32/src/flash/other.rs  |  12 +-
 11 files changed, 547 insertions(+), 194 deletions(-)
 create mode 100644 embassy-stm32/src/flash/asynch.rs

diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 21adb5ddf..440de85e8 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -47,6 +47,7 @@ embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true}
 embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true}
 
 embedded-storage = "0.3.0"
+embedded-storage-async = { version = "0.4.0", optional = true }
 
 defmt = { version = "0.3", optional = true }
 log = { version = "0.4.14", optional = true }
@@ -68,6 +69,7 @@ cfg-if = "1.0.0"
 embedded-io = { version = "0.4.0", features = ["async"], optional = true }
 chrono = { version = "^0.4", default-features = false, optional = true}
 bit_field = "0.10.2"
+paste = "1.0.12"
 
 [dev-dependencies]
 critical-section = { version = "1.1", features = ["std"] }
@@ -98,7 +100,7 @@ time-driver-tim12 = ["_time-driver"]
 time-driver-tim15 = ["_time-driver"]
 
 # Enable nightly-only features
-nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"]
+nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"]
 
 # Reexport stm32-metapac at `embassy_stm32::pac`.
 # This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version.
diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs
new file mode 100644
index 000000000..44e23d9c4
--- /dev/null
+++ b/embassy-stm32/src/flash/asynch.rs
@@ -0,0 +1,129 @@
+use atomic_polyfill::{fence, Ordering};
+use embassy_hal_common::drop::OnDrop;
+
+use super::{
+    ensure_sector_aligned, family, get_sector, Error, Flash, FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE,
+    REGION_ACCESS, WRITE_SIZE,
+};
+
+impl<'d> Flash<'d> {
+    pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
+        unsafe { write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes).await }
+    }
+
+    pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
+        unsafe { erase_sectored(FLASH_BASE as u32, from, to).await }
+    }
+}
+
+impl embedded_storage_async::nor_flash::NorFlash for Flash<'_> {
+    const WRITE_SIZE: usize = WRITE_SIZE;
+    const ERASE_SIZE: usize = MAX_ERASE_SIZE;
+
+    async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
+        self.write(offset, bytes).await
+    }
+
+    async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
+        self.erase(from, to).await
+    }
+}
+
+pub(super) async unsafe fn write_chunked(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> {
+    if offset + bytes.len() as u32 > size {
+        return Err(Error::Size);
+    }
+    if offset % WRITE_SIZE as u32 != 0 || bytes.len() % WRITE_SIZE != 0 {
+        return Err(Error::Unaligned);
+    }
+
+    let mut address = base + offset;
+    trace!("Writing {} bytes at 0x{:x}", bytes.len(), address);
+
+    for chunk in bytes.chunks(WRITE_SIZE) {
+        family::clear_all_err();
+        fence(Ordering::SeqCst);
+        family::unlock();
+        fence(Ordering::SeqCst);
+        family::enable_write();
+        fence(Ordering::SeqCst);
+
+        let _on_drop = OnDrop::new(|| {
+            family::disable_write();
+            fence(Ordering::SeqCst);
+            family::lock();
+        });
+
+        family::write(address, chunk.try_into().unwrap()).await?;
+        address += WRITE_SIZE as u32;
+    }
+    Ok(())
+}
+
+pub(super) async unsafe fn erase_sectored(base: u32, from: u32, to: u32) -> Result<(), Error> {
+    let start_address = base + from;
+    let end_address = base + to;
+    let regions = family::get_flash_regions();
+
+    ensure_sector_aligned(start_address, end_address, regions)?;
+
+    trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address);
+
+    let mut address = start_address;
+    while address < end_address {
+        let sector = get_sector(address, regions);
+        trace!("Erasing sector: {:?}", sector);
+
+        family::clear_all_err();
+        fence(Ordering::SeqCst);
+        family::unlock();
+        fence(Ordering::SeqCst);
+
+        let _on_drop = OnDrop::new(|| family::lock());
+
+        family::erase_sector(&sector).await?;
+        address += sector.size;
+    }
+    Ok(())
+}
+
+foreach_flash_region! {
+    ($type_name:ident, $write_size:literal, $erase_size:literal) => {
+        impl crate::_generated::flash_regions::$type_name<'_> {
+            pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
+                let _guard = REGION_ACCESS.lock().await;
+                unsafe { write_chunked(self.0.base, self.0.size, offset, bytes).await }
+            }
+
+            pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
+                let _guard = REGION_ACCESS.lock().await;
+                unsafe { erase_sectored(self.0.base, from, to).await }
+            }
+        }
+
+        impl embedded_storage_async::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> {
+            const READ_SIZE: usize = READ_SIZE;
+
+            async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
+                self.read(offset, bytes)
+            }
+
+            fn capacity(&self) -> usize {
+                self.0.size as usize
+            }
+        }
+
+        impl embedded_storage_async::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_> {
+            const WRITE_SIZE: usize = $write_size;
+            const ERASE_SIZE: usize = $erase_size;
+
+            async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
+                self.write(offset, bytes).await
+            }
+
+            async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
+                self.erase(from, to).await
+            }
+        }
+    };
+}
diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
index 432c8a43b..990104a38 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -1,44 +1,55 @@
 use atomic_polyfill::{fence, Ordering};
+use embassy_cortex_m::interrupt::InterruptExt;
+use embassy_futures::block_on;
 use embassy_hal_common::drop::OnDrop;
 use embassy_hal_common::{into_ref, PeripheralRef};
+use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
+use embassy_sync::mutex::Mutex;
+use stm32_metapac::FLASH_BASE;
 
-use super::{family, Error, FlashLayout, FlashRegion, FlashSector, FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, WRITE_SIZE};
-use crate::flash::FlashBank;
+use super::{
+    ensure_sector_aligned, family, get_sector, Error, FlashLayout, FlashRegion, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE,
+    WRITE_SIZE,
+};
+use crate::peripherals::FLASH;
 use crate::Peripheral;
 
 pub struct Flash<'d> {
-    inner: PeripheralRef<'d, crate::peripherals::FLASH>,
+    pub(crate) inner: PeripheralRef<'d, FLASH>,
 }
 
+pub(crate) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(());
+
 impl<'d> Flash<'d> {
-    pub fn new(p: impl Peripheral<P = crate::peripherals::FLASH> + 'd) -> Self {
-        into_ref!(p);
+    pub fn new(p: impl Peripheral<P = FLASH> + 'd, irq: impl Peripheral<P = crate::interrupt::FLASH> + 'd) -> Self {
+        into_ref!(p, irq);
+
+        irq.set_handler(family::on_interrupt);
+        irq.unpend();
+        irq.enable();
+
         Self { inner: p }
     }
 
     pub fn into_regions(self) -> FlashLayout<'d> {
         family::set_default_layout();
-        FlashLayout::new(self.release())
+        FlashLayout::new(self.inner)
     }
 
-    pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
-        blocking_read(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes)
+    pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
+        read_blocking(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes)
     }
 
-    pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
-        unsafe { blocking_write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) }
+    pub fn write_blocking(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
+        unsafe { write_chunked_blocking(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) }
     }
 
-    pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
-        unsafe { blocking_erase_sectored(FLASH_BASE as u32, from, to) }
-    }
-
-    pub(crate) fn release(self) -> PeripheralRef<'d, crate::peripherals::FLASH> {
-        unsafe { self.inner.clone_unchecked() }
+    pub fn erase_blocking(&mut self, from: u32, to: u32) -> Result<(), Error> {
+        unsafe { erase_sectored_blocking(FLASH_BASE as u32, from, to) }
     }
 }
 
-pub(super) fn blocking_read(base: u32, size: u32, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
+pub(super) fn read_blocking(base: u32, size: u32, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
     if offset + bytes.len() as u32 > size {
         return Err(Error::Size);
     }
@@ -49,7 +60,7 @@ pub(super) fn blocking_read(base: u32, size: u32, offset: u32, bytes: &mut [u8])
     Ok(())
 }
 
-pub(super) unsafe fn blocking_write_chunked(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> {
+pub(super) unsafe fn write_chunked_blocking(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> {
     if offset + bytes.len() as u32 > size {
         return Err(Error::Size);
     }
@@ -61,44 +72,31 @@ pub(super) unsafe fn blocking_write_chunked(base: u32, size: u32, offset: u32, b
     trace!("Writing {} bytes at 0x{:x}", bytes.len(), address);
 
     for chunk in bytes.chunks(WRITE_SIZE) {
-        critical_section::with(|_| {
-            family::clear_all_err();
-            fence(Ordering::SeqCst);
-            family::unlock();
-            fence(Ordering::SeqCst);
-            family::begin_write();
-            fence(Ordering::SeqCst);
+        family::clear_all_err();
+        fence(Ordering::SeqCst);
+        family::unlock();
+        fence(Ordering::SeqCst);
+        family::enable_blocking_write();
+        fence(Ordering::SeqCst);
 
-            let _on_drop = OnDrop::new(|| {
-                family::end_write();
-                fence(Ordering::SeqCst);
-                family::lock();
-            });
+        let _on_drop = OnDrop::new(|| {
+            family::disable_blocking_write();
+            fence(Ordering::SeqCst);
+            family::lock();
+        });
 
-            family::blocking_write(address, chunk.try_into().unwrap())
-        })?;
+        family::write_blocking(address, chunk.try_into().unwrap())?;
         address += WRITE_SIZE as u32;
     }
     Ok(())
 }
 
-pub(super) unsafe fn blocking_erase_sectored(base: u32, from: u32, to: u32) -> Result<(), Error> {
+pub(super) unsafe fn erase_sectored_blocking(base: u32, from: u32, to: u32) -> Result<(), Error> {
     let start_address = base + from;
     let end_address = base + to;
     let regions = family::get_flash_regions();
 
-    // Test if the address range is aligned at sector base addresses
-    let mut address = start_address;
-    while address < end_address {
-        let sector = get_sector(address, regions);
-        if sector.start != address {
-            return Err(Error::Unaligned);
-        }
-        address += sector.size;
-    }
-    if address != end_address {
-        return Err(Error::Unaligned);
-    }
+    ensure_sector_aligned(start_address, end_address, regions)?;
 
     trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address);
 
@@ -107,71 +105,28 @@ pub(super) unsafe fn blocking_erase_sectored(base: u32, from: u32, to: u32) -> R
         let sector = get_sector(address, regions);
         trace!("Erasing sector: {:?}", sector);
 
-        critical_section::with(|_| {
-            family::clear_all_err();
-            fence(Ordering::SeqCst);
-            family::unlock();
-            fence(Ordering::SeqCst);
+        family::clear_all_err();
+        fence(Ordering::SeqCst);
+        family::unlock();
+        fence(Ordering::SeqCst);
 
-            let _on_drop = OnDrop::new(|| {
-                family::lock();
-            });
+        let _on_drop = OnDrop::new(|| family::lock());
 
-            family::blocking_erase_sector(&sector)
-        })?;
+        family::erase_sector_blocking(&sector)?;
         address += sector.size;
     }
     Ok(())
 }
 
-pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector {
-    let mut current_bank = FlashBank::Bank1;
-    let mut bank_offset = 0;
-    for region in regions {
-        if region.bank != current_bank {
-            current_bank = region.bank;
-            bank_offset = 0;
-        }
-
-        if address < region.end() {
-            let index_in_region = (address - region.base) / region.erase_size;
-            return FlashSector {
-                bank: region.bank,
-                index_in_bank: bank_offset + index_in_region as u8,
-                start: region.base + index_in_region * region.erase_size,
-                size: region.erase_size,
-            };
-        }
-
-        bank_offset += region.sectors();
-    }
-
-    panic!("Flash sector not found");
-}
-
-impl FlashRegion {
-    pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
-        blocking_read(self.base, self.size, offset, bytes)
-    }
-
-    pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
-        unsafe { blocking_write_chunked(self.base, self.size, offset, bytes) }
-    }
-
-    pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
-        unsafe { blocking_erase_sectored(self.base, from, to) }
-    }
-}
-
 impl embedded_storage::nor_flash::ErrorType for Flash<'_> {
     type Error = Error;
 }
 
 impl embedded_storage::nor_flash::ReadNorFlash for Flash<'_> {
-    const READ_SIZE: usize = 1;
+    const READ_SIZE: usize = READ_SIZE;
 
     fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
-        self.blocking_read(offset, bytes)
+        self.read(offset, bytes)
     }
 
     fn capacity(&self) -> usize {
@@ -184,27 +139,112 @@ impl embedded_storage::nor_flash::NorFlash for Flash<'_> {
     const ERASE_SIZE: usize = MAX_ERASE_SIZE;
 
     fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
-        self.blocking_write(offset, bytes)
+        self.write_blocking(offset, bytes)
     }
 
     fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
-        self.blocking_erase(from, to)
+        self.erase_blocking(from, to)
+    }
+}
+
+#[cfg(feature = "nightly")]
+impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_> {
+    const READ_SIZE: usize = READ_SIZE;
+
+    async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
+        self.read(offset, bytes)
+    }
+
+    fn capacity(&self) -> usize {
+        FLASH_SIZE
+    }
+}
+
+pub struct BlockingFlashRegion<'d, const WRITE_SIZE: u32, const ERASE_SIZE: u32>(
+    &'static FlashRegion,
+    PeripheralRef<'d, FLASH>,
+);
+
+impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> {
+    pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
+        read_blocking(self.0.base, self.0.size, offset, bytes)
+    }
+
+    pub fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
+        let _guard = block_on(REGION_ACCESS.lock());
+        unsafe { write_chunked_blocking(self.0.base, self.0.size, offset, bytes) }
+    }
+
+    pub fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
+        let _guard = block_on(REGION_ACCESS.lock());
+        unsafe { erase_sectored_blocking(self.0.base, from, to) }
+    }
+}
+
+impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> embedded_storage::nor_flash::ErrorType
+    for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE>
+{
+    type Error = Error;
+}
+
+impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> embedded_storage::nor_flash::ReadNorFlash
+    for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE>
+{
+    const READ_SIZE: usize = READ_SIZE;
+
+    fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
+        self.read(offset, bytes)
+    }
+
+    fn capacity(&self) -> usize {
+        self.0.size as usize
+    }
+}
+
+impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> embedded_storage::nor_flash::NorFlash
+    for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE>
+{
+    const WRITE_SIZE: usize = WRITE_SIZE as usize;
+    const ERASE_SIZE: usize = ERASE_SIZE as usize;
+
+    fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
+        self.write(offset, bytes)
+    }
+
+    fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
+        self.erase(from, to)
     }
 }
 
 foreach_flash_region! {
     ($type_name:ident, $write_size:literal, $erase_size:literal) => {
-        impl crate::_generated::flash_regions::$type_name<'_> {
-            pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
-                blocking_read(self.0.base, self.0.size, offset, bytes)
+        paste::paste! {
+            pub type [<Blocking $type_name>]<'d> = BlockingFlashRegion<'d, $write_size, $erase_size>;
+        }
+
+        impl<'d> crate::_generated::flash_regions::$type_name<'d> {
+            /// Make this flash region work in a blocking context.
+            ///
+            /// SAFETY
+            ///
+            /// This function is unsafe as incorect usage of parallel blocking operations
+            /// on multiple regions may cause a deadlock because each region requires mutual access to the flash.
+            pub unsafe fn into_blocking(self) -> BlockingFlashRegion<'d, $write_size, $erase_size> {
+                BlockingFlashRegion(self.0, self.1)
             }
 
-            pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
-                unsafe { blocking_write_chunked(self.0.base, self.0.size, offset, bytes) }
+            pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
+                read_blocking(self.0.base, self.0.size, offset, bytes)
             }
 
-            pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
-                unsafe { blocking_erase_sectored(self.0.base, from, to) }
+            pub fn try_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
+                let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?;
+                unsafe { write_chunked_blocking(self.0.base, self.0.size, offset, bytes) }
+            }
+
+            pub fn try_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
+                let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?;
+                unsafe { erase_sectored_blocking(self.0.base, from, to) }
             }
         }
 
@@ -213,28 +253,15 @@ foreach_flash_region! {
         }
 
         impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> {
-            const READ_SIZE: usize = 1;
+            const READ_SIZE: usize = READ_SIZE;
 
             fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
-                self.blocking_read(offset, bytes)
+                self.read(offset, bytes)
             }
 
             fn capacity(&self) -> usize {
                 self.0.size as usize
             }
         }
-
-        impl embedded_storage::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_> {
-            const WRITE_SIZE: usize = $write_size;
-            const ERASE_SIZE: usize = $erase_size;
-
-            fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
-                self.blocking_write(offset, bytes)
-            }
-
-            fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
-                self.blocking_erase(from, to)
-            }
-        }
     };
 }
diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs
index c6441ef16..ecf3a6981 100644
--- a/embassy-stm32/src/flash/f0.rs
+++ b/embassy-stm32/src/flash/f0.rs
@@ -13,6 +13,10 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
     &FLASH_REGIONS
 }
 
+pub(crate) unsafe fn on_interrupt(_: *mut ()) {
+    unimplemented!();
+}
+
 pub(crate) unsafe fn lock() {
     pac::FLASH.cr().modify(|w| w.set_lock(true));
 }
@@ -22,17 +26,17 @@ pub(crate) unsafe fn unlock() {
     pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB));
 }
 
-pub(crate) unsafe fn begin_write() {
+pub(crate) unsafe fn enable_blocking_write() {
     assert_eq!(0, WRITE_SIZE % 2);
 
     pac::FLASH.cr().write(|w| w.set_pg(true));
 }
 
-pub(crate) unsafe fn end_write() {
+pub(crate) unsafe fn disable_blocking_write() {
     pac::FLASH.cr().write(|w| w.set_pg(false));
 }
 
-pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
+pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
     let mut address = start_address;
     for chunk in buf.chunks(2) {
         write_volatile(address as *mut u16, u16::from_le_bytes(chunk.try_into().unwrap()));
@@ -42,10 +46,10 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
         fence(Ordering::SeqCst);
     }
 
-    blocking_wait_ready()
+    wait_ready_blocking()
 }
 
-pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
+pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> {
     pac::FLASH.cr().modify(|w| {
         w.set_per(true);
     });
@@ -56,7 +60,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
         w.set_strt(true);
     });
 
-    let mut ret: Result<(), Error> = blocking_wait_ready();
+    let mut ret: Result<(), Error> = wait_ready_blocking();
 
     if !pac::FLASH.sr().read().eop() {
         trace!("FLASH: EOP not set");
@@ -88,7 +92,7 @@ pub(crate) unsafe fn clear_all_err() {
     });
 }
 
-unsafe fn blocking_wait_ready() -> Result<(), Error> {
+unsafe fn wait_ready_blocking() -> Result<(), Error> {
     loop {
         let sr = pac::FLASH.sr().read();
 
diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs
index 4c8172203..fd778f2b1 100644
--- a/embassy-stm32/src/flash/f3.rs
+++ b/embassy-stm32/src/flash/f3.rs
@@ -13,6 +13,10 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
     &FLASH_REGIONS
 }
 
+pub(crate) unsafe fn on_interrupt(_: *mut ()) {
+    unimplemented!();
+}
+
 pub(crate) unsafe fn lock() {
     pac::FLASH.cr().modify(|w| w.set_lock(true));
 }
@@ -22,17 +26,17 @@ pub(crate) unsafe fn unlock() {
     pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB));
 }
 
-pub(crate) unsafe fn begin_write() {
+pub(crate) unsafe fn enable_blocking_write() {
     assert_eq!(0, WRITE_SIZE % 2);
 
     pac::FLASH.cr().write(|w| w.set_pg(true));
 }
 
-pub(crate) unsafe fn end_write() {
+pub(crate) unsafe fn disable_blocking_write() {
     pac::FLASH.cr().write(|w| w.set_pg(false));
 }
 
-pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
+pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
     let mut address = start_address;
     for chunk in buf.chunks(2) {
         write_volatile(address as *mut u16, u16::from_le_bytes(chunk.try_into().unwrap()));
@@ -42,10 +46,10 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
         fence(Ordering::SeqCst);
     }
 
-    blocking_wait_ready()
+    wait_ready_blocking()
 }
 
-pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
+pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> {
     pac::FLASH.cr().modify(|w| {
         w.set_per(true);
     });
@@ -56,7 +60,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
         w.set_strt(true);
     });
 
-    let mut ret: Result<(), Error> = blocking_wait_ready();
+    let mut ret: Result<(), Error> = wait_ready_blocking();
 
     if !pac::FLASH.sr().read().eop() {
         trace!("FLASH: EOP not set");
@@ -88,7 +92,7 @@ pub(crate) unsafe fn clear_all_err() {
     });
 }
 
-unsafe fn blocking_wait_ready() -> Result<(), Error> {
+unsafe fn wait_ready_blocking() -> Result<(), Error> {
     loop {
         let sr = pac::FLASH.sr().read();
 
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 7f1c5f671..3c8f81eb0 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -2,6 +2,8 @@ use core::convert::TryInto;
 use core::ptr::write_volatile;
 use core::sync::atomic::{fence, Ordering};
 
+use embassy_sync::waitqueue::AtomicWaker;
+
 use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
 use crate::flash::Error;
 use crate::pac;
@@ -13,8 +15,8 @@ mod alt_regions {
 
     use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION};
     use crate::flash::{
-        blocking_erase_sectored, blocking_read, blocking_write_chunked, Bank1Region1, Bank1Region2, Error, Flash,
-        FlashBank, FlashRegion,
+        asynch, common, Bank1Region1, Bank1Region2, BlockingFlashRegion, Error, Flash, FlashBank, FlashRegion,
+        READ_SIZE, REGION_ACCESS,
     };
     use crate::peripherals::FLASH;
 
@@ -53,6 +55,15 @@ mod alt_regions {
     pub struct AltBank2Region2<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>);
     pub struct AltBank2Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>);
 
+    pub type BlockingAltBank1Region3<'d> =
+        BlockingFlashRegion<'d, { ALT_BANK1_REGION3.write_size }, { ALT_BANK1_REGION3.erase_size }>;
+    pub type BlockingAltBank2Region1<'d> =
+        BlockingFlashRegion<'d, { ALT_BANK2_REGION1.write_size }, { ALT_BANK2_REGION1.erase_size }>;
+    pub type BlockingAltBank2Region2<'d> =
+        BlockingFlashRegion<'d, { ALT_BANK2_REGION2.write_size }, { ALT_BANK2_REGION2.erase_size }>;
+    pub type BlockingAltBank2Region3<'d> =
+        BlockingFlashRegion<'d, { ALT_BANK2_REGION3.write_size }, { ALT_BANK2_REGION3.erase_size }>;
+
     pub struct AltFlashLayout<'d> {
         pub bank1_region1: Bank1Region1<'d>,
         pub bank1_region2: Bank1Region2<'d>,
@@ -69,7 +80,7 @@ mod alt_regions {
 
             // SAFETY: We never expose the cloned peripheral references, and their instance is not public.
             // Also, all blocking flash region operations are protected with a cs.
-            let p = self.release();
+            let p = self.inner;
             AltFlashLayout {
                 bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }),
                 bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }),
@@ -85,16 +96,30 @@ mod alt_regions {
     macro_rules! foreach_altflash_region {
         ($type_name:ident, $region:ident) => {
             impl $type_name<'_> {
-                pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
-                    blocking_read(self.0.base, self.0.size, offset, bytes)
+                pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
+                    common::read_blocking(self.0.base, self.0.size, offset, bytes)
                 }
 
-                pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
-                    unsafe { blocking_write_chunked(self.0.base, self.0.size, offset, bytes) }
+                #[cfg(all(feature = "nightly"))]
+                pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
+                    let _guard = REGION_ACCESS.lock().await;
+                    unsafe { asynch::write_chunked(self.0.base, self.0.size, offset, bytes).await }
                 }
 
-                pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
-                    unsafe { blocking_erase_sectored(self.0.base, from, to) }
+                #[cfg(all(feature = "nightly"))]
+                pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
+                    let _guard = REGION_ACCESS.lock().await;
+                    unsafe { asynch::erase_sectored(self.0.base, from, to).await }
+                }
+
+                pub fn try_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
+                    let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?;
+                    unsafe { common::write_chunked_blocking(self.0.base, self.0.size, offset, bytes) }
+                }
+
+                pub fn try_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
+                    let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?;
+                    unsafe { common::erase_sectored_blocking(self.0.base, from, to) }
                 }
             }
 
@@ -103,10 +128,10 @@ mod alt_regions {
             }
 
             impl embedded_storage::nor_flash::ReadNorFlash for $type_name<'_> {
-                const READ_SIZE: usize = 1;
+                const READ_SIZE: usize = READ_SIZE;
 
                 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
-                    self.blocking_read(offset, bytes)
+                    self.read(offset, bytes)
                 }
 
                 fn capacity(&self) -> usize {
@@ -114,16 +139,28 @@ mod alt_regions {
                 }
             }
 
-            impl embedded_storage::nor_flash::NorFlash for $type_name<'_> {
+            impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_> {
+                const READ_SIZE: usize = READ_SIZE;
+
+                async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
+                    self.read(offset, bytes)
+                }
+
+                fn capacity(&self) -> usize {
+                    self.0.size as usize
+                }
+            }
+
+            impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_> {
                 const WRITE_SIZE: usize = $region.write_size as usize;
                 const ERASE_SIZE: usize = $region.erase_size as usize;
 
-                fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
-                    self.blocking_write(offset, bytes)
+                async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
+                    self.write(offset, bytes).await
                 }
 
-                fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
-                    self.blocking_erase(from, to)
+                async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
+                    self.erase(from, to).await
                 }
             }
         };
@@ -138,6 +175,9 @@ mod alt_regions {
 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
 pub use alt_regions::*;
 
+#[cfg(feature = "nightly")]
+static WAKER: AtomicWaker = AtomicWaker::new();
+
 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
 pub fn set_default_layout() {
     unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(false)) };
@@ -160,6 +200,16 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
     &FLASH_REGIONS
 }
 
+pub(crate) unsafe fn on_interrupt(_: *mut ()) {
+    // Clear IRQ flags
+    pac::FLASH.sr().write(|w| {
+        w.set_operr(true);
+        w.set_eop(true);
+    });
+
+    WAKER.wake();
+}
+
 pub(crate) unsafe fn lock() {
     pac::FLASH.cr().modify(|w| w.set_lock(true));
 }
@@ -169,7 +219,28 @@ pub(crate) unsafe fn unlock() {
     pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB));
 }
 
-pub(crate) unsafe fn begin_write() {
+#[cfg(feature = "nightly")]
+pub(crate) unsafe fn enable_write() {
+    assert_eq!(0, WRITE_SIZE % 4);
+
+    pac::FLASH.cr().write(|w| {
+        w.set_pg(true);
+        w.set_psize(pac::flash::vals::Psize::PSIZE32);
+        w.set_eopie(true);
+        w.set_errie(true);
+    });
+}
+
+#[cfg(feature = "nightly")]
+pub(crate) unsafe fn disable_write() {
+    pac::FLASH.cr().write(|w| {
+        w.set_pg(false);
+        w.set_eopie(false);
+        w.set_errie(false);
+    });
+}
+
+pub(crate) unsafe fn enable_blocking_write() {
     assert_eq!(0, WRITE_SIZE % 4);
 
     pac::FLASH.cr().write(|w| {
@@ -178,11 +249,22 @@ pub(crate) unsafe fn begin_write() {
     });
 }
 
-pub(crate) unsafe fn end_write() {
+pub(crate) unsafe fn disable_blocking_write() {
     pac::FLASH.cr().write(|w| w.set_pg(false));
 }
 
-pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
+#[cfg(feature = "nightly")]
+pub(crate) async unsafe fn write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
+    write_start(start_address, buf);
+    wait_ready().await
+}
+
+pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
+    write_start(start_address, buf);
+    wait_ready_blocking()
+}
+
+unsafe fn write_start(start_address: u32, buf: &[u8; WRITE_SIZE]) {
     let mut address = start_address;
     for val in buf.chunks(4) {
         write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
@@ -191,11 +273,32 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
         // prevents parallelism errors
         fence(Ordering::SeqCst);
     }
-
-    blocking_wait_ready()
 }
 
-pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
+pub(crate) async unsafe fn erase_sector(sector: &FlashSector) -> Result<(), Error> {
+    let snb = ((sector.bank as u8) << 4) + sector.index_in_bank;
+
+    pac::FLASH.cr().modify(|w| {
+        w.set_ser(true);
+        w.set_snb(snb);
+        w.set_eopie(true);
+        w.set_errie(true);
+    });
+
+    pac::FLASH.cr().modify(|w| {
+        w.set_strt(true);
+    });
+
+    let ret: Result<(), Error> = wait_ready().await;
+    pac::FLASH.cr().modify(|w| {
+        w.set_eopie(false);
+        w.set_errie(false);
+    });
+    clear_all_err();
+    ret
+}
+
+pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> {
     let snb = ((sector.bank as u8) << 4) + sector.index_in_bank;
 
     pac::FLASH.cr().modify(|w| {
@@ -207,10 +310,8 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
         w.set_strt(true);
     });
 
-    let ret: Result<(), Error> = blocking_wait_ready();
-
+    let ret: Result<(), Error> = wait_ready_blocking();
     clear_all_err();
-
     ret
 }
 
@@ -220,11 +321,39 @@ pub(crate) unsafe fn clear_all_err() {
         w.set_pgperr(true);
         w.set_pgaerr(true);
         w.set_wrperr(true);
-        w.set_eop(true);
     });
 }
 
-unsafe fn blocking_wait_ready() -> Result<(), Error> {
+#[cfg(feature = "nightly")]
+pub(crate) async unsafe fn wait_ready() -> Result<(), Error> {
+    use core::task::Poll;
+
+    use futures::future::poll_fn;
+
+    poll_fn(|cx| {
+        WAKER.register(cx.waker());
+
+        let sr = pac::FLASH.sr().read();
+        if !sr.bsy() {
+            Poll::Ready(if sr.pgserr() {
+                Err(Error::Seq)
+            } else if sr.pgperr() {
+                Err(Error::Parallelism)
+            } else if sr.pgaerr() {
+                Err(Error::Unaligned)
+            } else if sr.wrperr() {
+                Err(Error::Protected)
+            } else {
+                Ok(())
+            })
+        } else {
+            return Poll::Pending;
+        }
+    })
+    .await
+}
+
+unsafe fn wait_ready_blocking() -> Result<(), Error> {
     loop {
         let sr = pac::FLASH.sr().read();
 
diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs
index ac2834a84..a0593b14b 100644
--- a/embassy-stm32/src/flash/f7.rs
+++ b/embassy-stm32/src/flash/f7.rs
@@ -12,6 +12,10 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
     &FLASH_REGIONS
 }
 
+pub(crate) unsafe fn on_interrupt(_: *mut ()) {
+    unimplemented!();
+}
+
 pub(crate) unsafe fn lock() {
     pac::FLASH.cr().modify(|w| w.set_lock(true));
 }
@@ -21,7 +25,7 @@ pub(crate) unsafe fn unlock() {
     pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB));
 }
 
-pub(crate) unsafe fn begin_write() {
+pub(crate) unsafe fn enable_blocking_write() {
     assert_eq!(0, WRITE_SIZE % 4);
 
     pac::FLASH.cr().write(|w| {
@@ -30,11 +34,11 @@ pub(crate) unsafe fn begin_write() {
     });
 }
 
-pub(crate) unsafe fn end_write() {
+pub(crate) unsafe fn disable_blocking_write() {
     pac::FLASH.cr().write(|w| w.set_pg(false));
 }
 
-pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
+pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
     let mut address = start_address;
     for val in buf.chunks(4) {
         write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
@@ -44,10 +48,10 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
         fence(Ordering::SeqCst);
     }
 
-    blocking_wait_ready()
+    wait_ready_blocking()
 }
 
-pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
+pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> {
     pac::FLASH.cr().modify(|w| {
         w.set_ser(true);
         w.set_snb(sector.index_in_bank)
@@ -57,12 +61,9 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
         w.set_strt(true);
     });
 
-    let ret: Result<(), Error> = blocking_wait_ready();
-
+    let ret: Result<(), Error> = wait_ready_blocking();
     pac::FLASH.cr().modify(|w| w.set_ser(false));
-
     clear_all_err();
-
     ret
 }
 
@@ -86,7 +87,7 @@ pub(crate) unsafe fn clear_all_err() {
     });
 }
 
-unsafe fn blocking_wait_ready() -> Result<(), Error> {
+unsafe fn wait_ready_blocking() -> Result<(), Error> {
     loop {
         let sr = pac::FLASH.sr().read();
 
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index 1b1631068..865f13283 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -17,6 +17,10 @@ pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
     &FLASH_REGIONS
 }
 
+pub(crate) unsafe fn on_interrupt(_: *mut ()) {
+    unimplemented!();
+}
+
 pub(crate) unsafe fn lock() {
     pac::FLASH.bank(0).cr().modify(|w| w.set_lock(true));
     if is_dual_bank() {
@@ -33,13 +37,13 @@ pub(crate) unsafe fn unlock() {
     }
 }
 
-pub(crate) unsafe fn begin_write() {
+pub(crate) unsafe fn enable_blocking_write() {
     assert_eq!(0, WRITE_SIZE % 4);
 }
 
-pub(crate) unsafe fn end_write() {}
+pub(crate) unsafe fn disable_blocking_write() {}
 
-pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
+pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
     // We cannot have the write setup sequence in begin_write as it depends on the address
     let bank = if start_address < BANK1_REGION.end() {
         pac::FLASH.bank(0)
@@ -60,7 +64,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
         write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
         address += val.len() as u32;
 
-        res = Some(blocking_wait_ready(bank));
+        res = Some(wait_ready_blocking(bank));
         bank.sr().modify(|w| {
             if w.eop() {
                 w.set_eop(true);
@@ -80,7 +84,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
     res.unwrap()
 }
 
-pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
+pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> {
     let bank = pac::FLASH.bank(sector.bank as usize);
     bank.cr().modify(|w| {
         w.set_ser(true);
@@ -91,12 +95,9 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
         w.set_start(true);
     });
 
-    let ret: Result<(), Error> = blocking_wait_ready(bank);
-
+    let ret: Result<(), Error> = wait_ready_blocking(bank);
     bank.cr().modify(|w| w.set_ser(false));
-
     bank_clear_all_err(bank);
-
     ret
 }
 
@@ -141,7 +142,7 @@ unsafe fn bank_clear_all_err(bank: pac::flash::Bank) {
     });
 }
 
-unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> {
+unsafe fn wait_ready_blocking(bank: pac::flash::Bank) -> Result<(), Error> {
     loop {
         let sr = bank.sr().read();
 
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index c94f61900..f8a0dac4c 100644
--- a/embassy-stm32/src/flash/l.rs
+++ b/embassy-stm32/src/flash/l.rs
@@ -12,6 +12,10 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
     &FLASH_REGIONS
 }
 
+pub(crate) unsafe fn on_interrupt(_: *mut ()) {
+    unimplemented!();
+}
+
 pub(crate) unsafe fn lock() {
     #[cfg(any(flash_wl, flash_wb, flash_l4))]
     pac::FLASH.cr().modify(|w| w.set_lock(true));
@@ -41,19 +45,19 @@ pub(crate) unsafe fn unlock() {
     }
 }
 
-pub(crate) unsafe fn begin_write() {
+pub(crate) unsafe fn enable_blocking_write() {
     assert_eq!(0, WRITE_SIZE % 4);
 
     #[cfg(any(flash_wl, flash_wb, flash_l4))]
     pac::FLASH.cr().write(|w| w.set_pg(true));
 }
 
-pub(crate) unsafe fn end_write() {
+pub(crate) unsafe fn disable_blocking_write() {
     #[cfg(any(flash_wl, flash_wb, flash_l4))]
     pac::FLASH.cr().write(|w| w.set_pg(false));
 }
 
-pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
+pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
     let mut address = start_address;
     for val in buf.chunks(4) {
         write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap()));
@@ -63,10 +67,10 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
         fence(Ordering::SeqCst);
     }
 
-    blocking_wait_ready()
+    wait_ready_blocking()
 }
 
-pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
+pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> {
     #[cfg(any(flash_l0, flash_l1))]
     {
         pac::FLASH.pecr().modify(|w| {
@@ -96,7 +100,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
         });
     }
 
-    let ret: Result<(), Error> = blocking_wait_ready();
+    let ret: Result<(), Error> = wait_ready_blocking();
 
     #[cfg(any(flash_wl, flash_wb, flash_l4))]
     pac::FLASH.cr().modify(|w| w.set_per(false));
@@ -108,7 +112,6 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
     });
 
     clear_all_err();
-
     ret
 }
 
@@ -150,7 +153,7 @@ pub(crate) unsafe fn clear_all_err() {
     });
 }
 
-unsafe fn blocking_wait_ready() -> Result<(), Error> {
+unsafe fn wait_ready_blocking() -> Result<(), Error> {
     loop {
         let sr = pac::FLASH.sr().read();
 
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index b93270ae1..e781f1b86 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -1,5 +1,7 @@
 use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind};
 
+#[cfg(all(feature = "nightly", flash_f4))]
+pub mod asynch;
 #[cfg(flash)]
 mod common;
 
@@ -10,6 +12,8 @@ pub use crate::_generated::flash_regions::*;
 pub use crate::_generated::MAX_ERASE_SIZE;
 pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE};
 
+pub const READ_SIZE: usize = 1;
+
 #[derive(Debug)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct FlashRegion {
@@ -76,6 +80,7 @@ pub enum Error {
     Protected,
     Unaligned,
     Parallelism,
+    TryLockError,
 }
 
 impl NorFlashError for Error {
@@ -87,3 +92,47 @@ impl NorFlashError for Error {
         }
     }
 }
+
+pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector {
+    let mut current_bank = FlashBank::Bank1;
+    let mut bank_offset = 0;
+    for region in regions {
+        if region.bank != current_bank {
+            current_bank = region.bank;
+            bank_offset = 0;
+        }
+
+        if address < region.end() {
+            let index_in_region = (address - region.base) / region.erase_size;
+            return FlashSector {
+                bank: region.bank,
+                index_in_bank: bank_offset + index_in_region as u8,
+                start: region.base + index_in_region * region.erase_size,
+                size: region.erase_size,
+            };
+        }
+
+        bank_offset += region.sectors();
+    }
+
+    panic!("Flash sector not found");
+}
+
+pub(crate) fn ensure_sector_aligned(
+    start_address: u32,
+    end_address: u32,
+    regions: &[&FlashRegion],
+) -> Result<(), Error> {
+    let mut address = start_address;
+    while address < end_address {
+        let sector = get_sector(address, regions);
+        if sector.start != address {
+            return Err(Error::Unaligned);
+        }
+        address += sector.size;
+    }
+    if address != end_address {
+        return Err(Error::Unaligned);
+    }
+    Ok(())
+}
diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs
index 556034654..e21b0b241 100644
--- a/embassy-stm32/src/flash/other.rs
+++ b/embassy-stm32/src/flash/other.rs
@@ -8,22 +8,26 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
     &FLASH_REGIONS
 }
 
+pub(crate) unsafe fn on_interrupt(_: *mut ()) {
+    unimplemented!();
+}
+
 pub(crate) unsafe fn lock() {
     unimplemented!();
 }
 pub(crate) unsafe fn unlock() {
     unimplemented!();
 }
-pub(crate) unsafe fn begin_write() {
+pub(crate) unsafe fn enable_blocking_write() {
     unimplemented!();
 }
-pub(crate) unsafe fn end_write() {
+pub(crate) unsafe fn disable_blocking_write() {
     unimplemented!();
 }
-pub(crate) unsafe fn blocking_write(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
+pub(crate) unsafe fn write_blocking(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
     unimplemented!();
 }
-pub(crate) unsafe fn blocking_erase_sector(_sector: &FlashSector) -> Result<(), Error> {
+pub(crate) unsafe fn erase_sector_blocking(_sector: &FlashSector) -> Result<(), Error> {
     unimplemented!();
 }
 pub(crate) unsafe fn clear_all_err() {

From 0a26870d363022a7d09500b6ecb28c0b455e81e7 Mon Sep 17 00:00:00 2001
From: Rasmus Melchior Jacobsen <rmja@laesoe.org>
Date: Wed, 24 May 2023 12:41:52 +0200
Subject: [PATCH 02/14] Align examples

---
 examples/stm32f3/src/bin/flash.rs       |  5 +-
 examples/stm32f4/src/bin/flash.rs       | 14 ++---
 examples/stm32f4/src/bin/flash_async.rs | 81 +++++++++++++++++++++++++
 examples/stm32f7/src/bin/flash.rs       |  5 +-
 examples/stm32h7/src/bin/flash.rs       |  5 +-
 examples/stm32l0/src/bin/flash.rs       |  5 +-
 examples/stm32l1/src/bin/flash.rs       |  5 +-
 examples/stm32wl/src/bin/flash.rs       |  5 +-
 8 files changed, 100 insertions(+), 25 deletions(-)
 create mode 100644 examples/stm32f4/src/bin/flash_async.rs

diff --git a/examples/stm32f3/src/bin/flash.rs b/examples/stm32f3/src/bin/flash.rs
index e40ad4fc0..0e5fb0658 100644
--- a/examples/stm32f3/src/bin/flash.rs
+++ b/examples/stm32f3/src/bin/flash.rs
@@ -4,8 +4,7 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
-use embassy_stm32::flash::Flash;
-use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
+use embassy_stm32::{flash::Flash, interrupt};
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
@@ -15,7 +14,7 @@ async fn main(_spawner: Spawner) {
 
     const ADDR: u32 = 0x26000;
 
-    let mut f = Flash::new(p.FLASH).into_regions().bank1_region;
+    let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() };
 
     info!("Reading...");
     let mut buf = [0u8; 8];
diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs
index bd3a7c95e..de4ecdb8f 100644
--- a/examples/stm32f4/src/bin/flash.rs
+++ b/examples/stm32f4/src/bin/flash.rs
@@ -4,7 +4,7 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
-use embassy_stm32::flash::Flash;
+use embassy_stm32::{flash::Flash, interrupt};
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
 
     // Once can also call `into_regions()` to get access to NorFlash implementations
     // for each of the unique characteristics.
-    let mut f = Flash::new(p.FLASH);
+    let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH));
 
     // Sector 5
     test_flash(&mut f, 128 * 1024, 128 * 1024);
@@ -31,19 +31,19 @@ fn test_flash(f: &mut Flash, offset: u32, size: u32) {
 
     info!("Reading...");
     let mut buf = [0u8; 32];
-    unwrap!(f.blocking_read(offset, &mut buf));
+    unwrap!(f.read(offset, &mut buf));
     info!("Read: {=[u8]:x}", buf);
 
     info!("Erasing...");
-    unwrap!(f.blocking_erase(offset, offset + size));
+    unwrap!(f.erase_blocking(offset, offset + size));
 
     info!("Reading...");
     let mut buf = [0u8; 32];
-    unwrap!(f.blocking_read(offset, &mut buf));
+    unwrap!(f.read(offset, &mut buf));
     info!("Read after erase: {=[u8]:x}", buf);
 
     info!("Writing...");
-    unwrap!(f.blocking_write(
+    unwrap!(f.write_blocking(
         offset,
         &[
             1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
@@ -53,7 +53,7 @@ fn test_flash(f: &mut Flash, offset: u32, size: u32) {
 
     info!("Reading...");
     let mut buf = [0u8; 32];
-    unwrap!(f.blocking_read(offset, &mut buf));
+    unwrap!(f.read(offset, &mut buf));
     info!("Read: {=[u8]:x}", buf);
     assert_eq!(
         &buf[..],
diff --git a/examples/stm32f4/src/bin/flash_async.rs b/examples/stm32f4/src/bin/flash_async.rs
new file mode 100644
index 000000000..c9d9df34b
--- /dev/null
+++ b/examples/stm32f4/src/bin/flash_async.rs
@@ -0,0 +1,81 @@
+#![no_std]
+#![no_main]
+#![feature(type_alias_impl_trait)]
+
+use defmt::{info, unwrap};
+use embassy_executor::Spawner;
+use embassy_time::{Timer, Duration};
+use embassy_stm32::flash::Flash;
+use embassy_stm32::gpio::{AnyPin, Level, Output, Pin, Speed};
+use embassy_stm32::{interrupt};
+use {defmt_rtt as _, panic_probe as _};
+
+#[embassy_executor::main]
+async fn main(spawner: Spawner) {
+    let p = embassy_stm32::init(Default::default());
+    info!("Hello Flash!");
+
+    let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH));
+
+    // Led should blink uninterrupted during ~2sec erase operation
+    spawner.spawn(blinky(p.PB7.degrade())).unwrap();
+
+    // Test on bank 2 in order not to stall CPU.
+    test_flash(&mut f, 1024 * 1024, 128 * 1024).await;
+}
+
+#[embassy_executor::task]
+async fn blinky(p: AnyPin) {
+    let mut led = Output::new(p, Level::High, Speed::Low);
+
+    loop {
+        info!("high");
+        led.set_high();
+        Timer::after(Duration::from_millis(300)).await;
+
+        info!("low");
+        led.set_low();
+        Timer::after(Duration::from_millis(300)).await;
+    }
+}
+
+async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) {
+    info!("Testing offset: {=u32:#X}, size: {=u32:#X}", offset, size);
+
+    info!("Reading...");
+    let mut buf = [0u8; 32];
+    unwrap!(f.read(offset, &mut buf));
+    info!("Read: {=[u8]:x}", buf);
+
+    info!("Erasing...");
+    unwrap!(f.erase(offset, offset + size).await);
+
+    info!("Reading...");
+    let mut buf = [0u8; 32];
+    unwrap!(f.read(offset, &mut buf));
+    info!("Read after erase: {=[u8]:x}", buf);
+
+    info!("Writing...");
+    unwrap!(
+        f.write(
+            offset,
+            &[
+                1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+                29, 30, 31, 32
+            ]
+        )
+        .await
+    );
+
+    info!("Reading...");
+    let mut buf = [0u8; 32];
+    unwrap!(f.read(offset, &mut buf));
+    info!("Read: {=[u8]:x}", buf);
+    assert_eq!(
+        &buf[..],
+        &[
+            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+            30, 31, 32
+        ]
+    );
+}
\ No newline at end of file
diff --git a/examples/stm32f7/src/bin/flash.rs b/examples/stm32f7/src/bin/flash.rs
index aabfe8557..717c82e86 100644
--- a/examples/stm32f7/src/bin/flash.rs
+++ b/examples/stm32f7/src/bin/flash.rs
@@ -4,9 +4,8 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
-use embassy_stm32::flash::Flash;
+use embassy_stm32::{flash::Flash, interrupt};
 use embassy_time::{Duration, Timer};
-use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
@@ -19,7 +18,7 @@ async fn main(_spawner: Spawner) {
     // wait a bit before accessing the flash
     Timer::after(Duration::from_millis(300)).await;
 
-    let mut f = Flash::new(p.FLASH).into_regions().bank1_region3;
+    let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region3.into_blocking() };
 
     info!("Reading...");
     let mut buf = [0u8; 32];
diff --git a/examples/stm32h7/src/bin/flash.rs b/examples/stm32h7/src/bin/flash.rs
index 7ee9838c9..aab72cae8 100644
--- a/examples/stm32h7/src/bin/flash.rs
+++ b/examples/stm32h7/src/bin/flash.rs
@@ -4,9 +4,8 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
-use embassy_stm32::flash::Flash;
+use embassy_stm32::{flash::Flash, interrupt};
 use embassy_time::{Duration, Timer};
-use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
@@ -19,7 +18,7 @@ async fn main(_spawner: Spawner) {
     // wait a bit before accessing the flash
     Timer::after(Duration::from_millis(300)).await;
 
-    let mut f = Flash::new(p.FLASH).into_regions().bank2_region;
+    let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank2_region.into_blocking() };
 
     info!("Reading...");
     let mut buf = [0u8; 32];
diff --git a/examples/stm32l0/src/bin/flash.rs b/examples/stm32l0/src/bin/flash.rs
index 337425028..0ed0d05fc 100644
--- a/examples/stm32l0/src/bin/flash.rs
+++ b/examples/stm32l0/src/bin/flash.rs
@@ -4,8 +4,7 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
-use embassy_stm32::flash::Flash;
-use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
+use embassy_stm32::{flash::Flash, interrupt};
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
@@ -15,7 +14,7 @@ async fn main(_spawner: Spawner) {
 
     const ADDR: u32 = 0x26000;
 
-    let mut f = Flash::new(p.FLASH).into_regions().bank1_region;
+    let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() };
 
     info!("Reading...");
     let mut buf = [0u8; 8];
diff --git a/examples/stm32l1/src/bin/flash.rs b/examples/stm32l1/src/bin/flash.rs
index 38feb0d76..c4d7d029c 100644
--- a/examples/stm32l1/src/bin/flash.rs
+++ b/examples/stm32l1/src/bin/flash.rs
@@ -4,8 +4,7 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
-use embassy_stm32::flash::Flash;
-use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
+use embassy_stm32::{flash::Flash, interrupt};
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
@@ -15,7 +14,7 @@ async fn main(_spawner: Spawner) {
 
     const ADDR: u32 = 0x26000;
 
-    let mut f = Flash::new(p.FLASH).into_regions().bank1_region;
+    let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() };
 
     info!("Reading...");
     let mut buf = [0u8; 8];
diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs
index e6bc2865c..df51ceb68 100644
--- a/examples/stm32wl/src/bin/flash.rs
+++ b/examples/stm32wl/src/bin/flash.rs
@@ -4,8 +4,7 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
-use embassy_stm32::flash::Flash;
-use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
+use embassy_stm32::{flash::Flash, interrupt};
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
@@ -15,7 +14,7 @@ async fn main(_spawner: Spawner) {
 
     const ADDR: u32 = 0x36000;
 
-    let mut f = Flash::new(p.FLASH).into_regions().bank1_region;
+    let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() };
 
     info!("Reading...");
     let mut buf = [0u8; 8];

From ff3a70ed9debd1ce4075c0a28c90bb0c6e693bce Mon Sep 17 00:00:00 2001
From: Rasmus Melchior Jacobsen <rmja@laesoe.org>
Date: Wed, 24 May 2023 12:42:35 +0200
Subject: [PATCH 03/14] Add missing nightly guards

---
 embassy-stm32/src/flash/f4.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 3c8f81eb0..9698bcd58 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -139,6 +139,7 @@ mod alt_regions {
                 }
             }
 
+            #[cfg(all(feature = "nightly"))]
             impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_> {
                 const READ_SIZE: usize = READ_SIZE;
 
@@ -151,6 +152,7 @@ mod alt_regions {
                 }
             }
 
+            #[cfg(all(feature = "nightly"))]
             impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_> {
                 const WRITE_SIZE: usize = $region.write_size as usize;
                 const ERASE_SIZE: usize = $region.erase_size as usize;

From 6804b6c0b49777489b132639290b5e977ec8ffd9 Mon Sep 17 00:00:00 2001
From: Rasmus Melchior Jacobsen <rmja@laesoe.org>
Date: Wed, 24 May 2023 12:45:59 +0200
Subject: [PATCH 04/14] Fix unused get_sector and ensure_sector_aligned

---
 embassy-stm32/src/flash/common.rs | 49 +++++++++++++++++++++++++++++--
 embassy-stm32/src/flash/mod.rs    | 44 ---------------------------
 2 files changed, 47 insertions(+), 46 deletions(-)

diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
index 990104a38..7cec5a3c9 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -8,8 +8,8 @@ use embassy_sync::mutex::Mutex;
 use stm32_metapac::FLASH_BASE;
 
 use super::{
-    ensure_sector_aligned, family, get_sector, Error, FlashLayout, FlashRegion, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE,
-    WRITE_SIZE,
+    family, Error, FlashLayout, FlashRegion, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE,
+    WRITE_SIZE, FlashSector, FlashBank,
 };
 use crate::peripherals::FLASH;
 use crate::Peripheral;
@@ -118,6 +118,51 @@ pub(super) unsafe fn erase_sectored_blocking(base: u32, from: u32, to: u32) -> R
     Ok(())
 }
 
+pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector {
+    let mut current_bank = FlashBank::Bank1;
+    let mut bank_offset = 0;
+    for region in regions {
+        if region.bank != current_bank {
+            current_bank = region.bank;
+            bank_offset = 0;
+        }
+
+        if address < region.end() {
+            let index_in_region = (address - region.base) / region.erase_size;
+            return FlashSector {
+                bank: region.bank,
+                index_in_bank: bank_offset + index_in_region as u8,
+                start: region.base + index_in_region * region.erase_size,
+                size: region.erase_size,
+            };
+        }
+
+        bank_offset += region.sectors();
+    }
+
+    panic!("Flash sector not found");
+}
+
+pub(crate) fn ensure_sector_aligned(
+    start_address: u32,
+    end_address: u32,
+    regions: &[&FlashRegion],
+) -> Result<(), Error> {
+    let mut address = start_address;
+    while address < end_address {
+        let sector = get_sector(address, regions);
+        if sector.start != address {
+            return Err(Error::Unaligned);
+        }
+        address += sector.size;
+    }
+    if address != end_address {
+        return Err(Error::Unaligned);
+    }
+    Ok(())
+}
+
+
 impl embedded_storage::nor_flash::ErrorType for Flash<'_> {
     type Error = Error;
 }
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index e781f1b86..1ef04e56f 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -92,47 +92,3 @@ impl NorFlashError for Error {
         }
     }
 }
-
-pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector {
-    let mut current_bank = FlashBank::Bank1;
-    let mut bank_offset = 0;
-    for region in regions {
-        if region.bank != current_bank {
-            current_bank = region.bank;
-            bank_offset = 0;
-        }
-
-        if address < region.end() {
-            let index_in_region = (address - region.base) / region.erase_size;
-            return FlashSector {
-                bank: region.bank,
-                index_in_bank: bank_offset + index_in_region as u8,
-                start: region.base + index_in_region * region.erase_size,
-                size: region.erase_size,
-            };
-        }
-
-        bank_offset += region.sectors();
-    }
-
-    panic!("Flash sector not found");
-}
-
-pub(crate) fn ensure_sector_aligned(
-    start_address: u32,
-    end_address: u32,
-    regions: &[&FlashRegion],
-) -> Result<(), Error> {
-    let mut address = start_address;
-    while address < end_address {
-        let sector = get_sector(address, regions);
-        if sector.start != address {
-            return Err(Error::Unaligned);
-        }
-        address += sector.size;
-    }
-    if address != end_address {
-        return Err(Error::Unaligned);
-    }
-    Ok(())
-}

From 1329a387e060d60ee2833d2eed6393f5dfc84d1a Mon Sep 17 00:00:00 2001
From: Rasmus Melchior Jacobsen <rmja@laesoe.org>
Date: Wed, 24 May 2023 12:55:17 +0200
Subject: [PATCH 05/14] Add more missing nightly guards

---
 embassy-stm32/src/flash/f4.rs | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 9698bcd58..0c008fd0d 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -2,12 +2,13 @@ use core::convert::TryInto;
 use core::ptr::write_volatile;
 use core::sync::atomic::{fence, Ordering};
 
-use embassy_sync::waitqueue::AtomicWaker;
-
 use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
 use crate::flash::Error;
 use crate::pac;
 
+#[cfg(feature = "nightly")]
+use embassy_sync::waitqueue::AtomicWaker;
+
 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
 mod alt_regions {
     use embassy_hal_common::PeripheralRef;
@@ -15,10 +16,12 @@ mod alt_regions {
 
     use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION};
     use crate::flash::{
-        asynch, common, Bank1Region1, Bank1Region2, BlockingFlashRegion, Error, Flash, FlashBank, FlashRegion,
+        common, Bank1Region1, Bank1Region2, BlockingFlashRegion, Error, Flash, FlashBank, FlashRegion,
         READ_SIZE, REGION_ACCESS,
     };
     use crate::peripherals::FLASH;
+    #[cfg(feature = "nightly")]
+    use crate::flash::asynch;
 
     pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion {
         size: 3 * BANK1_REGION3.erase_size,
@@ -100,13 +103,13 @@ mod alt_regions {
                     common::read_blocking(self.0.base, self.0.size, offset, bytes)
                 }
 
-                #[cfg(all(feature = "nightly"))]
+                #[cfg(feature = "nightly")]
                 pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
                     let _guard = REGION_ACCESS.lock().await;
                     unsafe { asynch::write_chunked(self.0.base, self.0.size, offset, bytes).await }
                 }
 
-                #[cfg(all(feature = "nightly"))]
+                #[cfg(feature = "nightly")]
                 pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
                     let _guard = REGION_ACCESS.lock().await;
                     unsafe { asynch::erase_sectored(self.0.base, from, to).await }
@@ -139,7 +142,7 @@ mod alt_regions {
                 }
             }
 
-            #[cfg(all(feature = "nightly"))]
+            #[cfg(feature = "nightly")]
             impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_> {
                 const READ_SIZE: usize = READ_SIZE;
 
@@ -152,7 +155,7 @@ mod alt_regions {
                 }
             }
 
-            #[cfg(all(feature = "nightly"))]
+            #[cfg(feature = "nightly")]
             impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_> {
                 const WRITE_SIZE: usize = $region.write_size as usize;
                 const ERASE_SIZE: usize = $region.erase_size as usize;
@@ -209,6 +212,7 @@ pub(crate) unsafe fn on_interrupt(_: *mut ()) {
         w.set_eop(true);
     });
 
+    #[cfg(feature = "nightly")]
     WAKER.wake();
 }
 
@@ -277,6 +281,7 @@ unsafe fn write_start(start_address: u32, buf: &[u8; WRITE_SIZE]) {
     }
 }
 
+#[cfg(feature = "nightly")]
 pub(crate) async unsafe fn erase_sector(sector: &FlashSector) -> Result<(), Error> {
     let snb = ((sector.bank as u8) << 4) + sector.index_in_bank;
 

From 966f0abf48cc143fc33e17a5fc9e138cf82ab05f Mon Sep 17 00:00:00 2001
From: Rasmus Melchior Jacobsen <rmja@laesoe.org>
Date: Wed, 24 May 2023 13:11:03 +0200
Subject: [PATCH 06/14] Run format with nightly

---
 embassy-stm32/src/flash/common.rs |  4 +---
 embassy-stm32/src/flash/f4.rs     | 16 ++++++++--------
 2 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
index 7cec5a3c9..e1fe7e9da 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -8,8 +8,7 @@ use embassy_sync::mutex::Mutex;
 use stm32_metapac::FLASH_BASE;
 
 use super::{
-    family, Error, FlashLayout, FlashRegion, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE,
-    WRITE_SIZE, FlashSector, FlashBank,
+    family, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE,
 };
 use crate::peripherals::FLASH;
 use crate::Peripheral;
@@ -162,7 +161,6 @@ pub(crate) fn ensure_sector_aligned(
     Ok(())
 }
 
-
 impl embedded_storage::nor_flash::ErrorType for Flash<'_> {
     type Error = Error;
 }
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 0c008fd0d..084bbdc6e 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -2,26 +2,26 @@ use core::convert::TryInto;
 use core::ptr::write_volatile;
 use core::sync::atomic::{fence, Ordering};
 
+#[cfg(feature = "nightly")]
+use embassy_sync::waitqueue::AtomicWaker;
+
 use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
 use crate::flash::Error;
 use crate::pac;
 
-#[cfg(feature = "nightly")]
-use embassy_sync::waitqueue::AtomicWaker;
-
 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
 mod alt_regions {
     use embassy_hal_common::PeripheralRef;
     use stm32_metapac::FLASH_SIZE;
 
     use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION};
-    use crate::flash::{
-        common, Bank1Region1, Bank1Region2, BlockingFlashRegion, Error, Flash, FlashBank, FlashRegion,
-        READ_SIZE, REGION_ACCESS,
-    };
-    use crate::peripherals::FLASH;
     #[cfg(feature = "nightly")]
     use crate::flash::asynch;
+    use crate::flash::{
+        common, Bank1Region1, Bank1Region2, BlockingFlashRegion, Error, Flash, FlashBank, FlashRegion, READ_SIZE,
+        REGION_ACCESS,
+    };
+    use crate::peripherals::FLASH;
 
     pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion {
         size: 3 * BANK1_REGION3.erase_size,

From dfd56031713aa04af682aa1b2b113a72831728f1 Mon Sep 17 00:00:00 2001
From: Rasmus Melchior Jacobsen <rmja@laesoe.org>
Date: Wed, 24 May 2023 17:24:28 +0200
Subject: [PATCH 07/14] Let FlashLayout and FlashRegion depends on a
 Blocking/Async mode generic

---
 embassy-stm32/Cargo.toml          |   1 -
 embassy-stm32/build.rs            |  16 ++-
 embassy-stm32/src/flash/asynch.rs |  35 ++++-
 embassy-stm32/src/flash/common.rs | 218 ++++++++++++------------------
 embassy-stm32/src/flash/f4.rs     | 112 +++++++--------
 embassy-stm32/src/flash/mod.rs    |   3 +
 6 files changed, 179 insertions(+), 206 deletions(-)

diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 440de85e8..2572eafce 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -69,7 +69,6 @@ cfg-if = "1.0.0"
 embedded-io = { version = "0.4.0", features = ["async"], optional = true }
 chrono = { version = "^0.4", default-features = false, optional = true}
 bit_field = "0.10.2"
-paste = "1.0.12"
 
 [dev-dependencies]
 critical-section = { version = "1.1", features = ["std"] }
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 540981727..29af3c80d 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -213,7 +213,7 @@ fn main() {
         let region_type = format_ident!("{}", get_flash_region_type_name(region.name));
         flash_regions.extend(quote! {
             #[cfg(flash)]
-            pub struct #region_type<'d>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>,);
+            pub struct #region_type<'d, MODE>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>, pub(crate) core::marker::PhantomData<MODE>);
         });
     }
 
@@ -224,11 +224,11 @@ fn main() {
             let field_name = format_ident!("{}", region_name.to_lowercase());
             let field_type = format_ident!("{}", get_flash_region_type_name(f.name));
             let field = quote! {
-                pub #field_name: #field_type<'d>
+                pub #field_name: #field_type<'d, MODE>
             };
             let region_name = format_ident!("{}", region_name);
             let init = quote! {
-                #field_name: #field_type(&#region_name, unsafe { p.clone_unchecked()})
+                #field_name: #field_type(&#region_name, unsafe { p.clone_unchecked()}, core::marker::PhantomData)
             };
 
             (field, (init, region_name))
@@ -238,15 +238,17 @@ fn main() {
     let regions_len = flash_memory_regions.len();
     flash_regions.extend(quote! {
         #[cfg(flash)]
-        pub struct FlashLayout<'d> {
-            #(#fields),*
+        pub struct FlashLayout<'d, MODE> {
+            #(#fields),*,
+            _mode: core::marker::PhantomData<MODE>,
         }
 
         #[cfg(flash)]
-        impl<'d> FlashLayout<'d> {
+        impl<'d, MODE> FlashLayout<'d, MODE> {
             pub(crate) fn new(p: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>) -> Self {
                 Self {
-                    #(#inits),*
+                    #(#inits),*,
+                    _mode: core::marker::PhantomData,
                 }
             }
         }
diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs
index 44e23d9c4..3564bbff5 100644
--- a/embassy-stm32/src/flash/asynch.rs
+++ b/embassy-stm32/src/flash/asynch.rs
@@ -1,12 +1,21 @@
 use atomic_polyfill::{fence, Ordering};
 use embassy_hal_common::drop::OnDrop;
+use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
+use embassy_sync::mutex::Mutex;
 
 use super::{
-    ensure_sector_aligned, family, get_sector, Error, Flash, FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE,
-    REGION_ACCESS, WRITE_SIZE,
+    ensure_sector_aligned, family, get_sector, read_blocking, Async, Error, Flash, FlashLayout, FLASH_BASE, FLASH_SIZE,
+    MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE,
 };
 
+pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(());
+
 impl<'d> Flash<'d> {
+    pub fn into_regions(self) -> FlashLayout<'d, Async> {
+        family::set_default_layout();
+        FlashLayout::new(self.inner)
+    }
+
     pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
         unsafe { write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes).await }
     }
@@ -16,6 +25,18 @@ impl<'d> Flash<'d> {
     }
 }
 
+impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_> {
+    const READ_SIZE: usize = READ_SIZE;
+
+    async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
+        self.read(offset, bytes)
+    }
+
+    fn capacity(&self) -> usize {
+        FLASH_SIZE
+    }
+}
+
 impl embedded_storage_async::nor_flash::NorFlash for Flash<'_> {
     const WRITE_SIZE: usize = WRITE_SIZE;
     const ERASE_SIZE: usize = MAX_ERASE_SIZE;
@@ -89,7 +110,11 @@ pub(super) async unsafe fn erase_sectored(base: u32, from: u32, to: u32) -> Resu
 
 foreach_flash_region! {
     ($type_name:ident, $write_size:literal, $erase_size:literal) => {
-        impl crate::_generated::flash_regions::$type_name<'_> {
+        impl crate::_generated::flash_regions::$type_name<'_, Async> {
+            pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
+                read_blocking(self.0.base, self.0.size, offset, bytes)
+            }
+
             pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
                 let _guard = REGION_ACCESS.lock().await;
                 unsafe { write_chunked(self.0.base, self.0.size, offset, bytes).await }
@@ -101,7 +126,7 @@ foreach_flash_region! {
             }
         }
 
-        impl embedded_storage_async::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> {
+        impl embedded_storage_async::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_, Async> {
             const READ_SIZE: usize = READ_SIZE;
 
             async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
@@ -113,7 +138,7 @@ foreach_flash_region! {
             }
         }
 
-        impl embedded_storage_async::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_> {
+        impl embedded_storage_async::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_, Async> {
             const WRITE_SIZE: usize = $write_size;
             const ERASE_SIZE: usize = $erase_size;
 
diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
index e1fe7e9da..8b38745cf 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -1,14 +1,12 @@
 use atomic_polyfill::{fence, Ordering};
 use embassy_cortex_m::interrupt::InterruptExt;
-use embassy_futures::block_on;
 use embassy_hal_common::drop::OnDrop;
 use embassy_hal_common::{into_ref, PeripheralRef};
-use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
-use embassy_sync::mutex::Mutex;
 use stm32_metapac::FLASH_BASE;
 
 use super::{
-    family, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE,
+    family, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE,
+    WRITE_SIZE,
 };
 use crate::peripherals::FLASH;
 use crate::Peripheral;
@@ -17,8 +15,6 @@ pub struct Flash<'d> {
     pub(crate) inner: PeripheralRef<'d, FLASH>,
 }
 
-pub(crate) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(());
-
 impl<'d> Flash<'d> {
     pub fn new(p: impl Peripheral<P = FLASH> + 'd, irq: impl Peripheral<P = crate::interrupt::FLASH> + 'd) -> Self {
         into_ref!(p, irq);
@@ -30,7 +26,7 @@ impl<'d> Flash<'d> {
         Self { inner: p }
     }
 
-    pub fn into_regions(self) -> FlashLayout<'d> {
+    pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> {
         family::set_default_layout();
         FlashLayout::new(self.inner)
     }
@@ -40,11 +36,19 @@ impl<'d> Flash<'d> {
     }
 
     pub fn write_blocking(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
-        unsafe { write_chunked_blocking(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) }
+        unsafe {
+            write_blocking(
+                FLASH_BASE as u32,
+                FLASH_SIZE as u32,
+                offset,
+                bytes,
+                write_chunk_unlocked,
+            )
+        }
     }
 
     pub fn erase_blocking(&mut self, from: u32, to: u32) -> Result<(), Error> {
-        unsafe { erase_sectored_blocking(FLASH_BASE as u32, from, to) }
+        unsafe { erase_blocking(FLASH_BASE as u32, from, to, erase_sector_unlocked) }
     }
 }
 
@@ -59,7 +63,13 @@ pub(super) fn read_blocking(base: u32, size: u32, offset: u32, bytes: &mut [u8])
     Ok(())
 }
 
-pub(super) unsafe fn write_chunked_blocking(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> {
+pub(super) unsafe fn write_blocking(
+    base: u32,
+    size: u32,
+    offset: u32,
+    bytes: &[u8],
+    write_chunk: unsafe fn(u32, &[u8]) -> Result<(), Error>,
+) -> Result<(), Error> {
     if offset + bytes.len() as u32 > size {
         return Err(Error::Size);
     }
@@ -71,26 +81,39 @@ pub(super) unsafe fn write_chunked_blocking(base: u32, size: u32, offset: u32, b
     trace!("Writing {} bytes at 0x{:x}", bytes.len(), address);
 
     for chunk in bytes.chunks(WRITE_SIZE) {
-        family::clear_all_err();
-        fence(Ordering::SeqCst);
-        family::unlock();
-        fence(Ordering::SeqCst);
-        family::enable_blocking_write();
-        fence(Ordering::SeqCst);
-
-        let _on_drop = OnDrop::new(|| {
-            family::disable_blocking_write();
-            fence(Ordering::SeqCst);
-            family::lock();
-        });
-
-        family::write_blocking(address, chunk.try_into().unwrap())?;
+        write_chunk(address, chunk)?;
         address += WRITE_SIZE as u32;
     }
     Ok(())
 }
 
-pub(super) unsafe fn erase_sectored_blocking(base: u32, from: u32, to: u32) -> Result<(), Error> {
+pub(super) unsafe fn write_chunk_unlocked(address: u32, chunk: &[u8]) -> Result<(), Error> {
+    family::clear_all_err();
+    fence(Ordering::SeqCst);
+    family::unlock();
+    fence(Ordering::SeqCst);
+    family::enable_blocking_write();
+    fence(Ordering::SeqCst);
+
+    let _on_drop = OnDrop::new(|| {
+        family::disable_blocking_write();
+        fence(Ordering::SeqCst);
+        family::lock();
+    });
+
+    family::write_blocking(address, chunk.try_into().unwrap())
+}
+
+pub(super) unsafe fn write_chunk_with_critical_section(address: u32, chunk: &[u8]) -> Result<(), Error> {
+    critical_section::with(|_| write_chunk_unlocked(address, chunk))
+}
+
+pub(super) unsafe fn erase_blocking(
+    base: u32,
+    from: u32,
+    to: u32,
+    erase_sector: unsafe fn(&FlashSector) -> Result<(), Error>,
+) -> Result<(), Error> {
     let start_address = base + from;
     let end_address = base + to;
     let regions = family::get_flash_regions();
@@ -103,21 +126,28 @@ pub(super) unsafe fn erase_sectored_blocking(base: u32, from: u32, to: u32) -> R
     while address < end_address {
         let sector = get_sector(address, regions);
         trace!("Erasing sector: {:?}", sector);
-
-        family::clear_all_err();
-        fence(Ordering::SeqCst);
-        family::unlock();
-        fence(Ordering::SeqCst);
-
-        let _on_drop = OnDrop::new(|| family::lock());
-
-        family::erase_sector_blocking(&sector)?;
+        erase_sector(&sector)?;
         address += sector.size;
     }
     Ok(())
 }
 
-pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector {
+pub(super) unsafe fn erase_sector_unlocked(sector: &FlashSector) -> Result<(), Error> {
+    family::clear_all_err();
+    fence(Ordering::SeqCst);
+    family::unlock();
+    fence(Ordering::SeqCst);
+
+    let _on_drop = OnDrop::new(|| family::lock());
+
+    family::erase_sector_blocking(&sector)
+}
+
+pub(super) unsafe fn erase_sector_with_critical_section(sector: &FlashSector) -> Result<(), Error> {
+    critical_section::with(|_| erase_sector_unlocked(sector))
+}
+
+pub(super) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector {
     let mut current_bank = FlashBank::Bank1;
     let mut bank_offset = 0;
     for region in regions {
@@ -142,7 +172,7 @@ pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector
     panic!("Flash sector not found");
 }
 
-pub(crate) fn ensure_sector_aligned(
+pub(super) fn ensure_sector_aligned(
     start_address: u32,
     end_address: u32,
     regions: &[&FlashRegion],
@@ -190,121 +220,49 @@ impl embedded_storage::nor_flash::NorFlash for Flash<'_> {
     }
 }
 
-#[cfg(feature = "nightly")]
-impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_> {
-    const READ_SIZE: usize = READ_SIZE;
-
-    async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
-        self.read(offset, bytes)
-    }
-
-    fn capacity(&self) -> usize {
-        FLASH_SIZE
-    }
-}
-
-pub struct BlockingFlashRegion<'d, const WRITE_SIZE: u32, const ERASE_SIZE: u32>(
-    &'static FlashRegion,
-    PeripheralRef<'d, FLASH>,
-);
-
-impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> {
-    pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
-        read_blocking(self.0.base, self.0.size, offset, bytes)
-    }
-
-    pub fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
-        let _guard = block_on(REGION_ACCESS.lock());
-        unsafe { write_chunked_blocking(self.0.base, self.0.size, offset, bytes) }
-    }
-
-    pub fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
-        let _guard = block_on(REGION_ACCESS.lock());
-        unsafe { erase_sectored_blocking(self.0.base, from, to) }
-    }
-}
-
-impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> embedded_storage::nor_flash::ErrorType
-    for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE>
-{
-    type Error = Error;
-}
-
-impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> embedded_storage::nor_flash::ReadNorFlash
-    for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE>
-{
-    const READ_SIZE: usize = READ_SIZE;
-
-    fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
-        self.read(offset, bytes)
-    }
-
-    fn capacity(&self) -> usize {
-        self.0.size as usize
-    }
-}
-
-impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> embedded_storage::nor_flash::NorFlash
-    for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE>
-{
-    const WRITE_SIZE: usize = WRITE_SIZE as usize;
-    const ERASE_SIZE: usize = ERASE_SIZE as usize;
-
-    fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
-        self.write(offset, bytes)
-    }
-
-    fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
-        self.erase(from, to)
-    }
-}
-
 foreach_flash_region! {
     ($type_name:ident, $write_size:literal, $erase_size:literal) => {
-        paste::paste! {
-            pub type [<Blocking $type_name>]<'d> = BlockingFlashRegion<'d, $write_size, $erase_size>;
-        }
-
-        impl<'d> crate::_generated::flash_regions::$type_name<'d> {
-            /// Make this flash region work in a blocking context.
-            ///
-            /// SAFETY
-            ///
-            /// This function is unsafe as incorect usage of parallel blocking operations
-            /// on multiple regions may cause a deadlock because each region requires mutual access to the flash.
-            pub unsafe fn into_blocking(self) -> BlockingFlashRegion<'d, $write_size, $erase_size> {
-                BlockingFlashRegion(self.0, self.1)
-            }
-
-            pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
+        impl<'d> crate::_generated::flash_regions::$type_name<'d, Blocking> {
+            pub fn read_blocking(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
                 read_blocking(self.0.base, self.0.size, offset, bytes)
             }
 
-            pub fn try_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
-                let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?;
-                unsafe { write_chunked_blocking(self.0.base, self.0.size, offset, bytes) }
+            pub fn write_blocking(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
+                unsafe { write_blocking(self.0.base, self.0.size, offset, bytes, write_chunk_with_critical_section) }
             }
 
-            pub fn try_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
-                let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?;
-                unsafe { erase_sectored_blocking(self.0.base, from, to) }
+            pub fn erase_blocking(&mut self, from: u32, to: u32) -> Result<(), Error> {
+                unsafe { erase_blocking(self.0.base, from, to, erase_sector_with_critical_section) }
             }
         }
 
-        impl embedded_storage::nor_flash::ErrorType for crate::_generated::flash_regions::$type_name<'_> {
+        impl<MODE> embedded_storage::nor_flash::ErrorType for crate::_generated::flash_regions::$type_name<'_, MODE> {
             type Error = Error;
         }
 
-        impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> {
+        impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_, Blocking> {
             const READ_SIZE: usize = READ_SIZE;
 
             fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
-                self.read(offset, bytes)
+                self.read_blocking(offset, bytes)
             }
 
             fn capacity(&self) -> usize {
                 self.0.size as usize
             }
         }
+
+        impl embedded_storage::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_, Blocking> {
+            const WRITE_SIZE: usize = $write_size;
+            const ERASE_SIZE: usize = $erase_size;
+
+            fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
+                self.write_blocking(offset, bytes)
+            }
+
+            fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
+                self.erase_blocking(from, to)
+            }
+        }
     };
 }
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 084bbdc6e..d50a35b41 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -11,6 +11,8 @@ use crate::pac;
 
 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
 mod alt_regions {
+    use core::marker::PhantomData;
+
     use embassy_hal_common::PeripheralRef;
     use stm32_metapac::FLASH_SIZE;
 
@@ -18,8 +20,7 @@ mod alt_regions {
     #[cfg(feature = "nightly")]
     use crate::flash::asynch;
     use crate::flash::{
-        common, Bank1Region1, Bank1Region2, BlockingFlashRegion, Error, Flash, FlashBank, FlashRegion, READ_SIZE,
-        REGION_ACCESS,
+        common, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion, READ_SIZE,
     };
     use crate::peripherals::FLASH;
 
@@ -53,101 +54,86 @@ mod alt_regions {
         &ALT_BANK2_REGION3,
     ];
 
-    pub struct AltBank1Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>);
-    pub struct AltBank2Region1<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>);
-    pub struct AltBank2Region2<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>);
-    pub struct AltBank2Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>);
+    pub struct AltBank1Region3<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
+    pub struct AltBank2Region1<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
+    pub struct AltBank2Region2<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
+    pub struct AltBank2Region3<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
 
-    pub type BlockingAltBank1Region3<'d> =
-        BlockingFlashRegion<'d, { ALT_BANK1_REGION3.write_size }, { ALT_BANK1_REGION3.erase_size }>;
-    pub type BlockingAltBank2Region1<'d> =
-        BlockingFlashRegion<'d, { ALT_BANK2_REGION1.write_size }, { ALT_BANK2_REGION1.erase_size }>;
-    pub type BlockingAltBank2Region2<'d> =
-        BlockingFlashRegion<'d, { ALT_BANK2_REGION2.write_size }, { ALT_BANK2_REGION2.erase_size }>;
-    pub type BlockingAltBank2Region3<'d> =
-        BlockingFlashRegion<'d, { ALT_BANK2_REGION3.write_size }, { ALT_BANK2_REGION3.erase_size }>;
-
-    pub struct AltFlashLayout<'d> {
-        pub bank1_region1: Bank1Region1<'d>,
-        pub bank1_region2: Bank1Region2<'d>,
-        pub bank1_region3: AltBank1Region3<'d>,
-        pub bank2_region1: AltBank2Region1<'d>,
-        pub bank2_region2: AltBank2Region2<'d>,
-        pub bank2_region3: AltBank2Region3<'d>,
-        pub otp_region: OTPRegion<'d>,
+    pub struct AltFlashLayout<'d, MODE> {
+        pub bank1_region1: Bank1Region1<'d, MODE>,
+        pub bank1_region2: Bank1Region2<'d, MODE>,
+        pub bank1_region3: AltBank1Region3<'d, MODE>,
+        pub bank2_region1: AltBank2Region1<'d, MODE>,
+        pub bank2_region2: AltBank2Region2<'d, MODE>,
+        pub bank2_region3: AltBank2Region3<'d, MODE>,
+        pub otp_region: OTPRegion<'d, MODE>,
     }
 
     impl<'d> Flash<'d> {
-        pub fn into_alt_regions(self) -> AltFlashLayout<'d> {
+        pub fn into_alt_regions(self) -> AltFlashLayout<'d, Async> {
+            unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) };
+
+            // SAFETY: We never expose the cloned peripheral references, and their instance is not public.
+            // Also, all async flash region operations are protected with a mutex.
+            let p = self.inner;
+            AltFlashLayout {
+                bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
+                bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
+                bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
+                bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
+                bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
+                bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
+                otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData),
+            }
+        }
+
+        pub fn into_alt_blocking_regions(self) -> AltFlashLayout<'d, Blocking> {
             unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) };
 
             // SAFETY: We never expose the cloned peripheral references, and their instance is not public.
             // Also, all blocking flash region operations are protected with a cs.
             let p = self.inner;
             AltFlashLayout {
-                bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }),
-                bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }),
-                bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }),
-                bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }),
-                bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }),
-                bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }),
-                otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }),
+                bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
+                bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
+                bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
+                bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
+                bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
+                bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
+                otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData),
             }
         }
     }
 
     macro_rules! foreach_altflash_region {
         ($type_name:ident, $region:ident) => {
-            impl $type_name<'_> {
-                pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
+            #[cfg(feature = "nightly")]
+            impl $type_name<'_, Async> {
+                pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
                     common::read_blocking(self.0.base, self.0.size, offset, bytes)
                 }
 
-                #[cfg(feature = "nightly")]
                 pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
-                    let _guard = REGION_ACCESS.lock().await;
+                    let _guard = asynch::REGION_ACCESS.lock().await;
                     unsafe { asynch::write_chunked(self.0.base, self.0.size, offset, bytes).await }
                 }
 
-                #[cfg(feature = "nightly")]
                 pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
-                    let _guard = REGION_ACCESS.lock().await;
+                    let _guard = asynch::REGION_ACCESS.lock().await;
                     unsafe { asynch::erase_sectored(self.0.base, from, to).await }
                 }
-
-                pub fn try_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
-                    let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?;
-                    unsafe { common::write_chunked_blocking(self.0.base, self.0.size, offset, bytes) }
-                }
-
-                pub fn try_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
-                    let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?;
-                    unsafe { common::erase_sectored_blocking(self.0.base, from, to) }
-                }
             }
 
-            impl embedded_storage::nor_flash::ErrorType for $type_name<'_> {
+            impl embedded_storage::nor_flash::ErrorType for $type_name<'_, Async> {
                 type Error = Error;
             }
 
-            impl embedded_storage::nor_flash::ReadNorFlash for $type_name<'_> {
-                const READ_SIZE: usize = READ_SIZE;
-
-                fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
-                    self.read(offset, bytes)
-                }
-
-                fn capacity(&self) -> usize {
-                    self.0.size as usize
-                }
-            }
-
             #[cfg(feature = "nightly")]
-            impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_> {
+            impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_, Async> {
                 const READ_SIZE: usize = READ_SIZE;
 
                 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
-                    self.read(offset, bytes)
+                    self.read(offset, bytes).await
                 }
 
                 fn capacity(&self) -> usize {
@@ -156,7 +142,7 @@ mod alt_regions {
             }
 
             #[cfg(feature = "nightly")]
-            impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_> {
+            impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_, Async> {
                 const WRITE_SIZE: usize = $region.write_size as usize;
                 const ERASE_SIZE: usize = $region.erase_size as usize;
 
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index 1ef04e56f..56a680a86 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -14,6 +14,9 @@ pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE};
 
 pub const READ_SIZE: usize = 1;
 
+pub struct Blocking;
+pub struct Async;
+
 #[derive(Debug)]
 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct FlashRegion {

From 8b13a7b33874483783cfd5be8fcbd73c888cd906 Mon Sep 17 00:00:00 2001
From: Rasmus Melchior Jacobsen <rmja@laesoe.org>
Date: Wed, 24 May 2023 17:31:35 +0200
Subject: [PATCH 08/14] Align examples

---
 examples/stm32f3/src/bin/flash.rs | 12 ++++++------
 examples/stm32f7/src/bin/flash.rs | 12 ++++++------
 examples/stm32h7/src/bin/flash.rs | 12 ++++++------
 examples/stm32l0/src/bin/flash.rs | 12 ++++++------
 examples/stm32l1/src/bin/flash.rs | 12 ++++++------
 examples/stm32wl/src/bin/flash.rs | 12 ++++++------
 6 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/examples/stm32f3/src/bin/flash.rs b/examples/stm32f3/src/bin/flash.rs
index 0e5fb0658..befae0a16 100644
--- a/examples/stm32f3/src/bin/flash.rs
+++ b/examples/stm32f3/src/bin/flash.rs
@@ -14,27 +14,27 @@ async fn main(_spawner: Spawner) {
 
     const ADDR: u32 = 0x26000;
 
-    let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() };
+    let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region;
 
     info!("Reading...");
     let mut buf = [0u8; 8];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read: {=[u8]:x}", buf);
 
     info!("Erasing...");
-    unwrap!(f.erase(ADDR, ADDR + 2048));
+    unwrap!(f.erase_blocking(ADDR, ADDR + 2048));
 
     info!("Reading...");
     let mut buf = [0u8; 8];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read after erase: {=[u8]:x}", buf);
 
     info!("Writing...");
-    unwrap!(f.write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
+    unwrap!(f.write_blocking(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
 
     info!("Reading...");
     let mut buf = [0u8; 8];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read: {=[u8]:x}", buf);
     assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
 }
diff --git a/examples/stm32f7/src/bin/flash.rs b/examples/stm32f7/src/bin/flash.rs
index 717c82e86..5507e7310 100644
--- a/examples/stm32f7/src/bin/flash.rs
+++ b/examples/stm32f7/src/bin/flash.rs
@@ -18,23 +18,23 @@ async fn main(_spawner: Spawner) {
     // wait a bit before accessing the flash
     Timer::after(Duration::from_millis(300)).await;
 
-    let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region3.into_blocking() };
+    let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region3;
 
     info!("Reading...");
     let mut buf = [0u8; 32];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read: {=[u8]:x}", buf);
 
     info!("Erasing...");
-    unwrap!(f.erase(ADDR, ADDR + 256 * 1024));
+    unwrap!(f.erase_blocking(ADDR, ADDR + 256 * 1024));
 
     info!("Reading...");
     let mut buf = [0u8; 32];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read after erase: {=[u8]:x}", buf);
 
     info!("Writing...");
-    unwrap!(f.write(
+    unwrap!(f.write_blocking(
         ADDR,
         &[
             1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
@@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) {
 
     info!("Reading...");
     let mut buf = [0u8; 32];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read: {=[u8]:x}", buf);
     assert_eq!(
         &buf[..],
diff --git a/examples/stm32h7/src/bin/flash.rs b/examples/stm32h7/src/bin/flash.rs
index aab72cae8..fe6dad249 100644
--- a/examples/stm32h7/src/bin/flash.rs
+++ b/examples/stm32h7/src/bin/flash.rs
@@ -18,23 +18,23 @@ async fn main(_spawner: Spawner) {
     // wait a bit before accessing the flash
     Timer::after(Duration::from_millis(300)).await;
 
-    let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank2_region.into_blocking() };
+    let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank2_region;
 
     info!("Reading...");
     let mut buf = [0u8; 32];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read: {=[u8]:x}", buf);
 
     info!("Erasing...");
-    unwrap!(f.erase(ADDR, ADDR + 128 * 1024));
+    unwrap!(f.erase_blocking(ADDR, ADDR + 128 * 1024));
 
     info!("Reading...");
     let mut buf = [0u8; 32];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read after erase: {=[u8]:x}", buf);
 
     info!("Writing...");
-    unwrap!(f.write(
+    unwrap!(f.write_blocking(
         ADDR,
         &[
             1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
@@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) {
 
     info!("Reading...");
     let mut buf = [0u8; 32];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read: {=[u8]:x}", buf);
     assert_eq!(
         &buf[..],
diff --git a/examples/stm32l0/src/bin/flash.rs b/examples/stm32l0/src/bin/flash.rs
index 0ed0d05fc..4182c87b1 100644
--- a/examples/stm32l0/src/bin/flash.rs
+++ b/examples/stm32l0/src/bin/flash.rs
@@ -14,27 +14,27 @@ async fn main(_spawner: Spawner) {
 
     const ADDR: u32 = 0x26000;
 
-    let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() };
+    let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region;
 
     info!("Reading...");
     let mut buf = [0u8; 8];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read: {=[u8]:x}", buf);
 
     info!("Erasing...");
-    unwrap!(f.erase(ADDR, ADDR + 128));
+    unwrap!(f.erase_blocking(ADDR, ADDR + 128));
 
     info!("Reading...");
     let mut buf = [0u8; 8];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read after erase: {=[u8]:x}", buf);
 
     info!("Writing...");
-    unwrap!(f.write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
+    unwrap!(f.write_blocking(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
 
     info!("Reading...");
     let mut buf = [0u8; 8];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read: {=[u8]:x}", buf);
     assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
 }
diff --git a/examples/stm32l1/src/bin/flash.rs b/examples/stm32l1/src/bin/flash.rs
index c4d7d029c..53052e7c5 100644
--- a/examples/stm32l1/src/bin/flash.rs
+++ b/examples/stm32l1/src/bin/flash.rs
@@ -14,27 +14,27 @@ async fn main(_spawner: Spawner) {
 
     const ADDR: u32 = 0x26000;
 
-    let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() };
+    let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region;
 
     info!("Reading...");
     let mut buf = [0u8; 8];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read: {=[u8]:x}", buf);
 
     info!("Erasing...");
-    unwrap!(f.erase(ADDR, ADDR + 256));
+    unwrap!(f.erase_blocking(ADDR, ADDR + 256));
 
     info!("Reading...");
     let mut buf = [0u8; 8];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read after erase: {=[u8]:x}", buf);
 
     info!("Writing...");
-    unwrap!(f.write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
+    unwrap!(f.write_blocking(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
 
     info!("Reading...");
     let mut buf = [0u8; 8];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read: {=[u8]:x}", buf);
     assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
 }
diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs
index df51ceb68..e03b69b82 100644
--- a/examples/stm32wl/src/bin/flash.rs
+++ b/examples/stm32wl/src/bin/flash.rs
@@ -14,27 +14,27 @@ async fn main(_spawner: Spawner) {
 
     const ADDR: u32 = 0x36000;
 
-    let mut f = unsafe { Flash::new(p.FLASH, interrupt::take!(FLASH)).into_regions().bank1_region.into_blocking() };
+    let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region;
 
     info!("Reading...");
     let mut buf = [0u8; 8];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read: {=[u8]:x}", buf);
 
     info!("Erasing...");
-    unwrap!(f.erase(ADDR, ADDR + 2048));
+    unwrap!(f.erase_blocking(ADDR, ADDR + 2048));
 
     info!("Reading...");
     let mut buf = [0u8; 8];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read: {=[u8]:x}", buf);
 
     info!("Writing...");
-    unwrap!(f.write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
+    unwrap!(f.write_blocking(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
 
     info!("Reading...");
     let mut buf = [0u8; 8];
-    unwrap!(f.read(ADDR, &mut buf));
+    unwrap!(f.read_blocking(ADDR, &mut buf));
     info!("Read: {=[u8]:x}", buf);
     assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
 }

From 9370973846310d013f5be586a4e37031fcb21a16 Mon Sep 17 00:00:00 2001
From: Rasmus Melchior Jacobsen <rmja@laesoe.org>
Date: Wed, 24 May 2023 17:35:49 +0200
Subject: [PATCH 09/14] Remove TryLockError,

---
 embassy-stm32/src/flash/mod.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index 56a680a86..02f6c5320 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -83,7 +83,6 @@ pub enum Error {
     Protected,
     Unaligned,
     Parallelism,
-    TryLockError,
 }
 
 impl NorFlashError for Error {

From e65ff85b88deef3e32cc437d28e36274b82ce03e Mon Sep 17 00:00:00 2001
From: Rasmus Melchior Jacobsen <rmja@laesoe.org>
Date: Wed, 24 May 2023 23:51:48 +0200
Subject: [PATCH 10/14] Default to Async mode

---
 embassy-stm32/build.rs        |  4 ++--
 embassy-stm32/src/flash/f4.rs | 10 +++++-----
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 29af3c80d..b766f0739 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -213,7 +213,7 @@ fn main() {
         let region_type = format_ident!("{}", get_flash_region_type_name(region.name));
         flash_regions.extend(quote! {
             #[cfg(flash)]
-            pub struct #region_type<'d, MODE>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>, pub(crate) core::marker::PhantomData<MODE>);
+            pub struct #region_type<'d, MODE = crate::flash::Async>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>, pub(crate) core::marker::PhantomData<MODE>);
         });
     }
 
@@ -238,7 +238,7 @@ fn main() {
     let regions_len = flash_memory_regions.len();
     flash_regions.extend(quote! {
         #[cfg(flash)]
-        pub struct FlashLayout<'d, MODE> {
+        pub struct FlashLayout<'d, MODE = crate::flash::Async> {
             #(#fields),*,
             _mode: core::marker::PhantomData<MODE>,
         }
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index d50a35b41..3d696223c 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -54,12 +54,12 @@ mod alt_regions {
         &ALT_BANK2_REGION3,
     ];
 
-    pub struct AltBank1Region3<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
-    pub struct AltBank2Region1<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
-    pub struct AltBank2Region2<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
-    pub struct AltBank2Region3<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
+    pub struct AltBank1Region3<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
+    pub struct AltBank2Region1<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
+    pub struct AltBank2Region2<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
+    pub struct AltBank2Region3<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>);
 
-    pub struct AltFlashLayout<'d, MODE> {
+    pub struct AltFlashLayout<'d, MODE = Async> {
         pub bank1_region1: Bank1Region1<'d, MODE>,
         pub bank1_region2: Bank1Region2<'d, MODE>,
         pub bank1_region3: AltBank1Region3<'d, MODE>,

From cd8198037fa37db9af7e9dde1e00122df9ed15a3 Mon Sep 17 00:00:00 2001
From: Rasmus Melchior Jacobsen <rmja@laesoe.org>
Date: Thu, 25 May 2023 13:08:40 +0200
Subject: [PATCH 11/14] Actually transition to dual bank mode - key was
 required

---
 embassy-stm32/src/flash/f4.rs | 29 ++++++++++++++++++++++++-----
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 3d696223c..50ab446bd 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -71,7 +71,7 @@ mod alt_regions {
 
     impl<'d> Flash<'d> {
         pub fn into_alt_regions(self) -> AltFlashLayout<'d, Async> {
-            unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) };
+            super::set_alt_layout();
 
             // SAFETY: We never expose the cloned peripheral references, and their instance is not public.
             // Also, all async flash region operations are protected with a mutex.
@@ -88,7 +88,7 @@ mod alt_regions {
         }
 
         pub fn into_alt_blocking_regions(self) -> AltFlashLayout<'d, Blocking> {
-            unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) };
+            super::set_alt_layout();
 
             // SAFETY: We never expose the cloned peripheral references, and their instance is not public.
             // Also, all blocking flash region operations are protected with a cs.
@@ -171,12 +171,31 @@ static WAKER: AtomicWaker = AtomicWaker::new();
 
 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
 pub fn set_default_layout() {
-    unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(false)) };
+    unsafe {
+        pac::FLASH.optkeyr().write(|w| w.set_optkey(0x08192A3B));
+        pac::FLASH.optkeyr().write(|w| w.set_optkey(0x4C5D6E7F));
+        pac::FLASH.optcr().modify(|r| {
+            r.set_db1m(false);
+            r.set_optlock(true)
+        });
+    };
 }
 
 #[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))]
 pub const fn set_default_layout() {}
 
+#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
+fn set_alt_layout() {
+    unsafe {
+        pac::FLASH.optkeyr().write(|w| w.set_optkey(0x08192A3B));
+        pac::FLASH.optkeyr().write(|w| w.set_optkey(0x4C5D6E7F));
+        pac::FLASH.optcr().modify(|r| {
+            r.set_db1m(true);
+            r.set_optlock(true)
+        });
+    };
+}
+
 #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
 pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
     if unsafe { pac::FLASH.optcr().read().db1m() } {
@@ -207,8 +226,8 @@ pub(crate) unsafe fn lock() {
 }
 
 pub(crate) unsafe fn unlock() {
-    pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123));
-    pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB));
+    pac::FLASH.keyr().write(|w| w.set_key(0x45670123));
+    pac::FLASH.keyr().write(|w| w.set_key(0xCDEF89AB));
 }
 
 #[cfg(feature = "nightly")]

From baf1c2efbe0b218f86b491b88e48531fde691851 Mon Sep 17 00:00:00 2001
From: Rasmus Melchior Jacobsen <rmja@laesoe.org>
Date: Thu, 25 May 2023 13:42:42 +0200
Subject: [PATCH 12/14] Align with new bind_interrupt

---
 embassy-stm32/src/flash/asynch.rs             |  3 ++
 embassy-stm32/src/flash/common.rs             | 41 +++++++++++++++----
 embassy-stm32/src/flash/f0.rs                 |  2 +-
 embassy-stm32/src/flash/f3.rs                 |  2 +-
 embassy-stm32/src/flash/f4.rs                 |  2 +-
 embassy-stm32/src/flash/f7.rs                 |  2 +-
 embassy-stm32/src/flash/h7.rs                 |  2 +-
 embassy-stm32/src/flash/l.rs                  |  2 +-
 embassy-stm32/src/flash/other.rs              |  2 +-
 examples/boot/application/rp/src/bin/a.rs     |  2 +-
 .../boot/application/stm32f3/src/bin/a.rs     |  2 +-
 .../boot/application/stm32f7/src/bin/a.rs     |  2 +-
 .../boot/application/stm32h7/src/bin/a.rs     |  2 +-
 .../boot/application/stm32l0/src/bin/a.rs     |  2 +-
 .../boot/application/stm32l1/src/bin/a.rs     |  2 +-
 .../boot/application/stm32l4/src/bin/a.rs     |  2 +-
 .../boot/application/stm32wl/src/bin/a.rs     |  2 +-
 examples/boot/bootloader/stm32/src/main.rs    |  3 +-
 examples/stm32f3/src/bin/flash.rs             |  4 +-
 examples/stm32f4/src/bin/flash.rs             |  4 +-
 examples/stm32f4/src/bin/flash_async.rs       | 10 +++--
 examples/stm32h7/src/bin/flash.rs             |  4 +-
 examples/stm32l0/src/bin/flash.rs             |  4 +-
 examples/stm32l1/src/bin/flash.rs             |  4 +-
 examples/stm32wl/src/bin/flash.rs             |  4 +-
 25 files changed, 71 insertions(+), 40 deletions(-)

diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs
index 3564bbff5..017fb17fa 100644
--- a/embassy-stm32/src/flash/asynch.rs
+++ b/embassy-stm32/src/flash/asynch.rs
@@ -12,15 +12,18 @@ pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new
 
 impl<'d> Flash<'d> {
     pub fn into_regions(self) -> FlashLayout<'d, Async> {
+        assert!(!self.blocking_only);
         family::set_default_layout();
         FlashLayout::new(self.inner)
     }
 
     pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
+        assert!(!self.blocking_only);
         unsafe { write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes).await }
     }
 
     pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
+        assert!(!self.blocking_only);
         unsafe { erase_sectored(FLASH_BASE as u32, from, to).await }
     }
 }
diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
index 8b38745cf..0a1ee5166 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -1,5 +1,5 @@
 use atomic_polyfill::{fence, Ordering};
-use embassy_cortex_m::interrupt::InterruptExt;
+use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
 use embassy_hal_common::drop::OnDrop;
 use embassy_hal_common::{into_ref, PeripheralRef};
 use stm32_metapac::FLASH_BASE;
@@ -9,21 +9,37 @@ use super::{
     WRITE_SIZE,
 };
 use crate::peripherals::FLASH;
-use crate::Peripheral;
+use crate::{interrupt, Peripheral};
 
 pub struct Flash<'d> {
     pub(crate) inner: PeripheralRef<'d, FLASH>,
+    pub(crate) blocking_only: bool,
 }
 
 impl<'d> Flash<'d> {
-    pub fn new(p: impl Peripheral<P = FLASH> + 'd, irq: impl Peripheral<P = crate::interrupt::FLASH> + 'd) -> Self {
-        into_ref!(p, irq);
+    pub fn new(
+        p: impl Peripheral<P = FLASH> + 'd,
+        _irq: impl interrupt::Binding<crate::interrupt::FLASH, InterruptHandler> + 'd,
+    ) -> Self {
+        into_ref!(p);
 
-        irq.set_handler(family::on_interrupt);
-        irq.unpend();
-        irq.enable();
+        let flash_irq = unsafe { crate::interrupt::FLASH::steal() };
+        flash_irq.unpend();
+        flash_irq.enable();
 
-        Self { inner: p }
+        Self {
+            inner: p,
+            blocking_only: false,
+        }
+    }
+
+    pub fn new_blocking_only(p: impl Peripheral<P = FLASH> + 'd) -> Self {
+        into_ref!(p);
+
+        Self {
+            inner: p,
+            blocking_only: true,
+        }
     }
 
     pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> {
@@ -52,6 +68,15 @@ impl<'d> Flash<'d> {
     }
 }
 
+/// Interrupt handler
+pub struct InterruptHandler;
+
+impl interrupt::Handler<crate::interrupt::FLASH> for InterruptHandler {
+    unsafe fn on_interrupt() {
+        family::on_interrupt();
+    }
+}
+
 pub(super) fn read_blocking(base: u32, size: u32, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
     if offset + bytes.len() as u32 > size {
         return Err(Error::Size);
diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs
index ecf3a6981..cd17486e6 100644
--- a/embassy-stm32/src/flash/f0.rs
+++ b/embassy-stm32/src/flash/f0.rs
@@ -13,7 +13,7 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
     &FLASH_REGIONS
 }
 
-pub(crate) unsafe fn on_interrupt(_: *mut ()) {
+pub(crate) unsafe fn on_interrupt() {
     unimplemented!();
 }
 
diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs
index fd778f2b1..4ce391288 100644
--- a/embassy-stm32/src/flash/f3.rs
+++ b/embassy-stm32/src/flash/f3.rs
@@ -13,7 +13,7 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
     &FLASH_REGIONS
 }
 
-pub(crate) unsafe fn on_interrupt(_: *mut ()) {
+pub(crate) unsafe fn on_interrupt() {
     unimplemented!();
 }
 
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 50ab446bd..2b0472640 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -210,7 +210,7 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
     &FLASH_REGIONS
 }
 
-pub(crate) unsafe fn on_interrupt(_: *mut ()) {
+pub(crate) unsafe fn on_interrupt() {
     // Clear IRQ flags
     pac::FLASH.sr().write(|w| {
         w.set_operr(true);
diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs
index a0593b14b..ab518bf89 100644
--- a/embassy-stm32/src/flash/f7.rs
+++ b/embassy-stm32/src/flash/f7.rs
@@ -12,7 +12,7 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
     &FLASH_REGIONS
 }
 
-pub(crate) unsafe fn on_interrupt(_: *mut ()) {
+pub(crate) unsafe fn on_interrupt() {
     unimplemented!();
 }
 
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index 865f13283..d6818d594 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -17,7 +17,7 @@ pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
     &FLASH_REGIONS
 }
 
-pub(crate) unsafe fn on_interrupt(_: *mut ()) {
+pub(crate) unsafe fn on_interrupt() {
     unimplemented!();
 }
 
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index f8a0dac4c..c2394e0c9 100644
--- a/embassy-stm32/src/flash/l.rs
+++ b/embassy-stm32/src/flash/l.rs
@@ -12,7 +12,7 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
     &FLASH_REGIONS
 }
 
-pub(crate) unsafe fn on_interrupt(_: *mut ()) {
+pub(crate) unsafe fn on_interrupt() {
     unimplemented!();
 }
 
diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs
index e21b0b241..e569951f9 100644
--- a/embassy-stm32/src/flash/other.rs
+++ b/embassy-stm32/src/flash/other.rs
@@ -8,7 +8,7 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] {
     &FLASH_REGIONS
 }
 
-pub(crate) unsafe fn on_interrupt(_: *mut ()) {
+pub(crate) unsafe fn on_interrupt() {
     unimplemented!();
 }
 
diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs
index e3ac634c2..2b84ec614 100644
--- a/examples/boot/application/rp/src/bin/a.rs
+++ b/examples/boot/application/rp/src/bin/a.rs
@@ -26,7 +26,7 @@ async fn main(_s: Spawner) {
     let mut watchdog = Watchdog::new(p.WATCHDOG);
     watchdog.start(Duration::from_secs(8));
 
-    let mut flash: Flash<_, FLASH_SIZE> = Flash::new(p.FLASH);
+    let mut flash: Flash<_, FLASH_SIZE> = Flash::new_blocking_only(p.FLASH);
 
     let mut updater = FirmwareUpdater::default();
 
diff --git a/examples/boot/application/stm32f3/src/bin/a.rs b/examples/boot/application/stm32f3/src/bin/a.rs
index d92d59b29..a69b6327f 100644
--- a/examples/boot/application/stm32f3/src/bin/a.rs
+++ b/examples/boot/application/stm32f3/src/bin/a.rs
@@ -17,7 +17,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let p = embassy_stm32::init(Default::default());
-    let flash = Flash::new(p.FLASH);
+    let flash = Flash::new_blocking_only(p.FLASH);
     let mut flash = BlockingAsync::new(flash);
 
     let button = Input::new(p.PC13, Pull::Up);
diff --git a/examples/boot/application/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs
index 79ab80e09..1f55db932 100644
--- a/examples/boot/application/stm32f7/src/bin/a.rs
+++ b/examples/boot/application/stm32f7/src/bin/a.rs
@@ -16,7 +16,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let p = embassy_stm32::init(Default::default());
-    let mut flash = Flash::new(p.FLASH);
+    let mut flash = Flash::new_blocking_only(p.FLASH);
 
     let button = Input::new(p.PC13, Pull::Down);
     let mut button = ExtiInput::new(button, p.EXTI13);
diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs
index 8b452be34..b8617c3bd 100644
--- a/examples/boot/application/stm32h7/src/bin/a.rs
+++ b/examples/boot/application/stm32h7/src/bin/a.rs
@@ -16,7 +16,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let p = embassy_stm32::init(Default::default());
-    let mut flash = Flash::new(p.FLASH);
+    let mut flash = Flash::new_blocking_only(p.FLASH);
 
     let button = Input::new(p.PC13, Pull::Down);
     let mut button = ExtiInput::new(button, p.EXTI13);
diff --git a/examples/boot/application/stm32l0/src/bin/a.rs b/examples/boot/application/stm32l0/src/bin/a.rs
index 59ca34386..c66635639 100644
--- a/examples/boot/application/stm32l0/src/bin/a.rs
+++ b/examples/boot/application/stm32l0/src/bin/a.rs
@@ -18,7 +18,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let p = embassy_stm32::init(Default::default());
-    let flash = Flash::new(p.FLASH);
+    let flash = Flash::new_blocking_only(p.FLASH);
     let mut flash = BlockingAsync::new(flash);
 
     let button = Input::new(p.PB2, Pull::Up);
diff --git a/examples/boot/application/stm32l1/src/bin/a.rs b/examples/boot/application/stm32l1/src/bin/a.rs
index 59ca34386..c66635639 100644
--- a/examples/boot/application/stm32l1/src/bin/a.rs
+++ b/examples/boot/application/stm32l1/src/bin/a.rs
@@ -18,7 +18,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let p = embassy_stm32::init(Default::default());
-    let flash = Flash::new(p.FLASH);
+    let flash = Flash::new_blocking_only(p.FLASH);
     let mut flash = BlockingAsync::new(flash);
 
     let button = Input::new(p.PB2, Pull::Up);
diff --git a/examples/boot/application/stm32l4/src/bin/a.rs b/examples/boot/application/stm32l4/src/bin/a.rs
index 6cddc6cc8..86936222c 100644
--- a/examples/boot/application/stm32l4/src/bin/a.rs
+++ b/examples/boot/application/stm32l4/src/bin/a.rs
@@ -17,7 +17,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let p = embassy_stm32::init(Default::default());
-    let flash = Flash::new(p.FLASH);
+    let flash = Flash::new_blocking_only(p.FLASH);
     let mut flash = BlockingAsync::new(flash);
 
     let button = Input::new(p.PC13, Pull::Up);
diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs
index 1ff47eddd..2982e8df1 100644
--- a/examples/boot/application/stm32wl/src/bin/a.rs
+++ b/examples/boot/application/stm32wl/src/bin/a.rs
@@ -17,7 +17,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
 #[embassy_executor::main]
 async fn main(_spawner: Spawner) {
     let p = embassy_stm32::init(Default::default());
-    let flash = Flash::new(p.FLASH);
+    let flash = Flash::new_blocking_only(p.FLASH);
     let mut flash = BlockingAsync::new(flash);
 
     let button = Input::new(p.PA0, Pull::Up);
diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs
index 49c21920b..5e8a4f2b3 100644
--- a/examples/boot/bootloader/stm32/src/main.rs
+++ b/examples/boot/bootloader/stm32/src/main.rs
@@ -20,8 +20,7 @@ fn main() -> ! {
     */
 
     let mut bl: BootLoader<2048> = BootLoader::default();
-    let flash = Flash::new(p.FLASH);
-    let layout = flash.into_regions();
+    let layout = Flash::new_blocking_only(p.FLASH).into_blocking_regions();
     let mut flash = BootFlash::new(layout.bank1_region);
     let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash));
     core::mem::drop(flash);
diff --git a/examples/stm32f3/src/bin/flash.rs b/examples/stm32f3/src/bin/flash.rs
index befae0a16..9a31b548d 100644
--- a/examples/stm32f3/src/bin/flash.rs
+++ b/examples/stm32f3/src/bin/flash.rs
@@ -4,7 +4,7 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
-use embassy_stm32::{flash::Flash, interrupt};
+use embassy_stm32::flash::Flash;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
 
     const ADDR: u32 = 0x26000;
 
-    let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region;
+    let mut f = Flash::new_blocking_only(p.FLASH).into_blocking_regions().bank1_region;
 
     info!("Reading...");
     let mut buf = [0u8; 8];
diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs
index de4ecdb8f..455af930b 100644
--- a/examples/stm32f4/src/bin/flash.rs
+++ b/examples/stm32f4/src/bin/flash.rs
@@ -4,7 +4,7 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
-use embassy_stm32::{flash::Flash, interrupt};
+use embassy_stm32::flash::Flash;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
 
     // Once can also call `into_regions()` to get access to NorFlash implementations
     // for each of the unique characteristics.
-    let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH));
+    let mut f = Flash::new_blocking_only(p.FLASH);
 
     // Sector 5
     test_flash(&mut f, 128 * 1024, 128 * 1024);
diff --git a/examples/stm32f4/src/bin/flash_async.rs b/examples/stm32f4/src/bin/flash_async.rs
index c9d9df34b..675337083 100644
--- a/examples/stm32f4/src/bin/flash_async.rs
+++ b/examples/stm32f4/src/bin/flash_async.rs
@@ -5,17 +5,21 @@
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
 use embassy_time::{Timer, Duration};
-use embassy_stm32::flash::Flash;
+use embassy_stm32::flash::{Flash, InterruptHandler};
 use embassy_stm32::gpio::{AnyPin, Level, Output, Pin, Speed};
-use embassy_stm32::{interrupt};
+use embassy_stm32::bind_interrupts;
 use {defmt_rtt as _, panic_probe as _};
 
+bind_interrupts!(struct Irqs {
+    FLASH => InterruptHandler;
+});
+
 #[embassy_executor::main]
 async fn main(spawner: Spawner) {
     let p = embassy_stm32::init(Default::default());
     info!("Hello Flash!");
 
-    let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH));
+    let mut f = Flash::new(p.FLASH, Irqs);
 
     // Led should blink uninterrupted during ~2sec erase operation
     spawner.spawn(blinky(p.PB7.degrade())).unwrap();
diff --git a/examples/stm32h7/src/bin/flash.rs b/examples/stm32h7/src/bin/flash.rs
index fe6dad249..c0c332c34 100644
--- a/examples/stm32h7/src/bin/flash.rs
+++ b/examples/stm32h7/src/bin/flash.rs
@@ -4,7 +4,7 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
-use embassy_stm32::{flash::Flash, interrupt};
+use embassy_stm32::flash::Flash;
 use embassy_time::{Duration, Timer};
 use {defmt_rtt as _, panic_probe as _};
 
@@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) {
     // wait a bit before accessing the flash
     Timer::after(Duration::from_millis(300)).await;
 
-    let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank2_region;
+    let mut f = Flash::new_blocking_only(p.FLASH).into_blocking_regions().bank2_region;
 
     info!("Reading...");
     let mut buf = [0u8; 32];
diff --git a/examples/stm32l0/src/bin/flash.rs b/examples/stm32l0/src/bin/flash.rs
index 4182c87b1..57ccf7f57 100644
--- a/examples/stm32l0/src/bin/flash.rs
+++ b/examples/stm32l0/src/bin/flash.rs
@@ -4,7 +4,7 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
-use embassy_stm32::{flash::Flash, interrupt};
+use embassy_stm32::flash::Flash;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
 
     const ADDR: u32 = 0x26000;
 
-    let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region;
+    let mut f = Flash::new_blocking_only(p.FLASH).into_blocking_regions().bank1_region;
 
     info!("Reading...");
     let mut buf = [0u8; 8];
diff --git a/examples/stm32l1/src/bin/flash.rs b/examples/stm32l1/src/bin/flash.rs
index 53052e7c5..71174bfbc 100644
--- a/examples/stm32l1/src/bin/flash.rs
+++ b/examples/stm32l1/src/bin/flash.rs
@@ -4,7 +4,7 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
-use embassy_stm32::{flash::Flash, interrupt};
+use embassy_stm32::flash::Flash;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
 
     const ADDR: u32 = 0x26000;
 
-    let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region;
+    let mut f = Flash::new_blocking_only(p.FLASH).into_blocking_regions().bank1_region;
 
     info!("Reading...");
     let mut buf = [0u8; 8];
diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs
index e03b69b82..51bd0db4e 100644
--- a/examples/stm32wl/src/bin/flash.rs
+++ b/examples/stm32wl/src/bin/flash.rs
@@ -4,7 +4,7 @@
 
 use defmt::{info, unwrap};
 use embassy_executor::Spawner;
-use embassy_stm32::{flash::Flash, interrupt};
+use embassy_stm32::flash::Flash;
 use {defmt_rtt as _, panic_probe as _};
 
 #[embassy_executor::main]
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
 
     const ADDR: u32 = 0x36000;
 
-    let mut f = Flash::new(p.FLASH, interrupt::take!(FLASH)).into_blocking_regions().bank1_region;
+    let mut f = Flash::new_blocking_only(p.FLASH).into_blocking_regions().bank1_region;
 
     info!("Reading...");
     let mut buf = [0u8; 8];

From 8b1eaf00a0fd24459407a70e76bdbc16983b9af6 Mon Sep 17 00:00:00 2001
From: Rasmus Melchior Jacobsen <rmja@laesoe.org>
Date: Thu, 25 May 2023 13:54:40 +0200
Subject: [PATCH 13/14] Simplify SR->Result

---
 embassy-stm32/src/flash/f4.rs | 45 +++++++++++++----------------------
 1 file changed, 17 insertions(+), 28 deletions(-)

diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 2b0472640..53e58835e 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -4,6 +4,7 @@ use core::sync::atomic::{fence, Ordering};
 
 #[cfg(feature = "nightly")]
 use embassy_sync::waitqueue::AtomicWaker;
+use pac::flash::regs::Sr;
 
 use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
 use crate::flash::Error;
@@ -347,17 +348,7 @@ pub(crate) async unsafe fn wait_ready() -> Result<(), Error> {
 
         let sr = pac::FLASH.sr().read();
         if !sr.bsy() {
-            Poll::Ready(if sr.pgserr() {
-                Err(Error::Seq)
-            } else if sr.pgperr() {
-                Err(Error::Parallelism)
-            } else if sr.pgaerr() {
-                Err(Error::Unaligned)
-            } else if sr.wrperr() {
-                Err(Error::Protected)
-            } else {
-                Ok(())
-            })
+            Poll::Ready(get_result(sr))
         } else {
             return Poll::Pending;
         }
@@ -370,27 +361,25 @@ unsafe fn wait_ready_blocking() -> Result<(), Error> {
         let sr = pac::FLASH.sr().read();
 
         if !sr.bsy() {
-            if sr.pgserr() {
-                return Err(Error::Seq);
-            }
-
-            if sr.pgperr() {
-                return Err(Error::Parallelism);
-            }
-
-            if sr.pgaerr() {
-                return Err(Error::Unaligned);
-            }
-
-            if sr.wrperr() {
-                return Err(Error::Protected);
-            }
-
-            return Ok(());
+            return get_result(sr);
         }
     }
 }
 
+fn get_result(sr: Sr) -> Result<(), Error> {
+    if sr.pgserr() {
+        Err(Error::Seq)
+    } else if sr.pgperr() {
+        Err(Error::Parallelism)
+    } else if sr.pgaerr() {
+        Err(Error::Unaligned)
+    } else if sr.wrperr() {
+        Err(Error::Protected)
+    } else {
+        Ok(())
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;

From c02759ad91994191944b4fd1a4b47cd310416c04 Mon Sep 17 00:00:00 2001
From: Rasmus Melchior Jacobsen <rmja@laesoe.org>
Date: Thu, 25 May 2023 13:59:32 +0200
Subject: [PATCH 14/14] Fix unused errors

---
 embassy-stm32/src/flash/common.rs | 3 +++
 embassy-stm32/src/flash/f4.rs     | 8 +++-----
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
index 0a1ee5166..547e30312 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -13,6 +13,7 @@ use crate::{interrupt, Peripheral};
 
 pub struct Flash<'d> {
     pub(crate) inner: PeripheralRef<'d, FLASH>,
+    #[cfg(all(feature = "nightly", flash_f4))]
     pub(crate) blocking_only: bool,
 }
 
@@ -29,6 +30,7 @@ impl<'d> Flash<'d> {
 
         Self {
             inner: p,
+            #[cfg(all(feature = "nightly", flash_f4))]
             blocking_only: false,
         }
     }
@@ -38,6 +40,7 @@ impl<'d> Flash<'d> {
 
         Self {
             inner: p,
+            #[cfg(all(feature = "nightly", flash_f4))]
             blocking_only: true,
         }
     }
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 53e58835e..aa3433b23 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -20,9 +20,7 @@ mod alt_regions {
     use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION};
     #[cfg(feature = "nightly")]
     use crate::flash::asynch;
-    use crate::flash::{
-        common, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion, READ_SIZE,
-    };
+    use crate::flash::{Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion};
     use crate::peripherals::FLASH;
 
     pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion {
@@ -111,7 +109,7 @@ mod alt_regions {
             #[cfg(feature = "nightly")]
             impl $type_name<'_, Async> {
                 pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
-                    common::read_blocking(self.0.base, self.0.size, offset, bytes)
+                    crate::flash::common::read_blocking(self.0.base, self.0.size, offset, bytes)
                 }
 
                 pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
@@ -131,7 +129,7 @@ mod alt_regions {
 
             #[cfg(feature = "nightly")]
             impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_, Async> {
-                const READ_SIZE: usize = READ_SIZE;
+                const READ_SIZE: usize = crate::flash::READ_SIZE;
 
                 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
                     self.read(offset, bytes).await