11//! Flash memory
22
3+ // See ST document PM0075 for more information
4+
35use crate :: pac:: { flash, FLASH } ;
46
57pub const FLASH_START : u32 = 0x0800_0000 ;
68pub 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 ;
912const KEY1 : u32 = 0x45670123 ;
1013const 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+
5467impl 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}
340483impl Parts {
341484 pub fn writer ( & mut self , sector_sz : SectorSize , flash_sz : FlashSize ) -> FlashWriter {
0 commit comments