xmc4_hal/
flash.rs

1use crate::pac::FLASH0;
2
3pub type PageData = [u32; 64];
4
5const UNCACHED_BASE: u32 = 0xC000000;
6
7const PROTECTION_CONFIRM_CODE: u32 = 0x8AFE15C3;
8
9const PROTECTION_CONFIRM_OFFSET: u32 = 512;
10
11const BYTES_PER_UCB: u32 = 1024;
12
13const UCB0: u32 = UNCACHED_BASE;
14
15pub struct FlashSector {
16    pub number: u8,
17    pub offset: usize,
18    pub size: usize,
19}
20
21impl FlashSector {
22    pub fn contains(&self, offset: usize) -> bool {
23        self.offset <= offset && offset < self.offset + self.size
24    }
25}
26
27pub struct FlashSectorIterator {
28    index: u8,
29    start_sector: u8,
30    start_offset: usize,
31    end_offset: usize,
32}
33
34impl FlashSectorIterator {
35    fn new(start_sector: u8, start_offset: usize, end_offset: usize) -> Self {
36        Self {
37            index: 0,
38            start_sector,
39            start_offset,
40            end_offset,
41        }
42    }
43}
44
45impl Iterator for FlashSectorIterator {
46    type Item = FlashSector;
47    fn next(&mut self) -> Option<Self::Item> {
48        if self.start_offset >= self.end_offset {
49            None
50        } else {
51            let size = match self.index {
52                8..=11 => 0x20000,
53                _ => 0x4000,
54            };
55
56            let sector = FlashSector {
57                number: self.start_sector + self.index,
58                offset: self.start_offset,
59                size,
60            };
61            self.index += 1;
62            self.start_offset += size;
63
64            Some(sector)
65        }
66    }
67}
68
69#[derive(Copy, Clone, Debug)]
70pub enum Margin {
71    Default,
72    Tight0,
73    Tight1,
74}
75
76#[derive(Copy, Clone, Debug)]
77pub enum User {
78    User0,
79    User1,
80    User2,
81}
82
83impl From<User> for u32 {
84    fn from(value: User) -> Self {
85        value as u32
86    }
87}
88
89#[derive(Copy, Clone, Debug)]
90pub enum Event {
91    VerifyAndOperationError,
92    CommandSequenceError,
93    ProtectionError,
94    SingleBitError,
95    DoubleBitError,
96    EndOfBusy,
97}
98
99pub struct Flash {
100    pub regs: FLASH0,
101}
102
103// IMPLEMENT PERIPHERAL AFTER THIS LINE
104
105impl Flash {
106    pub fn new(flash: FLASH0) -> Self {
107        Self { regs: flash }
108    }
109
110    pub fn is_busy(&self) -> bool {
111        self.regs.fsr().read().pbusy().bit_is_set()
112    }
113
114    /// Enables the wait state for error correction process. It enables one additional wait state for ECC by setting WSECPF.
115    pub fn enable_wait_state_for_ecc(&self) {
116        self.regs.fcon().write(|w| w.wsecpf().set_bit());
117    }
118
119    pub fn disable_wait_state_for_ecc(&self) {
120        self.regs.fcon().write(|w| w.wsecpf().clear_bit());
121    }
122
123    pub fn enable_dynamic_idle(&self) {
124        self.regs.fcon().write(|w| w.idle().set_bit());
125    }
126
127    pub fn disable_dynamic_idle(&self) {
128        self.regs.fcon().write(|w| w.idle().clear_bit());
129    }
130
131    pub fn enable_sleep_request(&self) {
132        self.regs.fcon().write(|w| w.sleep().set_bit());
133    }
134
135    pub fn disable_sleep_request(&self) {
136        self.regs.fcon().write(|w| w.sleep().clear_bit());
137    }
138
139    pub fn set_margin(&self, margin: Margin) {
140        match margin {
141            // TODO Should look at updating the SVD so that'value' methods have real names
142            Margin::Default => self.regs.marp().write(|w| w.margin().value1()),
143            Margin::Tight0 => self.regs.marp().write(|w| w.margin().value2()),
144            Margin::Tight1 => self.regs.marp().write(|w| w.margin().value3()),
145        };
146    }
147
148    pub fn enable_double_bit_error_trap(&self) {
149        self.regs.marp().write(|w| w.trapdis().clear_bit());
150    }
151
152    pub fn disable_double_bit_error_trap(&self) {
153        self.regs.marp().write(|w| w.trapdis().set_bit());
154    }
155
156    pub fn set_wait_states(&self, wait_states: u8) {
157        // TODO The SVD is weird on this and should be improved to not be a 4 value enum that really can do 16 numbers.
158        self.regs
159            .fcon()
160            .write(|w| unsafe { w.wspflash().bits(wait_states) });
161    }
162
163    pub fn install_bmi(&self) {
164        unimplemented!();
165    }
166
167    pub fn install_protection(&self, user: User, mask: u32, password0: u32, password1: u32) {
168        // TODO, explain where all numbers came from
169        self.enter_page_mode_command();
170        self.load_page_command(mask, 0);
171        self.load_page_command(mask, 0);
172        self.load_page_command(password0, password1);
173        self.load_page_command(password0, password1);
174        let mut index = 0;
175
176        while index < 56 {
177            self.load_page_command(0, 0);
178            index += 2;
179        }
180
181        let start_address = (UCB0 + (user as u32 * BYTES_PER_UCB)) as *mut u32;
182
183        self.write_ucb_page_command(start_address);
184
185        while self.regs.fsr().read().pbusy().bit_is_set() {}
186    }
187
188    pub fn confirm_protection(&self, user: User) {
189        // TODO, explain where all numbers came from
190        self.enter_page_mode_command();
191        self.load_page_command(PROTECTION_CONFIRM_CODE, 0);
192        self.load_page_command(PROTECTION_CONFIRM_CODE, 0);
193        let mut index = 0;
194
195        while index < 60 {
196            self.load_page_command(0, 0);
197            index += 2;
198        }
199
200        let start_address = (UNCACHED_BASE + (user as u32 * 1024) + 512) as *mut u32;
201
202        self.write_ucb_page_command(start_address);
203
204        while self.regs.fsr().read().pbusy().bit_is_set() {}
205    }
206
207    pub fn verify_read_protection(&self, password0: u32, password1: u32) -> bool {
208        let result = if self.regs.fsr().read().proin().bit_is_set() {
209            self.clear_status();
210            self.disable_read_protection_command(password0, password1);
211            self.regs.fsr().read().rprodis().bit_is_set()
212        } else {
213            false
214        };
215
216        result
217    }
218
219    pub fn verify_write_protection(
220        &self,
221        user: User,
222        _mask: u32,
223        password0: u32,
224        password1: u32,
225    ) -> bool {
226        let mut result = false;
227        let wproinx = match user {
228            User::User0 => self.regs.fsr().read().wproin0().bit_is_set(),
229            User::User1 => self.regs.fsr().read().wproin1().bit_is_set(),
230            User::User2 => self.regs.fsr().read().wproin2().bit_is_set(),
231        };
232
233        if wproinx {
234            self.clear_status();
235            self.disable_sector_write_protection_command(user, password0, password1);
236            let wprodisx = match user {
237                User::User0 => self.regs.fsr().read().wprodis0().bit_is_set(),
238                User::User1 => self.regs.fsr().read().wprodis1().bit_is_set(),
239                User::User2 => false, // Option does not exist, should not get here
240            };
241
242            result = wprodisx && self.regs.fsr().read().bits() == (_mask & 0xFFFF7FFF);
243        }
244
245        result
246    }
247
248    pub fn resume_protection(&self) {
249        let address1 = (UNCACHED_BASE + 0x5554) as *mut u32;
250        unsafe {
251            *address1 = 0x5E;
252        }
253    }
254
255    pub fn repair_physical_sector(&self) {
256        self.clear_status();
257        self.repair_physical_sector_command();
258    }
259
260    pub fn erase_physical_sector(&self, address: *mut u32) {
261        self.clear_status();
262        self.erase_physical_sector_command(address);
263        while self.regs.fsr().read().pbusy().bit_is_set() {}
264    }
265
266    pub fn erase_ucb(&self, ucb_start_address: *mut u32) {
267        let address1 = (UNCACHED_BASE + 0x5554) as *mut u32;
268        let address2 = (UNCACHED_BASE + 0xAAA8) as *mut u32;
269
270        unsafe {
271            *address1 = 0xAA;
272            *address2 = 0x55;
273            *address1 = 0x80;
274            *address1 = 0xAA;
275            *address2 = 0x55;
276            *ucb_start_address = 0xC0;
277        }
278
279        while self.regs.fsr().read().pbusy().bit_is_set() {}
280    }
281
282    /// Reset the status of the PFLASH
283    pub fn reset(&self) {
284        let address1 = (UNCACHED_BASE + 0x5554) as *mut u32;
285        unsafe {
286            *address1 = 0xF0;
287        }
288    }
289
290    fn enter_page_mode_command(&self) {
291        let address = (UNCACHED_BASE + 0x5554) as *mut u32;
292
293        unsafe {
294            *address = 0x50;
295        }
296    }
297
298    fn load_page_command(&self, low_word: u32, high_word: u32) {
299        let address_low = (UNCACHED_BASE + 0x55F0) as *mut u32;
300        let address_high = (UNCACHED_BASE + 0x55F4) as *mut u32;
301
302        unsafe {
303            *address_low = low_word;
304            *address_high = high_word;
305        }
306    }
307
308    fn write_page_command(&self, start_address: *mut u32) {
309        let address1 = (UNCACHED_BASE + 0x5554) as *mut u32;
310        let address2 = (UNCACHED_BASE + 0xAAA8) as *mut u32;
311
312        unsafe {
313            *address1 = 0xAA;
314            *address2 = 0x55;
315            *address1 = 0xA0;
316            *start_address = 0xAA;
317        }
318    }
319
320    fn write_ucb_page_command(&self, start_address: *mut u32) {
321        let address1 = (UNCACHED_BASE + 0x5554) as *mut u32;
322        let address2 = (UNCACHED_BASE + 0xAAA8) as *mut u32;
323
324        unsafe {
325            *address1 = 0xAA;
326            *address2 = 0x55;
327            *address1 = 0xC0;
328            *start_address = 0xAA;
329        }
330    }
331
332    fn erase_sector_command(&self, start_address: *mut u32) {
333        let address1 = (UNCACHED_BASE + 0x5554) as *mut u32;
334        let address2 = (UNCACHED_BASE + 0xAAA8) as *mut u32;
335
336        unsafe {
337            *address1 = 0xAA;
338            *address2 = 0x55;
339            *address1 = 0x80;
340            *address1 = 0xAA;
341            *address2 = 0x55;
342            *start_address = 0x30;
343        }
344    }
345
346    fn disable_sector_write_protection_command(&self, user: User, password0: u32, password1: u32) {
347        let address1 = (UNCACHED_BASE + 0x5554) as *mut u32;
348        let address2 = (UNCACHED_BASE + 0xAAA8) as *mut u32;
349        let address3 = (UNCACHED_BASE + 0x553C) as *mut u32;
350        let address4 = (UNCACHED_BASE + 0x5558) as *mut u32;
351
352        unsafe {
353            *address1 = 0xAA;
354            *address2 = 0x55;
355            *address3 = user as u32;
356            *address2 = password0;
357            *address2 = password1;
358            *address4 = 0x05;
359        }
360    }
361
362    fn disable_read_protection_command(&self, password0: u32, password1: u32) {
363        let address1 = (UNCACHED_BASE + 0x5554) as *mut u32;
364        let address2 = (UNCACHED_BASE + 0xAAA8) as *mut u32;
365        let address3 = (UNCACHED_BASE + 0x553C) as *mut u32;
366        let address4 = (UNCACHED_BASE + 0x5558) as *mut u32;
367
368        unsafe {
369            *address1 = 0x55;
370            *address2 = 0xAA;
371            *address3 = 0x00;
372            *address2 = password0;
373            *address2 = password1;
374            *address4 = 0x08;
375        }
376    }
377
378    fn erase_physical_sector_command(&self, start_address: *mut u32) {
379        let address1 = (UNCACHED_BASE + 0x5554) as *mut u32;
380        let address2 = (UNCACHED_BASE + 0xAAA8) as *mut u32;
381
382        unsafe {
383            *address1 = 0xAA;
384            *address2 = 0x55;
385            *address1 = 0x80;
386            *address1 = 0xAA;
387            *address2 = 0x55;
388            *start_address = 0x40;
389        }
390    }
391
392    /// Command to erase physical sector4 which is starting with the specified address.
393    /// This comand is only available if PROCON1.PRS = 1.
394    fn repair_physical_sector_command(&self) {
395        let address1 = (UNCACHED_BASE + 0x5554) as *mut u32;
396        let address2 = (UNCACHED_BASE + 0xAAA8) as *mut u32;
397        let sector4 = (UNCACHED_BASE + 0x10000) as *mut u32;
398
399        unsafe {
400            *address1 = 0xAA;
401            *address2 = 0x55;
402            *address1 = 0x80;
403            *address1 = 0xAA;
404            *address2 = 0x55;
405            *sector4 = 0x40;
406        }
407    }
408
409    pub fn clear_status(&self) {
410        let address = (UNCACHED_BASE + 0x5554) as *mut u32;
411        unsafe {
412            *address = 0xF5;
413        }
414    }
415
416    pub fn get_status(&self) -> u32 {
417        self.regs.fsr().read().bits()
418    }
419
420    pub fn enable_event(&self, event: Event) {
421        match event {
422            Event::VerifyAndOperationError => self.regs.fcon().write(|w| w.voperm().set_bit()),
423            Event::CommandSequenceError => self.regs.fcon().write(|w| w.sqerm().set_bit()),
424            Event::ProtectionError => self.regs.fcon().write(|w| w.proerm().set_bit()),
425            Event::SingleBitError => self.regs.fcon().write(|w| w.pfsberm().set_bit()),
426            Event::DoubleBitError => self.regs.fcon().write(|w| w.pfdberm().set_bit()),
427            Event::EndOfBusy => self.regs.fcon().write(|w| w.eobm().set_bit()),
428        };
429    }
430
431    pub fn disable_event(&self, event: Event) {
432        match event {
433            Event::VerifyAndOperationError => self.regs.fcon().write(|w| w.voperm().clear_bit()),
434            Event::CommandSequenceError => self.regs.fcon().write(|w| w.sqerm().clear_bit()),
435            Event::ProtectionError => self.regs.fcon().write(|w| w.proerm().clear_bit()),
436            Event::SingleBitError => self.regs.fcon().write(|w| w.pfsberm().clear_bit()),
437            Event::DoubleBitError => self.regs.fcon().write(|w| w.pfdberm().clear_bit()),
438            Event::EndOfBusy => self.regs.fcon().write(|w| w.eobm().clear_bit()),
439        };
440    }
441
442    pub fn program_page(&self, address: *mut u32, data: PageData) {
443        let mut index = 0;
444
445        self.clear_status();
446        self.enter_page_mode_command();
447
448        while index < data.len() {
449            self.load_page_command(data[index], data[index + 1]);
450            index += 2;
451        }
452        self.write_page_command(address);
453
454        while self.regs.fsr().read().pbusy().bit_is_set() {}
455    }
456
457    pub fn erase_sector(&self, address: *mut u32) {
458        self.clear_status();
459        self.erase_sector_command(address);
460        while self.regs.fsr().read().pbusy().bit_is_set() {}
461    }
462}