Skip to content

Commit a34e0de

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

File tree

2 files changed

+154
-0
lines changed

2 files changed

+154
-0
lines changed

src/flash.rs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
use crate::signature::FlashSize;
2+
use crate::stm32::FLASH;
3+
use core::{ptr, 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+
let snb = if sector < 12 { sector } else { sector + 4 };
86+
87+
#[rustfmt::skip]
88+
self.flash.cr.modify(|_, w| unsafe {
89+
w
90+
// start
91+
.strt().set_bit()
92+
.psize().bits(PSIZE_X8)
93+
// sector number
94+
.snb().bits(snb)
95+
// sectore erase
96+
.ser().set_bit()
97+
// no programming
98+
.pg().clear_bit()
99+
});
100+
self.wait_ready();
101+
self.ok()
102+
}
103+
104+
/// Program bytes into flash with offset into flash memory
105+
pub fn program<I>(&mut self, offset: usize, bytes: I) -> Result<(), Error>
106+
where
107+
I: Iterator<Item = u8>,
108+
{
109+
let ptr = (self.flash.address() + offset) as *mut u8;
110+
111+
#[rustfmt::skip]
112+
self.flash.cr.modify(|_, w| unsafe {
113+
w
114+
.psize().bits(PSIZE_X8)
115+
// no sectore erase
116+
.ser().clear_bit()
117+
// programming
118+
.pg().set_bit()
119+
});
120+
for (i, byte) in bytes.into_iter().enumerate() {
121+
unsafe {
122+
ptr::write_volatile(ptr.wrapping_add(i), byte);
123+
}
124+
}
125+
self.wait_ready();
126+
self.ok()?;
127+
128+
self.flash.cr.modify(|_, w| w.pg().clear_bit());
129+
Ok(())
130+
}
131+
132+
fn ok(&self) -> Result<(), Error> {
133+
Error::read(&self.flash).map(Err).unwrap_or(Ok(()))
134+
}
135+
136+
fn wait_ready(&self) {
137+
while self.flash.sr.read().bsy().bit() {}
138+
}
139+
}
140+
141+
const UNLOCK_KEY1: u32 = 0x45670123;
142+
const UNLOCK_KEY2: u32 = 0xCDEF89AB;
143+
144+
fn unlock(flash: &FLASH) {
145+
flash.keyr.write(|w| unsafe { w.key().bits(UNLOCK_KEY1) });
146+
flash.keyr.write(|w| unsafe { w.key().bits(UNLOCK_KEY2) });
147+
assert!(!flash.cr.read().lock().bit())
148+
}
149+
150+
fn lock(flash: &FLASH) {
151+
flash.cr.modify(|_, w| w.lock().set_bit());
152+
}

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)