Skip to content

Commit 82609d4

Browse files
Implement flash read un/protection per PM0075
1 parent 68fd3d6 commit 82609d4

File tree

2 files changed

+151
-7
lines changed

2 files changed

+151
-7
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1010
### Added
1111

1212
- LSB/MSB bit format selection for `SPI`
13+
- Flash read un/protection
1314

1415
### Fixed
1516
- Fix > 2 byte i2c reads

Diff for: src/flash.rs

+150-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
//! Flash memory
22
3+
// See ST document PM0075 for more information
4+
35
use crate::pac::{flash, FLASH};
46

57
pub const FLASH_START: u32 = 0x0800_0000;
68
pub const FLASH_END: u32 = 0x080F_FFFF;
79

8-
const _RDPRT_KEY: u16 = 0x00A5;
10+
const OPT_BYTES_BASE: u32 = 0x1FFF_F800;
11+
const RDPRT_KEY: u8 = 0xA5;
912
const KEY1: u32 = 0x45670123;
1013
const KEY2: u32 = 0xCDEF89AB;
1114

@@ -24,6 +27,7 @@ pub enum Error {
2427
WriteError,
2528
VerifyError,
2629
UnlockError,
30+
UnlockOptError,
2731
LockError,
2832
}
2933

@@ -51,6 +55,15 @@ pub enum FlashSize {
5155
Sz768K = 768,
5256
Sz1M = 1024,
5357
}
58+
59+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
60+
pub enum ProtectionStatus {
61+
Unprotected,
62+
Read,
63+
Write,
64+
ReadWrite,
65+
}
66+
5467
impl FlashSize {
5568
const fn kbytes(self) -> u32 {
5669
SZ_1K as u32 * self as u32
@@ -101,6 +114,111 @@ impl<'a> FlashWriter<'a> {
101114
}
102115
}
103116

117+
fn unlock_opt(&mut self) -> Result<()> {
118+
// First we must unlock the FPEC
119+
self.unlock()?;
120+
121+
// Wait for any ongoing operations
122+
while self.flash.sr.sr().read().bsy().bit_is_set() {}
123+
124+
// NOTE(unsafe) write Keys to the OPTKEYR register. This is safe because the
125+
// only side effect of these writes is to unlock the option bytes
126+
// register, which is the intent of this function. Do not rearrange the
127+
// order of these writes.
128+
self.flash
129+
.optkeyr
130+
.optkeyr()
131+
.write(|w| unsafe { w.optkey().bits(KEY1) });
132+
133+
self.flash
134+
.optkeyr
135+
.optkeyr()
136+
.write(|w| unsafe { w.optkey().bits(KEY2) });
137+
138+
// Verify success
139+
if self.flash.cr.cr().read().optwre().bit_is_set() {
140+
Ok(())
141+
} else {
142+
Err(Error::UnlockOptError)
143+
}
144+
}
145+
146+
fn lock_opt(&mut self) -> Result<()> {
147+
// Reset the OPTWRE bit before relocking flash generally
148+
self.flash.cr.cr().write(|w| w.optwre().clear_bit());
149+
self.lock()
150+
}
151+
152+
/// Erases the Option Bytes. Requires Option Bytes registers to be unlocked.
153+
fn erase_opt(&mut self) -> Result<()> {
154+
// Ensure OPTWRE is set
155+
if self.flash.cr.cr().read().optwre().bit_is_set() {
156+
// Erase the option bytes and wait
157+
self.flash.cr.cr().modify(|_, w| w.opter().set_bit());
158+
self.flash.cr.cr().modify(|_, w| w.strt().set_bit());
159+
while self.flash.sr.sr().read().bsy().bit_is_set() {}
160+
161+
// Clear EOP bit if set
162+
if self.flash.sr.sr().read().eop().bit_is_set() {
163+
self.flash.sr.sr().modify(|_, w| w.eop().clear_bit());
164+
}
165+
// Clear the OPTER bit
166+
self.flash.cr.cr().modify(|_, w| w.opter().clear_bit());
167+
Ok(())
168+
} else {
169+
Err(Error::UnlockOptError)
170+
}
171+
}
172+
173+
fn set_rdp(&mut self, val: u8) -> Result<()> {
174+
// First we need to unlock the Option Byte programming
175+
self.unlock_opt()?;
176+
177+
// Wait for operation to finish
178+
while self.flash.sr.sr().read().bsy().bit_is_set() {}
179+
180+
// First we must rease the Option Bytes
181+
self.erase_opt()?;
182+
183+
// Now set the OPTPG bit to enable write access to Option Bytes
184+
self.flash.cr.cr().modify(|_, w| w.optpg().set_bit());
185+
186+
let intended_rdp = val as u16;
187+
let opt_ptr = OPT_BYTES_BASE as *mut u16;
188+
unsafe {
189+
core::ptr::write_volatile(opt_ptr, intended_rdp);
190+
}
191+
192+
// // Wait for operation to finish
193+
while self.flash.sr.sr().read().bsy().bit_is_set() {}
194+
195+
// Clear OPTPG bit
196+
self.flash.cr.cr().modify(|_, w| w.optpg().clear_bit());
197+
198+
// Check for an error condition
199+
if self.flash.sr.sr().read().pgerr().bit_is_set() {
200+
// Clear the error bit
201+
self.flash.sr.sr().modify(|_, w| w.pgerr().clear_bit());
202+
// Before returning, re-lock flash.
203+
self.lock_opt()?;
204+
return Err(Error::ProgrammingError);
205+
}
206+
207+
// Wait for operation to finish
208+
while self.flash.sr.sr().read().bsy().bit_is_set() {}
209+
210+
// Now we should re-lock the Option Bytes. NOTE: We intentionally
211+
// do not do this before checking PEGERR in case of side-effects.
212+
self.lock_opt()?;
213+
214+
let curr_rdp = unsafe { *opt_ptr };
215+
if curr_rdp == intended_rdp | !(intended_rdp & 0xFF) << 8 {
216+
Ok(())
217+
} else {
218+
Err(Error::ProgrammingError)
219+
}
220+
}
221+
104222
fn valid_address(&self, offset: u32) -> Result<()> {
105223
if FLASH_START + offset > FLASH_END {
106224
Err(Error::AddressLargerThanFlash)
@@ -288,6 +406,31 @@ impl<'a> FlashWriter<'a> {
288406
pub fn change_verification(&mut self, verify: bool) {
289407
self.verify = verify;
290408
}
409+
410+
/// Reads the OBR and WRPR registers to determine protection status of flash
411+
pub fn protection_status(&mut self) -> ProtectionStatus {
412+
let read_prot = self.flash.obr.obr().read().rdprt().bit_is_set();
413+
let write_prot = self.flash.wrpr.wrpr().read().wrp().bits() == 0;
414+
match (read_prot, write_prot) {
415+
(false, false) => ProtectionStatus::Unprotected,
416+
(true, false) => ProtectionStatus::Read,
417+
(false, true) => ProtectionStatus::Write,
418+
(true, true) => ProtectionStatus::ReadWrite,
419+
}
420+
}
421+
422+
/// Enables Read Protection by setting RDP Option Byte. Will not take efect until
423+
/// MCU has been reset (e.g. via `cortex_m::peripheral::SCB::sys_reset()`)
424+
pub fn protect_read(&mut self) -> Result<()> {
425+
// We can write any value that is not RDPRT_KEY to enable read protection.
426+
// Arbitrarily choose to write 0xBB
427+
self.set_rdp(0xBB)
428+
}
429+
430+
/// NOTE(unsafe) This will cause flash to be erased! Un-protects flash from read.
431+
pub unsafe fn unprotect_read(&mut self) -> Result<()> {
432+
self.set_rdp(RDPRT_KEY)
433+
}
291434
}
292435

293436
/// Extension trait to constrain the FLASH peripheral
@@ -303,10 +446,10 @@ impl FlashExt for FLASH {
303446
ar: AR { _0: () },
304447
cr: CR { _0: () },
305448
keyr: KEYR { _0: () },
306-
_obr: OBR { _0: () },
307-
_optkeyr: OPTKEYR { _0: () },
449+
obr: OBR { _0: () },
450+
optkeyr: OPTKEYR { _0: () },
308451
sr: SR { _0: () },
309-
_wrpr: WRPR { _0: () },
452+
wrpr: WRPR { _0: () },
310453
}
311454
}
312455
}
@@ -326,16 +469,16 @@ pub struct Parts {
326469
pub(crate) keyr: KEYR,
327470

328471
/// Opaque OBR register
329-
pub(crate) _obr: OBR,
472+
pub(crate) obr: OBR,
330473

331474
/// Opaque OPTKEYR register
332-
pub(crate) _optkeyr: OPTKEYR,
475+
pub(crate) optkeyr: OPTKEYR,
333476

334477
/// Opaque SR register
335478
pub(crate) sr: SR,
336479

337480
/// Opaque WRPR register
338-
pub(crate) _wrpr: WRPR,
481+
pub(crate) wrpr: WRPR,
339482
}
340483
impl Parts {
341484
pub fn writer(&mut self, sector_sz: SectorSize, flash_sz: FlashSize) -> FlashWriter {

0 commit comments

Comments
 (0)