diff options
| author | Rasmus Melchior Jacobsen <[email protected]> | 2023-05-24 12:17:12 +0200 |
|---|---|---|
| committer | Rasmus Melchior Jacobsen <[email protected]> | 2023-05-25 20:07:41 +0200 |
| commit | 0e90e98e9b477302a3cd2550dbd438907ed10ca6 (patch) | |
| tree | 4ec2c5d7bce91ac44659ad4ebc93a04ee7966d1b | |
| parent | 06f5c309c06e61790b24a7bfddad1324741b767f (diff) | |
stm32: Add async flash write/erase to f4
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/asynch.rs | 129 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/common.rs | 255 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/f0.rs | 18 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/f3.rs | 18 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/f4.rs | 181 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/f7.rs | 21 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/h7.rs | 21 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/l.rs | 19 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/mod.rs | 49 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/other.rs | 12 |
11 files changed, 540 insertions, 187 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 0d7e03bf5..73841bdc8 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} | |||
| 47 | embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true} | 47 | embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true} |
| 48 | 48 | ||
| 49 | embedded-storage = "0.3.0" | 49 | embedded-storage = "0.3.0" |
| 50 | embedded-storage-async = { version = "0.4.0", optional = true } | ||
| 50 | 51 | ||
| 51 | defmt = { version = "0.3", optional = true } | 52 | defmt = { version = "0.3", optional = true } |
| 52 | log = { version = "0.4.14", optional = true } | 53 | log = { version = "0.4.14", optional = true } |
| @@ -68,6 +69,7 @@ cfg-if = "1.0.0" | |||
| 68 | embedded-io = { version = "0.4.0", features = ["async"], optional = true } | 69 | embedded-io = { version = "0.4.0", features = ["async"], optional = true } |
| 69 | chrono = { version = "^0.4", default-features = false, optional = true} | 70 | chrono = { version = "^0.4", default-features = false, optional = true} |
| 70 | bit_field = "0.10.2" | 71 | bit_field = "0.10.2" |
| 72 | paste = "1.0.12" | ||
| 71 | 73 | ||
| 72 | [dev-dependencies] | 74 | [dev-dependencies] |
| 73 | critical-section = { version = "1.1", features = ["std"] } | 75 | critical-section = { version = "1.1", features = ["std"] } |
| @@ -98,7 +100,7 @@ time-driver-tim12 = ["_time-driver"] | |||
| 98 | time-driver-tim15 = ["_time-driver"] | 100 | time-driver-tim15 = ["_time-driver"] |
| 99 | 101 | ||
| 100 | # Enable nightly-only features | 102 | # Enable nightly-only features |
| 101 | nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"] | 103 | nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"] |
| 102 | 104 | ||
| 103 | # Reexport stm32-metapac at `embassy_stm32::pac`. | 105 | # Reexport stm32-metapac at `embassy_stm32::pac`. |
| 104 | # This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version. | 106 | # 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 @@ | |||
| 1 | use atomic_polyfill::{fence, Ordering}; | ||
| 2 | use embassy_hal_common::drop::OnDrop; | ||
| 3 | |||
| 4 | use super::{ | ||
| 5 | ensure_sector_aligned, family, get_sector, Error, Flash, FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, | ||
| 6 | REGION_ACCESS, WRITE_SIZE, | ||
| 7 | }; | ||
| 8 | |||
| 9 | impl<'d> Flash<'d> { | ||
| 10 | pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | ||
| 11 | unsafe { write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes).await } | ||
| 12 | } | ||
| 13 | |||
| 14 | pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | ||
| 15 | unsafe { erase_sectored(FLASH_BASE as u32, from, to).await } | ||
| 16 | } | ||
| 17 | } | ||
| 18 | |||
| 19 | impl embedded_storage_async::nor_flash::NorFlash for Flash<'_> { | ||
| 20 | const WRITE_SIZE: usize = WRITE_SIZE; | ||
| 21 | const ERASE_SIZE: usize = MAX_ERASE_SIZE; | ||
| 22 | |||
| 23 | async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | ||
| 24 | self.write(offset, bytes).await | ||
| 25 | } | ||
| 26 | |||
| 27 | async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | ||
| 28 | self.erase(from, to).await | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | pub(super) async unsafe fn write_chunked(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> { | ||
| 33 | if offset + bytes.len() as u32 > size { | ||
| 34 | return Err(Error::Size); | ||
| 35 | } | ||
| 36 | if offset % WRITE_SIZE as u32 != 0 || bytes.len() % WRITE_SIZE != 0 { | ||
| 37 | return Err(Error::Unaligned); | ||
| 38 | } | ||
| 39 | |||
| 40 | let mut address = base + offset; | ||
| 41 | trace!("Writing {} bytes at 0x{:x}", bytes.len(), address); | ||
| 42 | |||
| 43 | for chunk in bytes.chunks(WRITE_SIZE) { | ||
| 44 | family::clear_all_err(); | ||
| 45 | fence(Ordering::SeqCst); | ||
| 46 | family::unlock(); | ||
| 47 | fence(Ordering::SeqCst); | ||
| 48 | family::enable_write(); | ||
| 49 | fence(Ordering::SeqCst); | ||
| 50 | |||
| 51 | let _on_drop = OnDrop::new(|| { | ||
| 52 | family::disable_write(); | ||
| 53 | fence(Ordering::SeqCst); | ||
| 54 | family::lock(); | ||
| 55 | }); | ||
| 56 | |||
| 57 | family::write(address, chunk.try_into().unwrap()).await?; | ||
| 58 | address += WRITE_SIZE as u32; | ||
| 59 | } | ||
| 60 | Ok(()) | ||
| 61 | } | ||
| 62 | |||
| 63 | pub(super) async unsafe fn erase_sectored(base: u32, from: u32, to: u32) -> Result<(), Error> { | ||
| 64 | let start_address = base + from; | ||
| 65 | let end_address = base + to; | ||
| 66 | let regions = family::get_flash_regions(); | ||
| 67 | |||
| 68 | ensure_sector_aligned(start_address, end_address, regions)?; | ||
| 69 | |||
| 70 | trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); | ||
| 71 | |||
| 72 | let mut address = start_address; | ||
| 73 | while address < end_address { | ||
| 74 | let sector = get_sector(address, regions); | ||
| 75 | trace!("Erasing sector: {:?}", sector); | ||
| 76 | |||
| 77 | family::clear_all_err(); | ||
| 78 | fence(Ordering::SeqCst); | ||
| 79 | family::unlock(); | ||
| 80 | fence(Ordering::SeqCst); | ||
| 81 | |||
| 82 | let _on_drop = OnDrop::new(|| family::lock()); | ||
| 83 | |||
| 84 | family::erase_sector(§or).await?; | ||
| 85 | address += sector.size; | ||
| 86 | } | ||
| 87 | Ok(()) | ||
| 88 | } | ||
| 89 | |||
| 90 | foreach_flash_region! { | ||
| 91 | ($type_name:ident, $write_size:literal, $erase_size:literal) => { | ||
| 92 | impl crate::_generated::flash_regions::$type_name<'_> { | ||
| 93 | pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | ||
| 94 | let _guard = REGION_ACCESS.lock().await; | ||
| 95 | unsafe { write_chunked(self.0.base, self.0.size, offset, bytes).await } | ||
| 96 | } | ||
| 97 | |||
| 98 | pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | ||
| 99 | let _guard = REGION_ACCESS.lock().await; | ||
| 100 | unsafe { erase_sectored(self.0.base, from, to).await } | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | impl embedded_storage_async::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> { | ||
| 105 | const READ_SIZE: usize = READ_SIZE; | ||
| 106 | |||
| 107 | async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | ||
| 108 | self.read(offset, bytes) | ||
| 109 | } | ||
| 110 | |||
| 111 | fn capacity(&self) -> usize { | ||
| 112 | self.0.size as usize | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | impl embedded_storage_async::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_> { | ||
| 117 | const WRITE_SIZE: usize = $write_size; | ||
| 118 | const ERASE_SIZE: usize = $erase_size; | ||
| 119 | |||
| 120 | async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | ||
| 121 | self.write(offset, bytes).await | ||
| 122 | } | ||
| 123 | |||
| 124 | async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | ||
| 125 | self.erase(from, to).await | ||
| 126 | } | ||
| 127 | } | ||
| 128 | }; | ||
| 129 | } | ||
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 @@ | |||
| 1 | use atomic_polyfill::{fence, Ordering}; | 1 | use atomic_polyfill::{fence, Ordering}; |
| 2 | use embassy_cortex_m::interrupt::InterruptExt; | ||
| 3 | use embassy_futures::block_on; | ||
| 2 | use embassy_hal_common::drop::OnDrop; | 4 | use embassy_hal_common::drop::OnDrop; |
| 3 | use embassy_hal_common::{into_ref, PeripheralRef}; | 5 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 4 | 6 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | |
| 5 | use super::{family, Error, FlashLayout, FlashRegion, FlashSector, FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, WRITE_SIZE}; | 7 | use embassy_sync::mutex::Mutex; |
| 6 | use crate::flash::FlashBank; | 8 | use stm32_metapac::FLASH_BASE; |
| 9 | |||
| 10 | use super::{ | ||
| 11 | ensure_sector_aligned, family, get_sector, Error, FlashLayout, FlashRegion, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, | ||
| 12 | WRITE_SIZE, | ||
| 13 | }; | ||
| 14 | use crate::peripherals::FLASH; | ||
| 7 | use crate::Peripheral; | 15 | use crate::Peripheral; |
| 8 | 16 | ||
| 9 | pub struct Flash<'d> { | 17 | pub struct Flash<'d> { |
| 10 | inner: PeripheralRef<'d, crate::peripherals::FLASH>, | 18 | pub(crate) inner: PeripheralRef<'d, FLASH>, |
| 11 | } | 19 | } |
| 12 | 20 | ||
| 21 | pub(crate) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(()); | ||
| 22 | |||
| 13 | impl<'d> Flash<'d> { | 23 | impl<'d> Flash<'d> { |
| 14 | pub fn new(p: impl Peripheral<P = crate::peripherals::FLASH> + 'd) -> Self { | 24 | pub fn new(p: impl Peripheral<P = FLASH> + 'd, irq: impl Peripheral<P = crate::interrupt::FLASH> + 'd) -> Self { |
| 15 | into_ref!(p); | 25 | into_ref!(p, irq); |
| 26 | |||
| 27 | irq.set_handler(family::on_interrupt); | ||
| 28 | irq.unpend(); | ||
| 29 | irq.enable(); | ||
| 30 | |||
| 16 | Self { inner: p } | 31 | Self { inner: p } |
| 17 | } | 32 | } |
| 18 | 33 | ||
| 19 | pub fn into_regions(self) -> FlashLayout<'d> { | 34 | pub fn into_regions(self) -> FlashLayout<'d> { |
| 20 | family::set_default_layout(); | 35 | family::set_default_layout(); |
| 21 | FlashLayout::new(self.release()) | 36 | FlashLayout::new(self.inner) |
| 22 | } | 37 | } |
| 23 | 38 | ||
| 24 | pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | 39 | pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { |
| 25 | blocking_read(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) | 40 | read_blocking(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) |
| 26 | } | 41 | } |
| 27 | 42 | ||
| 28 | pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | 43 | pub fn write_blocking(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { |
| 29 | unsafe { blocking_write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) } | 44 | unsafe { write_chunked_blocking(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) } |
| 30 | } | 45 | } |
| 31 | 46 | ||
| 32 | pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | 47 | pub fn erase_blocking(&mut self, from: u32, to: u32) -> Result<(), Error> { |
| 33 | unsafe { blocking_erase_sectored(FLASH_BASE as u32, from, to) } | 48 | unsafe { erase_sectored_blocking(FLASH_BASE as u32, from, to) } |
| 34 | } | ||
| 35 | |||
| 36 | pub(crate) fn release(self) -> PeripheralRef<'d, crate::peripherals::FLASH> { | ||
| 37 | unsafe { self.inner.clone_unchecked() } | ||
| 38 | } | 49 | } |
| 39 | } | 50 | } |
| 40 | 51 | ||
| 41 | pub(super) fn blocking_read(base: u32, size: u32, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | 52 | pub(super) fn read_blocking(base: u32, size: u32, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { |
| 42 | if offset + bytes.len() as u32 > size { | 53 | if offset + bytes.len() as u32 > size { |
| 43 | return Err(Error::Size); | 54 | return Err(Error::Size); |
| 44 | } | 55 | } |
| @@ -49,7 +60,7 @@ pub(super) fn blocking_read(base: u32, size: u32, offset: u32, bytes: &mut [u8]) | |||
| 49 | Ok(()) | 60 | Ok(()) |
| 50 | } | 61 | } |
| 51 | 62 | ||
| 52 | pub(super) unsafe fn blocking_write_chunked(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> { | 63 | pub(super) unsafe fn write_chunked_blocking(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> { |
| 53 | if offset + bytes.len() as u32 > size { | 64 | if offset + bytes.len() as u32 > size { |
| 54 | return Err(Error::Size); | 65 | return Err(Error::Size); |
| 55 | } | 66 | } |
| @@ -61,44 +72,31 @@ pub(super) unsafe fn blocking_write_chunked(base: u32, size: u32, offset: u32, b | |||
| 61 | trace!("Writing {} bytes at 0x{:x}", bytes.len(), address); | 72 | trace!("Writing {} bytes at 0x{:x}", bytes.len(), address); |
| 62 | 73 | ||
| 63 | for chunk in bytes.chunks(WRITE_SIZE) { | 74 | for chunk in bytes.chunks(WRITE_SIZE) { |
| 64 | critical_section::with(|_| { | 75 | family::clear_all_err(); |
| 65 | family::clear_all_err(); | 76 | fence(Ordering::SeqCst); |
| 66 | fence(Ordering::SeqCst); | 77 | family::unlock(); |
| 67 | family::unlock(); | 78 | fence(Ordering::SeqCst); |
| 79 | family::enable_blocking_write(); | ||
| 80 | fence(Ordering::SeqCst); | ||
| 81 | |||
| 82 | let _on_drop = OnDrop::new(|| { | ||
| 83 | family::disable_blocking_write(); | ||
| 68 | fence(Ordering::SeqCst); | 84 | fence(Ordering::SeqCst); |
| 69 | family::begin_write(); | 85 | family::lock(); |
| 70 | fence(Ordering::SeqCst); | 86 | }); |
| 71 | |||
| 72 | let _on_drop = OnDrop::new(|| { | ||
| 73 | family::end_write(); | ||
| 74 | fence(Ordering::SeqCst); | ||
| 75 | family::lock(); | ||
| 76 | }); | ||
| 77 | 87 | ||
| 78 | family::blocking_write(address, chunk.try_into().unwrap()) | 88 | family::write_blocking(address, chunk.try_into().unwrap())?; |
| 79 | })?; | ||
| 80 | address += WRITE_SIZE as u32; | 89 | address += WRITE_SIZE as u32; |
| 81 | } | 90 | } |
| 82 | Ok(()) | 91 | Ok(()) |
| 83 | } | 92 | } |
| 84 | 93 | ||
| 85 | pub(super) unsafe fn blocking_erase_sectored(base: u32, from: u32, to: u32) -> Result<(), Error> { | 94 | pub(super) unsafe fn erase_sectored_blocking(base: u32, from: u32, to: u32) -> Result<(), Error> { |
| 86 | let start_address = base + from; | 95 | let start_address = base + from; |
| 87 | let end_address = base + to; | 96 | let end_address = base + to; |
| 88 | let regions = family::get_flash_regions(); | 97 | let regions = family::get_flash_regions(); |
| 89 | 98 | ||
| 90 | // Test if the address range is aligned at sector base addresses | 99 | ensure_sector_aligned(start_address, end_address, regions)?; |
| 91 | let mut address = start_address; | ||
| 92 | while address < end_address { | ||
| 93 | let sector = get_sector(address, regions); | ||
| 94 | if sector.start != address { | ||
| 95 | return Err(Error::Unaligned); | ||
| 96 | } | ||
| 97 | address += sector.size; | ||
| 98 | } | ||
| 99 | if address != end_address { | ||
| 100 | return Err(Error::Unaligned); | ||
| 101 | } | ||
| 102 | 100 | ||
| 103 | trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); | 101 | trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); |
| 104 | 102 | ||
| @@ -107,104 +105,146 @@ pub(super) unsafe fn blocking_erase_sectored(base: u32, from: u32, to: u32) -> R | |||
| 107 | let sector = get_sector(address, regions); | 105 | let sector = get_sector(address, regions); |
| 108 | trace!("Erasing sector: {:?}", sector); | 106 | trace!("Erasing sector: {:?}", sector); |
| 109 | 107 | ||
| 110 | critical_section::with(|_| { | 108 | family::clear_all_err(); |
| 111 | family::clear_all_err(); | 109 | fence(Ordering::SeqCst); |
| 112 | fence(Ordering::SeqCst); | 110 | family::unlock(); |
| 113 | family::unlock(); | 111 | fence(Ordering::SeqCst); |
| 114 | fence(Ordering::SeqCst); | ||
| 115 | 112 | ||
| 116 | let _on_drop = OnDrop::new(|| { | 113 | let _on_drop = OnDrop::new(|| family::lock()); |
| 117 | family::lock(); | ||
| 118 | }); | ||
| 119 | 114 | ||
| 120 | family::blocking_erase_sector(§or) | 115 | family::erase_sector_blocking(§or)?; |
| 121 | })?; | ||
| 122 | address += sector.size; | 116 | address += sector.size; |
| 123 | } | 117 | } |
| 124 | Ok(()) | 118 | Ok(()) |
| 125 | } | 119 | } |
| 126 | 120 | ||
| 127 | pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector { | 121 | impl embedded_storage::nor_flash::ErrorType for Flash<'_> { |
| 128 | let mut current_bank = FlashBank::Bank1; | 122 | type Error = Error; |
| 129 | let mut bank_offset = 0; | 123 | } |
| 130 | for region in regions { | ||
| 131 | if region.bank != current_bank { | ||
| 132 | current_bank = region.bank; | ||
| 133 | bank_offset = 0; | ||
| 134 | } | ||
| 135 | 124 | ||
| 136 | if address < region.end() { | 125 | impl embedded_storage::nor_flash::ReadNorFlash for Flash<'_> { |
| 137 | let index_in_region = (address - region.base) / region.erase_size; | 126 | const READ_SIZE: usize = READ_SIZE; |
| 138 | return FlashSector { | ||
| 139 | bank: region.bank, | ||
| 140 | index_in_bank: bank_offset + index_in_region as u8, | ||
| 141 | start: region.base + index_in_region * region.erase_size, | ||
| 142 | size: region.erase_size, | ||
| 143 | }; | ||
| 144 | } | ||
| 145 | 127 | ||
| 146 | bank_offset += region.sectors(); | 128 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { |
| 129 | self.read(offset, bytes) | ||
| 147 | } | 130 | } |
| 148 | 131 | ||
| 149 | panic!("Flash sector not found"); | 132 | fn capacity(&self) -> usize { |
| 133 | FLASH_SIZE | ||
| 134 | } | ||
| 150 | } | 135 | } |
| 151 | 136 | ||
| 152 | impl FlashRegion { | 137 | impl embedded_storage::nor_flash::NorFlash for Flash<'_> { |
| 153 | pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | 138 | const WRITE_SIZE: usize = WRITE_SIZE; |
| 154 | blocking_read(self.base, self.size, offset, bytes) | 139 | const ERASE_SIZE: usize = MAX_ERASE_SIZE; |
| 140 | |||
| 141 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | ||
| 142 | self.write_blocking(offset, bytes) | ||
| 143 | } | ||
| 144 | |||
| 145 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | ||
| 146 | self.erase_blocking(from, to) | ||
| 155 | } | 147 | } |
| 148 | } | ||
| 149 | |||
| 150 | #[cfg(feature = "nightly")] | ||
| 151 | impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_> { | ||
| 152 | const READ_SIZE: usize = READ_SIZE; | ||
| 156 | 153 | ||
| 157 | pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | 154 | async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { |
| 158 | unsafe { blocking_write_chunked(self.base, self.size, offset, bytes) } | 155 | self.read(offset, bytes) |
| 159 | } | 156 | } |
| 160 | 157 | ||
| 161 | pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | 158 | fn capacity(&self) -> usize { |
| 162 | unsafe { blocking_erase_sectored(self.base, from, to) } | 159 | FLASH_SIZE |
| 163 | } | 160 | } |
| 164 | } | 161 | } |
| 165 | 162 | ||
| 166 | impl embedded_storage::nor_flash::ErrorType for Flash<'_> { | 163 | pub struct BlockingFlashRegion<'d, const WRITE_SIZE: u32, const ERASE_SIZE: u32>( |
| 164 | &'static FlashRegion, | ||
| 165 | PeripheralRef<'d, FLASH>, | ||
| 166 | ); | ||
| 167 | |||
| 168 | impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> { | ||
| 169 | pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | ||
| 170 | read_blocking(self.0.base, self.0.size, offset, bytes) | ||
| 171 | } | ||
| 172 | |||
| 173 | pub fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | ||
| 174 | let _guard = block_on(REGION_ACCESS.lock()); | ||
| 175 | unsafe { write_chunked_blocking(self.0.base, self.0.size, offset, bytes) } | ||
| 176 | } | ||
| 177 | |||
| 178 | pub fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | ||
| 179 | let _guard = block_on(REGION_ACCESS.lock()); | ||
| 180 | unsafe { erase_sectored_blocking(self.0.base, from, to) } | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> embedded_storage::nor_flash::ErrorType | ||
| 185 | for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> | ||
| 186 | { | ||
| 167 | type Error = Error; | 187 | type Error = Error; |
| 168 | } | 188 | } |
| 169 | 189 | ||
| 170 | impl embedded_storage::nor_flash::ReadNorFlash for Flash<'_> { | 190 | impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> embedded_storage::nor_flash::ReadNorFlash |
| 171 | const READ_SIZE: usize = 1; | 191 | for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> |
| 192 | { | ||
| 193 | const READ_SIZE: usize = READ_SIZE; | ||
| 172 | 194 | ||
| 173 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | 195 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { |
| 174 | self.blocking_read(offset, bytes) | 196 | self.read(offset, bytes) |
| 175 | } | 197 | } |
| 176 | 198 | ||
| 177 | fn capacity(&self) -> usize { | 199 | fn capacity(&self) -> usize { |
| 178 | FLASH_SIZE | 200 | self.0.size as usize |
| 179 | } | 201 | } |
| 180 | } | 202 | } |
| 181 | 203 | ||
| 182 | impl embedded_storage::nor_flash::NorFlash for Flash<'_> { | 204 | impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> embedded_storage::nor_flash::NorFlash |
| 183 | const WRITE_SIZE: usize = WRITE_SIZE; | 205 | for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> |
| 184 | const ERASE_SIZE: usize = MAX_ERASE_SIZE; | 206 | { |
| 207 | const WRITE_SIZE: usize = WRITE_SIZE as usize; | ||
| 208 | const ERASE_SIZE: usize = ERASE_SIZE as usize; | ||
| 185 | 209 | ||
| 186 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | 210 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { |
| 187 | self.blocking_write(offset, bytes) | 211 | self.write(offset, bytes) |
| 188 | } | 212 | } |
| 189 | 213 | ||
| 190 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | 214 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { |
| 191 | self.blocking_erase(from, to) | 215 | self.erase(from, to) |
| 192 | } | 216 | } |
| 193 | } | 217 | } |
| 194 | 218 | ||
| 195 | foreach_flash_region! { | 219 | foreach_flash_region! { |
| 196 | ($type_name:ident, $write_size:literal, $erase_size:literal) => { | 220 | ($type_name:ident, $write_size:literal, $erase_size:literal) => { |
| 197 | impl crate::_generated::flash_regions::$type_name<'_> { | 221 | paste::paste! { |
| 198 | pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | 222 | pub type [<Blocking $type_name>]<'d> = BlockingFlashRegion<'d, $write_size, $erase_size>; |
| 199 | blocking_read(self.0.base, self.0.size, offset, bytes) | 223 | } |
| 224 | |||
| 225 | impl<'d> crate::_generated::flash_regions::$type_name<'d> { | ||
| 226 | /// Make this flash region work in a blocking context. | ||
| 227 | /// | ||
| 228 | /// SAFETY | ||
| 229 | /// | ||
| 230 | /// This function is unsafe as incorect usage of parallel blocking operations | ||
| 231 | /// on multiple regions may cause a deadlock because each region requires mutual access to the flash. | ||
| 232 | pub unsafe fn into_blocking(self) -> BlockingFlashRegion<'d, $write_size, $erase_size> { | ||
| 233 | BlockingFlashRegion(self.0, self.1) | ||
| 200 | } | 234 | } |
| 201 | 235 | ||
| 202 | pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | 236 | pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { |
| 203 | unsafe { blocking_write_chunked(self.0.base, self.0.size, offset, bytes) } | 237 | read_blocking(self.0.base, self.0.size, offset, bytes) |
| 204 | } | 238 | } |
| 205 | 239 | ||
| 206 | pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | 240 | pub fn try_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { |
| 207 | unsafe { blocking_erase_sectored(self.0.base, from, to) } | 241 | let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?; |
| 242 | unsafe { write_chunked_blocking(self.0.base, self.0.size, offset, bytes) } | ||
| 243 | } | ||
| 244 | |||
| 245 | pub fn try_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | ||
| 246 | let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?; | ||
| 247 | unsafe { erase_sectored_blocking(self.0.base, from, to) } | ||
| 208 | } | 248 | } |
| 209 | } | 249 | } |
| 210 | 250 | ||
| @@ -213,28 +253,15 @@ foreach_flash_region! { | |||
| 213 | } | 253 | } |
| 214 | 254 | ||
| 215 | impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> { | 255 | impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> { |
| 216 | const READ_SIZE: usize = 1; | 256 | const READ_SIZE: usize = READ_SIZE; |
| 217 | 257 | ||
| 218 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | 258 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { |
| 219 | self.blocking_read(offset, bytes) | 259 | self.read(offset, bytes) |
| 220 | } | 260 | } |
| 221 | 261 | ||
| 222 | fn capacity(&self) -> usize { | 262 | fn capacity(&self) -> usize { |
| 223 | self.0.size as usize | 263 | self.0.size as usize |
| 224 | } | 264 | } |
| 225 | } | 265 | } |
| 226 | |||
| 227 | impl embedded_storage::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_> { | ||
| 228 | const WRITE_SIZE: usize = $write_size; | ||
| 229 | const ERASE_SIZE: usize = $erase_size; | ||
| 230 | |||
| 231 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | ||
| 232 | self.blocking_write(offset, bytes) | ||
| 233 | } | ||
| 234 | |||
| 235 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | ||
| 236 | self.blocking_erase(from, to) | ||
| 237 | } | ||
| 238 | } | ||
| 239 | }; | 266 | }; |
| 240 | } | 267 | } |
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] { | |||
| 13 | &FLASH_REGIONS | 13 | &FLASH_REGIONS |
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | pub(crate) unsafe fn on_interrupt(_: *mut ()) { | ||
| 17 | unimplemented!(); | ||
| 18 | } | ||
| 19 | |||
| 16 | pub(crate) unsafe fn lock() { | 20 | pub(crate) unsafe fn lock() { |
| 17 | pac::FLASH.cr().modify(|w| w.set_lock(true)); | 21 | pac::FLASH.cr().modify(|w| w.set_lock(true)); |
| 18 | } | 22 | } |
| @@ -22,17 +26,17 @@ pub(crate) unsafe fn unlock() { | |||
| 22 | pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); | 26 | pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); |
| 23 | } | 27 | } |
| 24 | 28 | ||
| 25 | pub(crate) unsafe fn begin_write() { | 29 | pub(crate) unsafe fn enable_blocking_write() { |
| 26 | assert_eq!(0, WRITE_SIZE % 2); | 30 | assert_eq!(0, WRITE_SIZE % 2); |
| 27 | 31 | ||
| 28 | pac::FLASH.cr().write(|w| w.set_pg(true)); | 32 | pac::FLASH.cr().write(|w| w.set_pg(true)); |
| 29 | } | 33 | } |
| 30 | 34 | ||
| 31 | pub(crate) unsafe fn end_write() { | 35 | pub(crate) unsafe fn disable_blocking_write() { |
| 32 | pac::FLASH.cr().write(|w| w.set_pg(false)); | 36 | pac::FLASH.cr().write(|w| w.set_pg(false)); |
| 33 | } | 37 | } |
| 34 | 38 | ||
| 35 | pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | 39 | pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { |
| 36 | let mut address = start_address; | 40 | let mut address = start_address; |
| 37 | for chunk in buf.chunks(2) { | 41 | for chunk in buf.chunks(2) { |
| 38 | write_volatile(address as *mut u16, u16::from_le_bytes(chunk.try_into().unwrap())); | 42 | 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]) | |||
| 42 | fence(Ordering::SeqCst); | 46 | fence(Ordering::SeqCst); |
| 43 | } | 47 | } |
| 44 | 48 | ||
| 45 | blocking_wait_ready() | 49 | wait_ready_blocking() |
| 46 | } | 50 | } |
| 47 | 51 | ||
| 48 | pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { | 52 | pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> { |
| 49 | pac::FLASH.cr().modify(|w| { | 53 | pac::FLASH.cr().modify(|w| { |
| 50 | w.set_per(true); | 54 | w.set_per(true); |
| 51 | }); | 55 | }); |
| @@ -56,7 +60,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 56 | w.set_strt(true); | 60 | w.set_strt(true); |
| 57 | }); | 61 | }); |
| 58 | 62 | ||
| 59 | let mut ret: Result<(), Error> = blocking_wait_ready(); | 63 | let mut ret: Result<(), Error> = wait_ready_blocking(); |
| 60 | 64 | ||
| 61 | if !pac::FLASH.sr().read().eop() { | 65 | if !pac::FLASH.sr().read().eop() { |
| 62 | trace!("FLASH: EOP not set"); | 66 | trace!("FLASH: EOP not set"); |
| @@ -88,7 +92,7 @@ pub(crate) unsafe fn clear_all_err() { | |||
| 88 | }); | 92 | }); |
| 89 | } | 93 | } |
| 90 | 94 | ||
| 91 | unsafe fn blocking_wait_ready() -> Result<(), Error> { | 95 | unsafe fn wait_ready_blocking() -> Result<(), Error> { |
| 92 | loop { | 96 | loop { |
| 93 | let sr = pac::FLASH.sr().read(); | 97 | let sr = pac::FLASH.sr().read(); |
| 94 | 98 | ||
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] { | |||
| 13 | &FLASH_REGIONS | 13 | &FLASH_REGIONS |
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | pub(crate) unsafe fn on_interrupt(_: *mut ()) { | ||
| 17 | unimplemented!(); | ||
| 18 | } | ||
| 19 | |||
| 16 | pub(crate) unsafe fn lock() { | 20 | pub(crate) unsafe fn lock() { |
| 17 | pac::FLASH.cr().modify(|w| w.set_lock(true)); | 21 | pac::FLASH.cr().modify(|w| w.set_lock(true)); |
| 18 | } | 22 | } |
| @@ -22,17 +26,17 @@ pub(crate) unsafe fn unlock() { | |||
| 22 | pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); | 26 | pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); |
| 23 | } | 27 | } |
| 24 | 28 | ||
| 25 | pub(crate) unsafe fn begin_write() { | 29 | pub(crate) unsafe fn enable_blocking_write() { |
| 26 | assert_eq!(0, WRITE_SIZE % 2); | 30 | assert_eq!(0, WRITE_SIZE % 2); |
| 27 | 31 | ||
| 28 | pac::FLASH.cr().write(|w| w.set_pg(true)); | 32 | pac::FLASH.cr().write(|w| w.set_pg(true)); |
| 29 | } | 33 | } |
| 30 | 34 | ||
| 31 | pub(crate) unsafe fn end_write() { | 35 | pub(crate) unsafe fn disable_blocking_write() { |
| 32 | pac::FLASH.cr().write(|w| w.set_pg(false)); | 36 | pac::FLASH.cr().write(|w| w.set_pg(false)); |
| 33 | } | 37 | } |
| 34 | 38 | ||
| 35 | pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | 39 | pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { |
| 36 | let mut address = start_address; | 40 | let mut address = start_address; |
| 37 | for chunk in buf.chunks(2) { | 41 | for chunk in buf.chunks(2) { |
| 38 | write_volatile(address as *mut u16, u16::from_le_bytes(chunk.try_into().unwrap())); | 42 | 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]) | |||
| 42 | fence(Ordering::SeqCst); | 46 | fence(Ordering::SeqCst); |
| 43 | } | 47 | } |
| 44 | 48 | ||
| 45 | blocking_wait_ready() | 49 | wait_ready_blocking() |
| 46 | } | 50 | } |
| 47 | 51 | ||
| 48 | pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { | 52 | pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> { |
| 49 | pac::FLASH.cr().modify(|w| { | 53 | pac::FLASH.cr().modify(|w| { |
| 50 | w.set_per(true); | 54 | w.set_per(true); |
| 51 | }); | 55 | }); |
| @@ -56,7 +60,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 56 | w.set_strt(true); | 60 | w.set_strt(true); |
| 57 | }); | 61 | }); |
| 58 | 62 | ||
| 59 | let mut ret: Result<(), Error> = blocking_wait_ready(); | 63 | let mut ret: Result<(), Error> = wait_ready_blocking(); |
| 60 | 64 | ||
| 61 | if !pac::FLASH.sr().read().eop() { | 65 | if !pac::FLASH.sr().read().eop() { |
| 62 | trace!("FLASH: EOP not set"); | 66 | trace!("FLASH: EOP not set"); |
| @@ -88,7 +92,7 @@ pub(crate) unsafe fn clear_all_err() { | |||
| 88 | }); | 92 | }); |
| 89 | } | 93 | } |
| 90 | 94 | ||
| 91 | unsafe fn blocking_wait_ready() -> Result<(), Error> { | 95 | unsafe fn wait_ready_blocking() -> Result<(), Error> { |
| 92 | loop { | 96 | loop { |
| 93 | let sr = pac::FLASH.sr().read(); | 97 | let sr = pac::FLASH.sr().read(); |
| 94 | 98 | ||
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; | |||
| 2 | use core::ptr::write_volatile; | 2 | use core::ptr::write_volatile; |
| 3 | use core::sync::atomic::{fence, Ordering}; | 3 | use core::sync::atomic::{fence, Ordering}; |
| 4 | 4 | ||
| 5 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 6 | |||
| 5 | use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | 7 | use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; |
| 6 | use crate::flash::Error; | 8 | use crate::flash::Error; |
| 7 | use crate::pac; | 9 | use crate::pac; |
| @@ -13,8 +15,8 @@ mod alt_regions { | |||
| 13 | 15 | ||
| 14 | use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION}; | 16 | use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION}; |
| 15 | use crate::flash::{ | 17 | use crate::flash::{ |
| 16 | blocking_erase_sectored, blocking_read, blocking_write_chunked, Bank1Region1, Bank1Region2, Error, Flash, | 18 | asynch, common, Bank1Region1, Bank1Region2, BlockingFlashRegion, Error, Flash, FlashBank, FlashRegion, |
| 17 | FlashBank, FlashRegion, | 19 | READ_SIZE, REGION_ACCESS, |
| 18 | }; | 20 | }; |
| 19 | use crate::peripherals::FLASH; | 21 | use crate::peripherals::FLASH; |
| 20 | 22 | ||
| @@ -53,6 +55,15 @@ mod alt_regions { | |||
| 53 | pub struct AltBank2Region2<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); | 55 | pub struct AltBank2Region2<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); |
| 54 | pub struct AltBank2Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); | 56 | pub struct AltBank2Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); |
| 55 | 57 | ||
| 58 | pub type BlockingAltBank1Region3<'d> = | ||
| 59 | BlockingFlashRegion<'d, { ALT_BANK1_REGION3.write_size }, { ALT_BANK1_REGION3.erase_size }>; | ||
| 60 | pub type BlockingAltBank2Region1<'d> = | ||
| 61 | BlockingFlashRegion<'d, { ALT_BANK2_REGION1.write_size }, { ALT_BANK2_REGION1.erase_size }>; | ||
| 62 | pub type BlockingAltBank2Region2<'d> = | ||
| 63 | BlockingFlashRegion<'d, { ALT_BANK2_REGION2.write_size }, { ALT_BANK2_REGION2.erase_size }>; | ||
| 64 | pub type BlockingAltBank2Region3<'d> = | ||
| 65 | BlockingFlashRegion<'d, { ALT_BANK2_REGION3.write_size }, { ALT_BANK2_REGION3.erase_size }>; | ||
| 66 | |||
| 56 | pub struct AltFlashLayout<'d> { | 67 | pub struct AltFlashLayout<'d> { |
| 57 | pub bank1_region1: Bank1Region1<'d>, | 68 | pub bank1_region1: Bank1Region1<'d>, |
| 58 | pub bank1_region2: Bank1Region2<'d>, | 69 | pub bank1_region2: Bank1Region2<'d>, |
| @@ -69,7 +80,7 @@ mod alt_regions { | |||
| 69 | 80 | ||
| 70 | // SAFETY: We never expose the cloned peripheral references, and their instance is not public. | 81 | // SAFETY: We never expose the cloned peripheral references, and their instance is not public. |
| 71 | // Also, all blocking flash region operations are protected with a cs. | 82 | // Also, all blocking flash region operations are protected with a cs. |
| 72 | let p = self.release(); | 83 | let p = self.inner; |
| 73 | AltFlashLayout { | 84 | AltFlashLayout { |
| 74 | bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }), | 85 | bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }), |
| 75 | bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }), | 86 | bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }), |
| @@ -85,16 +96,30 @@ mod alt_regions { | |||
| 85 | macro_rules! foreach_altflash_region { | 96 | macro_rules! foreach_altflash_region { |
| 86 | ($type_name:ident, $region:ident) => { | 97 | ($type_name:ident, $region:ident) => { |
| 87 | impl $type_name<'_> { | 98 | impl $type_name<'_> { |
| 88 | pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | 99 | pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { |
| 89 | blocking_read(self.0.base, self.0.size, offset, bytes) | 100 | common::read_blocking(self.0.base, self.0.size, offset, bytes) |
| 101 | } | ||
| 102 | |||
| 103 | #[cfg(all(feature = "nightly"))] | ||
| 104 | pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | ||
| 105 | let _guard = REGION_ACCESS.lock().await; | ||
| 106 | unsafe { asynch::write_chunked(self.0.base, self.0.size, offset, bytes).await } | ||
| 90 | } | 107 | } |
| 91 | 108 | ||
| 92 | pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | 109 | #[cfg(all(feature = "nightly"))] |
| 93 | unsafe { blocking_write_chunked(self.0.base, self.0.size, offset, bytes) } | 110 | pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { |
| 111 | let _guard = REGION_ACCESS.lock().await; | ||
| 112 | unsafe { asynch::erase_sectored(self.0.base, from, to).await } | ||
| 94 | } | 113 | } |
| 95 | 114 | ||
| 96 | pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | 115 | pub fn try_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { |
| 97 | unsafe { blocking_erase_sectored(self.0.base, from, to) } | 116 | let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?; |
| 117 | unsafe { common::write_chunked_blocking(self.0.base, self.0.size, offset, bytes) } | ||
| 118 | } | ||
| 119 | |||
| 120 | pub fn try_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | ||
| 121 | let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?; | ||
| 122 | unsafe { common::erase_sectored_blocking(self.0.base, from, to) } | ||
| 98 | } | 123 | } |
| 99 | } | 124 | } |
| 100 | 125 | ||
| @@ -103,10 +128,22 @@ mod alt_regions { | |||
| 103 | } | 128 | } |
| 104 | 129 | ||
| 105 | impl embedded_storage::nor_flash::ReadNorFlash for $type_name<'_> { | 130 | impl embedded_storage::nor_flash::ReadNorFlash for $type_name<'_> { |
| 106 | const READ_SIZE: usize = 1; | 131 | const READ_SIZE: usize = READ_SIZE; |
| 107 | 132 | ||
| 108 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | 133 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { |
| 109 | self.blocking_read(offset, bytes) | 134 | self.read(offset, bytes) |
| 135 | } | ||
| 136 | |||
| 137 | fn capacity(&self) -> usize { | ||
| 138 | self.0.size as usize | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_> { | ||
| 143 | const READ_SIZE: usize = READ_SIZE; | ||
| 144 | |||
| 145 | async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | ||
| 146 | self.read(offset, bytes) | ||
| 110 | } | 147 | } |
| 111 | 148 | ||
| 112 | fn capacity(&self) -> usize { | 149 | fn capacity(&self) -> usize { |
| @@ -114,16 +151,16 @@ mod alt_regions { | |||
| 114 | } | 151 | } |
| 115 | } | 152 | } |
| 116 | 153 | ||
| 117 | impl embedded_storage::nor_flash::NorFlash for $type_name<'_> { | 154 | impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_> { |
| 118 | const WRITE_SIZE: usize = $region.write_size as usize; | 155 | const WRITE_SIZE: usize = $region.write_size as usize; |
| 119 | const ERASE_SIZE: usize = $region.erase_size as usize; | 156 | const ERASE_SIZE: usize = $region.erase_size as usize; |
| 120 | 157 | ||
| 121 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | 158 | async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { |
| 122 | self.blocking_write(offset, bytes) | 159 | self.write(offset, bytes).await |
| 123 | } | 160 | } |
| 124 | 161 | ||
| 125 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | 162 | async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { |
| 126 | self.blocking_erase(from, to) | 163 | self.erase(from, to).await |
| 127 | } | 164 | } |
| 128 | } | 165 | } |
| 129 | }; | 166 | }; |
| @@ -138,6 +175,9 @@ mod alt_regions { | |||
| 138 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] | 175 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] |
| 139 | pub use alt_regions::*; | 176 | pub use alt_regions::*; |
| 140 | 177 | ||
| 178 | #[cfg(feature = "nightly")] | ||
| 179 | static WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 180 | |||
| 141 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] | 181 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] |
| 142 | pub fn set_default_layout() { | 182 | pub fn set_default_layout() { |
| 143 | unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(false)) }; | 183 | unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(false)) }; |
| @@ -160,6 +200,16 @@ pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | |||
| 160 | &FLASH_REGIONS | 200 | &FLASH_REGIONS |
| 161 | } | 201 | } |
| 162 | 202 | ||
| 203 | pub(crate) unsafe fn on_interrupt(_: *mut ()) { | ||
| 204 | // Clear IRQ flags | ||
| 205 | pac::FLASH.sr().write(|w| { | ||
| 206 | w.set_operr(true); | ||
| 207 | w.set_eop(true); | ||
| 208 | }); | ||
| 209 | |||
| 210 | WAKER.wake(); | ||
| 211 | } | ||
| 212 | |||
| 163 | pub(crate) unsafe fn lock() { | 213 | pub(crate) unsafe fn lock() { |
| 164 | pac::FLASH.cr().modify(|w| w.set_lock(true)); | 214 | pac::FLASH.cr().modify(|w| w.set_lock(true)); |
| 165 | } | 215 | } |
| @@ -169,20 +219,52 @@ pub(crate) unsafe fn unlock() { | |||
| 169 | pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); | 219 | pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); |
| 170 | } | 220 | } |
| 171 | 221 | ||
| 172 | pub(crate) unsafe fn begin_write() { | 222 | #[cfg(feature = "nightly")] |
| 223 | pub(crate) unsafe fn enable_write() { | ||
| 173 | assert_eq!(0, WRITE_SIZE % 4); | 224 | assert_eq!(0, WRITE_SIZE % 4); |
| 174 | 225 | ||
| 175 | pac::FLASH.cr().write(|w| { | 226 | pac::FLASH.cr().write(|w| { |
| 176 | w.set_pg(true); | 227 | w.set_pg(true); |
| 177 | w.set_psize(pac::flash::vals::Psize::PSIZE32); | 228 | w.set_psize(pac::flash::vals::Psize::PSIZE32); |
| 229 | w.set_eopie(true); | ||
| 230 | w.set_errie(true); | ||
| 231 | }); | ||
| 232 | } | ||
| 233 | |||
| 234 | #[cfg(feature = "nightly")] | ||
| 235 | pub(crate) unsafe fn disable_write() { | ||
| 236 | pac::FLASH.cr().write(|w| { | ||
| 237 | w.set_pg(false); | ||
| 238 | w.set_eopie(false); | ||
| 239 | w.set_errie(false); | ||
| 178 | }); | 240 | }); |
| 179 | } | 241 | } |
| 180 | 242 | ||
| 181 | pub(crate) unsafe fn end_write() { | 243 | pub(crate) unsafe fn enable_blocking_write() { |
| 244 | assert_eq!(0, WRITE_SIZE % 4); | ||
| 245 | |||
| 246 | pac::FLASH.cr().write(|w| { | ||
| 247 | w.set_pg(true); | ||
| 248 | w.set_psize(pac::flash::vals::Psize::PSIZE32); | ||
| 249 | }); | ||
| 250 | } | ||
| 251 | |||
| 252 | pub(crate) unsafe fn disable_blocking_write() { | ||
| 182 | pac::FLASH.cr().write(|w| w.set_pg(false)); | 253 | pac::FLASH.cr().write(|w| w.set_pg(false)); |
| 183 | } | 254 | } |
| 184 | 255 | ||
| 185 | pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | 256 | #[cfg(feature = "nightly")] |
| 257 | pub(crate) async unsafe fn write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | ||
| 258 | write_start(start_address, buf); | ||
| 259 | wait_ready().await | ||
| 260 | } | ||
| 261 | |||
| 262 | pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | ||
| 263 | write_start(start_address, buf); | ||
| 264 | wait_ready_blocking() | ||
| 265 | } | ||
| 266 | |||
| 267 | unsafe fn write_start(start_address: u32, buf: &[u8; WRITE_SIZE]) { | ||
| 186 | let mut address = start_address; | 268 | let mut address = start_address; |
| 187 | for val in buf.chunks(4) { | 269 | for val in buf.chunks(4) { |
| 188 | write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); | 270 | 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]) | |||
| 191 | // prevents parallelism errors | 273 | // prevents parallelism errors |
| 192 | fence(Ordering::SeqCst); | 274 | fence(Ordering::SeqCst); |
| 193 | } | 275 | } |
| 276 | } | ||
| 277 | |||
| 278 | pub(crate) async unsafe fn erase_sector(sector: &FlashSector) -> Result<(), Error> { | ||
| 279 | let snb = ((sector.bank as u8) << 4) + sector.index_in_bank; | ||
| 280 | |||
| 281 | pac::FLASH.cr().modify(|w| { | ||
| 282 | w.set_ser(true); | ||
| 283 | w.set_snb(snb); | ||
| 284 | w.set_eopie(true); | ||
| 285 | w.set_errie(true); | ||
| 286 | }); | ||
| 287 | |||
| 288 | pac::FLASH.cr().modify(|w| { | ||
| 289 | w.set_strt(true); | ||
| 290 | }); | ||
| 194 | 291 | ||
| 195 | blocking_wait_ready() | 292 | let ret: Result<(), Error> = wait_ready().await; |
| 293 | pac::FLASH.cr().modify(|w| { | ||
| 294 | w.set_eopie(false); | ||
| 295 | w.set_errie(false); | ||
| 296 | }); | ||
| 297 | clear_all_err(); | ||
| 298 | ret | ||
| 196 | } | 299 | } |
| 197 | 300 | ||
| 198 | pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { | 301 | pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> { |
| 199 | let snb = ((sector.bank as u8) << 4) + sector.index_in_bank; | 302 | let snb = ((sector.bank as u8) << 4) + sector.index_in_bank; |
| 200 | 303 | ||
| 201 | pac::FLASH.cr().modify(|w| { | 304 | pac::FLASH.cr().modify(|w| { |
| @@ -207,10 +310,8 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 207 | w.set_strt(true); | 310 | w.set_strt(true); |
| 208 | }); | 311 | }); |
| 209 | 312 | ||
| 210 | let ret: Result<(), Error> = blocking_wait_ready(); | 313 | let ret: Result<(), Error> = wait_ready_blocking(); |
| 211 | |||
| 212 | clear_all_err(); | 314 | clear_all_err(); |
| 213 | |||
| 214 | ret | 315 | ret |
| 215 | } | 316 | } |
| 216 | 317 | ||
| @@ -220,11 +321,39 @@ pub(crate) unsafe fn clear_all_err() { | |||
| 220 | w.set_pgperr(true); | 321 | w.set_pgperr(true); |
| 221 | w.set_pgaerr(true); | 322 | w.set_pgaerr(true); |
| 222 | w.set_wrperr(true); | 323 | w.set_wrperr(true); |
| 223 | w.set_eop(true); | ||
| 224 | }); | 324 | }); |
| 225 | } | 325 | } |
| 226 | 326 | ||
| 227 | unsafe fn blocking_wait_ready() -> Result<(), Error> { | 327 | #[cfg(feature = "nightly")] |
| 328 | pub(crate) async unsafe fn wait_ready() -> Result<(), Error> { | ||
| 329 | use core::task::Poll; | ||
| 330 | |||
| 331 | use futures::future::poll_fn; | ||
| 332 | |||
| 333 | poll_fn(|cx| { | ||
| 334 | WAKER.register(cx.waker()); | ||
| 335 | |||
| 336 | let sr = pac::FLASH.sr().read(); | ||
| 337 | if !sr.bsy() { | ||
| 338 | Poll::Ready(if sr.pgserr() { | ||
| 339 | Err(Error::Seq) | ||
| 340 | } else if sr.pgperr() { | ||
| 341 | Err(Error::Parallelism) | ||
| 342 | } else if sr.pgaerr() { | ||
| 343 | Err(Error::Unaligned) | ||
| 344 | } else if sr.wrperr() { | ||
| 345 | Err(Error::Protected) | ||
| 346 | } else { | ||
| 347 | Ok(()) | ||
| 348 | }) | ||
| 349 | } else { | ||
| 350 | return Poll::Pending; | ||
| 351 | } | ||
| 352 | }) | ||
| 353 | .await | ||
| 354 | } | ||
| 355 | |||
| 356 | unsafe fn wait_ready_blocking() -> Result<(), Error> { | ||
| 228 | loop { | 357 | loop { |
| 229 | let sr = pac::FLASH.sr().read(); | 358 | let sr = pac::FLASH.sr().read(); |
| 230 | 359 | ||
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] { | |||
| 12 | &FLASH_REGIONS | 12 | &FLASH_REGIONS |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | pub(crate) unsafe fn on_interrupt(_: *mut ()) { | ||
| 16 | unimplemented!(); | ||
| 17 | } | ||
| 18 | |||
| 15 | pub(crate) unsafe fn lock() { | 19 | pub(crate) unsafe fn lock() { |
| 16 | pac::FLASH.cr().modify(|w| w.set_lock(true)); | 20 | pac::FLASH.cr().modify(|w| w.set_lock(true)); |
| 17 | } | 21 | } |
| @@ -21,7 +25,7 @@ pub(crate) unsafe fn unlock() { | |||
| 21 | pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); | 25 | pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); |
| 22 | } | 26 | } |
| 23 | 27 | ||
| 24 | pub(crate) unsafe fn begin_write() { | 28 | pub(crate) unsafe fn enable_blocking_write() { |
| 25 | assert_eq!(0, WRITE_SIZE % 4); | 29 | assert_eq!(0, WRITE_SIZE % 4); |
| 26 | 30 | ||
| 27 | pac::FLASH.cr().write(|w| { | 31 | pac::FLASH.cr().write(|w| { |
| @@ -30,11 +34,11 @@ pub(crate) unsafe fn begin_write() { | |||
| 30 | }); | 34 | }); |
| 31 | } | 35 | } |
| 32 | 36 | ||
| 33 | pub(crate) unsafe fn end_write() { | 37 | pub(crate) unsafe fn disable_blocking_write() { |
| 34 | pac::FLASH.cr().write(|w| w.set_pg(false)); | 38 | pac::FLASH.cr().write(|w| w.set_pg(false)); |
| 35 | } | 39 | } |
| 36 | 40 | ||
| 37 | pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | 41 | pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { |
| 38 | let mut address = start_address; | 42 | let mut address = start_address; |
| 39 | for val in buf.chunks(4) { | 43 | for val in buf.chunks(4) { |
| 40 | write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); | 44 | 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]) | |||
| 44 | fence(Ordering::SeqCst); | 48 | fence(Ordering::SeqCst); |
| 45 | } | 49 | } |
| 46 | 50 | ||
| 47 | blocking_wait_ready() | 51 | wait_ready_blocking() |
| 48 | } | 52 | } |
| 49 | 53 | ||
| 50 | pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { | 54 | pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> { |
| 51 | pac::FLASH.cr().modify(|w| { | 55 | pac::FLASH.cr().modify(|w| { |
| 52 | w.set_ser(true); | 56 | w.set_ser(true); |
| 53 | w.set_snb(sector.index_in_bank) | 57 | w.set_snb(sector.index_in_bank) |
| @@ -57,12 +61,9 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 57 | w.set_strt(true); | 61 | w.set_strt(true); |
| 58 | }); | 62 | }); |
| 59 | 63 | ||
| 60 | let ret: Result<(), Error> = blocking_wait_ready(); | 64 | let ret: Result<(), Error> = wait_ready_blocking(); |
| 61 | |||
| 62 | pac::FLASH.cr().modify(|w| w.set_ser(false)); | 65 | pac::FLASH.cr().modify(|w| w.set_ser(false)); |
| 63 | |||
| 64 | clear_all_err(); | 66 | clear_all_err(); |
| 65 | |||
| 66 | ret | 67 | ret |
| 67 | } | 68 | } |
| 68 | 69 | ||
| @@ -86,7 +87,7 @@ pub(crate) unsafe fn clear_all_err() { | |||
| 86 | }); | 87 | }); |
| 87 | } | 88 | } |
| 88 | 89 | ||
| 89 | unsafe fn blocking_wait_ready() -> Result<(), Error> { | 90 | unsafe fn wait_ready_blocking() -> Result<(), Error> { |
| 90 | loop { | 91 | loop { |
| 91 | let sr = pac::FLASH.sr().read(); | 92 | let sr = pac::FLASH.sr().read(); |
| 92 | 93 | ||
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] { | |||
| 17 | &FLASH_REGIONS | 17 | &FLASH_REGIONS |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | pub(crate) unsafe fn on_interrupt(_: *mut ()) { | ||
| 21 | unimplemented!(); | ||
| 22 | } | ||
| 23 | |||
| 20 | pub(crate) unsafe fn lock() { | 24 | pub(crate) unsafe fn lock() { |
| 21 | pac::FLASH.bank(0).cr().modify(|w| w.set_lock(true)); | 25 | pac::FLASH.bank(0).cr().modify(|w| w.set_lock(true)); |
| 22 | if is_dual_bank() { | 26 | if is_dual_bank() { |
| @@ -33,13 +37,13 @@ pub(crate) unsafe fn unlock() { | |||
| 33 | } | 37 | } |
| 34 | } | 38 | } |
| 35 | 39 | ||
| 36 | pub(crate) unsafe fn begin_write() { | 40 | pub(crate) unsafe fn enable_blocking_write() { |
| 37 | assert_eq!(0, WRITE_SIZE % 4); | 41 | assert_eq!(0, WRITE_SIZE % 4); |
| 38 | } | 42 | } |
| 39 | 43 | ||
| 40 | pub(crate) unsafe fn end_write() {} | 44 | pub(crate) unsafe fn disable_blocking_write() {} |
| 41 | 45 | ||
| 42 | pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | 46 | pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { |
| 43 | // We cannot have the write setup sequence in begin_write as it depends on the address | 47 | // We cannot have the write setup sequence in begin_write as it depends on the address |
| 44 | let bank = if start_address < BANK1_REGION.end() { | 48 | let bank = if start_address < BANK1_REGION.end() { |
| 45 | pac::FLASH.bank(0) | 49 | pac::FLASH.bank(0) |
| @@ -60,7 +64,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) | |||
| 60 | write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); | 64 | write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); |
| 61 | address += val.len() as u32; | 65 | address += val.len() as u32; |
| 62 | 66 | ||
| 63 | res = Some(blocking_wait_ready(bank)); | 67 | res = Some(wait_ready_blocking(bank)); |
| 64 | bank.sr().modify(|w| { | 68 | bank.sr().modify(|w| { |
| 65 | if w.eop() { | 69 | if w.eop() { |
| 66 | w.set_eop(true); | 70 | w.set_eop(true); |
| @@ -80,7 +84,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) | |||
| 80 | res.unwrap() | 84 | res.unwrap() |
| 81 | } | 85 | } |
| 82 | 86 | ||
| 83 | pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { | 87 | pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> { |
| 84 | let bank = pac::FLASH.bank(sector.bank as usize); | 88 | let bank = pac::FLASH.bank(sector.bank as usize); |
| 85 | bank.cr().modify(|w| { | 89 | bank.cr().modify(|w| { |
| 86 | w.set_ser(true); | 90 | w.set_ser(true); |
| @@ -91,12 +95,9 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 91 | w.set_start(true); | 95 | w.set_start(true); |
| 92 | }); | 96 | }); |
| 93 | 97 | ||
| 94 | let ret: Result<(), Error> = blocking_wait_ready(bank); | 98 | let ret: Result<(), Error> = wait_ready_blocking(bank); |
| 95 | |||
| 96 | bank.cr().modify(|w| w.set_ser(false)); | 99 | bank.cr().modify(|w| w.set_ser(false)); |
| 97 | |||
| 98 | bank_clear_all_err(bank); | 100 | bank_clear_all_err(bank); |
| 99 | |||
| 100 | ret | 101 | ret |
| 101 | } | 102 | } |
| 102 | 103 | ||
| @@ -141,7 +142,7 @@ unsafe fn bank_clear_all_err(bank: pac::flash::Bank) { | |||
| 141 | }); | 142 | }); |
| 142 | } | 143 | } |
| 143 | 144 | ||
| 144 | unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> { | 145 | unsafe fn wait_ready_blocking(bank: pac::flash::Bank) -> Result<(), Error> { |
| 145 | loop { | 146 | loop { |
| 146 | let sr = bank.sr().read(); | 147 | let sr = bank.sr().read(); |
| 147 | 148 | ||
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] { | |||
| 12 | &FLASH_REGIONS | 12 | &FLASH_REGIONS |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | pub(crate) unsafe fn on_interrupt(_: *mut ()) { | ||
| 16 | unimplemented!(); | ||
| 17 | } | ||
| 18 | |||
| 15 | pub(crate) unsafe fn lock() { | 19 | pub(crate) unsafe fn lock() { |
| 16 | #[cfg(any(flash_wl, flash_wb, flash_l4))] | 20 | #[cfg(any(flash_wl, flash_wb, flash_l4))] |
| 17 | pac::FLASH.cr().modify(|w| w.set_lock(true)); | 21 | pac::FLASH.cr().modify(|w| w.set_lock(true)); |
| @@ -41,19 +45,19 @@ pub(crate) unsafe fn unlock() { | |||
| 41 | } | 45 | } |
| 42 | } | 46 | } |
| 43 | 47 | ||
| 44 | pub(crate) unsafe fn begin_write() { | 48 | pub(crate) unsafe fn enable_blocking_write() { |
| 45 | assert_eq!(0, WRITE_SIZE % 4); | 49 | assert_eq!(0, WRITE_SIZE % 4); |
| 46 | 50 | ||
| 47 | #[cfg(any(flash_wl, flash_wb, flash_l4))] | 51 | #[cfg(any(flash_wl, flash_wb, flash_l4))] |
| 48 | pac::FLASH.cr().write(|w| w.set_pg(true)); | 52 | pac::FLASH.cr().write(|w| w.set_pg(true)); |
| 49 | } | 53 | } |
| 50 | 54 | ||
| 51 | pub(crate) unsafe fn end_write() { | 55 | pub(crate) unsafe fn disable_blocking_write() { |
| 52 | #[cfg(any(flash_wl, flash_wb, flash_l4))] | 56 | #[cfg(any(flash_wl, flash_wb, flash_l4))] |
| 53 | pac::FLASH.cr().write(|w| w.set_pg(false)); | 57 | pac::FLASH.cr().write(|w| w.set_pg(false)); |
| 54 | } | 58 | } |
| 55 | 59 | ||
| 56 | pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | 60 | pub(crate) unsafe fn write_blocking(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { |
| 57 | let mut address = start_address; | 61 | let mut address = start_address; |
| 58 | for val in buf.chunks(4) { | 62 | for val in buf.chunks(4) { |
| 59 | write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); | 63 | 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]) | |||
| 63 | fence(Ordering::SeqCst); | 67 | fence(Ordering::SeqCst); |
| 64 | } | 68 | } |
| 65 | 69 | ||
| 66 | blocking_wait_ready() | 70 | wait_ready_blocking() |
| 67 | } | 71 | } |
| 68 | 72 | ||
| 69 | pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { | 73 | pub(crate) unsafe fn erase_sector_blocking(sector: &FlashSector) -> Result<(), Error> { |
| 70 | #[cfg(any(flash_l0, flash_l1))] | 74 | #[cfg(any(flash_l0, flash_l1))] |
| 71 | { | 75 | { |
| 72 | pac::FLASH.pecr().modify(|w| { | 76 | pac::FLASH.pecr().modify(|w| { |
| @@ -96,7 +100,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 96 | }); | 100 | }); |
| 97 | } | 101 | } |
| 98 | 102 | ||
| 99 | let ret: Result<(), Error> = blocking_wait_ready(); | 103 | let ret: Result<(), Error> = wait_ready_blocking(); |
| 100 | 104 | ||
| 101 | #[cfg(any(flash_wl, flash_wb, flash_l4))] | 105 | #[cfg(any(flash_wl, flash_wb, flash_l4))] |
| 102 | pac::FLASH.cr().modify(|w| w.set_per(false)); | 106 | pac::FLASH.cr().modify(|w| w.set_per(false)); |
| @@ -108,7 +112,6 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 108 | }); | 112 | }); |
| 109 | 113 | ||
| 110 | clear_all_err(); | 114 | clear_all_err(); |
| 111 | |||
| 112 | ret | 115 | ret |
| 113 | } | 116 | } |
| 114 | 117 | ||
| @@ -150,7 +153,7 @@ pub(crate) unsafe fn clear_all_err() { | |||
| 150 | }); | 153 | }); |
| 151 | } | 154 | } |
| 152 | 155 | ||
| 153 | unsafe fn blocking_wait_ready() -> Result<(), Error> { | 156 | unsafe fn wait_ready_blocking() -> Result<(), Error> { |
| 154 | loop { | 157 | loop { |
| 155 | let sr = pac::FLASH.sr().read(); | 158 | let sr = pac::FLASH.sr().read(); |
| 156 | 159 | ||
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 @@ | |||
| 1 | use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; | 1 | use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; |
| 2 | 2 | ||
| 3 | #[cfg(all(feature = "nightly", flash_f4))] | ||
| 4 | pub mod asynch; | ||
| 3 | #[cfg(flash)] | 5 | #[cfg(flash)] |
| 4 | mod common; | 6 | mod common; |
| 5 | 7 | ||
| @@ -10,6 +12,8 @@ pub use crate::_generated::flash_regions::*; | |||
| 10 | pub use crate::_generated::MAX_ERASE_SIZE; | 12 | pub use crate::_generated::MAX_ERASE_SIZE; |
| 11 | pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; | 13 | pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; |
| 12 | 14 | ||
| 15 | pub const READ_SIZE: usize = 1; | ||
| 16 | |||
| 13 | #[derive(Debug)] | 17 | #[derive(Debug)] |
| 14 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 18 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 15 | pub struct FlashRegion { | 19 | pub struct FlashRegion { |
| @@ -76,6 +80,7 @@ pub enum Error { | |||
| 76 | Protected, | 80 | Protected, |
| 77 | Unaligned, | 81 | Unaligned, |
| 78 | Parallelism, | 82 | Parallelism, |
| 83 | TryLockError, | ||
| 79 | } | 84 | } |
| 80 | 85 | ||
| 81 | impl NorFlashError for Error { | 86 | impl NorFlashError for Error { |
| @@ -87,3 +92,47 @@ impl NorFlashError for Error { | |||
| 87 | } | 92 | } |
| 88 | } | 93 | } |
| 89 | } | 94 | } |
| 95 | |||
| 96 | pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector { | ||
| 97 | let mut current_bank = FlashBank::Bank1; | ||
| 98 | let mut bank_offset = 0; | ||
| 99 | for region in regions { | ||
| 100 | if region.bank != current_bank { | ||
| 101 | current_bank = region.bank; | ||
| 102 | bank_offset = 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | if address < region.end() { | ||
| 106 | let index_in_region = (address - region.base) / region.erase_size; | ||
| 107 | return FlashSector { | ||
| 108 | bank: region.bank, | ||
| 109 | index_in_bank: bank_offset + index_in_region as u8, | ||
| 110 | start: region.base + index_in_region * region.erase_size, | ||
| 111 | size: region.erase_size, | ||
| 112 | }; | ||
| 113 | } | ||
| 114 | |||
| 115 | bank_offset += region.sectors(); | ||
| 116 | } | ||
| 117 | |||
| 118 | panic!("Flash sector not found"); | ||
| 119 | } | ||
| 120 | |||
| 121 | pub(crate) fn ensure_sector_aligned( | ||
| 122 | start_address: u32, | ||
| 123 | end_address: u32, | ||
| 124 | regions: &[&FlashRegion], | ||
| 125 | ) -> Result<(), Error> { | ||
| 126 | let mut address = start_address; | ||
| 127 | while address < end_address { | ||
| 128 | let sector = get_sector(address, regions); | ||
| 129 | if sector.start != address { | ||
| 130 | return Err(Error::Unaligned); | ||
| 131 | } | ||
| 132 | address += sector.size; | ||
| 133 | } | ||
| 134 | if address != end_address { | ||
| 135 | return Err(Error::Unaligned); | ||
| 136 | } | ||
| 137 | Ok(()) | ||
| 138 | } | ||
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] { | |||
| 8 | &FLASH_REGIONS | 8 | &FLASH_REGIONS |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | pub(crate) unsafe fn on_interrupt(_: *mut ()) { | ||
| 12 | unimplemented!(); | ||
| 13 | } | ||
| 14 | |||
| 11 | pub(crate) unsafe fn lock() { | 15 | pub(crate) unsafe fn lock() { |
| 12 | unimplemented!(); | 16 | unimplemented!(); |
| 13 | } | 17 | } |
| 14 | pub(crate) unsafe fn unlock() { | 18 | pub(crate) unsafe fn unlock() { |
| 15 | unimplemented!(); | 19 | unimplemented!(); |
| 16 | } | 20 | } |
| 17 | pub(crate) unsafe fn begin_write() { | 21 | pub(crate) unsafe fn enable_blocking_write() { |
| 18 | unimplemented!(); | 22 | unimplemented!(); |
| 19 | } | 23 | } |
| 20 | pub(crate) unsafe fn end_write() { | 24 | pub(crate) unsafe fn disable_blocking_write() { |
| 21 | unimplemented!(); | 25 | unimplemented!(); |
| 22 | } | 26 | } |
| 23 | pub(crate) unsafe fn blocking_write(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | 27 | pub(crate) unsafe fn write_blocking(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { |
| 24 | unimplemented!(); | 28 | unimplemented!(); |
| 25 | } | 29 | } |
| 26 | pub(crate) unsafe fn blocking_erase_sector(_sector: &FlashSector) -> Result<(), Error> { | 30 | pub(crate) unsafe fn erase_sector_blocking(_sector: &FlashSector) -> Result<(), Error> { |
| 27 | unimplemented!(); | 31 | unimplemented!(); |
| 28 | } | 32 | } |
| 29 | pub(crate) unsafe fn clear_all_err() { | 33 | pub(crate) unsafe fn clear_all_err() { |
