1use crate::gcr::clocks::{Clock, SystemClock};
3
4pub const FLASH_BASE: u32 = 0x1000_0000;
6pub const FLASH_SIZE: u32 = 0x0008_0000;
8pub const FLASH_END: u32 = FLASH_BASE + FLASH_SIZE;
10pub const FLASH_PAGE_COUNT: u32 = 64;
12pub const FLASH_PAGE_SIZE: u32 = 0x2000;
14
15#[derive(Debug, PartialEq)]
17pub enum FlashError {
18 InvalidAddress,
20 AccessViolation,
22 NeedsErase,
25}
26
27pub struct Flc {
56 flc: crate::pac::Flc,
57 sys_clk: Clock<SystemClock>,
58}
59
60impl Flc {
61 pub fn new(flc: crate::pac::Flc, sys_clk: Clock<SystemClock>) -> Self {
63 let s = Self { flc, sys_clk };
64 s.config();
65 s
66 }
67
68 #[inline]
70 fn config(&self) {
71 while self.is_busy() {}
73 let flc_div = self.sys_clk.frequency / 1_000_000;
75 self.flc
76 .clkdiv()
77 .modify(|_, w| unsafe { w.clkdiv().bits(flc_div as u8) });
78 if self.flc.intr().read().af().bit_is_set() {
80 self.flc.intr().write(|w| w.af().clear_bit());
81 }
82 }
83
84 #[inline]
86 pub fn is_busy(&self) -> bool {
87 let ctrl = self.flc.ctrl().read();
88 ctrl.pend().is_busy()
89 || ctrl.pge().bit_is_set()
90 || ctrl.me().bit_is_set()
91 || ctrl.wr().bit_is_set()
92 }
93
94 #[inline]
96 pub fn check_address(&self, address: u32) -> Result<(), FlashError> {
97 if address < FLASH_BASE || address >= FLASH_END {
98 return Err(FlashError::InvalidAddress);
99 }
100 Ok(())
101 }
102
103 #[inline]
105 pub fn check_page_number(&self, page_number: u32) -> Result<(), FlashError> {
106 if page_number >= FLASH_PAGE_COUNT {
107 return Err(FlashError::InvalidAddress);
108 }
109 Ok(())
110 }
111
112 #[inline]
114 pub fn get_address(&self, page_number: u32) -> Result<u32, FlashError> {
115 self.check_page_number(page_number)?;
116
117 let address = FLASH_BASE + FLASH_PAGE_SIZE * page_number;
118
119 Ok(address)
120 }
121
122 #[inline]
124 pub fn get_page_number(&self, address: u32) -> Result<u32, FlashError> {
125 self.check_address(address)?;
126 let page_num = (address >> 13) & (FLASH_PAGE_COUNT - 1);
127 if page_num >= FLASH_PAGE_COUNT {
129 return Err(FlashError::InvalidAddress);
130 }
131 Ok(page_num)
132 }
133
134 #[inline]
136 fn set_address(&self, address: u32) -> Result<(), FlashError> {
137 self.check_address(address)?;
138 let phys_addr = address & (FLASH_SIZE - 1);
140 self.flc
142 .addr()
143 .write(|w| unsafe { w.addr().bits(phys_addr) });
144 Ok(())
145 }
146
147 #[inline]
149 fn unlock_flash(&self) {
150 self.flc.ctrl().modify(|_, w| w.unlock().unlocked());
151 while self.flc.ctrl().read().unlock().is_locked() {}
152 }
153
154 #[inline]
156 fn lock_flash(&self) {
157 self.flc.ctrl().modify(|_, w| w.unlock().locked());
158 while self.flc.ctrl().read().unlock().is_unlocked() {}
159 }
160
161 #[cfg_attr(feature = "flashprog-linkage", link_section = ".flashprog")]
163 #[inline]
164 fn commit_write(&self) {
165 self.flc.ctrl().modify(|_, w| w.wr().start());
166 while !self.flc.ctrl().read().wr().is_complete() {}
167 while self.is_busy() {}
168 }
169
170 #[cfg_attr(feature = "flashprog-linkage", link_section = ".flashprog")]
172 #[inline]
173 fn commit_erase(&self) {
174 self.flc.ctrl().modify(|_, w| w.pge().start());
175 while !self.flc.ctrl().read().pge().is_complete() {}
176 while self.is_busy() {}
177 }
178
179 #[doc(hidden)]
182 #[cfg_attr(feature = "flashprog-linkage", link_section = ".flashprog")]
183 #[inline(never)]
184 fn _write_128(&self, address: u32, data: &[u32; 4]) -> Result<(), FlashError> {
185 if address & 0b1111 != 0 {
187 return Err(FlashError::InvalidAddress);
188 }
189 self.check_address(address)?;
190 self.config();
192 for i in 0..4 {
194 let old_data = unsafe { core::ptr::read_volatile((address + i * 4) as *const u32) };
196 if (old_data & data[i as usize]) != data[i as usize] {
197 return Err(FlashError::NeedsErase);
198 }
199 }
200 self.set_address(address)?;
201 unsafe {
203 self.flc.data(0).write(|w| w.data().bits(data[0]));
204 self.flc.data(1).write(|w| w.data().bits(data[1]));
205 self.flc.data(2).write(|w| w.data().bits(data[2]));
206 self.flc.data(3).write(|w| w.data().bits(data[3]));
207 }
208 self.unlock_flash();
209 self.commit_write();
211 self.lock_flash();
212 if self.flc.intr().read().af().bit_is_set() {
214 self.flc.intr().write(|w| w.af().clear_bit());
215 return Err(FlashError::AccessViolation);
216 }
217 Ok(())
218 }
219
220 #[doc(hidden)]
222 #[cfg_attr(feature = "flashprog-linkage", link_section = ".flashprog")]
223 #[inline(never)]
224 fn _erase_page(&self, address: u32) -> Result<(), FlashError> {
225 while self.is_busy() {}
226 self.set_address(address)?;
227 self.unlock_flash();
228 self.flc.ctrl().modify(|_, w| w.erase_code().erase_page());
230 self.commit_erase();
232 self.lock_flash();
233 if self.flc.intr().read().af().bit_is_set() {
235 self.flc.intr().write(|w| w.af().clear_bit());
236 return Err(FlashError::AccessViolation);
237 }
238 Ok(())
239 }
240
241 pub fn write_128(&self, address: u32, data: &[u32; 4]) -> Result<(), FlashError> {
253 self._write_128(address, &data)
254 }
255
256 pub fn write_32(&self, address: u32, data: u32) -> Result<(), FlashError> {
272 if address & 0b11 != 0 {
274 return Err(FlashError::InvalidAddress);
275 }
276 self.check_address(address)?;
277 let addr_128 = address & !0b1111;
278 self.check_address(addr_128)?;
279 let addr_128_ptr = addr_128 as *const u32;
280 let mut prev_data: [u32; 4] = [0xFFFF_FFFF; 4];
282 unsafe {
284 prev_data[0] = core::ptr::read_volatile(addr_128_ptr);
285 prev_data[1] = core::ptr::read_volatile(addr_128_ptr.offset(1));
286 prev_data[2] = core::ptr::read_volatile(addr_128_ptr.offset(2));
287 prev_data[3] = core::ptr::read_volatile(addr_128_ptr.offset(3));
288 }
289 let data_idx = (address & 0b1100) >> 2;
291 prev_data[data_idx as usize] = data;
293 self._write_128(addr_128, &prev_data)
295 }
296
297 pub fn read_128(&self, address: u32) -> Result<[u32; 4], FlashError> {
301 if address & 0b1111 != 0 {
303 return Err(FlashError::InvalidAddress);
304 }
305 self.check_address(address)?;
306 let addr_128_ptr = address as *const u32;
307 unsafe {
309 Ok([
310 core::ptr::read_volatile(addr_128_ptr),
311 core::ptr::read_volatile(addr_128_ptr.offset(1)),
312 core::ptr::read_volatile(addr_128_ptr.offset(2)),
313 core::ptr::read_volatile(addr_128_ptr.offset(3)),
314 ])
315 }
316 }
317
318 pub fn read_32(&self, address: u32) -> Result<u32, FlashError> {
321 if address & 0b11 != 0 {
323 return Err(FlashError::InvalidAddress);
324 }
325 self.check_address(address)?;
326 let addr_32_ptr = address as *const u32;
327 unsafe { Ok(core::ptr::read_volatile(addr_32_ptr)) }
329 }
330
331 pub unsafe fn erase_page(&self, address: u32) -> Result<(), FlashError> {
336 self._erase_page(address)
337 }
338
339 pub fn disable_page_write(&self, address: u32) -> Result<(), FlashError> {
342 while self.is_busy() {}
343 let page_num = self.get_page_number(address)?;
344 if page_num < 32 {
346 let write_lock_bit = 1 << page_num;
347 self.flc
348 .welr0()
349 .write(|w| unsafe { w.bits(write_lock_bit) });
350 while self.flc.welr0().read().bits() & write_lock_bit == write_lock_bit {}
351 } else {
352 let write_lock_bit = 1 << (page_num - 32);
353 self.flc
354 .welr1()
355 .write(|w| unsafe { w.bits(write_lock_bit) });
356 while self.flc.welr1().read().bits() & write_lock_bit == write_lock_bit {}
357 }
358 Ok(())
359 }
360
361 pub fn disable_page_read(&self, address: u32) -> Result<(), FlashError> {
364 while self.is_busy() {}
365 let page_num = self.get_page_number(address)?;
366 if page_num < 32 {
368 let read_lock_bit = 1 << page_num;
369 self.flc.rlr0().write(|w| unsafe { w.bits(read_lock_bit) });
370 while self.flc.rlr0().read().bits() & read_lock_bit == read_lock_bit {}
371 } else {
372 let read_lock_bit = 1 << (page_num - 32);
373 self.flc.rlr1().write(|w| unsafe { w.bits(read_lock_bit) });
374 while self.flc.rlr1().read().bits() & read_lock_bit == read_lock_bit {}
375 }
376 Ok(())
377 }
378}