Skip to content

Commit 9bbdac8

Browse files
authored
Merge pull request #347 from stm32-rs/flash
Implement flash read/erase/program
2 parents 4d67776 + 68ae4f1 commit 9bbdac8

File tree

4 files changed

+177
-3
lines changed

4 files changed

+177
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
134134
STM32F417, STM32F423, STM32F427, STM32F429, STM32F437, STM32F439, STM32F469,
135135
and STM32F479 [#262]
136136
- Added `gpio::gpiox::Pxi::downgrade2` method [#272]
137+
- Added flash driver
137138

138139
[#231]: https://github.com/stm32-rs/stm32f4xx-hal/pull/231
139140
[#262]: https://github.com/stm32-rs/stm32f4xx-hal/pull/262

src/flash.rs

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
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+
#[allow(clippy::len_without_is_empty)]
36+
pub trait FlashExt {
37+
/// Memory-mapped address
38+
fn address(&self) -> usize;
39+
/// Size in bytes
40+
fn len(&self) -> usize;
41+
/// Returns a read-only view of flash memory
42+
fn read(&self) -> &[u8] {
43+
let ptr = self.address() as *const _;
44+
unsafe { slice::from_raw_parts(ptr, self.len()) }
45+
}
46+
/// Unlock flash for erasing/programming until this method's
47+
/// result is dropped
48+
fn unlocked(&mut self) -> UnlockedFlash;
49+
}
50+
51+
impl FlashExt for FLASH {
52+
fn address(&self) -> usize {
53+
0x0800_0000
54+
}
55+
56+
fn len(&self) -> usize {
57+
FlashSize::get().bytes()
58+
}
59+
60+
fn unlocked(&mut self) -> UnlockedFlash {
61+
unlock(self);
62+
UnlockedFlash { flash: self }
63+
}
64+
}
65+
66+
const PSIZE_X8: u8 = 0b00;
67+
68+
/// Result of `FlashExt::unlocked()`
69+
pub struct UnlockedFlash<'a> {
70+
flash: &'a mut FLASH,
71+
}
72+
73+
/// Automatically lock flash erase/program when leaving scope
74+
impl Drop for UnlockedFlash<'_> {
75+
fn drop(&mut self) {
76+
lock(&self.flash);
77+
}
78+
}
79+
80+
impl UnlockedFlash<'_> {
81+
/// Erase a flash sector
82+
///
83+
/// Refer to the reference manual to see which sector corresponds
84+
/// to which memory address.
85+
pub fn erase(&mut self, sector: u8) -> Result<(), Error> {
86+
let snb = if sector < 12 { sector } else { sector + 4 };
87+
88+
#[rustfmt::skip]
89+
self.flash.cr.modify(|_, w| unsafe {
90+
w
91+
// start
92+
.strt().set_bit()
93+
.psize().bits(PSIZE_X8)
94+
// sector number
95+
.snb().bits(snb)
96+
// sectore erase
97+
.ser().set_bit()
98+
// no programming
99+
.pg().clear_bit()
100+
});
101+
self.wait_ready();
102+
self.ok()
103+
}
104+
105+
/// Program bytes with offset into flash memory,
106+
/// aligned to 128-bit rows
107+
pub fn program<'a, I>(&mut self, mut offset: usize, mut bytes: I) -> Result<(), Error>
108+
where
109+
I: Iterator<Item = &'a u8>,
110+
{
111+
let ptr = self.flash.address() as *mut u8;
112+
let mut bytes_written = 1;
113+
while bytes_written > 0 {
114+
bytes_written = 0;
115+
let amount = 16 - (offset % 16);
116+
117+
#[rustfmt::skip]
118+
self.flash.cr.modify(|_, w| unsafe {
119+
w
120+
.psize().bits(PSIZE_X8)
121+
// no sector erase
122+
.ser().clear_bit()
123+
// programming
124+
.pg().set_bit()
125+
});
126+
for _ in 0..amount {
127+
match bytes.next() {
128+
Some(byte) => {
129+
unsafe {
130+
ptr::write_volatile(ptr.add(offset), *byte);
131+
}
132+
offset += 1;
133+
bytes_written += 1;
134+
}
135+
None => break,
136+
}
137+
}
138+
self.wait_ready();
139+
self.ok()?;
140+
}
141+
self.flash.cr.modify(|_, w| w.pg().clear_bit());
142+
143+
Ok(())
144+
}
145+
146+
fn ok(&self) -> Result<(), Error> {
147+
Error::read(&self.flash).map(Err).unwrap_or(Ok(()))
148+
}
149+
150+
fn wait_ready(&self) {
151+
while self.flash.sr.read().bsy().bit() {}
152+
}
153+
}
154+
155+
const UNLOCK_KEY1: u32 = 0x45670123;
156+
const UNLOCK_KEY2: u32 = 0xCDEF89AB;
157+
158+
fn unlock(flash: &FLASH) {
159+
flash.keyr.write(|w| unsafe { w.key().bits(UNLOCK_KEY1) });
160+
flash.keyr.write(|w| unsafe { w.key().bits(UNLOCK_KEY2) });
161+
assert!(!flash.cr.read().lock().bit())
162+
}
163+
164+
fn lock(flash: &FLASH) {
165+
flash.cr.modify(|_, w| w.lock().set_bit());
166+
}

src/gpio/convert.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -603,17 +603,17 @@ impl<MODE, const P: char, const N: u8> Pin<MODE, P, N> {
603603
fn mode<M: PinMode>(&mut self) {
604604
let offset = 2 * N;
605605
unsafe {
606-
&(*Gpio::<P>::ptr()).pupdr.modify(|r, w| {
606+
(*Gpio::<P>::ptr()).pupdr.modify(|r, w| {
607607
w.bits((r.bits() & !(0b11 << offset)) | (u32::from(M::PUPDR) << offset))
608608
});
609609

610610
if let Some(otyper) = M::OTYPER {
611-
&(*Gpio::<P>::ptr())
611+
(*Gpio::<P>::ptr())
612612
.otyper
613613
.modify(|r, w| w.bits(r.bits() & !(0b1 << N) | (u32::from(otyper) << N)));
614614
}
615615

616-
&(*Gpio::<P>::ptr()).moder.modify(|r, w| {
616+
(*Gpio::<P>::ptr()).moder.modify(|r, w| {
617617
w.bits((r.bits() & !(0b11 << offset)) | (u32::from(M::MODER) << offset))
618618
});
619619
}

src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@ compile_error!(
2323
stm32f479"
2424
);
2525

26+
#[cfg(feature = "device-selected")]
2627
pub use embedded_hal as hal;
2728

29+
#[cfg(feature = "device-selected")]
2830
pub use nb;
31+
#[cfg(feature = "device-selected")]
2932
pub use nb::block;
3033

3134
#[cfg(feature = "stm32f401")]
@@ -141,6 +144,8 @@ pub use pac as stm32;
141144
pub mod dma;
142145
#[cfg(feature = "device-selected")]
143146
pub mod dwt;
147+
#[cfg(feature = "device-selected")]
148+
pub mod flash;
144149
#[cfg(all(
145150
feature = "device-selected",
146151
feature = "fsmc_lcd",
@@ -176,7 +181,9 @@ pub mod timer;
176181
#[cfg(feature = "device-selected")]
177182
pub mod watchdog;
178183

184+
#[cfg(feature = "device-selected")]
179185
mod sealed {
180186
pub trait Sealed {}
181187
}
188+
#[cfg(feature = "device-selected")]
182189
pub(crate) use sealed::Sealed;

0 commit comments

Comments
 (0)