Skip to content

Commit 72ae805

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

File tree

2 files changed

+167
-0
lines changed

2 files changed

+167
-0
lines changed

src/flash.rs

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
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 with offset into flash memory,
105+
/// aligned to 128-bit rows
106+
pub fn program<I>(&mut self, mut offset: usize, mut bytes: I) -> Result<(), Error>
107+
where
108+
I: Iterator<Item = u8>,
109+
{
110+
let ptr = self.flash.address() as *mut u8;
111+
let mut bytes_written = 1;
112+
while bytes_written > 0 {
113+
bytes_written = 0;
114+
let amount = 16 - (offset % 16);
115+
116+
#[rustfmt::skip]
117+
self.flash.cr.modify(|_, w| unsafe {
118+
w
119+
.psize().bits(PSIZE_X8)
120+
// no sector erase
121+
.ser().clear_bit()
122+
// programming
123+
.pg().set_bit()
124+
});
125+
for _ in 0..amount {
126+
match bytes.next() {
127+
Some(byte) => {
128+
unsafe {
129+
ptr::write_volatile(ptr.add(offset), byte);
130+
}
131+
offset += 1;
132+
bytes_written += 1;
133+
}
134+
None => break,
135+
}
136+
}
137+
self.wait_ready();
138+
self.ok()?;
139+
}
140+
self.flash.cr.modify(|_, w| w.pg().clear_bit());
141+
142+
Ok(())
143+
}
144+
145+
fn ok(&self) -> Result<(), Error> {
146+
Error::read(&self.flash).map(Err).unwrap_or(Ok(()))
147+
}
148+
149+
fn wait_ready(&self) {
150+
while self.flash.sr.read().bsy().bit() {}
151+
}
152+
}
153+
154+
const UNLOCK_KEY1: u32 = 0x45670123;
155+
const UNLOCK_KEY2: u32 = 0xCDEF89AB;
156+
157+
fn unlock(flash: &FLASH) {
158+
flash.keyr.write(|w| unsafe { w.key().bits(UNLOCK_KEY1) });
159+
flash.keyr.write(|w| unsafe { w.key().bits(UNLOCK_KEY2) });
160+
assert!(!flash.cr.read().lock().bit())
161+
}
162+
163+
fn lock(flash: &FLASH) {
164+
flash.cr.modify(|_, w| w.lock().set_bit());
165+
}

src/lib.rs

+2
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)