aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/flash/common.rs
diff options
context:
space:
mode:
authorRasmus Melchior Jacobsen <[email protected]>2023-05-24 12:17:12 +0200
committerRasmus Melchior Jacobsen <[email protected]>2023-05-25 20:07:41 +0200
commit0e90e98e9b477302a3cd2550dbd438907ed10ca6 (patch)
tree4ec2c5d7bce91ac44659ad4ebc93a04ee7966d1b /embassy-stm32/src/flash/common.rs
parent06f5c309c06e61790b24a7bfddad1324741b767f (diff)
stm32: Add async flash write/erase to f4
Diffstat (limited to 'embassy-stm32/src/flash/common.rs')
-rw-r--r--embassy-stm32/src/flash/common.rs255
1 files changed, 141 insertions, 114 deletions
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 @@
1use atomic_polyfill::{fence, Ordering}; 1use atomic_polyfill::{fence, Ordering};
2use embassy_cortex_m::interrupt::InterruptExt;
3use embassy_futures::block_on;
2use embassy_hal_common::drop::OnDrop; 4use embassy_hal_common::drop::OnDrop;
3use embassy_hal_common::{into_ref, PeripheralRef}; 5use embassy_hal_common::{into_ref, PeripheralRef};
4 6use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
5use super::{family, Error, FlashLayout, FlashRegion, FlashSector, FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, WRITE_SIZE}; 7use embassy_sync::mutex::Mutex;
6use crate::flash::FlashBank; 8use stm32_metapac::FLASH_BASE;
9
10use super::{
11 ensure_sector_aligned, family, get_sector, Error, FlashLayout, FlashRegion, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE,
12 WRITE_SIZE,
13};
14use crate::peripherals::FLASH;
7use crate::Peripheral; 15use crate::Peripheral;
8 16
9pub struct Flash<'d> { 17pub struct Flash<'d> {
10 inner: PeripheralRef<'d, crate::peripherals::FLASH>, 18 pub(crate) inner: PeripheralRef<'d, FLASH>,
11} 19}
12 20
21pub(crate) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(());
22
13impl<'d> Flash<'d> { 23impl<'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
41pub(super) fn blocking_read(base: u32, size: u32, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 52pub(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
52pub(super) unsafe fn blocking_write_chunked(base: u32, size: u32, offset: u32, bytes: &[u8]) -> Result<(), Error> { 63pub(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
85pub(super) unsafe fn blocking_erase_sectored(base: u32, from: u32, to: u32) -> Result<(), Error> { 94pub(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(&sector) 115 family::erase_sector_blocking(&sector)?;
121 })?;
122 address += sector.size; 116 address += sector.size;
123 } 117 }
124 Ok(()) 118 Ok(())
125} 119}
126 120
127pub(crate) fn get_sector(address: u32, regions: &[&FlashRegion]) -> FlashSector { 121impl 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() { 125impl 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
152impl FlashRegion { 137impl 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")]
151impl 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
166impl embedded_storage::nor_flash::ErrorType for Flash<'_> { 163pub struct BlockingFlashRegion<'d, const WRITE_SIZE: u32, const ERASE_SIZE: u32>(
164 &'static FlashRegion,
165 PeripheralRef<'d, FLASH>,
166);
167
168impl<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
184impl<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
170impl embedded_storage::nor_flash::ReadNorFlash for Flash<'_> { 190impl<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
182impl embedded_storage::nor_flash::NorFlash for Flash<'_> { 204impl<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
195foreach_flash_region! { 219foreach_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}