stm32f4xx_hal/
flash.rs

1use embedded_storage::nor_flash::{
2    ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash,
3};
4
5use crate::pac::flash::cr::PSIZE;
6use crate::pac::FLASH;
7use crate::signature::FlashSize;
8use core::{ptr, slice};
9
10/// Flash erase/program error
11#[derive(Debug, Clone, Copy)]
12pub enum Error {
13    ProgrammingSequence,
14    ProgrammingParallelism,
15    ProgrammingAlignment,
16    WriteProtection,
17    Operation,
18}
19
20impl Error {
21    fn read(flash: &FLASH) -> Option<Self> {
22        let sr = flash.sr().read();
23        if sr.pgserr().bit() {
24            Some(Error::ProgrammingSequence)
25        } else if sr.pgperr().bit() {
26            Some(Error::ProgrammingParallelism)
27        } else if sr.pgaerr().bit() {
28            Some(Error::ProgrammingAlignment)
29        } else if sr.wrperr().bit() {
30            Some(Error::WriteProtection)
31        } else if sr.operr().bit() {
32            Some(Error::Operation)
33        } else {
34            None
35        }
36    }
37}
38
39/// Flash methods implemented for `pac::FLASH`
40#[allow(clippy::len_without_is_empty)]
41pub trait FlashExt {
42    /// Memory-mapped address
43    fn address(&self) -> usize;
44    /// Size in bytes
45    fn len(&self) -> usize;
46    /// Returns a read-only view of flash memory
47    fn read(&self) -> &[u8] {
48        let ptr = self.address() as *const _;
49        unsafe { slice::from_raw_parts(ptr, self.len()) }
50    }
51    /// Unlock flash for erasing/programming until this method's
52    /// result is dropped
53    fn unlocked(&mut self) -> UnlockedFlash;
54    // Returns true if flash is in dual bank organization
55    fn dual_bank(&self) -> bool;
56    /// Returns flash memory sector of a given offset. Returns none if offset is out of range.
57    fn sector(&self, offset: usize) -> Option<FlashSector>;
58}
59
60impl FlashExt for FLASH {
61    fn address(&self) -> usize {
62        0x0800_0000
63    }
64
65    fn len(&self) -> usize {
66        FlashSize::get().bytes()
67    }
68
69    fn unlocked(&mut self) -> UnlockedFlash {
70        unlock(self);
71        UnlockedFlash { flash: self }
72    }
73
74    fn dual_bank(&self) -> bool {
75        match self.len() / 1024 {
76            // 1 MB devices depend on configuration
77            1024 => {
78                if cfg!(any(
79                    feature = "stm32f427",
80                    feature = "stm32f429",
81                    feature = "stm32f437",
82                    feature = "stm32f439",
83                    feature = "stm32f469",
84                    feature = "stm32f479",
85                )) {
86                    // DB1M bit is not present in all SVDs
87                    // self.optcr.read().db1m().bit_is_set()
88                    self.optcr().read().bits() & (1 << 30) != 0
89                } else {
90                    false
91                }
92            }
93            // 2 MB devices are always dual bank
94            2048 => true,
95            // All other devices are single bank
96            _ => false,
97        }
98    }
99
100    fn sector(&self, offset: usize) -> Option<FlashSector> {
101        flash_sectors(self.len(), self.dual_bank()).find(|s| s.contains(offset))
102    }
103}
104
105/// Read-only flash
106///
107/// # Examples
108///
109/// ```
110/// use stm32f4xx_hal::pac::Peripherals;
111/// use stm32f4xx_hal::flash::LockedFlash;
112/// use embedded_storage::nor_flash::ReadNorFlash;
113///
114/// let dp = Peripherals::take().unwrap();
115/// let mut flash = LockedFlash::new(dp.FLASH);
116/// println!("Flash capacity: {}", ReadNorFlash::capacity(&flash));
117///
118/// let mut buf = [0u8; 64];
119/// ReadNorFlash::read(&mut flash, 0x0, &mut buf).unwrap();
120/// println!("First 64 bytes of flash memory: {:?}", buf);
121/// ```
122pub struct LockedFlash {
123    flash: FLASH,
124}
125
126impl LockedFlash {
127    pub fn new(flash: FLASH) -> Self {
128        Self { flash }
129    }
130}
131
132impl FlashExt for LockedFlash {
133    fn address(&self) -> usize {
134        self.flash.address()
135    }
136
137    fn len(&self) -> usize {
138        self.flash.len()
139    }
140
141    fn unlocked(&mut self) -> UnlockedFlash {
142        self.flash.unlocked()
143    }
144
145    fn dual_bank(&self) -> bool {
146        self.flash.dual_bank()
147    }
148
149    fn sector(&self, offset: usize) -> Option<FlashSector> {
150        self.flash.sector(offset)
151    }
152}
153
154/// Result of `FlashExt::unlocked()`
155///
156/// # Examples
157///
158/// ```
159/// use stm32f4xx_hal::pac::Peripherals;
160/// use stm32f4xx_hal::flash::{FlashExt, LockedFlash, UnlockedFlash};
161/// use embedded_storage::nor_flash::NorFlash;
162///
163/// let dp = Peripherals::take().unwrap();
164/// let mut flash = LockedFlash::new(dp.FLASH);
165///
166/// // Unlock flash for writing
167/// let mut unlocked_flash = flash.unlocked();
168///
169/// // Erase the second 128 KB sector.
170/// NorFlash::erase(&mut unlocked_flash, 128 * 1024, 256 * 1024).unwrap();
171///
172/// // Write some data at the start of the second 128 KB sector.
173/// let buf = [0u8; 64];
174/// NorFlash::write(&mut unlocked_flash, 128 * 1024, &buf).unwrap();
175///
176/// // Lock flash by dropping
177/// drop(unlocked_flash);
178/// ```
179pub struct UnlockedFlash<'a> {
180    flash: &'a mut FLASH,
181}
182
183/// Automatically lock flash erase/program when leaving scope
184impl Drop for UnlockedFlash<'_> {
185    fn drop(&mut self) {
186        lock(self.flash);
187    }
188}
189
190impl UnlockedFlash<'_> {
191    /// Erase a flash sector
192    ///
193    /// Refer to the reference manual to see which sector corresponds
194    /// to which memory address.
195    pub fn erase(&mut self, sector: u8) -> Result<(), Error> {
196        let snb = if sector < 12 { sector } else { sector + 4 };
197
198        self.flash.cr().modify(|_, w| {
199            // start
200            w.strt().set_bit();
201            w.psize().variant(PSIZE::Psize8);
202            // sector number
203            unsafe {
204                w.snb().bits(snb);
205            }
206            // sectore erase
207            w.ser().set_bit();
208            // no programming
209            w.pg().clear_bit()
210        });
211        self.wait_ready();
212        self.ok()
213    }
214
215    /// Program bytes with offset into flash memory,
216    /// aligned to 128-bit rows
217    pub fn program<'a, I>(&mut self, mut offset: usize, mut bytes: I) -> Result<(), Error>
218    where
219        I: Iterator<Item = &'a u8>,
220    {
221        let ptr = self.flash.address() as *mut u8;
222        let mut bytes_written = 1;
223        while bytes_written > 0 {
224            bytes_written = 0;
225            let amount = 16 - (offset % 16);
226
227            self.flash.cr().modify(|_, w| {
228                w.psize().variant(PSIZE::Psize8);
229                // no sector erase
230                w.ser().clear_bit();
231                // programming
232                w.pg().set_bit()
233            });
234            for _ in 0..amount {
235                match bytes.next() {
236                    Some(byte) => {
237                        unsafe {
238                            ptr::write_volatile(ptr.add(offset), *byte);
239                        }
240                        offset += 1;
241                        bytes_written += 1;
242                    }
243                    None => break,
244                }
245            }
246            self.wait_ready();
247            self.ok()?;
248        }
249        self.flash.cr().modify(|_, w| w.pg().clear_bit());
250
251        Ok(())
252    }
253
254    fn ok(&self) -> Result<(), Error> {
255        Error::read(self.flash).map(Err).unwrap_or(Ok(()))
256    }
257
258    fn wait_ready(&self) {
259        while self.flash.sr().read().bsy().bit() {}
260    }
261}
262
263const UNLOCK_KEY1: u32 = 0x45670123;
264const UNLOCK_KEY2: u32 = 0xCDEF89AB;
265
266fn unlock(flash: &FLASH) {
267    flash.keyr().write(|w| unsafe { w.key().bits(UNLOCK_KEY1) });
268    flash.keyr().write(|w| unsafe { w.key().bits(UNLOCK_KEY2) });
269    assert!(!flash.cr().read().lock().bit())
270}
271
272fn lock(flash: &FLASH) {
273    flash.cr().modify(|_, w| w.lock().set_bit());
274}
275
276/// Flash memory sector
277pub struct FlashSector {
278    /// Sector number
279    pub number: u8,
280    /// Offset from base memory address
281    pub offset: usize,
282    /// Sector size in bytes
283    pub size: usize,
284}
285
286impl FlashSector {
287    /// Returns true if given offset belongs to this sector
288    pub fn contains(&self, offset: usize) -> bool {
289        self.offset <= offset && offset < self.offset + self.size
290    }
291}
292
293/// Iterator of flash memory sectors in a single bank.
294/// Yields a size sequence of [16, 16, 16, 64, 128, 128, ..]
295pub struct FlashSectorIterator {
296    index: u8,
297    start_sector: u8,
298    start_offset: usize,
299    end_offset: usize,
300}
301
302impl FlashSectorIterator {
303    fn new(start_sector: u8, start_offset: usize, end_offset: usize) -> Self {
304        Self {
305            index: 0,
306            start_sector,
307            start_offset,
308            end_offset,
309        }
310    }
311}
312
313impl Iterator for FlashSectorIterator {
314    type Item = FlashSector;
315
316    fn next(&mut self) -> Option<Self::Item> {
317        if self.start_offset >= self.end_offset {
318            None
319        } else {
320            // First 4 sectors are 16 KB, then one 64 KB and the rest are 128 KB
321            let size = match self.index {
322                0..=3 => 16 * 1024,
323                4 => 64 * 1024,
324                _ => 128 * 1024,
325            };
326
327            let sector = FlashSector {
328                number: self.start_sector + self.index,
329                offset: self.start_offset,
330                size,
331            };
332
333            self.index += 1;
334            self.start_offset += size;
335
336            Some(sector)
337        }
338    }
339}
340
341/// Returns iterator of flash memory sectors for single and dual bank flash.
342/// Sectors are returned in continuous memory order, while sector numbers can have spaces between banks.
343pub fn flash_sectors(flash_size: usize, dual_bank: bool) -> impl Iterator<Item = FlashSector> {
344    if dual_bank {
345        // Second memory bank always starts from sector 12
346        FlashSectorIterator::new(0, 0, flash_size / 2).chain(FlashSectorIterator::new(
347            12,
348            flash_size / 2,
349            flash_size,
350        ))
351    } else {
352        // Chain an empty iterator to match types
353        FlashSectorIterator::new(0, 0, flash_size).chain(FlashSectorIterator::new(0, 0, 0))
354    }
355}
356
357impl NorFlashError for Error {
358    fn kind(&self) -> NorFlashErrorKind {
359        match self {
360            Error::ProgrammingAlignment => NorFlashErrorKind::NotAligned,
361            _ => NorFlashErrorKind::Other,
362        }
363    }
364}
365
366impl ErrorType for LockedFlash {
367    type Error = Error;
368}
369
370impl ErrorType for UnlockedFlash<'_> {
371    type Error = Error;
372}
373
374impl ReadNorFlash for LockedFlash {
375    const READ_SIZE: usize = 1;
376
377    fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
378        let offset = offset as usize;
379        bytes.copy_from_slice(&self.flash.read()[offset..offset + bytes.len()]);
380        Ok(())
381    }
382
383    fn capacity(&self) -> usize {
384        self.flash.len()
385    }
386}
387
388impl<'a> ReadNorFlash for UnlockedFlash<'a> {
389    const READ_SIZE: usize = 1;
390
391    fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
392        let offset = offset as usize;
393        bytes.copy_from_slice(&self.flash.read()[offset..offset + bytes.len()]);
394        Ok(())
395    }
396
397    fn capacity(&self) -> usize {
398        self.flash.len()
399    }
400}
401
402impl<'a> NorFlash for UnlockedFlash<'a> {
403    const WRITE_SIZE: usize = 1;
404
405    // Use largest sector size of 128 KB. All smaller sectors will be erased together.
406    const ERASE_SIZE: usize = 128 * 1024;
407
408    fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
409        let mut current = from as usize;
410
411        for sector in flash_sectors(self.flash.len(), self.flash.dual_bank()) {
412            if sector.contains(current) {
413                UnlockedFlash::erase(self, sector.number)?;
414                current += sector.size;
415            }
416
417            if current >= to as usize {
418                break;
419            }
420        }
421
422        Ok(())
423    }
424
425    fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
426        self.program(offset as usize, bytes.iter())
427    }
428}
429
430// STM32F4 supports multiple writes
431impl<'a> MultiwriteNorFlash for UnlockedFlash<'a> {}