1
1
//! Flash memory
2
+ //!
3
+ //! Quickstart:
4
+ //!
5
+ //! 1. [`Flash::unlock`]
6
+ //! 2. [`Flash::page_erase`]
7
+ //! 3. [`Flash::program_bytes`]
2
8
3
9
use crate :: pac;
4
- use core:: { ops:: Range , ptr:: write_volatile} ;
10
+ use core:: { mem :: size_of , ops:: Range , ptr:: write_volatile, slice :: ChunksExact } ;
5
11
use num_integer:: Integer ;
6
12
7
13
/// Starting address of the flash memory.
@@ -25,6 +31,36 @@ pub fn flash_end() -> usize {
25
31
OFFSET + crate :: info:: flash_size ( ) as usize
26
32
}
27
33
34
+ /// Range of flash memory.
35
+ ///
36
+ /// This is calculated at runtime using the info registers.
37
+ ///
38
+ /// # Example
39
+ ///
40
+ /// ```no_run
41
+ /// use core::ops::Range;
42
+ /// use stm32wlxx_hal::flash::flash_range;
43
+ ///
44
+ /// // valid for the nucleo-wl55jc with 256k flash
45
+ /// assert_eq!(
46
+ /// flash_range(),
47
+ /// Range {
48
+ /// start: 0x0800_0000,
49
+ /// end: 0x0804_0000
50
+ /// }
51
+ /// );
52
+ /// assert!(flash_range().contains(&0x0800_0000));
53
+ /// assert!(flash_range().contains(&0x0803_FFFF));
54
+ /// assert!(!flash_range().contains(&0x0804_0000));
55
+ /// ```
56
+ #[ inline]
57
+ pub fn flash_range ( ) -> Range < usize > {
58
+ Range {
59
+ start : FLASH_START ,
60
+ end : FLASH_START + crate :: info:: flash_size ( ) as usize ,
61
+ }
62
+ }
63
+
28
64
/// Number of flash pages.
29
65
///
30
66
/// This is calculated at runtime using the info registers.
@@ -68,7 +104,16 @@ impl Page {
68
104
///
69
105
/// # Safety
70
106
///
71
- /// 1. The `idx` argument must point to a valid flash page.
107
+ /// 1. The `idx` argument must be a valid page number, less than the value
108
+ /// returned by [`num_pages`].
109
+ ///
110
+ /// # Example
111
+ ///
112
+ /// ```
113
+ /// use stm32wlxx_hal::flash::Page;
114
+ ///
115
+ /// let page0 = unsafe { Page::from_index_unchecked(0) };
116
+ /// ```
72
117
#[ inline]
73
118
pub const unsafe fn from_index_unchecked ( idx : u8 ) -> Self {
74
119
Page { idx }
@@ -150,9 +195,9 @@ impl Page {
150
195
/// # Example
151
196
///
152
197
/// ```
153
- /// # let page7 = unsafe { Page::from_index_unchecked(7) };
154
198
/// use stm32wlxx_hal::flash::Page;
155
199
///
200
+ /// let page7 = unsafe { Page::from_index_unchecked(7) };
156
201
/// assert_eq!(page7.to_index(), 7);
157
202
/// ```
158
203
#[ inline]
@@ -164,11 +209,12 @@ impl Page {
164
209
///
165
210
/// # Example
166
211
///
167
- /// ```no_run
168
- /// # let page127 = unsafe { Page::from_index_unchecked(127) };
169
- /// # let page0 = unsafe { Page::from_index_unchecked(0) };
212
+ /// ```
170
213
/// use stm32wlxx_hal::flash::Page;
171
214
///
215
+ /// let page127 = unsafe { Page::from_index_unchecked(127) };
216
+ /// let page0 = unsafe { Page::from_index_unchecked(0) };
217
+ ///
172
218
/// assert_eq!(page0.addr(), 0x0800_0000);
173
219
/// assert_eq!(page127.addr(), 0x0803_F800);
174
220
/// ```
@@ -180,11 +226,11 @@ impl Page {
180
226
///
181
227
/// # Example
182
228
///
183
- /// ```no_run
184
- /// # let page0 = unsafe { Page::from_index_unchecked(0) };
229
+ /// ```
185
230
/// use core::ops::Range;
186
231
/// use stm32wlxx_hal::flash::Page;
187
232
///
233
+ /// let page0 = unsafe { Page::from_index_unchecked(0) };
188
234
/// assert_eq!(
189
235
/// page0.addr_range(),
190
236
/// Range {
@@ -201,11 +247,104 @@ impl Page {
201
247
}
202
248
}
203
249
250
+ impl From < Page > for AlignedAddr {
251
+ #[ inline]
252
+ fn from ( page : Page ) -> Self {
253
+ AlignedAddr { addr : page. addr ( ) }
254
+ }
255
+ }
256
+
257
+ /// Error for conversions to [`AlignedAddr`].
258
+ #[ derive( Debug , Copy , Clone , Eq , PartialEq ) ]
259
+ #[ cfg_attr( feature = "defmt" , derive( defmt:: Format ) ) ]
260
+ pub struct AlignedAddrError ( pub ( crate ) ( ) ) ;
261
+
262
+ impl AlignedAddrError {
263
+ pub ( crate ) const fn new ( ) -> Self {
264
+ Self ( ( ) )
265
+ }
266
+ }
267
+
268
+ /// A `u64` aligned flash address.
269
+ ///
270
+ /// An argument of [`Flash::program_bytes`].
271
+ ///
272
+ /// # Example
273
+ ///
274
+ /// Create an aligned flash address by converting from `usize`.
275
+ ///
276
+ /// ```no_run
277
+ /// use stm32wlxx_hal::flash::AlignedAddr;
278
+ ///
279
+ /// let addr: AlignedAddr = AlignedAddr::try_from(0x0803_F800_usize)?;
280
+ /// # Ok::<(), stm32wlxx_hal::flash::AlignedAddrError>(())
281
+ /// ```
282
+ #[ derive( Debug , Copy , Clone , Eq , PartialEq , Ord , PartialOrd ) ]
283
+ #[ cfg_attr( feature = "defmt" , derive( defmt:: Format ) ) ]
284
+ pub struct AlignedAddr {
285
+ addr : usize ,
286
+ }
287
+
288
+ impl AlignedAddr {
289
+ /// Create a page address from an index without checking bounds.
290
+ ///
291
+ /// # Safety
292
+ ///
293
+ /// 1. The `addr` argument must be a multiple of 8.
294
+ /// 2. The `addr` argument must be a valid flash address, within the range
295
+ /// returned by [`flash_range`].
296
+ ///
297
+ /// # Example
298
+ ///
299
+ /// ```
300
+ /// use stm32wlxx_hal::flash::Page;
301
+ ///
302
+ /// let page0 = unsafe { Page::from_index_unchecked(0) };
303
+ /// ```
304
+ pub const unsafe fn new_unchecked ( addr : usize ) -> Self {
305
+ Self { addr }
306
+ }
307
+ }
308
+
309
+ impl From < AlignedAddr > for usize {
310
+ #[ inline]
311
+ fn from ( addr : AlignedAddr ) -> Self {
312
+ addr. addr
313
+ }
314
+ }
315
+
316
+ impl From < AlignedAddr > for u32 {
317
+ #[ inline]
318
+ fn from ( addr : AlignedAddr ) -> Self {
319
+ addr. addr as u32
320
+ }
321
+ }
322
+
323
+ impl TryFrom < u32 > for AlignedAddr {
324
+ type Error = AlignedAddrError ;
325
+
326
+ fn try_from ( addr : u32 ) -> Result < Self , Self :: Error > {
327
+ Self :: try_from ( addr as usize )
328
+ }
329
+ }
330
+
331
+ impl TryFrom < usize > for AlignedAddr {
332
+ type Error = AlignedAddrError ;
333
+
334
+ fn try_from ( addr : usize ) -> Result < Self , Self :: Error > {
335
+ if addr % size_of :: < u64 > ( ) != 0 || !flash_range ( ) . contains ( & addr) {
336
+ Err ( AlignedAddrError :: new ( ) )
337
+ } else {
338
+ Ok ( AlignedAddr { addr } )
339
+ }
340
+ }
341
+ }
342
+
204
343
/// Flash errors.
205
344
#[ derive( Debug , PartialEq , Eq , Clone , Copy , Hash ) ]
206
345
#[ cfg_attr( feature = "defmt" , derive( defmt:: Format ) ) ]
207
346
pub enum Error {
208
- /// Busy Error .
347
+ /// Busy error .
209
348
///
210
349
/// A flash programming sequence was started while the previous sequence
211
350
/// was still in-progress.
@@ -215,6 +354,11 @@ pub enum Error {
215
354
/// A flash programming sequence was started with a program erase suspend
216
355
/// bit set.
217
356
Suspend ,
357
+ /// Overflow error.
358
+ ///
359
+ /// Returned by [`Flash::standard_program_generic`], or [`Flash::program_bytes`]
360
+ /// when the target data and address would exceed the end of flash memory.
361
+ Overflow ,
218
362
/// Fast programming data miss error.
219
363
///
220
364
/// In Fast programming mode, 32 double-words (256 bytes) must be sent to
@@ -404,6 +548,69 @@ impl<'a> Flash<'a> {
404
548
ret
405
549
}
406
550
551
+ /// Program any number of bytes.
552
+ ///
553
+ /// This is the safest possible method for programming.
554
+ ///
555
+ /// # Safety
556
+ ///
557
+ /// 1. Do not write to flash memory that is being used for your code.
558
+ ///
559
+ /// # Example
560
+ ///
561
+ /// ```no_run
562
+ /// use stm32wlxx_hal::{
563
+ /// flash::{Flash, Page},
564
+ /// pac,
565
+ /// };
566
+ ///
567
+ /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
568
+ ///
569
+ /// let my_data: [u8; 3] = [0x14, 0x15, 0x16];
570
+ ///
571
+ /// let last_page: Page = Page::from_index(127).unwrap();
572
+ ///
573
+ /// let mut flash: Flash = Flash::unlock(&mut dp.FLASH);
574
+ /// unsafe {
575
+ /// flash.page_erase(last_page)?;
576
+ /// flash.program_bytes(&my_data, last_page.into())?;
577
+ /// }
578
+ /// # Ok::<(), stm32wlxx_hal::flash::Error>(())
579
+ /// ```
580
+ pub unsafe fn program_bytes ( & mut self , from : & [ u8 ] , to : AlignedAddr ) -> Result < ( ) , Error > {
581
+ if from. is_empty ( ) {
582
+ return Ok ( ( ) ) ;
583
+ }
584
+
585
+ if !flash_range ( ) . contains ( & usize:: from ( to) . saturating_add ( from. len ( ) ) ) {
586
+ return Err ( Error :: Overflow ) ;
587
+ }
588
+
589
+ let chunks_exact: ChunksExact < u8 > = from. chunks_exact ( 8 ) ;
590
+ let remainder: & [ u8 ] = chunks_exact. remainder ( ) ;
591
+ let remainder_len: usize = remainder. len ( ) ;
592
+
593
+ let last_u64: u64 = chunks_exact
594
+ . remainder ( )
595
+ . iter ( )
596
+ . enumerate ( )
597
+ . fold ( 0 , |acc, ( n, byte) | acc | u64:: from ( * byte) << ( 8 * n) ) ;
598
+
599
+ for ( n, chunk) in chunks_exact. enumerate ( ) {
600
+ let chunk_u64: u64 = u64:: from_le_bytes ( chunk. try_into ( ) . unwrap ( ) ) ;
601
+ let addr: usize = n * size_of :: < u64 > ( ) + usize:: from ( to) ;
602
+
603
+ self . standard_program ( & chunk_u64, addr as * mut u64 ) ?;
604
+ }
605
+
606
+ if remainder_len != 0 {
607
+ let last_addr: usize = ( usize:: from ( to) + from. len ( ) ) . prev_multiple_of ( & 8 ) ;
608
+ self . standard_program ( & last_u64, last_addr as * mut u64 ) ?;
609
+ }
610
+
611
+ Ok ( ( ) )
612
+ }
613
+
407
614
/// Program a user-defined type.
408
615
///
409
616
/// # Safety
@@ -418,11 +625,15 @@ impl<'a> Flash<'a> {
418
625
from : * const T ,
419
626
to : * mut T ,
420
627
) -> Result < ( ) , Error > {
421
- let size: isize = core :: mem :: size_of :: < T > ( ) as isize ;
628
+ let size: isize = size_of :: < T > ( ) as isize ;
422
629
if size == 0 {
423
630
return Ok ( ( ) ) ;
424
631
}
425
632
633
+ if !flash_range ( ) . contains ( & ( size_of :: < T > ( ) + to as usize ) ) {
634
+ return Err ( Error :: Overflow ) ;
635
+ }
636
+
426
637
let sr: u32 = self . sr ( ) ;
427
638
if sr & flags:: BSY != 0 {
428
639
return Err ( Error :: Busy ) ;
@@ -533,6 +744,25 @@ impl<'a> Flash<'a> {
533
744
/// # Safety
534
745
///
535
746
/// 1. Do not erase flash memory that is being used for your code.
747
+ ///
748
+ /// # Example
749
+ ///
750
+ /// Erase the last page.
751
+ ///
752
+ /// ```no_run
753
+ /// use stm32wlxx_hal::{
754
+ /// flash::{Flash, Page},
755
+ /// pac,
756
+ /// };
757
+ ///
758
+ /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
759
+ ///
760
+ /// let last_page: Page = Page::from_index(127).unwrap();
761
+ ///
762
+ /// let mut flash: Flash = Flash::unlock(&mut dp.FLASH);
763
+ /// unsafe { flash.page_erase(last_page)? };
764
+ /// # Ok::<(), stm32wlxx_hal::flash::Error>(())
765
+ /// ```
536
766
pub unsafe fn page_erase ( & mut self , page : Page ) -> Result < ( ) , Error > {
537
767
let sr: u32 = self . sr ( ) ;
538
768
if sr & flags:: BSY != 0 {
0 commit comments