stm32g0xx_hal/flash/
mod.rs

1mod traits;
2
3use crate::stm32::FLASH;
4use core::convert::TryInto;
5use core::mem;
6use cortex_m::interrupt;
7pub use traits::{Error, FlashPage, Read, Result, WriteErase};
8
9/// The first address of flash memory
10pub const FLASH_START: usize = 0x0800_0000;
11pub const FLASH_END: usize = 0x0801_FFFF;
12
13/// The size of a Flash memory page, in bytes
14pub const PAGE_SIZE: u32 = 2048;
15/// How many Flash memory pages there are
16pub const NUM_PAGES: u32 = 64;
17
18const FLASH_KEY1: u32 = 0x4567_0123;
19const FLASH_KEY2: u32 = 0xCDEF_89AB;
20
21impl FlashPage {
22    /// This gives the starting address of a flash page in physical address
23    pub const fn to_address(&self) -> usize {
24        FLASH_START + self.0 * PAGE_SIZE as usize
25    }
26}
27
28pub trait FlashExt {
29    /// Unlocks Flash memory for erasure and writing
30    fn unlock(self) -> core::result::Result<UnlockedFlash, FLASH>;
31}
32
33impl FlashExt for FLASH {
34    fn unlock(self) -> core::result::Result<UnlockedFlash, FLASH> {
35        // Wait, while the memory interface is busy.
36        while self.sr.read().bsy().bit_is_set() {}
37
38        // Unlock flash
39        self.keyr.write(|w| unsafe { w.keyr().bits(FLASH_KEY1) });
40        self.keyr.write(|w| unsafe { w.keyr().bits(FLASH_KEY2) });
41
42        // Verify success
43        if self.cr.read().lock().bit_is_clear() {
44            Ok(UnlockedFlash { f: self })
45        } else {
46            Err(self)
47        }
48    }
49}
50
51/// Handle for an unlocked flash on which operations can be performed
52pub struct UnlockedFlash {
53    f: FLASH,
54}
55
56impl UnlockedFlash {
57    /// Consumes the unlocked flash instance returning the locked one
58    pub fn lock(self) -> FLASH {
59        self.f.cr.modify(|_, w| w.lock().set_bit());
60        self.f
61    }
62}
63
64impl Read for UnlockedFlash {
65    type NativeType = u8;
66
67    fn read_native(&self, address: usize, array: &mut [Self::NativeType]) {
68        let mut address = address as *const Self::NativeType;
69
70        for data in array {
71            unsafe {
72                *data = core::ptr::read(address);
73                address = address.add(1);
74            }
75        }
76    }
77
78    fn read(&self, address: usize, buf: &mut [u8]) {
79        self.read_native(address, buf);
80    }
81}
82
83impl WriteErase for UnlockedFlash {
84    type NativeType = u64;
85
86    fn status(&self) -> Result {
87        let sr = self.f.sr.read();
88
89        if sr.bsy().bit_is_set() {
90            return Err(Error::Busy);
91        }
92
93        if sr.pgaerr().bit_is_set() || sr.progerr().bit_is_set() || sr.wrperr().bit_is_set() {
94            return Err(Error::Illegal);
95        }
96
97        Ok(())
98    }
99
100    fn erase_page(&mut self, page: FlashPage) -> Result {
101        if page.0 >= NUM_PAGES as usize {
102            return Err(Error::PageOutOfRange);
103        }
104
105        // Wait, while the memory interface is busy.
106        while self.f.sr.read().bsy().bit_is_set() {}
107
108        self.clear_errors();
109
110        // We absoluty can't have any access to Flash while preparing the
111        // erase, or the process will be interrupted. This includes any
112        // access to the vector table or interrupt handlers that might be
113        // caused by an interrupt.
114        interrupt::free(|_| {
115            self.f.cr.modify(|_, w| unsafe {
116                w.per().set_bit().pnb().bits(page.0 as u8).strt().set_bit()
117            });
118        });
119
120        let result = self.wait();
121        self.f.cr.modify(|_, w| w.per().clear_bit());
122
123        result
124    }
125
126    fn write_native(&mut self, address: usize, array: &[Self::NativeType]) -> Result {
127        // Wait, while the memory interface is busy.
128        while self.f.sr.read().bsy().bit_is_set() {}
129
130        // Enable Flash programming
131        self.clear_errors();
132        self.f.cr.modify(|_, w| w.pg().set_bit());
133
134        // It is only possible to program a double word (2 x 32-bit data).
135        let mut address = address as *mut u32;
136
137        for &word in array {
138            // We absoluty can't have any access to Flash while preparing the
139            // write, or the process will be interrupted. This includes any
140            // access to the vector table or interrupt handlers that might be
141            // caused by an interrupt.
142            interrupt::free(|_| {
143                // Safe, because we've verified the valididty of `address`.
144                unsafe {
145                    address.write_volatile(word as u32);
146                    address.offset(1).write_volatile((word >> 32) as u32);
147
148                    address = address.add(2);
149                }
150            });
151
152            self.wait()?;
153
154            if self.f.sr.read().eop().bit_is_set() {
155                self.f.sr.modify(|_, w| w.eop().clear_bit());
156            }
157        }
158
159        self.f.cr.modify(|_, w| w.pg().clear_bit());
160
161        Ok(())
162    }
163
164    fn write(&mut self, address: usize, data: &[u8]) -> Result {
165        let address_offset = address % mem::align_of::<Self::NativeType>();
166        let unaligned_size = (mem::size_of::<Self::NativeType>() - address_offset)
167            % mem::size_of::<Self::NativeType>();
168
169        if unaligned_size > 0 {
170            let unaligned_data = &data[..unaligned_size];
171            // Handle unaligned address data, make it into a native write
172            let mut data = 0xffff_ffff_ffff_ffffu64;
173            for b in unaligned_data {
174                data = (data >> 8) | ((*b as Self::NativeType) << 56);
175            }
176
177            let unaligned_address = address - address_offset;
178            let native = &[data];
179            self.write_native(unaligned_address, native)?;
180        }
181
182        // Handle aligned address data
183        let aligned_data = &data[unaligned_size..];
184        let mut aligned_address = if unaligned_size > 0 {
185            address - address_offset + mem::size_of::<Self::NativeType>()
186        } else {
187            address
188        };
189
190        let mut chunks = aligned_data.chunks_exact(mem::size_of::<Self::NativeType>());
191
192        for exact_chunk in &mut chunks {
193            // Write chunks
194            let native = &[Self::NativeType::from_ne_bytes(
195                exact_chunk.try_into().unwrap(),
196            )];
197            self.write_native(aligned_address, native)?;
198            aligned_address += mem::size_of::<Self::NativeType>();
199        }
200
201        let rem = chunks.remainder();
202
203        if !rem.is_empty() {
204            let mut data = 0xffff_ffff_ffff_ffffu64;
205            // Write remainder
206            for b in rem.iter().rev() {
207                data = (data << 8) | *b as Self::NativeType;
208            }
209
210            let native = &[data];
211            self.write_native(aligned_address, native)?;
212        }
213
214        Ok(())
215    }
216}
217
218impl UnlockedFlash {
219    fn clear_errors(&mut self) {
220        self.f.sr.modify(|_, w| {
221            w.progerr()
222                .set_bit()
223                .pgserr()
224                .set_bit()
225                .rderr()
226                .set_bit()
227                .optverr()
228                .set_bit()
229                .sizerr()
230                .set_bit()
231                .pgaerr()
232                .set_bit()
233                .wrperr()
234                .set_bit()
235        });
236    }
237
238    fn wait(&self) -> Result {
239        while self.f.sr.read().bsy().bit_is_set() {}
240        self.status()
241    }
242}