stm32g0xx_hal/flash/
mod.rs1mod 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
9pub const FLASH_START: usize = 0x0800_0000;
11pub const FLASH_END: usize = 0x0801_FFFF;
12
13pub const PAGE_SIZE: u32 = 2048;
15pub const NUM_PAGES: u32 = 64;
17
18const FLASH_KEY1: u32 = 0x4567_0123;
19const FLASH_KEY2: u32 = 0xCDEF_89AB;
20
21impl FlashPage {
22 pub const fn to_address(&self) -> usize {
24 FLASH_START + self.0 * PAGE_SIZE as usize
25 }
26}
27
28pub trait FlashExt {
29 fn unlock(self) -> core::result::Result<UnlockedFlash, FLASH>;
31}
32
33impl FlashExt for FLASH {
34 fn unlock(self) -> core::result::Result<UnlockedFlash, FLASH> {
35 while self.sr.read().bsy().bit_is_set() {}
37
38 self.keyr.write(|w| unsafe { w.keyr().bits(FLASH_KEY1) });
40 self.keyr.write(|w| unsafe { w.keyr().bits(FLASH_KEY2) });
41
42 if self.cr.read().lock().bit_is_clear() {
44 Ok(UnlockedFlash { f: self })
45 } else {
46 Err(self)
47 }
48 }
49}
50
51pub struct UnlockedFlash {
53 f: FLASH,
54}
55
56impl UnlockedFlash {
57 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 while self.f.sr.read().bsy().bit_is_set() {}
107
108 self.clear_errors();
109
110 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 while self.f.sr.read().bsy().bit_is_set() {}
129
130 self.clear_errors();
132 self.f.cr.modify(|_, w| w.pg().set_bit());
133
134 let mut address = address as *mut u32;
136
137 for &word in array {
138 interrupt::free(|_| {
143 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 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 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 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 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}