diff options
| author | Rasmus Melchior Jacobsen <[email protected]> | 2023-03-25 16:04:45 +0100 |
|---|---|---|
| committer | Rasmus Melchior Jacobsen <[email protected]> | 2023-03-25 16:04:45 +0100 |
| commit | bc69eb596e2496a5eb0cf1252ada12f2710aaff2 (patch) | |
| tree | d2a4c233d439cba49e2512fce076155b30d20d3c /embassy-stm32/src/flash/mod.rs | |
| parent | 245147634bfbdcd325eea20be19286708bb29c9f (diff) | |
Add is_eraseable_range and split write into consecutive parts
Diffstat (limited to 'embassy-stm32/src/flash/mod.rs')
| -rw-r--r-- | embassy-stm32/src/flash/mod.rs | 85 |
1 files changed, 58 insertions, 27 deletions
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index b6cecfdb3..c704909ac 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs | |||
| @@ -1,8 +1,10 @@ | |||
| 1 | use embassy_hal_common::{into_ref, PeripheralRef}; | 1 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 2 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 3 | use embassy_sync::mutex::{Mutex, MutexGuard}; | ||
| 2 | use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; | 4 | use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; |
| 3 | 5 | ||
| 4 | pub use crate::_generated::flash_regions::*; | 6 | pub use crate::_generated::flash_regions::*; |
| 5 | pub use crate::pac::{FLASH_BASE, FLASH_SIZE}; | 7 | pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; |
| 6 | use crate::peripherals::FLASH; | 8 | use crate::peripherals::FLASH; |
| 7 | use crate::Peripheral; | 9 | use crate::Peripheral; |
| 8 | 10 | ||
| @@ -17,6 +19,8 @@ pub struct Flash<'d> { | |||
| 17 | _inner: PeripheralRef<'d, FLASH>, | 19 | _inner: PeripheralRef<'d, FLASH>, |
| 18 | } | 20 | } |
| 19 | 21 | ||
| 22 | static REGION_LOCK: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(()); | ||
| 23 | |||
| 20 | impl<'d> Flash<'d> { | 24 | impl<'d> Flash<'d> { |
| 21 | pub fn new(p: impl Peripheral<P = FLASH> + 'd) -> Self { | 25 | pub fn new(p: impl Peripheral<P = FLASH> + 'd) -> Self { |
| 22 | into_ref!(p); | 26 | into_ref!(p); |
| @@ -33,7 +37,6 @@ impl<'d> Flash<'d> { | |||
| 33 | } | 37 | } |
| 34 | 38 | ||
| 35 | let first_address = FLASH_BASE as u32 + offset; | 39 | let first_address = FLASH_BASE as u32 + offset; |
| 36 | |||
| 37 | let flash_data = unsafe { core::slice::from_raw_parts(first_address as *const u8, bytes.len()) }; | 40 | let flash_data = unsafe { core::slice::from_raw_parts(first_address as *const u8, bytes.len()) }; |
| 38 | bytes.copy_from_slice(flash_data); | 41 | bytes.copy_from_slice(flash_data); |
| 39 | Ok(()) | 42 | Ok(()) |
| @@ -43,39 +46,56 @@ impl<'d> Flash<'d> { | |||
| 43 | if offset as usize + buf.len() > FLASH_SIZE { | 46 | if offset as usize + buf.len() > FLASH_SIZE { |
| 44 | return Err(Error::Size); | 47 | return Err(Error::Size); |
| 45 | } | 48 | } |
| 46 | if offset as usize % family::MAX_WRITE_SIZE != 0 || buf.len() as usize % family::MAX_WRITE_SIZE != 0 { | 49 | if offset as usize % WRITE_SIZE != 0 || buf.len() as usize % WRITE_SIZE != 0 { |
| 47 | return Err(Error::Unaligned); | 50 | return Err(Error::Unaligned); |
| 48 | } | 51 | } |
| 49 | 52 | ||
| 50 | let first_address = FLASH_BASE as u32 + offset; | 53 | let start_address = FLASH_BASE as u32 + offset; |
| 51 | trace!("Writing {} bytes at 0x{:x}", buf.len(), first_address); | 54 | trace!("Writing {} bytes at 0x{:x}", buf.len(), start_address); |
| 55 | |||
| 56 | // No need to take lock here as we only have one mut flash reference. | ||
| 52 | 57 | ||
| 53 | unsafe { | 58 | unsafe { |
| 54 | family::clear_all_err(); | 59 | family::clear_all_err(); |
| 55 | |||
| 56 | family::unlock(); | 60 | family::unlock(); |
| 57 | let res = family::blocking_write(first_address, buf); | 61 | let res = Flash::blocking_write_all(start_address, buf); |
| 58 | family::lock(); | 62 | family::lock(); |
| 59 | res | 63 | res |
| 60 | } | 64 | } |
| 61 | } | 65 | } |
| 62 | 66 | ||
| 67 | unsafe fn blocking_write_all(start_address: u32, buf: &[u8]) -> Result<(), Error> { | ||
| 68 | family::begin_write(); | ||
| 69 | let mut address = start_address; | ||
| 70 | for chunk in buf.chunks(WRITE_SIZE) { | ||
| 71 | let res = unsafe { family::blocking_write(address, chunk.try_into().unwrap()) }; | ||
| 72 | if res.is_err() { | ||
| 73 | family::end_write(); | ||
| 74 | return res; | ||
| 75 | } | ||
| 76 | address += WRITE_SIZE as u32; | ||
| 77 | } | ||
| 78 | |||
| 79 | family::end_write(); | ||
| 80 | Ok(()) | ||
| 81 | } | ||
| 82 | |||
| 63 | pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | 83 | pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { |
| 64 | if to < from || to as usize > FLASH_SIZE { | 84 | if to < from || to as usize > FLASH_SIZE { |
| 65 | return Err(Error::Size); | 85 | return Err(Error::Size); |
| 66 | } | 86 | } |
| 67 | if (from as usize % family::MAX_ERASE_SIZE) != 0 || (to as usize % family::MAX_ERASE_SIZE) != 0 { | 87 | |
| 88 | let start_address = FLASH_BASE as u32 + from; | ||
| 89 | let end_address = FLASH_BASE as u32 + to; | ||
| 90 | if !family::is_eraseable_range(start_address, end_address) { | ||
| 68 | return Err(Error::Unaligned); | 91 | return Err(Error::Unaligned); |
| 69 | } | 92 | } |
| 70 | 93 | trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); | |
| 71 | let from_address = FLASH_BASE as u32 + from; | ||
| 72 | let to_address = FLASH_BASE as u32 + to; | ||
| 73 | 94 | ||
| 74 | unsafe { | 95 | unsafe { |
| 75 | family::clear_all_err(); | 96 | family::clear_all_err(); |
| 76 | |||
| 77 | family::unlock(); | 97 | family::unlock(); |
| 78 | let res = family::blocking_erase(from_address, to_address); | 98 | let res = family::blocking_erase(start_address, end_address); |
| 79 | family::lock(); | 99 | family::lock(); |
| 80 | res | 100 | res |
| 81 | } | 101 | } |
| @@ -101,7 +121,6 @@ pub trait FlashRegion { | |||
| 101 | } | 121 | } |
| 102 | 122 | ||
| 103 | let first_address = Self::BASE as u32 + offset; | 123 | let first_address = Self::BASE as u32 + offset; |
| 104 | |||
| 105 | let flash_data = unsafe { core::slice::from_raw_parts(first_address as *const u8, bytes.len()) }; | 124 | let flash_data = unsafe { core::slice::from_raw_parts(first_address as *const u8, bytes.len()) }; |
| 106 | bytes.copy_from_slice(flash_data); | 125 | bytes.copy_from_slice(flash_data); |
| 107 | Ok(()) | 126 | Ok(()) |
| @@ -115,17 +134,19 @@ pub trait FlashRegion { | |||
| 115 | return Err(Error::Unaligned); | 134 | return Err(Error::Unaligned); |
| 116 | } | 135 | } |
| 117 | 136 | ||
| 118 | let first_address = Self::BASE as u32 + offset; | 137 | let start_address = Self::BASE as u32 + offset; |
| 119 | trace!("Writing {} bytes from 0x{:x}", buf.len(), first_address); | 138 | trace!("Writing {} bytes from 0x{:x}", buf.len(), start_address); |
| 120 | 139 | ||
| 121 | critical_section::with(|_| unsafe { | 140 | // Protect agains simultaneous write/erase to multiple regions. |
| 122 | family::clear_all_err(); | 141 | let _guard = take_lock_spin(); |
| 123 | 142 | ||
| 143 | unsafe { | ||
| 144 | family::clear_all_err(); | ||
| 124 | family::unlock(); | 145 | family::unlock(); |
| 125 | let res = family::blocking_write(first_address, buf); | 146 | let res = Flash::blocking_write_all(start_address, buf); |
| 126 | family::lock(); | 147 | family::lock(); |
| 127 | res | 148 | res |
| 128 | }) | 149 | } |
| 129 | } | 150 | } |
| 130 | 151 | ||
| 131 | fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | 152 | fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { |
| @@ -136,18 +157,28 @@ pub trait FlashRegion { | |||
| 136 | return Err(Error::Unaligned); | 157 | return Err(Error::Unaligned); |
| 137 | } | 158 | } |
| 138 | 159 | ||
| 139 | let from_address = Self::BASE as u32 + from; | 160 | let start_address = Self::BASE as u32 + from; |
| 140 | let to_address = Self::BASE as u32 + to; | 161 | let end_address = Self::BASE as u32 + to; |
| 141 | trace!("Erasing from 0x{:x} to 0x{:x}", from_address, to_address); | 162 | trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); |
| 142 | 163 | ||
| 143 | critical_section::with(|_| unsafe { | 164 | // Protect agains simultaneous write/erase to multiple regions. |
| 144 | family::clear_all_err(); | 165 | let _guard = take_lock_spin(); |
| 145 | 166 | ||
| 167 | unsafe { | ||
| 168 | family::clear_all_err(); | ||
| 146 | family::unlock(); | 169 | family::unlock(); |
| 147 | let res = family::blocking_erase(from_address, to_address); | 170 | let res = family::blocking_erase(start_address, end_address); |
| 148 | family::lock(); | 171 | family::lock(); |
| 149 | res | 172 | res |
| 150 | }) | 173 | } |
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | fn take_lock_spin() -> MutexGuard<'static, CriticalSectionRawMutex, ()> { | ||
| 178 | loop { | ||
| 179 | if let Ok(guard) = REGION_LOCK.try_lock() { | ||
| 180 | return guard; | ||
| 181 | } | ||
| 151 | } | 182 | } |
| 152 | } | 183 | } |
| 153 | 184 | ||
