Skip to content

Commit e0b6bcb

Browse files
committed
stm32: async flash erase/write for h7
1 parent aad02db commit e0b6bcb

File tree

3 files changed

+158
-37
lines changed

3 files changed

+158
-37
lines changed

embassy-stm32/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6666
- feat: add flash support for c0 family ([#4874](https://github.com/embassy-rs/embassy/pull/4874))
6767
- fix: fixing channel numbers on vbat and vddcore for adc on adc
6868
- adc: adding disable to vbat
69+
- feat: stm32/flash: add async support for h7 family
6970

7071
## 0.4.0 - 2025-08-26
7172

embassy-stm32/src/flash/h7.rs

Lines changed: 155 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,31 @@
11
use core::ptr::write_volatile;
22
use core::sync::atomic::{Ordering, fence};
33

4+
use embassy_sync::waitqueue::AtomicWaker;
5+
use pac::flash::regs::Sr;
6+
47
use super::{BANK1_REGION, FLASH_REGIONS, FlashSector, WRITE_SIZE};
58
use crate::flash::Error;
69
use crate::pac;
710

11+
static WAKER: AtomicWaker = AtomicWaker::new();
12+
13+
pub(crate) unsafe fn on_interrupt() {
14+
// Clear IRQ flags
15+
pac::FLASH.bank(0).ccr().write(|w| {
16+
w.set_clr_eop(true);
17+
w.set_clr_operr(true);
18+
});
19+
if is_dual_bank() {
20+
pac::FLASH.bank(1).ccr().write(|w| {
21+
w.set_clr_eop(true);
22+
w.set_clr_operr(true);
23+
});
24+
}
25+
26+
WAKER.wake();
27+
}
28+
829
const fn is_dual_bank() -> bool {
930
FLASH_REGIONS.len() >= 2
1031
}
@@ -29,12 +50,68 @@ pub(crate) unsafe fn unlock() {
2950
}
3051
}
3152

53+
pub(crate) unsafe fn enable_write() {
54+
enable_blocking_write();
55+
}
56+
57+
pub(crate) unsafe fn disable_write() {
58+
disable_blocking_write();
59+
}
60+
3261
pub(crate) unsafe fn enable_blocking_write() {
3362
assert_eq!(0, WRITE_SIZE % 4);
3463
}
3564

3665
pub(crate) unsafe fn disable_blocking_write() {}
3766

67+
pub(crate) async unsafe fn write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
68+
// We cannot have the write setup sequence in begin_write as it depends on the address
69+
let bank = if start_address < BANK1_REGION.end() {
70+
pac::FLASH.bank(0)
71+
} else {
72+
pac::FLASH.bank(1)
73+
};
74+
bank.cr().write(|w| {
75+
w.set_pg(true);
76+
#[cfg(flash_h7)]
77+
w.set_psize(2); // 32 bits at once
78+
w.set_eopie(true);
79+
w.set_operrie(true);
80+
});
81+
cortex_m::asm::isb();
82+
cortex_m::asm::dsb();
83+
fence(Ordering::SeqCst);
84+
85+
let mut res = None;
86+
let mut address = start_address;
87+
for val in buf.chunks(4) {
88+
write_volatile(address as *mut u32, u32::from_le_bytes(unwrap!(val.try_into())));
89+
address += val.len() as u32;
90+
91+
res = Some(wait_ready(bank).await);
92+
bank.sr().modify(|w| {
93+
if w.eop() {
94+
w.set_eop(true);
95+
}
96+
});
97+
if unwrap!(res).is_err() {
98+
break;
99+
}
100+
}
101+
102+
cortex_m::asm::isb();
103+
cortex_m::asm::dsb();
104+
fence(Ordering::SeqCst);
105+
106+
bank.cr().write(|w| {
107+
w.set_pg(false);
108+
w.set_eopie(false);
109+
w.set_operrie(false);
110+
});
111+
112+
unwrap!(res)
113+
}
114+
38115
pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
39116
// We cannot have the write setup sequence in begin_write as it depends on the address
40117
let bank = if start_address < BANK1_REGION.end() {
@@ -77,6 +154,36 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
77154
unwrap!(res)
78155
}
79156

