@@ -160,6 +160,59 @@ impl FLASH {
160
160
} )
161
161
}
162
162
163
+ /// Writes a half-page (16 words) of Flash memory
164
+ ///
165
+ /// The memory written to must have been erased before, otherwise this
166
+ /// method will return an error.
167
+ ///
168
+ /// # Panics
169
+ ///
170
+ /// This method will panic, unless all of the following is true:
171
+ /// - `address` points to Flash memory
172
+ /// - `address` is aligned to a half-page boundary (16 words, 64 bytes)
173
+ /// - `words` has a length of 16
174
+ pub fn write_flash_half_page ( & mut self , address : * mut u32 , words : & [ u32 ] )
175
+ -> Result
176
+ {
177
+ self . unlock ( |self_| {
178
+ let memory = self_. verify_address ( address) ;
179
+
180
+ if !memory. is_flash ( ) {
181
+ panic ! ( "Address does not point to Flash memory" ) ;
182
+ }
183
+ if address as u32 & 0x3f != 0 {
184
+ panic ! ( "Address is not aligned to half-page boundary" ) ;
185
+ }
186
+ if words. len ( ) != 16 {
187
+ panic ! ( "`words` is not exactly a half-page of memory" ) ;
188
+ }
189
+
190
+ // Wait, while the memory interface is busy.
191
+ while self_. flash . sr . read ( ) . bsy ( ) . is_active ( ) { }
192
+
193
+ // Enable write operation
194
+ self_. flash . pecr . modify ( |_, w| {
195
+ // Half-page programming mode
196
+ w. fprg ( ) . set_bit ( ) ;
197
+ // Required for mass operations in Flash memory
198
+ w. prog ( ) . set_bit ( ) ;
199
+
200
+ w
201
+ } ) ;
202
+
203
+ // Safe, because we've verified the valididty of `address` and the
204
+ // length `words`.
205
+ unsafe { write_half_page ( address, words. as_ptr ( ) ) ; }
206
+
207
+ // Wait for operation to complete
208
+ while self_. flash . sr . read ( ) . bsy ( ) . is_active ( ) { }
209
+
210
+ self_. check_errors ( )
211
+
212
+ // No need to reset PECR flags, that's done by `unlock`.
213
+ } )
214
+ }
215
+
163
216
fn unlock ( & mut self , f : impl FnOnce ( & mut Self ) -> Result ) -> Result {
164
217
// Unlock everything that needs unlocking
165
218
self . flash . pekeyr . write ( |w| w. pekeyr ( ) . bits ( 0x89ABCDEF ) ) ;
@@ -261,6 +314,28 @@ pub fn flash_size_in_kb() -> u32 {
261
314
}
262
315
263
316
317
+ extern {
318
+ /// Writes a half-page at the given address
319
+ ///
320
+ /// Unfortunately this function had to be implemented in C. No access to
321
+ /// Flash memory is allowed after the first word has been written, and that
322
+ /// includes execution of code that is located in Flash. This means the
323
+ /// function that writes the half-page has to be executed from memory, and
324
+ /// is not allowed to call any functions that are not located in memory.
325
+ ///
326
+ /// Unfortunately I found this impossible to achieve in Rust. I can write
327
+ /// a Rust function that is located in RAM, using `#[link_section=".data"]`,
328
+ /// but I failed to write any useful Rust code that doesn't include function
329
+ /// calls to _something_ that is outside of my control, as so much of Rust's
330
+ /// functionality is defined in terms of function calls.
331
+ ///
332
+ /// I ended up writing it in C, as that was the only solution I could come
333
+ /// up with that will run on the stable channel (is nightly is acceptable,
334
+ /// we could use a Rust function with inline assembly).
335
+ fn write_half_page ( address : * mut u32 , words : * const u32 ) ;
336
+ }
337
+
338
+
264
339
#[ derive( Copy , Clone , Eq , PartialEq ) ]
265
340
enum Memory {
266
341
Flash ,
0 commit comments