Skip to content

Commit b5532de

Browse files
committed
Implement flash read/erase/program
1 parent 4b04112 commit b5532de

File tree

2 files changed

+152
-0
lines changed

2 files changed

+152
-0
lines changed

src/flash.rs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
use crate::signature::FlashSize;
2+
use crate::stm32::FLASH;
3+
use core::slice;
4+
5+
/// Flash erase/program error
6+
#[derive(Debug, Clone, Copy)]
7+
pub enum Error {
8+
ProgrammingSequence,
9+
ProgrammingParallelism,
10+
ProgrammingAlignment,
11+
WriteProtection,
12+
Operation,
13+
}
14+
15+
impl Error {
16+
fn read(flash: &FLASH) -> Option<Self> {
17+
let sr = flash.sr.read();
18+
if sr.pgserr().bit() {
19+
Some(Error::ProgrammingSequence)
20+
} else if sr.pgperr().bit() {
21+
Some(Error::ProgrammingParallelism)
22+
} else if sr.pgaerr().bit() {
23+
Some(Error::ProgrammingAlignment)
24+
} else if sr.wrperr().bit() {
25+
Some(Error::WriteProtection)
26+
} else if sr.operr().bit() {
27+
Some(Error::Operation)
28+
} else {
29+
None
30+
}
31+
}
32+
}
33+
34+
/// Flash methods implemented for `stm32::FLASH`
35+
pub trait FlashExt {
36+
/// Memory-mapped address
37+
fn address(&self) -> usize;
38+
/// Size in bytes
39+
fn len(&self) -> usize;
40+
/// Returns a read-only view of flash memory
41+
fn read(&self) -> &[u8] {
42+
let ptr = self.address() as *const _;
43+
unsafe { slice::from_raw_parts(ptr, self.len()) }
44+
}
45+
/// Unlock flash for erasing/programming until this method's
46+
/// result is dropped
47+
fn unlocked(&mut self) -> UnlockedFlash;
48+
}
49+
50+
impl FlashExt for FLASH {
51+
fn address(&self) -> usize {
52+
0x0800_0000
53+
}
54+
55+
fn len(&self) -> usize {
56+
FlashSize::get().bytes()
57+
}
58+
59+
fn unlocked(&mut self) -> UnlockedFlash {
60+
unlock(self);
61+
UnlockedFlash { flash: self }
62+
}
63+
}
64+
65+
const PSIZE_X8: u8 = 0b00;
66+
67+
/// Result of `FlashExt::unlocked()`
68+
pub struct UnlockedFlash<'a> {
69+
flash: &'a mut FLASH,
70+
}
71+
72+
/// Automatically lock flash erase/program when leaving scope
73+
impl Drop for UnlockedFlash<'_> {
74+
fn drop(&mut self) {
75+
lock(&self.flash);
76+
}
77+
}
78+
79+
impl UnlockedFlash<'_> {
80+
/// Erase a flash sector
81+
///
82+
/// Refer to the reference manual to see which sector corresponds
83+
/// to which memory address.
84+
pub fn erase(&mut self, sector: u8) -> Result<(), Error> {
85+
#[rustfmt::skip]
86+
self.flash.cr.modify(|_, w| unsafe {
87+
w
88+
// start
89+
.strt().set_bit()
90+
.psize().bits(PSIZE_X8)
91+
// sector number
92+
.snb().bits(sector)
93+
// sectore erase
94+
.ser().set_bit()
95+
// no programming
96+
.pg().clear_bit()
97+
});
98+
self.wait_ready();
99+
self.ok()
100+
}
101+
102+
/// Program bytes into flash with offset into flash memory
103+
pub fn program<I>(&mut self, offset: usize, bytes: I) -> Result<(), Error>
104+
where
105+
I: IntoIterator<Item = u8>,
106+
{
107+
let ptr = (self.flash.address() + offset) as *mut u8;
108+
109+
#[rustfmt::skip]
110+
self.flash.cr.modify(|_, w| unsafe {
111+
w
112+
.psize().bits(PSIZE_X8)
113+
// no sectore erase
114+
.ser().clear_bit()
115+
// programming
116+
.pg().set_bit()
117+
});
118+
for (i, byte) in bytes.into_iter().enumerate() {
119+
unsafe {
120+
*ptr.wrapping_add(i) = byte;
121+
}
122+
}
123+
self.wait_ready();
124+
self.ok()?;
125+
126+
self.flash.cr.modify(|_, w| w.pg().clear_bit());
127+
Ok(())
128+
}
129+
130+
fn ok(&self) -> Result<(), Error> {
131+
Error::read(&self.flash).map(Err).unwrap_or(Ok(()))
132+
}
133+
134+
fn wait_ready(&self) {
135+
while self.flash.sr.read().bsy().bit() {}
136+
}
137+
}
138+
139+
const UNLOCK_KEY1: u32 = 0x45670123;
140+
const UNLOCK_KEY2: u32 = 0xCDEF89AB;
141+
142+
fn unlock(flash: &FLASH) {
143+
flash.keyr.write(|w| unsafe { w.key().bits(UNLOCK_KEY1) });
144+
flash.keyr.write(|w| unsafe { w.key().bits(UNLOCK_KEY2) });
145+
assert!(!flash.cr.read().lock().bit())
146+
}
147+
148+
fn lock(flash: &FLASH) {
149+
flash.cr.modify(|_, w| w.lock().set_bit());
150+
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ pub mod dma;
159159
#[cfg(feature = "device-selected")]
160160
pub mod dwt;
161161
#[cfg(feature = "device-selected")]
162+
pub mod flash;
163+
#[cfg(feature = "device-selected")]
162164
pub mod prelude;
163165
#[cfg(feature = "device-selected")]
164166
pub mod pwm;

0 commit comments

Comments
 (0)