aboutsummaryrefslogtreecommitdiff
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
parent06f5c309c06e61790b24a7bfddad1324741b767f (diff)
stm32: Add async flash write/erase to f4
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/src/flash/asynch.rs129
-rw-r--r--embassy-stm32/src/flash/common.rs255
-rw-r--r--embassy-stm32/src/flash/f0.rs18
-rw-r--r--embassy-stm32/src/flash/f3.rs18
-rw-r--r--embassy-stm32/src/flash/f4.rs181
-rw-r--r--embassy-stm32/src/flash/f7.rs21
-rw-r--r--embassy-stm32/src/flash/h7.rs21
-rw-r--r--embassy-stm32/src/flash/l.rs19
-rw-r--r--embassy-stm32/src/flash/mod.rs49
-rw-r--r--embassy-stm32/src/flash/other.rs12
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}
47embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true} 47embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true}
48 48
49embedded-storage = "0.3.0" 49embedded-storage = "0.3.0"
50embedded-storage-async = { version = "0.4.0", optional = true }
50 51
51defmt = { version = "0.3", optional = true } 52defmt = { version = "0.3", optional = true }
52log = { version = "0.4.14", optional = true } 53log = { version = "0.4.14", optional = true }
@@ -68,6 +69,7 @@ cfg-if = "1.0.0"
68embedded-io = { version = "0.4.0", features = ["async"], optional = true } 69embedded-io = { version = "0.4.0", features = ["async"], optional = true }
69chrono = { version = "^0.4", default-features = false, optional = true} 70chrono = { version = "^0.4", default-features = false, optional = true}
70bit_field = "0.10.2" 71bit_field = "0.10.2"
72paste = "1.0.12"
71 73
72[dev-dependencies] 74[dev-dependencies]
73critical-section = { version = "1.1", features = ["std"] } 75critical-section = { version = "1.1", features = ["std"] }
@@ -98,7 +100,7 @@ time-driver-tim12 = ["_time-driver"]
98time-driver-tim15 = ["_time-driver"] 100time-driver-tim15 = ["_time-driver"]
99 101
100# Enable nightly-only features 102# Enable nightly-only features
101nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"] 103nightly = ["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 @@
1use atomic_polyfill::{fence, Ordering};
2use embassy_hal_common::drop::OnDrop;
3
4use 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
9impl<'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
19impl 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
32pub(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
63pub(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(&sector).await?;
85 address += sector.size;
86 }
87 Ok(())
88}
89
90foreach_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 @@
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}
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
16pub(crate) unsafe fn on_interrupt(_: *mut ()) {
17 unimplemented!();
18}
19
16pub(crate) unsafe fn lock() { 20pub(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
25pub(crate) unsafe fn begin_write() { 29pub(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
31pub(crate) unsafe fn end_write() { 35pub(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
35pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { 39pub(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
48pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 52pub(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
91unsafe fn blocking_wait_ready() -> Result<(), Error> { 95unsafe 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
16pub(crate) unsafe fn on_interrupt(_: *mut ()) {
17 unimplemented!();
18}
19
16pub(crate) unsafe fn lock() { 20pub(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
25pub(crate) unsafe fn begin_write() { 29pub(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
31pub(crate) unsafe fn end_write() { 35pub(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
35pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { 39pub(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
48pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 52pub(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
91unsafe fn blocking_wait_ready() -> Result<(), Error> { 95unsafe 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;
2use core::ptr::write_volatile; 2use core::ptr::write_volatile;
3use core::sync::atomic::{fence, Ordering}; 3use core::sync::atomic::{fence, Ordering};
4 4
5use embassy_sync::waitqueue::AtomicWaker;
6
5use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 7use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
6use crate::flash::Error; 8use crate::flash::Error;
7use crate::pac; 9use 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))]
139pub use alt_regions::*; 176pub use alt_regions::*;
140 177
178#[cfg(feature = "nightly")]
179static WAKER: AtomicWaker = AtomicWaker::new();
180
141#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] 181#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
142pub fn set_default_layout() { 182pub 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
203pub(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
163pub(crate) unsafe fn lock() { 213pub(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
172pub(crate) unsafe fn begin_write() { 222#[cfg(feature = "nightly")]
223pub(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")]
235pub(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
181pub(crate) unsafe fn end_write() { 243pub(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
252pub(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
185pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { 256#[cfg(feature = "nightly")]
257pub(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
262pub(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
267unsafe 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
278pub(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
198pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 301pub(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
227unsafe fn blocking_wait_ready() -> Result<(), Error> { 327#[cfg(feature = "nightly")]
328pub(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
356unsafe 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
15pub(crate) unsafe fn on_interrupt(_: *mut ()) {
16 unimplemented!();
17}
18
15pub(crate) unsafe fn lock() { 19pub(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
24pub(crate) unsafe fn begin_write() { 28pub(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
33pub(crate) unsafe fn end_write() { 37pub(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
37pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { 41pub(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
50pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 54pub(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
89unsafe fn blocking_wait_ready() -> Result<(), Error> { 90unsafe 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
20pub(crate) unsafe fn on_interrupt(_: *mut ()) {
21 unimplemented!();
22}
23
20pub(crate) unsafe fn lock() { 24pub(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
36pub(crate) unsafe fn begin_write() { 40pub(crate) unsafe fn enable_blocking_write() {
37 assert_eq!(0, WRITE_SIZE % 4); 41 assert_eq!(0, WRITE_SIZE % 4);
38} 42}
39 43
40pub(crate) unsafe fn end_write() {} 44pub(crate) unsafe fn disable_blocking_write() {}
41 45
42pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { 46pub(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
83pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 87pub(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
144unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> { 145unsafe 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
15pub(crate) unsafe fn on_interrupt(_: *mut ()) {
16 unimplemented!();
17}
18
15pub(crate) unsafe fn lock() { 19pub(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
44pub(crate) unsafe fn begin_write() { 48pub(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
51pub(crate) unsafe fn end_write() { 55pub(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
56pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { 60pub(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
69pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 73pub(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
153unsafe fn blocking_wait_ready() -> Result<(), Error> { 156unsafe 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 @@
1use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; 1use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind};
2 2
3#[cfg(all(feature = "nightly", flash_f4))]
4pub mod asynch;
3#[cfg(flash)] 5#[cfg(flash)]
4mod common; 6mod common;
5 7
@@ -10,6 +12,8 @@ pub use crate::_generated::flash_regions::*;
10pub use crate::_generated::MAX_ERASE_SIZE; 12pub use crate::_generated::MAX_ERASE_SIZE;
11pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; 13pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE};
12 14
15pub 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))]
15pub struct FlashRegion { 19pub 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
81impl NorFlashError for Error { 86impl NorFlashError for Error {
@@ -87,3 +92,47 @@ impl NorFlashError for Error {
87 } 92 }
88 } 93 }
89} 94}
95
96pub(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
121pub(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
11pub(crate) unsafe fn on_interrupt(_: *mut ()) {
12 unimplemented!();
13}
14
11pub(crate) unsafe fn lock() { 15pub(crate) unsafe fn lock() {
12 unimplemented!(); 16 unimplemented!();
13} 17}
14pub(crate) unsafe fn unlock() { 18pub(crate) unsafe fn unlock() {
15 unimplemented!(); 19 unimplemented!();
16} 20}
17pub(crate) unsafe fn begin_write() { 21pub(crate) unsafe fn enable_blocking_write() {
18 unimplemented!(); 22 unimplemented!();
19} 23}
20pub(crate) unsafe fn end_write() { 24pub(crate) unsafe fn disable_blocking_write() {
21 unimplemented!(); 25 unimplemented!();
22} 26}
23pub(crate) unsafe fn blocking_write(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { 27pub(crate) unsafe fn write_blocking(_start_address: u32, _buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
24 unimplemented!(); 28 unimplemented!();
25} 29}
26pub(crate) unsafe fn blocking_erase_sector(_sector: &FlashSector) -> Result<(), Error> { 30pub(crate) unsafe fn erase_sector_blocking(_sector: &FlashSector) -> Result<(), Error> {
27 unimplemented!(); 31 unimplemented!();
28} 32}
29pub(crate) unsafe fn clear_all_err() { 33pub(crate) unsafe fn clear_all_err() {