157+
pub(crate) async unsafe fn erase_sector(sector: &FlashSector) -> Result<(), Error> {
158+
let bank = pac::FLASH.bank(sector.bank as usize);
159+
bank.cr().modify(|w| {
160+
w.set_ser(true);
161+
#[cfg(flash_h7)]
162+
w.set_snb(sector.index_in_bank);
163+
#[cfg(flash_h7ab)]
164+
w.set_ssn(sector.index_in_bank);
165+
w.set_eopie(true);
166+
w.set_operrie(true);
167+
});
168+
169+
bank.cr().modify(|w| {
170+
w.set_start(true);
171+
});
172+
173+
cortex_m::asm::isb();
174+
cortex_m::asm::dsb();
175+
fence(Ordering::SeqCst);
176+
177+
let ret: Result<(), Error> = wait_ready(bank).await;
178+
bank.cr().modify(|w| {
179+
w.set_ser(false);
180+
w.set_eopie(false);
181+
w.set_operrie(false);
182+
});
183+
bank_clear_all_err(bank);
184+
ret
185+
}
186+
80187
pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
81188
let bank = pac::FLASH.bank(sector.bank as usize);
82189
bank.cr().modify(|w| {
@@ -112,46 +219,59 @@ unsafe fn bank_clear_all_err(bank: pac::flash::Bank) {
112219
bank.sr().modify(|_| {});
113220
}
114221

222+
async fn wait_ready(bank: pac::flash::Bank) -> Result<(), Error> {
223+
use core::future::poll_fn;
224+
use core::task::Poll;
225+
226+
poll_fn(|cx| {
227+
WAKER.register(cx.waker());
228+
229+
let sr = bank.sr().read();
230+
if !sr.bsy() && !sr.qw() {
231+
Poll::Ready(get_result(sr))
232+
} else {
233+
return Poll::Pending;
234+
}
235+
})
236+
.await
237+
}
238+
115239
unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> {
116240
loop {
117241
let sr = bank.sr().read();
118242

119243
if !sr.bsy() && !sr.qw() {
120-
if sr.wrperr() {
121-
return Err(Error::Protected);
122-
}
123-
if sr.pgserr() {
124-
error!("pgserr");
125-
return Err(Error::Seq);
126-
}
127-
if sr.incerr() {
128-
// writing to a different address when programming 256 bit word was not finished
129-
error!("incerr");
130-
return Err(Error::Seq);
131-
}
132-
if sr.crcrderr() {
133-
error!("crcrderr");
134-
return Err(Error::Seq);
135-
}
136-
if sr.operr() {
137-
return Err(Error::Prog);
138-
}
139-
if sr.sneccerr1() {
140-
// single ECC error
141-
return Err(Error::Prog);
142-
}
143-
if sr.dbeccerr() {
144-
// double ECC error
145-
return Err(Error::Prog);
146-
}
147-
if sr.rdperr() {
148-
return Err(Error::Protected);
149-
}
150-
if sr.rdserr() {
151-
return Err(Error::Protected);
152-
}
153-
154-
return Ok(());
244+
return get_result(sr);
155245
}
156246
}
157247
}
248+
249+
fn get_result(sr: Sr) -> Result<(), Error> {
250+
if sr.wrperr() {
251+
Err(Error::Protected)
252+
} else if sr.pgserr() {
253+
error!("pgserr");
254+
Err(Error::Seq)
255+
} else if sr.incerr() {
256+
// writing to a different address when programming 256 bit word was not finished
257+
error!("incerr");
258+
Err(Error::Seq)
259+
} else if sr.crcrderr() {
260+
error!("crcrderr");
261+
Err(Error::Seq)
262+
} else if sr.operr() {
263+
Err(Error::Prog)
264+
} else if sr.sneccerr1() {
265+
// single ECC error
266+
Err(Error::Prog)
267+
} else if sr.dbeccerr() {
268+
// double ECC error
269+
Err(Error::Prog)
270+
} else if sr.rdperr() {
271+
Err(Error::Protected)
272+
} else if sr.rdserr() {
273+
Err(Error::Protected)
274+
} else {
275+
Ok(())
276+
}
277+
}

embassy-stm32/src/flash/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
//! Flash memory (FLASH)
22
use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind};
33

4-
#[cfg(flash_f4)]
4+
#[cfg(any(flash_f4, flash_h7, flash_h7ab))]
55
mod asynch;
66
#[cfg(flash)]
77
mod common;
88
#[cfg(eeprom)]
99
mod eeprom;
1010

11-
#[cfg(flash_f4)]
11+
#[cfg(any(flash_f4, flash_h7, flash_h7ab))]
1212
pub use asynch::InterruptHandler;
1313
#[cfg(flash)]
1414
pub use common::*;

0 commit comments

Comments
 (0)