diff options
| author | Rasmus Melchior Jacobsen <[email protected]> | 2023-05-24 17:24:28 +0200 |
|---|---|---|
| committer | Rasmus Melchior Jacobsen <[email protected]> | 2023-05-25 20:07:42 +0200 |
| commit | 44b6494ab7ec3e742aa9f82a8ca9ebdfc23ebbba (patch) | |
| tree | b1266b7f9f0488017098bcca3f7ba3fb9e93603e /embassy-stm32/src | |
| parent | 6df62397048778ce521c14b21b4aced7c22567c2 (diff) | |
Let FlashLayout and FlashRegion depends on a Blocking/Async mode generic
Diffstat (limited to 'embassy-stm32/src')
| -rw-r--r-- | embassy-stm32/src/flash/asynch.rs | 35 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/common.rs | 218 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/f4.rs | 114 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/mod.rs | 3 |
4 files changed, 171 insertions, 199 deletions
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 @@ | |||
| 1 | use atomic_polyfill::{fence, Ordering}; | 1 | use atomic_polyfill::{fence, Ordering}; |
| 2 | use embassy_hal_common::drop::OnDrop; | 2 | use embassy_hal_common::drop::OnDrop; |
| 3 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 4 | use embassy_sync::mutex::Mutex; | ||
| 3 | 5 | ||
| 4 | use super::{ | 6 | use super::{ |
| 5 | ensure_sector_aligned, family, get_sector, Error, Flash, FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, | 7 | ensure_sector_aligned, family, get_sector, read_blocking, Async, Error, Flash, FlashLayout, FLASH_BASE, FLASH_SIZE, |
| 6 | REGION_ACCESS, WRITE_SIZE, | 8 | MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE, |
| 7 | }; | 9 | }; |
| 8 | 10 | ||
| 11 | pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(()); | ||
| 12 | |||
| 9 | impl<'d> Flash<'d> { | 13 | impl<'d> Flash<'d> { |
| 14 | pub fn into_regions(self) -> FlashLayout<'d, Async> { | ||
| 15 | family::set_default_layout(); | ||
| 16 | FlashLayout::new(self.inner) | ||
| 17 | } | ||
| 18 | |||
| 10 | pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | 19 | 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 } | 20 | unsafe { write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes).await } |
| 12 | } | 21 | } |
| @@ -16,6 +25,18 @@ impl<'d> Flash<'d> { | |||
| 16 | } | 25 | } |
| 17 | } | 26 | } |
| 18 | 27 | ||
| 28 | impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_> { | ||
| 29 | const READ_SIZE: usize = READ_SIZE; | ||
| 30 | |||
| 31 | async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | ||
| 32 | self.read(offset, bytes) | ||
| 33 | } | ||
| 34 | |||
| 35 | fn capacity(&self) -> usize { | ||
| 36 | FLASH_SIZE | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 19 | impl embedded_storage_async::nor_flash::NorFlash for Flash<'_> { | 40 | impl embedded_storage_async::nor_flash::NorFlash for Flash<'_> { |
| 20 | const WRITE_SIZE: usize = WRITE_SIZE; | 41 | const WRITE_SIZE: usize = WRITE_SIZE; |
| 21 | const ERASE_SIZE: usize = MAX_ERASE_SIZE; | 42 | 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 | |||
| 89 | 110 | ||
| 90 | foreach_flash_region! { | 111 | foreach_flash_region! { |
| 91 | ($type_name:ident, $write_size:literal, $erase_size:literal) => { | 112 | ($type_name:ident, $write_size:literal, $erase_size:literal) => { |
| 92 | impl crate::_generated::flash_regions::$type_name<'_> { | 113 | impl crate::_generated::flash_regions::$type_name<'_, Async> { |
| 114 | pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | ||
| 115 | read_blocking(self.0.base, self.0.size, offset, bytes) | ||
| 116 | } | ||
| 117 | |||
| 93 | pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | 118 | pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { |
| 94 | let _guard = REGION_ACCESS.lock().await; | 119 | let _guard = REGION_ACCESS.lock().await; |
| 95 | unsafe { write_chunked(self.0.base, self.0.size, offset, bytes).await } | 120 | unsafe { write_chunked(self.0.base, self.0.size, offset, bytes).await } |
| @@ -101,7 +126,7 @@ foreach_flash_region! { | |||
| 101 | } | 126 | } |
| 102 | } | 127 | } |
| 103 | 128 | ||
| 104 | impl embedded_storage_async::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> { | 129 | impl embedded_storage_async::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_, Async> { |
| 105 | const READ_SIZE: usize = READ_SIZE; | 130 | const READ_SIZE: usize = READ_SIZE; |
| 106 | 131 | ||
| 107 | async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | 132 | async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { |
| @@ -113,7 +138,7 @@ foreach_flash_region! { | |||
| 113 | } | 138 | } |
| 114 | } | 139 | } |
| 115 | 140 | ||
| 116 | impl embedded_storage_async::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_> { | 141 | impl embedded_storage_async::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_, Async> { |
| 117 | const WRITE_SIZE: usize = $write_size; | 142 | const WRITE_SIZE: usize = $write_size; |
| 118 | const ERASE_SIZE: usize = $erase_size; | 143 | const ERASE_SIZE: usize = $erase_size; |
| 119 | 144 | ||
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 @@ | |||
| 1 | use atomic_polyfill::{fence, Ordering}; | 1 | use atomic_polyfill::{fence, Ordering}; |
| 2 | use embassy_cortex_m::interrupt::InterruptExt; | 2 | use embassy_cortex_m::interrupt::InterruptExt; |
| 3 | use embassy_futures::block_on; | ||
| 4 | use embassy_hal_common::drop::OnDrop; | 3 | use embassy_hal_common::drop::OnDrop; |
| 5 | use embassy_hal_common::{into_ref, PeripheralRef}; | 4 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 6 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 7 | use embassy_sync::mutex::Mutex; | ||
| 8 | use stm32_metapac::FLASH_BASE; | 5 | use stm32_metapac::FLASH_BASE; |
| 9 | 6 | ||
| 10 | use super::{ | 7 | use super::{ |
| 11 | family, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE, | 8 | family, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, |
| 9 | WRITE_SIZE, | ||
| 12 | }; | 10 | }; |
| 13 | use crate::peripherals::FLASH; | 11 | use crate::peripherals::FLASH; |
| 14 | use crate::Peripheral; | 12 | use crate::Peripheral; |
| @@ -17,8 +15,6 @@ pub struct Flash<'d> { | |||
| 17 | pub(crate) inner: PeripheralRef<'d, FLASH>, | 15 | pub(crate) inner: PeripheralRef<'d, FLASH>, |
| 18 | } | 16 | } |
| 19 | 17 | ||
| 20 | pub(crate) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(()); | ||
| 21 | |||
| 22 | impl<'d> Flash<'d> { | 18 | impl<'d> Flash<'d> { |
| 23 | pub fn new(p: impl Peripheral<P = FLASH> + 'd, irq: impl Peripheral<P = crate::interrupt::FLASH> + 'd) -> Self { | 19 | pub fn new(p: impl Peripheral<P = FLASH> + 'd, irq: impl Peripheral<P = crate::interrupt::FLASH> + 'd) -> Self { |
| 24 | into_ref!(p, irq); | 20 | into_ref!(p, irq); |
| @@ -30,7 +26,7 @@ impl<'d> Flash<'d> { | |||
| 30 | Self { inner: p } | 26 | Self { inner: p } |
| 31 | } | 27 | } |
| 32 | 28 | ||
| 33 | pub fn into_regions(self) -> FlashLayout<'d> { | 29 | pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> { |
| 34 | family::set_default_layout(); | 30 | family::set_default_layout(); |
| 35 | FlashLayout::new(self.inner) | 31 | FlashLayout::new(self.inner) |
| 36 | } | 32 | } |
| @@ -40,11 +36,19 @@ impl<'d> Flash<'d> { | |||
| 40 | } | 36 | } |
| 41 | 37 | ||
| 42 | pub fn write_blocking(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | 38 | pub fn write_blocking(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { |
| 43 | unsafe { write_chunked_blocking(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) } | 39 | unsafe { |
| 40 | write_blocking( | ||
| 41 | FLASH_BASE as u32, | ||
| 42 | FLASH_SIZE as u32, | ||
| 43 | offset, | ||
| 44 | bytes, | ||
| 45 | write_chunk_unlocked, | ||
| 46 | ) | ||
| 47 | } | ||
| 44 | } | 48 | } |
| 45 | 49 | ||
| 46 | pub fn erase_blocking(&mut self, from: u32, to: u32) -> Result<(), Error> { | 50 | pub fn erase_blocking(&mut self, from: u32, to: u32) -> Result<(), Error> { |
| 47 | unsafe { erase_sectored_blocking(FLASH_BASE as u32, from, to) } | 51 | unsafe { erase_blocking(FLASH_BASE as u32, from, to, erase_sector_unlocked) } |
| 48 | } | 52 | } |
| 49 | } | 53 | } |
| 50 | 54 | ||
| @@ -59,7 +63,13 @@ pub(super) fn read_blocking(base: u32, size: u32, offset: u32, bytes: &mut [u8]) | |||
| 59 | Ok(()) | 63 | Ok(()) |
| 60 | } | 64 | } |
| 61 | 65 | ||
| 62 | pub(super) unsafe fn write_chunked_blocking(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> { | 66 | pub(super) unsafe fn write_blocking( |
| 67 | base: u32, | ||
| 68 | size: u32, | ||
| 69 | offset: u32, | ||
| 70 | bytes: &[u8], | ||
| 71 | write_chunk: unsafe fn(u32, &[u8]) -> Result<(), Error>, | ||
| 72 | ) -> Result<(), Error> { | ||
| 63 | if offset + bytes.len() as u32 > size { | 73 | if offset + bytes.len() as u32 > size { |
| 64 | return Err(Error::Size); | 74 | return Err(Error::Size); |
| 65 | } | 75 | } |
| @@ -71,26 +81,39 @@ pub(super) unsafe fn write_chunked_blocking(base: u32, size: u32, offset: u32, b | |||
| 71 | trace!("Writing {} bytes at 0x{:x}", bytes.len(), address); | 81 | trace!("Writing {} bytes at 0x{:x}", bytes.len(), address); |
| 72 | 82 | ||
| 73 | for chunk in bytes.chunks(WRITE_SIZE) { | 83 | for chunk in bytes.chunks(WRITE_SIZE) { |
| 74 | family::clear_all_err(); | 84 | write_chunk(address, chunk)?; |
| 75 | fence(Ordering::SeqCst); | ||
| 76 | family::unlock(); | ||
| 77 | fence(Ordering::SeqCst); | ||
| 78 | family::enable_blocking_write(); | ||
| 79 | fence(Ordering::SeqCst); | ||
| 80 | |||
| 81 | let _on_drop = OnDrop::new(|| { | ||
| 82 | family::disable_blocking_write(); | ||
| 83 | fence(Ordering::SeqCst); | ||
| 84 | family::lock(); | ||
| 85 | }); | ||
| 86 | |||
| 87 | family::write_blocking(address, chunk.try_into().unwrap())?; | ||
| 88 | address += WRITE_SIZE as u32; | 85 | address += WRITE_SIZE as u32; |
| 89 | } | 86 | } |
| 90 | Ok(()) | 87 | Ok(()) |
| 91 | } | 88 | } |
| 92 | 89 | ||
| 93 | pub(super) unsafe fn erase_sectored_blocking(base: u32, from: u32, to: u32) -> Result<(), Error> { | 90 | pub(super) unsafe fn write_chunk_unlocked(address: u32, chunk: &[u8]) -> Result<(), Error> { |
| 91 | family::clear_all_err(); | ||
| 92 | fence(Ordering::SeqCst); | ||
| 93 | family::unlock(); | ||
| 94 | fence(Ordering::SeqCst); | ||
| 95 | family::enable_blocking_write(); | ||
| 96 | fence(Ordering::SeqCst); | ||
| 97 | |||
| 98 | let _on_drop = OnDrop::new(|| { | ||
| 99 | family::disable_blocking_write(); | ||
| 100 | fence(Ordering::SeqCst); | ||
| 101 | family::lock(); | ||
| 102 | }); | ||
| 103 | |||
| 104 | family::write_blocking(address, chunk.try_into().unwrap()) | ||
| 105 | } | ||
| 106 | |||
| 107 | pub(super) unsafe fn write_chunk_with_critical_section(address: u32, chunk: &[u8]) -> Result<(), Error> { | ||
| 108 | critical_section::with(|_| write_chunk_unlocked(address, chunk)) | ||
| 109 | } | ||
| 110 | |||
| 111 | pub(super) unsafe fn erase_blocking( | ||
| 112 | base: u32, | ||
| 113 | from: u32, | ||
| 114 | to: u32, | ||
| 115 | erase_sector: unsafe fn(&FlashSector) -> Result<(), Error>, | ||
| 116 | ) -> Result<(), Error> { | ||
| 94 | let start_address = base + from; | 117 | let start_address = base + from; |
| 95 | let end_address = base + to; | 118 | let end_address = base + to; |
| 96 | let regions = family::get_flash_regions(); | 119 | let regions = family::get_flash_regions(); |
| @@ -103,21 +126,28 @@ pub(super) unsafe fn erase_sectored_blocking(base: u32, from: u32, to: u32) -> R | |||
| 103 | while address < end_address { | 126 | while address < end_address { |
| 104 | let sector = get_sector(address, regions); | 127 | let sector = get_sector(address, regions); |
| 105 | trace!("Erasing sector: {:?}", sector); | 128 | trace!("Erasing sector: {:?}", sector); |
| 106 | 129 | erase_sector(§or)?; | |
| 107 | family::clear_all_err(); | ||
| 108 | fence(Ordering::SeqCst); | ||
| 109 | family::unlock(); | ||
| 110 | fence(Ordering::SeqCst); | ||
| 111 | |||
| 112 | let _on_drop = OnDrop::new(|| family::lock()); | ||
| 113 | |||
| 114 | family::erase_sector_blocking(§or)?; | ||
| 115 | address += sector.size; | 130 | address += sector.size; |
| 116 | } | 131 | } |
| 117 | Ok(()) | 132 | Ok(()) |
| 118 | } | 133 | } |
| 119 | 134 | ||
| 120 | pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector { | 135 | pub(super) unsafe fn erase_sector_unlocked(sector: &FlashSector) -> Result<(), Error> { |
| 136 | family::clear_all_err(); | ||
| 137 | fence(Ordering::SeqCst); | ||
| 138 | family::unlock(); | ||
| 139 | fence(Ordering::SeqCst); | ||
| 140 | |||
| 141 | let _on_drop = OnDrop::new(|| family::lock()); | ||
| 142 | |||
| 143 | family::erase_sector_blocking(§or) | ||
| 144 | } | ||
| 145 | |||
| 146 | pub(super) unsafe fn erase_sector_with_critical_section(sector: &FlashSector) -> Result<(), Error> { | ||
| 147 | critical_section::with(|_| erase_sector_unlocked(sector)) | ||
| 148 | } | ||
| 149 | |||
| 150 | pub(super) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector { | ||
| 121 | let mut current_bank = FlashBank::Bank1; | 151 | let mut current_bank = FlashBank::Bank1; |
| 122 | let mut bank_offset = 0; | 152 | let mut bank_offset = 0; |
| 123 | for region in regions { | 153 | for region in regions { |
| @@ -142,7 +172,7 @@ pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector | |||
| 142 | panic!("Flash sector not found"); | 172 | panic!("Flash sector not found"); |
| 143 | } | 173 | } |
| 144 | 174 | ||
| 145 | pub(crate) fn ensure_sector_aligned( | 175 | pub(super) fn ensure_sector_aligned( |
| 146 | start_address: u32, | 176 | start_address: u32, |
| 147 | end_address: u32, | 177 | end_address: u32, |
| 148 | regions: &[&FlashRegion], | 178 | regions: &[&FlashRegion], |
| @@ -190,121 +220,49 @@ impl embedded_storage::nor_flash::NorFlash for Flash<'_> { | |||
| 190 | } | 220 | } |
| 191 | } | 221 | } |
| 192 | 222 | ||
| 193 | #[cfg(feature = "nightly")] | ||
| 194 | impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_> { | ||
| 195 | const READ_SIZE: usize = READ_SIZE; | ||
| 196 | |||
| 197 | async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | ||
| 198 | self.read(offset, bytes) | ||
| 199 | } | ||
| 200 | |||
| 201 | fn capacity(&self) -> usize { | ||
| 202 | FLASH_SIZE | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | pub struct BlockingFlashRegion<'d, const WRITE_SIZE: u32, const ERASE_SIZE: u32>( | ||
| 207 | &'static FlashRegion, | ||
| 208 | PeripheralRef<'d, FLASH>, | ||
| 209 | ); | ||
| 210 | |||
| 211 | impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> { | ||
| 212 | pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | ||
| 213 | read_blocking(self.0.base, self.0.size, offset, bytes) | ||
| 214 | } | ||
| 215 | |||
| 216 | pub fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | ||
| 217 | let _guard = block_on(REGION_ACCESS.lock()); | ||
| 218 | unsafe { write_chunked_blocking(self.0.base, self.0.size, offset, bytes) } | ||
| 219 | } | ||
| 220 | |||
| 221 | pub fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | ||
| 222 | let _guard = block_on(REGION_ACCESS.lock()); | ||
| 223 | unsafe { erase_sectored_blocking(self.0.base, from, to) } | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> embedded_storage::nor_flash::ErrorType | ||
| 228 | for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> | ||
| 229 | { | ||
| 230 | type Error = Error; | ||
| 231 | } | ||
| 232 | |||
| 233 | impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> embedded_storage::nor_flash::ReadNorFlash | ||
| 234 | for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> | ||
| 235 | { | ||
| 236 | const READ_SIZE: usize = READ_SIZE; | ||
| 237 | |||
| 238 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | ||
| 239 | self.read(offset, bytes) | ||
| 240 | } | ||
| 241 | |||
| 242 | fn capacity(&self) -> usize { | ||
| 243 | self.0.size as usize | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | impl<const WRITE_SIZE: u32, const ERASE_SIZE: u32> embedded_storage::nor_flash::NorFlash | ||
| 248 | for BlockingFlashRegion<'_, WRITE_SIZE, ERASE_SIZE> | ||
| 249 | { | ||
| 250 | const WRITE_SIZE: usize = WRITE_SIZE as usize; | ||
| 251 | const ERASE_SIZE: usize = ERASE_SIZE as usize; | ||
| 252 | |||
| 253 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | ||
| 254 | self.write(offset, bytes) | ||
| 255 | } | ||
| 256 | |||
| 257 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | ||
| 258 | self.erase(from, to) | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | foreach_flash_region! { | 223 | foreach_flash_region! { |
| 263 | ($type_name:ident, $write_size:literal, $erase_size:literal) => { | 224 | ($type_name:ident, $write_size:literal, $erase_size:literal) => { |
| 264 | paste::paste! { | 225 | impl<'d> crate::_generated::flash_regions::$type_name<'d, Blocking> { |
| 265 | pub type [<Blocking $type_name>]<'d> = BlockingFlashRegion<'d, $write_size, $erase_size>; | 226 | pub fn read_blocking(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { |
| 266 | } | ||
| 267 | |||
| 268 | impl<'d> crate::_generated::flash_regions::$type_name<'d> { | ||
| 269 | /// Make this flash region work in a blocking context. | ||
| 270 | /// | ||
| 271 | /// SAFETY | ||
| 272 | /// | ||
| 273 | /// This function is unsafe as incorect usage of parallel blocking operations | ||
| 274 | /// on multiple regions may cause a deadlock because each region requires mutual access to the flash. | ||
| 275 | pub unsafe fn into_blocking(self) -> BlockingFlashRegion<'d, $write_size, $erase_size> { | ||
| 276 | BlockingFlashRegion(self.0, self.1) | ||
| 277 | } | ||
| 278 | |||
| 279 | pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | ||
| 280 | read_blocking(self.0.base, self.0.size, offset, bytes) | 227 | read_blocking(self.0.base, self.0.size, offset, bytes) |
| 281 | } | 228 | } |
| 282 | 229 | ||
| 283 | pub fn try_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | 230 | pub fn write_blocking(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { |
| 284 | let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?; | 231 | unsafe { write_blocking(self.0.base, self.0.size, offset, bytes, write_chunk_with_critical_section) } |
| 285 | unsafe { write_chunked_blocking(self.0.base, self.0.size, offset, bytes) } | ||
| 286 | } | 232 | } |
| 287 | 233 | ||
| 288 | pub fn try_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | 234 | pub fn erase_blocking(&mut self, from: u32, to: u32) -> Result<(), Error> { |
| 289 | let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?; | 235 | unsafe { erase_blocking(self.0.base, from, to, erase_sector_with_critical_section) } |
| 290 | unsafe { erase_sectored_blocking(self.0.base, from, to) } | ||
| 291 | } | 236 | } |
| 292 | } | 237 | } |
| 293 | 238 | ||
| 294 | impl embedded_storage::nor_flash::ErrorType for crate::_generated::flash_regions::$type_name<'_> { | 239 | impl<MODE> embedded_storage::nor_flash::ErrorType for crate::_generated::flash_regions::$type_name<'_, MODE> { |
| 295 | type Error = Error; | 240 | type Error = Error; |
| 296 | } | 241 | } |
| 297 | 242 | ||
| 298 | impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_> { | 243 | impl embedded_storage::nor_flash::ReadNorFlash for crate::_generated::flash_regions::$type_name<'_, Blocking> { |
| 299 | const READ_SIZE: usize = READ_SIZE; | 244 | const READ_SIZE: usize = READ_SIZE; |
| 300 | 245 | ||
| 301 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | 246 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { |
| 302 | self.read(offset, bytes) | 247 | self.read_blocking(offset, bytes) |
| 303 | } | 248 | } |
| 304 | 249 | ||
| 305 | fn capacity(&self) -> usize { | 250 | fn capacity(&self) -> usize { |
| 306 | self.0.size as usize | 251 | self.0.size as usize |
| 307 | } | 252 | } |
| 308 | } | 253 | } |
| 254 | |||
| 255 | impl embedded_storage::nor_flash::NorFlash for crate::_generated::flash_regions::$type_name<'_, Blocking> { | ||
| 256 | const WRITE_SIZE: usize = $write_size; | ||
| 257 | const ERASE_SIZE: usize = $erase_size; | ||
| 258 | |||
| 259 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | ||
| 260 | self.write_blocking(offset, bytes) | ||
| 261 | } | ||
| 262 | |||
| 263 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | ||
| 264 | self.erase_blocking(from, to) | ||
| 265 | } | ||
| 266 | } | ||
| 309 | }; | 267 | }; |
| 310 | } | 268 | } |
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; | |||
| 11 | 11 | ||
| 12 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] | 12 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] |
| 13 | mod alt_regions { | 13 | mod alt_regions { |
| 14 | use core::marker::PhantomData; | ||
| 15 | |||
| 14 | use embassy_hal_common::PeripheralRef; | 16 | use embassy_hal_common::PeripheralRef; |
| 15 | use stm32_metapac::FLASH_SIZE; | 17 | use stm32_metapac::FLASH_SIZE; |
| 16 | 18 | ||
| @@ -18,8 +20,7 @@ mod alt_regions { | |||
| 18 | #[cfg(feature = "nightly")] | 20 | #[cfg(feature = "nightly")] |
| 19 | use crate::flash::asynch; | 21 | use crate::flash::asynch; |
| 20 | use crate::flash::{ | 22 | use crate::flash::{ |
| 21 | common, Bank1Region1, Bank1Region2, BlockingFlashRegion, Error, Flash, FlashBank, FlashRegion, READ_SIZE, | 23 | common, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion, READ_SIZE, |
| 22 | REGION_ACCESS, | ||
| 23 | }; | 24 | }; |
| 24 | use crate::peripherals::FLASH; | 25 | use crate::peripherals::FLASH; |
| 25 | 26 | ||
| @@ -53,101 +54,86 @@ mod alt_regions { | |||
| 53 | &ALT_BANK2_REGION3, | 54 | &ALT_BANK2_REGION3, |
| 54 | ]; | 55 | ]; |
| 55 | 56 | ||
| 56 | pub struct AltBank1Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); | 57 | pub struct AltBank1Region3<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>); |
| 57 | pub struct AltBank2Region1<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); | 58 | pub struct AltBank2Region1<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>); |
| 58 | pub struct AltBank2Region2<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); | 59 | pub struct AltBank2Region2<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>); |
| 59 | pub struct AltBank2Region3<'d>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>); | 60 | pub struct AltBank2Region3<'d, MODE>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData<MODE>); |
| 60 | 61 | ||
| 61 | pub type BlockingAltBank1Region3<'d> = | 62 | pub struct AltFlashLayout<'d, MODE> { |
| 62 | BlockingFlashRegion<'d, { ALT_BANK1_REGION3.write_size }, { ALT_BANK1_REGION3.erase_size }>; | 63 | pub bank1_region1: Bank1Region1<'d, MODE>, |
| 63 | pub type BlockingAltBank2Region1<'d> = | 64 | pub bank1_region2: Bank1Region2<'d, MODE>, |
| 64 | BlockingFlashRegion<'d, { ALT_BANK2_REGION1.write_size }, { ALT_BANK2_REGION1.erase_size }>; | 65 | pub bank1_region3: AltBank1Region3<'d, MODE>, |
| 65 | pub type BlockingAltBank2Region2<'d> = | 66 | pub bank2_region1: AltBank2Region1<'d, MODE>, |
| 66 | BlockingFlashRegion<'d, { ALT_BANK2_REGION2.write_size }, { ALT_BANK2_REGION2.erase_size }>; | 67 | pub bank2_region2: AltBank2Region2<'d, MODE>, |
| 67 | pub type BlockingAltBank2Region3<'d> = | 68 | pub bank2_region3: AltBank2Region3<'d, MODE>, |
| 68 | BlockingFlashRegion<'d, { ALT_BANK2_REGION3.write_size }, { ALT_BANK2_REGION3.erase_size }>; | 69 | pub otp_region: OTPRegion<'d, MODE>, |
| 69 | |||
| 70 | pub struct AltFlashLayout<'d> { | ||
| 71 | pub bank1_region1: Bank1Region1<'d>, | ||
| 72 | pub bank1_region2: Bank1Region2<'d>, | ||
| 73 | pub bank1_region3: AltBank1Region3<'d>, | ||
| 74 | pub bank2_region1: AltBank2Region1<'d>, | ||
| 75 | pub bank2_region2: AltBank2Region2<'d>, | ||
| 76 | pub bank2_region3: AltBank2Region3<'d>, | ||
| 77 | pub otp_region: OTPRegion<'d>, | ||
| 78 | } | 70 | } |
| 79 | 71 | ||
| 80 | impl<'d> Flash<'d> { | 72 | impl<'d> Flash<'d> { |
| 81 | pub fn into_alt_regions(self) -> AltFlashLayout<'d> { | 73 | pub fn into_alt_regions(self) -> AltFlashLayout<'d, Async> { |
| 74 | unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) }; | ||
| 75 | |||
| 76 | // SAFETY: We never expose the cloned peripheral references, and their instance is not public. | ||
| 77 | // Also, all async flash region operations are protected with a mutex. | ||
| 78 | let p = self.inner; | ||
| 79 | AltFlashLayout { | ||
| 80 | bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }, PhantomData), | ||
| 81 | bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }, PhantomData), | ||
| 82 | bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }, PhantomData), | ||
| 83 | bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData), | ||
| 84 | bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData), | ||
| 85 | bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData), | ||
| 86 | otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData), | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | pub fn into_alt_blocking_regions(self) -> AltFlashLayout<'d, Blocking> { | ||
| 82 | unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) }; | 91 | unsafe { crate::pac::FLASH.optcr().modify(|r| r.set_db1m(true)) }; |
| 83 | 92 | ||
| 84 | // SAFETY: We never expose the cloned peripheral references, and their instance is not public. | 93 | // SAFETY: We never expose the cloned peripheral references, and their instance is not public. |
| 85 | // Also, all blocking flash region operations are protected with a cs. | 94 | // Also, all blocking flash region operations are protected with a cs. |
| 86 | let p = self.inner; | 95 | let p = self.inner; |
| 87 | AltFlashLayout { | 96 | AltFlashLayout { |
| 88 | bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }), | 97 | bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }, PhantomData), |
| 89 | bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }), | 98 | bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }, PhantomData), |
| 90 | bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }), | 99 | bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }, PhantomData), |
| 91 | bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }), | 100 | bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData), |
| 92 | bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }), | 101 | bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData), |
| 93 | bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }), | 102 | bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData), |
| 94 | otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }), | 103 | otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData), |
| 95 | } | 104 | } |
| 96 | } | 105 | } |
| 97 | } | 106 | } |
| 98 | 107 | ||
| 99 | macro_rules! foreach_altflash_region { | 108 | macro_rules! foreach_altflash_region { |
| 100 | ($type_name:ident, $region:ident) => { | 109 | ($type_name:ident, $region:ident) => { |
| 101 | impl $type_name<'_> { | 110 | #[cfg(feature = "nightly")] |
| 102 | pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | 111 | impl $type_name<'_, Async> { |
| 112 | pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | ||
| 103 | common::read_blocking(self.0.base, self.0.size, offset, bytes) | 113 | common::read_blocking(self.0.base, self.0.size, offset, bytes) |
| 104 | } | 114 | } |
| 105 | 115 | ||
| 106 | #[cfg(feature = "nightly")] | ||
| 107 | pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | 116 | pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { |
| 108 | let _guard = REGION_ACCESS.lock().await; | 117 | let _guard = asynch::REGION_ACCESS.lock().await; |
| 109 | unsafe { asynch::write_chunked(self.0.base, self.0.size, offset, bytes).await } | 118 | unsafe { asynch::write_chunked(self.0.base, self.0.size, offset, bytes).await } |
| 110 | } | 119 | } |
| 111 | 120 | ||
| 112 | #[cfg(feature = "nightly")] | ||
| 113 | pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | 121 | pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { |
| 114 | let _guard = REGION_ACCESS.lock().await; | 122 | let _guard = asynch::REGION_ACCESS.lock().await; |
| 115 | unsafe { asynch::erase_sectored(self.0.base, from, to).await } | 123 | unsafe { asynch::erase_sectored(self.0.base, from, to).await } |
| 116 | } | 124 | } |
| 117 | |||
| 118 | pub fn try_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | ||
| 119 | let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?; | ||
| 120 | unsafe { common::write_chunked_blocking(self.0.base, self.0.size, offset, bytes) } | ||
| 121 | } | ||
| 122 | |||
| 123 | pub fn try_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | ||
| 124 | let _guard = REGION_ACCESS.try_lock().map_err(|_| Error::TryLockError)?; | ||
| 125 | unsafe { common::erase_sectored_blocking(self.0.base, from, to) } | ||
| 126 | } | ||
| 127 | } | 125 | } |
| 128 | 126 | ||
| 129 | impl embedded_storage::nor_flash::ErrorType for $type_name<'_> { | 127 | impl embedded_storage::nor_flash::ErrorType for $type_name<'_, Async> { |
| 130 | type Error = Error; | 128 | type Error = Error; |
| 131 | } | 129 | } |
| 132 | 130 | ||
| 133 | impl embedded_storage::nor_flash::ReadNorFlash for $type_name<'_> { | ||
| 134 | const READ_SIZE: usize = READ_SIZE; | ||
| 135 | |||
| 136 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | ||
| 137 | self.read(offset, bytes) | ||
| 138 | } | ||
| 139 | |||
| 140 | fn capacity(&self) -> usize { | ||
| 141 | self.0.size as usize | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | #[cfg(feature = "nightly")] | 131 | #[cfg(feature = "nightly")] |
| 146 | impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_> { | 132 | impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_, Async> { |
| 147 | const READ_SIZE: usize = READ_SIZE; | 133 | const READ_SIZE: usize = READ_SIZE; |
| 148 | 134 | ||
| 149 | async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | 135 | async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { |
| 150 | self.read(offset, bytes) | 136 | self.read(offset, bytes).await |
| 151 | } | 137 | } |
| 152 | 138 | ||
| 153 | fn capacity(&self) -> usize { | 139 | fn capacity(&self) -> usize { |
| @@ -156,7 +142,7 @@ mod alt_regions { | |||
| 156 | } | 142 | } |
| 157 | 143 | ||
| 158 | #[cfg(feature = "nightly")] | 144 | #[cfg(feature = "nightly")] |
| 159 | impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_> { | 145 | impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_, Async> { |
| 160 | const WRITE_SIZE: usize = $region.write_size as usize; | 146 | const WRITE_SIZE: usize = $region.write_size as usize; |
| 161 | const ERASE_SIZE: usize = $region.erase_size as usize; | 147 | const ERASE_SIZE: usize = $region.erase_size as usize; |
| 162 | 148 | ||
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}; | |||
| 14 | 14 | ||
| 15 | pub const READ_SIZE: usize = 1; | 15 | pub const READ_SIZE: usize = 1; |
| 16 | 16 | ||
| 17 | pub struct Blocking; | ||
| 18 | pub struct Async; | ||
| 19 | |||
| 17 | #[derive(Debug)] | 20 | #[derive(Debug)] |
| 18 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 21 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 19 | pub struct FlashRegion { | 22 | pub struct FlashRegion { |
