stm32f7xx_hal/
flash.rs

1//! Flash memory
2
3use crate::pac::FLASH;
4use nb::block;
5
6/// Base address of flash memory on AXIM interface.
7const FLASH_BASE: *mut u8 = 0x800_0000 as *mut u8;
8
9/// The last valid flash address in any STM32F7 device
10const MAX_FLASH_ADDRESS: *mut u8 = 0x81F_FFFF as *mut u8;
11
12/// Flash programming error.
13#[derive(Debug, PartialEq, Eq)]
14pub enum Error {
15    Busy,
16    Locked,
17    EraseSequence,
18    ProgrammingParallelism,
19    ProgrammingAlignment,
20    WriteProtection,
21}
22
23/// Embedded flash memory.
24pub struct Flash {
25    registers: FLASH,
26}
27
28impl Flash {
29    /// Creates a new Flash instance.
30    pub fn new(flash: FLASH) -> Self {
31        Self { registers: flash }
32    }
33
34    /// Unlocks the flash memory.
35    pub fn unlock(&mut self) {
36        if !self.is_locked() {
37            // don't try to unlock the flash if it's already unlocked, because
38            // trying to unlock the flash twice causes a HardFault
39            return;
40        }
41
42        self.registers.keyr.write(|w| w.key().bits(0x45670123));
43        self.registers.keyr.write(|w| w.key().bits(0xCDEF89AB));
44    }
45
46    /// Locks the flash memory.
47    pub fn lock(&mut self) {
48        self.registers.cr.modify(|_, w| w.lock().set_bit());
49    }
50
51    /// Returns `true` if the flash memory is locked.
52    fn is_locked(&self) -> bool {
53        self.registers.cr.read().lock().is_locked()
54    }
55
56    /// Returns `true` if a flash operation is in progress.
57    fn is_busy(&self) -> bool {
58        self.registers.sr.read().bsy().bit_is_set()
59    }
60
61    /// Starts a sector erase sequence.
62    ///
63    /// The returned `EraseSequence` object can be used to wait for the completion of the
64    /// erase sequence by blocking on the `wait` method.
65    pub fn erase_sector(&mut self, sector_number: u8) -> Result<EraseSequence<'_>, Error> {
66        EraseSequence::new_erase_sector(self, sector_number)
67    }
68
69    /// Erases a flash sector.
70    ///
71    /// This method blocks until the sector is erased or an error occurred.
72    pub fn blocking_erase_sector(&mut self, sector_number: u8) -> Result<(), Error> {
73        let mut sequence = self.erase_sector(sector_number)?;
74        block!(sequence.wait())
75    }
76
77    /// Starts a mass erases of the flash memory.
78    ///
79    /// The returned `EraseSequence` object can be used to wait for the completion of the
80    /// erase sequence by blocking on the `wait` method.
81    pub fn mass_erase(&mut self) -> Result<EraseSequence<'_>, Error> {
82        EraseSequence::new_mass_erase(self)
83    }
84
85    /// Mass erases the flash memory.
86    ///
87    /// This method blocks until the flash is erased or an error occurred.
88    pub fn blocking_mass_erase(&mut self) -> Result<(), Error> {
89        let mut sequence = self.mass_erase()?;
90        block!(sequence.wait())
91    }
92
93    /// Starts a programming sequence.
94    ///
95    /// Note that you must block on the `wait` method in the returned `ProgrammingSequence` object
96    /// in order to program all bytes.
97    pub fn program<'a, 'b>(
98        &'a mut self,
99        start_offset: usize,
100        data: &'b [u8],
101    ) -> Result<ProgrammingSequence<'a, 'b>, Error> {
102        ProgrammingSequence::new(self, start_offset, data)
103    }
104
105    /// Programs a block of flash memory.
106    ///
107    /// This method blocks until the block is programed or an error occurred.
108    pub fn blocking_program(&mut self, start_offset: usize, data: &[u8]) -> Result<(), Error> {
109        let mut sequence = self.program(start_offset, data)?;
110        block!(sequence.wait())
111    }
112
113    /// Releases the flash peripheral.
114    pub fn free(self) -> FLASH {
115        self.registers
116    }
117
118    /// Returns an error if the flash is locked or busy.
119    fn check_locked_or_busy(&self) -> Result<(), Error> {
120        if self.is_locked() {
121            Err(Error::Locked)
122        } else if self.is_busy() {
123            Err(Error::Busy)
124        } else {
125            Ok(())
126        }
127    }
128
129    /// Checks the error flags.
130    fn check_errors(&self) -> Result<(), Error> {
131        let sr = self.registers.sr.read();
132
133        if sr.erserr().bit_is_set() {
134            Err(Error::EraseSequence)
135        } else if sr.pgperr().bit_is_set() {
136            Err(Error::ProgrammingParallelism)
137        } else if sr.pgaerr().bit_is_set() {
138            Err(Error::ProgrammingAlignment)
139        } else if sr.wrperr().bit_is_set() {
140            Err(Error::WriteProtection)
141        } else {
142            Ok(())
143        }
144    }
145
146    /// Clears all error flags.
147    fn clear_errors(&mut self) {
148        self.registers.sr.write(|w| {
149            w.erserr()
150                .set_bit()
151                .pgperr()
152                .set_bit()
153                .pgaerr()
154                .set_bit()
155                .wrperr()
156                .set_bit()
157        });
158    }
159}
160
161/// Erase sequence.
162pub struct EraseSequence<'a> {
163    flash: &'a mut Flash,
164}
165
166impl<'a> EraseSequence<'a> {
167    /// Creates a sector erase sequence.
168    fn new_erase_sector(flash: &'a mut Flash, sector_number: u8) -> Result<Self, Error> {
169        flash.check_locked_or_busy()?;
170        flash.clear_errors();
171
172        //TODO: This should check if sector_number is valid for this device
173
174        flash.registers.cr.modify(|_, w| unsafe {
175            #[cfg(any(
176                feature = "stm32f765",
177                feature = "stm32f767",
178                feature = "stm32f769",
179                feature = "stm32f777",
180                feature = "stm32f778",
181                feature = "stm32f779",
182            ))]
183            w.mer1().clear_bit().mer2().clear_bit();
184            #[cfg(not(any(
185                feature = "stm32f765",
186                feature = "stm32f767",
187                feature = "stm32f769",
188                feature = "stm32f777",
189                feature = "stm32f778",
190                feature = "stm32f779",
191            )))]
192            w.mer().clear_bit();
193            w.ser().set_bit().snb().bits(sector_number)
194        });
195        flash.registers.cr.modify(|_, w| w.strt().start());
196
197        Ok(Self { flash })
198    }
199
200    /// Creates a mass erase sequence.
201    fn new_mass_erase(flash: &'a mut Flash) -> Result<Self, Error> {
202        flash.check_locked_or_busy()?;
203        flash.clear_errors();
204
205        flash.registers.cr.modify(|_, w| {
206            #[cfg(any(
207                feature = "stm32f765",
208                feature = "stm32f767",
209                feature = "stm32f769",
210                feature = "stm32f777",
211                feature = "stm32f778",
212                feature = "stm32f779",
213            ))]
214            w.mer1().set_bit().mer2().set_bit();
215            #[cfg(not(any(
216                feature = "stm32f765",
217                feature = "stm32f767",
218                feature = "stm32f769",
219                feature = "stm32f777",
220                feature = "stm32f778",
221                feature = "stm32f779",
222            )))]
223            w.mer().set_bit();
224            w.ser().clear_bit()
225        });
226
227        flash.registers.cr.modify(|_, w| w.strt().start());
228
229        Ok(Self { flash })
230    }
231
232    /// Waits until the erase sequence is finished.
233    pub fn wait(&mut self) -> nb::Result<(), Error> {
234        self.flash.check_errors().map_err(nb::Error::from)?;
235
236        if self.flash.is_busy() {
237            Err(nb::Error::WouldBlock)
238        } else {
239            Ok(())
240        }
241    }
242}
243
244/// Programming sequence.
245pub struct ProgrammingSequence<'a, 'b> {
246    flash: &'a mut Flash,
247    data: &'b [u8],
248    address: *mut u8,
249}
250
251impl<'a, 'b> ProgrammingSequence<'a, 'b> {
252    /// Creates a programming sequence.
253    fn new(flash: &'a mut Flash, start_offset: usize, data: &'b [u8]) -> Result<Self, Error> {
254        flash.check_locked_or_busy()?;
255        flash.clear_errors();
256
257        flash
258            .registers
259            .cr
260            .modify(|_, w| w.psize().psize8().pg().set_bit());
261
262        let address = unsafe { FLASH_BASE.add(start_offset) };
263
264        Ok(Self {
265            flash,
266            data,
267            address,
268        })
269    }
270
271    /// Waits until the programming sequence is finished.
272    pub fn wait(&mut self) -> nb::Result<(), Error> {
273        if self.flash.is_busy() {
274            return Err(nb::Error::WouldBlock);
275        }
276
277        if let Err(error) = self.flash.check_errors() {
278            // make sure programing mode is disabled when an error occurred
279            self.flash.registers.cr.modify(|_, w| w.pg().clear_bit());
280
281            return Err(error.into());
282        }
283
284        if let Some((first, rest)) = self.data.split_first() {
285            if self.address >= FLASH_BASE && self.address <= MAX_FLASH_ADDRESS {
286                unsafe {
287                    core::ptr::write_volatile(self.address, *first);
288                }
289            }
290
291            // ensure data is written byte by byte to prevent programming parallelism errors
292            cortex_m::asm::dmb();
293
294            self.address = unsafe { self.address.add(1) };
295            self.data = rest;
296
297            Err(nb::Error::WouldBlock)
298        } else {
299            self.flash.registers.cr.modify(|_, w| w.pg().clear_bit());
300
301            Ok(())
302        }
303    }
304}