1
1
//! Flash memory
2
2
3
+ // See ST document PM0075 for more information
4
+
3
5
use crate :: pac:: { flash, FLASH } ;
4
6
5
7
pub const FLASH_START : u32 = 0x0800_0000 ;
6
8
pub const FLASH_END : u32 = 0x080F_FFFF ;
7
9
8
- const _RDPRT_KEY: u16 = 0x00A5 ;
10
+ const OPT_BYTES_BASE : u32 = 0x1FFF_F800 ;
11
+ const RDPRT_KEY : u8 = 0xA5 ;
9
12
const KEY1 : u32 = 0x45670123 ;
10
13
const KEY2 : u32 = 0xCDEF89AB ;
11
14
@@ -24,6 +27,7 @@ pub enum Error {
24
27
WriteError ,
25
28
VerifyError ,
26
29
UnlockError ,
30
+ UnlockOptError ,
27
31
LockError ,
28
32
}
29
33
@@ -51,6 +55,15 @@ pub enum FlashSize {
51
55
Sz768K = 768 ,
52
56
Sz1M = 1024 ,
53
57
}
58
+
59
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Ord , PartialOrd ) ]
60
+ pub enum ProtectionStatus {
61
+ Unprotected ,
62
+ Read ,
63
+ Write ,
64
+ ReadWrite ,
65
+ }
66
+
54
67
impl FlashSize {
55
68
const fn kbytes ( self ) -> u32 {
56
69
SZ_1K as u32 * self as u32
@@ -101,6 +114,111 @@ impl<'a> FlashWriter<'a> {
101
114
}
102
115
}
103
116
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
+
104
222
fn valid_address ( & self , offset : u32 ) -> Result < ( ) > {
105
223
if FLASH_START + offset > FLASH_END {
106
224
Err ( Error :: AddressLargerThanFlash )
@@ -288,6 +406,31 @@ impl<'a> FlashWriter<'a> {
288
406
pub fn change_verification ( & mut self , verify : bool ) {
289
407
self . verify = verify;
290
408
}
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
+ }
291
434
}
292
435
293
436
/// Extension trait to constrain the FLASH peripheral
@@ -303,10 +446,10 @@ impl FlashExt for FLASH {
303
446
ar : AR { _0 : ( ) } ,
304
447
cr : CR { _0 : ( ) } ,
305
448
keyr : KEYR { _0 : ( ) } ,
306
- _obr : OBR { _0 : ( ) } ,
307
- _optkeyr : OPTKEYR { _0 : ( ) } ,
449
+ obr : OBR { _0 : ( ) } ,
450
+ optkeyr : OPTKEYR { _0 : ( ) } ,
308
451
sr : SR { _0 : ( ) } ,
309
- _wrpr : WRPR { _0 : ( ) } ,
452
+ wrpr : WRPR { _0 : ( ) } ,
310
453
}
311
454
}
312
455
}
@@ -326,16 +469,16 @@ pub struct Parts {
326
469
pub ( crate ) keyr : KEYR ,
327
470
328
471
/// Opaque OBR register
329
- pub ( crate ) _obr : OBR ,
472
+ pub ( crate ) obr : OBR ,
330
473
331
474
/// Opaque OPTKEYR register
332
- pub ( crate ) _optkeyr : OPTKEYR ,
475
+ pub ( crate ) optkeyr : OPTKEYR ,
333
476
334
477
/// Opaque SR register
335
478
pub ( crate ) sr : SR ,
336
479
337
480
/// Opaque WRPR register
338
- pub ( crate ) _wrpr : WRPR ,
481
+ pub ( crate ) wrpr : WRPR ,
339
482
}
340
483
impl Parts {
341
484
pub fn writer ( & mut self , sector_sz : SectorSize , flash_sz : FlashSize ) -> FlashWriter {
0 commit comments