lpc55_hal/drivers/
flash.rs

1use core::convert::TryInto;
2// use cortex_m_semihosting::hprintln;
3
4use crate::{
5    peripherals::flash::Flash,
6    traits::flash::{Error, Read, Result, WriteErase},
7    typestates::init_state::Enabled,
8};
9
10pub use generic_array::{
11    typenum::{U16, U512, U8},
12    GenericArray,
13};
14
15// one physical word of Flash consists of 128 bits (or 4 u32, or 16 bytes)
16// one page is 32 physical words, or 128 u32s, or 512 bytes)
17
18// reads must be physical word aligned (16 bytes)
19// erase and write must be page aligned (512 bytes)
20
21pub const READ_SIZE: usize = 16;
22pub const WRITE_SIZE: usize = 512;
23pub const PAGE_SIZE: usize = 512;
24
25pub struct FlashGordon {
26    flash: Flash<Enabled>,
27}
28
29impl FlashGordon {
30    pub fn new(flash: Flash<Enabled>) -> Self {
31        flash.raw.event.write(|w| w.rst().set_bit());
32        // seems immediate
33        while flash.raw.int_status.read().done().bit_is_clear() {}
34
35        // first thing to check! illegal command
36        debug_assert!(flash.raw.int_status.read().err().bit_is_clear());
37        // first thing to check! legal command failed
38        debug_assert!(flash.raw.int_status.read().fail().bit_is_clear());
39
40        FlashGordon { flash }
41    }
42
43    fn clear_status(&self) {
44        self.flash.raw.int_clr_status.write(|w| {
45            w.done()
46                .set_bit()
47                .ecc_err()
48                .set_bit()
49                .err()
50                .set_bit()
51                .fail()
52                .set_bit()
53        });
54    }
55
56    fn status(&self) -> Result {
57        let status = self.flash.raw.int_status.read();
58        // if status.done().bit_is_clear() {
59        //     return Err(Error::Busy);
60        // }
61        if status.err().bit_is_set() {
62            return Err(Error::Illegal);
63        }
64        if status.ecc_err().bit_is_set() {
65            return Err(Error::EccError);
66        }
67        if status.fail().bit_is_set() {
68            return Err(Error::Failure);
69        }
70
71        Ok(())
72    }
73
74    pub fn just_program_at(&mut self, address: usize) -> Result {
75        let flash = &self.flash.raw;
76        assert!(flash.int_status.read().done().bit_is_set());
77        self.clear_status();
78
79        flash.event.write(|w| w.rst().set_bit());
80        // seems immediate
81        while flash.int_status.read().done().bit_is_clear() {}
82        self.status()?;
83        self.clear_status();
84
85        flash
86            .starta
87            .write(|w| unsafe { w.starta().bits((address >> 4) as u32) });
88        flash
89            .cmd
90            .write(|w| unsafe { w.bits(FlashCommands::Program as u32) });
91        while flash.int_status.read().done().bit_is_clear() {}
92        debug_assert!(flash.int_status.read().err().bit_is_clear());
93        debug_assert!(flash.int_status.read().fail().bit_is_clear());
94        self.status()?;
95
96        Ok(())
97    }
98
99    pub fn clear_page_register(&mut self) {
100        let flash = &self.flash.raw;
101        assert!(flash.int_status.read().done().bit_is_set());
102        self.clear_status();
103
104        for i in 0..32 {
105            for j in 0..4 {
106                flash.dataw[j].write(|w| unsafe { w.bits(0x0) });
107            }
108            flash.starta.write(|w| unsafe { w.starta().bits(i as u32) });
109            flash
110                .cmd
111                .write(|w| unsafe { w.bits(FlashCommands::Write as u32) });
112
113            while flash.int_status.read().done().bit_is_clear() {}
114            debug_assert!(flash.int_status.read().err().bit_is_clear());
115            debug_assert!(flash.int_status.read().fail().bit_is_clear());
116            assert!(self.status().is_ok());
117        }
118    }
119
120    pub fn write_u8(&mut self, address: usize, byte: u8) -> Result {
121        self.clear_page_register();
122        let flash = &self.flash.raw;
123        // which "physical word" is this?
124        let page_register_column = (address & (512 - 1)) >> 4;
125        let mut word = [0u8; 4];
126        word[address % 4] = byte;
127        // redundant since done in clear_page_register
128        for j in 0..4 {
129            flash.dataw[j].write(|w| unsafe { w.bits(0) });
130        }
131        flash.dataw[(address >> 2) % 4].write(|w| unsafe { w.bits(u32::from_ne_bytes(word)) });
132        flash
133            .starta
134            .write(|w| unsafe { w.starta().bits(page_register_column as u32) });
135        self.clear_status();
136        flash
137            .cmd
138            .write(|w| unsafe { w.bits(FlashCommands::Write as u32) });
139        while flash.int_status.read().done().bit_is_clear() {}
140        self.status()?;
141
142        self.clear_status();
143        // self.just_program_at(address & !(512 - 1));
144        flash
145            .starta
146            .write(|w| unsafe { w.starta().bits((address >> 4) as u32) });
147        flash
148            .cmd
149            .write(|w| unsafe { w.bits(FlashCommands::Program as u32) });
150        while flash.int_status.read().done().bit_is_clear() {}
151        self.status()?;
152        Ok(())
153    }
154
155    pub fn write_u32(&mut self, address: usize, word: u32) -> Result {
156        self.clear_page_register();
157        let flash = &self.flash.raw;
158
159        // which "physical word" is this?
160        let page_register_column = (address & (512 - 1)) >> 4;
161        // redundant since done in clear_page_register
162        for j in 0..4 {
163            flash.dataw[j].write(|w| unsafe { w.bits(0) });
164        }
165        flash.dataw[(address >> 2) % 4].write(|w| unsafe { w.bits(word) });
166        flash
167            .starta
168            .write(|w| unsafe { w.starta().bits(page_register_column as u32) });
169        self.clear_status();
170        flash
171            .cmd
172            .write(|w| unsafe { w.bits(FlashCommands::Write as u32) });
173        while flash.int_status.read().done().bit_is_clear() {}
174        self.status()?;
175
176        self.clear_status();
177        // self.just_program_at(address & !(512 - 1));
178        flash
179            .starta
180            .write(|w| unsafe { w.starta().bits((address >> 4) as u32) });
181        flash
182            .cmd
183            .write(|w| unsafe { w.bits(FlashCommands::Program as u32) });
184        while flash.int_status.read().done().bit_is_clear() {}
185        self.status()?;
186
187        Ok(())
188    }
189
190    pub fn write_u128(&mut self, address: usize, data: u128) -> Result {
191        // self.clear_page_register();
192
193        let flash = &self.flash.raw;
194
195        let buf: [u8; 16] = data.to_ne_bytes();
196
197        for (i, chunk) in buf.chunks(4).enumerate() {
198            flash.dataw[i]
199                .write(|w| unsafe { w.bits(u32::from_ne_bytes(chunk.try_into().unwrap())) });
200        }
201        flash
202            .starta
203            .write(|w| unsafe { w.starta().bits((address >> 4) as u32) });
204        self.clear_status();
205        flash
206            .cmd
207            .write(|w| unsafe { w.bits(FlashCommands::Write as u32) });
208        while flash.int_status.read().done().bit_is_clear() {}
209        self.status()?;
210
211        self.clear_status();
212        // self.just_program_at(address & !(512 - 1));
213        flash
214            .starta
215            .write(|w| unsafe { w.starta().bits((address >> 4) as u32) });
216        flash
217            .cmd
218            .write(|w| unsafe { w.bits(FlashCommands::Program as u32) });
219        while flash.int_status.read().done().bit_is_clear() {}
220        self.status()?;
221
222        Ok(())
223    }
224
225    pub fn read_u128(&mut self, address: usize) -> u128 {
226        let mut buf = [0u8; 16];
227        self.read(address, &mut buf);
228        u128::from_ne_bytes(buf)
229    }
230}
231
232impl Read<U16> for FlashGordon {
233    // this reads 16B or one flash word
234    // address is in bytes, whereas starta expects address in flash words
235    // so starta = address / 16 = address >> 4
236    fn read_native(&self, address: usize, array: &mut GenericArray<u8, U16>) {
237        // hprintln!("native read from {} of {:?} (first 16)", address, &array[..16]).ok();
238        let flash = &self.flash.raw;
239
240        assert!(flash.int_status.read().done().bit_is_set());
241        self.clear_status();
242        // if self.status().is_err() {
243        //     cortex_m_semihosting::dbg!(flash.int_status.read().bits());
244        //     assert!(self.status().is_ok());
245        // }
246        assert!(self.status().is_ok());
247
248        let addr = address as u32;
249        debug_assert!(addr & (READ_SIZE as u32 - 1) == 0);
250
251        flash
252            .starta
253            .write(|w| unsafe { w.starta().bits(addr >> 4) });
254        // want to have normal reads
255        flash.dataw[0].write(|w| unsafe { w.bits(0) });
256        flash
257            .cmd
258            .write(|w| unsafe { w.bits(FlashCommands::ReadSingleWord as u32) });
259        while flash.int_status.read().done().bit_is_clear() {
260            continue;
261        }
262
263        assert!(flash.int_status.read().err().bit_is_clear());
264        debug_assert!(flash.int_status.read().fail().bit_is_clear());
265
266        // each dataw[i] now contains 4 bytes
267        for (i, chunk) in array.chunks_mut(4).enumerate() {
268            chunk.copy_from_slice(&flash.dataw[i].read().bits().to_ne_bytes());
269        }
270    }
271}
272
273impl WriteErase<U512, U512> for FlashGordon {
274    fn status(&self) -> Result {
275        self.status()
276    }
277
278    // TODO: use critical section?
279    fn erase_page(&mut self, page: usize) -> Result {
280        // starta is still in flash words, of which a page has 32
281        let starta = page * 32;
282        // hprintln!("native erase page {}", page).ok();
283
284        let flash = &self.flash.raw;
285        assert!(flash.int_status.read().done().bit_is_set());
286        self.clear_status();
287        assert!(flash.int_status.read().done().bit_is_clear());
288
289        flash
290            .starta
291            .write(|w| unsafe { w.starta().bits(starta as u32) });
292        flash
293            .stopa
294            .write(|w| unsafe { w.stopa().bits(starta as u32) });
295        flash
296            .cmd
297            .write(|w| unsafe { w.bits(FlashCommands::EraseRange as u32) });
298        while flash.int_status.read().done().bit_is_clear() {}
299
300        debug_assert!(flash.int_status.read().err().bit_is_clear());
301        debug_assert!(flash.int_status.read().fail().bit_is_clear());
302        // cortex_m_semihosting::dbg!(self.status());
303        self.status()?;
304
305        Ok(())
306    }
307
308    fn write_native(
309        &mut self,
310        address: usize,
311        array: &GenericArray<u8, U512>,
312        // cs: &CriticalSection,
313    ) -> Result {
314        // hprintln!("native write to {} of {:?} (first 16)", address, &array[..16]).ok();
315        let flash = &self.flash.raw;
316        assert!(flash.int_status.read().done().bit_is_set());
317        self.clear_status();
318
319        // maybe check the page is erased?
320
321        // write one physical word (16 bytes) at a time
322        for (i, chunk) in array.chunks(16).enumerate() {
323            let starta = (address >> 4) + i;
324            flash
325                .starta
326                .write(|w| unsafe { w.starta().bits(starta as u32) });
327
328            for (j, word) in chunk.chunks(4).enumerate() {
329                flash.dataw[j]
330                    .write(|w| unsafe { w.bits(u32::from_ne_bytes(word.try_into().unwrap())) });
331            }
332
333            flash
334                .cmd
335                .write(|w| unsafe { w.bits(FlashCommands::Write as u32) });
336            // flash.cmd.write(|w| unsafe { w.bits(FlashCommands::WriteProgram as u32) });
337            while flash.int_status.read().done().bit_is_clear() {}
338            debug_assert!(flash.int_status.read().err().bit_is_clear());
339            debug_assert!(flash.int_status.read().fail().bit_is_clear());
340            self.status()?;
341        }
342        self.clear_status();
343
344        let starta = address >> 4;
345        flash
346            .starta
347            .write(|w| unsafe { w.starta().bits(starta as u32) });
348        flash
349            .cmd
350            .write(|w| unsafe { w.bits(FlashCommands::Program as u32) });
351        while flash.int_status.read().done().bit_is_clear() {}
352        debug_assert!(flash.int_status.read().err().bit_is_clear());
353        debug_assert!(flash.int_status.read().fail().bit_is_clear());
354        self.status()?;
355
356        Ok(())
357    }
358}
359
360#[allow(dead_code)]
361#[repr(C)]
362pub enum FlashCommands {
363    Init = 0x0,
364    PowerDown = 0x1,
365    SetReadMode = 0x2,
366    ReadSingleWord = 0x3,
367    EraseRange = 0x4,
368    BlankCheck = 0x5,
369    MarginCheck = 0x6,
370    Checksum = 0x7,
371    Write = 0x8,
372    WriteProgram = 0xA,
373    Program = 0xC,
374    /// report ECC error (correction) count
375    ReportEcc = 0xD,
376}
377
378#[cfg(feature = "littlefs")]
379#[allow(non_camel_case_types)]
380pub mod littlefs_params {
381    use super::*;
382    pub const READ_SIZE: usize = 16;
383    pub const WRITE_SIZE: usize = 512;
384    pub const BLOCK_SIZE: usize = 512;
385
386    // no wear-leveling for now
387    pub const BLOCK_CYCLES: isize = -1;
388
389    pub type CACHE_SIZE = U512;
390    pub type LOOKAHEAD_SIZE = U8;
391}
392
393#[cfg(feature = "littlefs")]
394#[macro_export]
395macro_rules! littlefs2_filesystem {
396    ($Name:ident: (
397        $BASE_OFFSET:expr
398    )) => {
399        littlefs2_filesystem!(
400            $Name: (
401                $BASE_OFFSET,
402                //     631.5KB
403                ((631 * 1024 + 512) - $BASE_OFFSET) / 512
404            )
405        );
406    };
407    ($Name:ident: (
408        $BASE_OFFSET:expr,
409        $BLOCK_COUNT:expr
410    )) => {
411        //
412        // Compile time assertion that $BASE_OFFSET is 512 byte aligned.
413        const _ZERO_SIZED_CHECK: usize = ((core::mem::size_of::<[u8; ($BASE_OFFSET % 512)]>() == 0) as usize) - 1;
414        // Compile time assertion that flash region does NOT spill over the 631.5KB boundary.
415        const _OVERFLOW_SIZE_CHECK: usize = ((
416            core::mem::size_of::<[u8; (($BASE_OFFSET + $BLOCK_COUNT * 512) <= (631 * 1024 + 512)) as usize]>() == 1) as usize) - 1;
417
418        pub struct $Name {
419            flash_gordon: $crate::drivers::flash::FlashGordon
420        }
421
422        impl $Name {
423            const BASE_OFFSET: usize = $BASE_OFFSET;
424
425            pub fn new (flash_gordon: $crate::drivers::flash::FlashGordon) -> Self {
426                Self { flash_gordon }
427            }
428        }
429
430        impl littlefs2::driver::Storage for $Name {
431            const READ_SIZE: usize = $crate::drivers::flash::littlefs_params::READ_SIZE;
432            const WRITE_SIZE: usize = $crate::drivers::flash::littlefs_params::WRITE_SIZE;
433            const BLOCK_SIZE: usize = $crate::drivers::flash::littlefs_params::BLOCK_SIZE;
434
435            const BLOCK_COUNT: usize = $BLOCK_COUNT;
436            const BLOCK_CYCLES: isize = $crate::drivers::flash::littlefs_params::BLOCK_CYCLES;
437
438            type CACHE_SIZE = $crate::drivers::flash::littlefs_params::CACHE_SIZE;
439            type LOOKAHEAD_SIZE = $crate::drivers::flash::littlefs_params::LOOKAHEAD_SIZE;
440
441
442            fn read(&mut self, off: usize, buf: &mut [u8]) -> littlefs2::io::Result<usize> {
443                <$crate::drivers::flash::FlashGordon as $crate::traits::flash::Read<$crate::drivers::flash::U16>>
444                    ::read(&self.flash_gordon, Self::BASE_OFFSET + off, buf);
445                Ok(buf.len())
446            }
447
448            fn write(&mut self, off: usize, data: &[u8]) -> littlefs2::io::Result<usize> {
449                let ret = <$crate::drivers::flash::FlashGordon as $crate::traits::flash::WriteErase<$crate::drivers::flash::U512, $crate::drivers::flash::U512>>
450                    ::write(&mut self.flash_gordon, Self::BASE_OFFSET + off, data);
451                ret
452                    .map(|_| data.len())
453                    .map_err(|_| littlefs2::io::Error::IO)
454            }
455
456            fn erase(&mut self, off: usize, len: usize) -> littlefs2::io::Result<usize> {
457                let first_page = (Self::BASE_OFFSET + off) / 512;
458                let pages = len / 512;
459                for i in 0..pages {
460                    <$crate::drivers::flash::FlashGordon as $crate::traits::flash::WriteErase<$crate::drivers::flash::U512, $crate::drivers::flash::U512>>
461                        ::erase_page(&mut self.flash_gordon, first_page + i)
462                        .map_err(|_| littlefs2::io::Error::IO)?;
463                }
464                Ok(512 * len)
465            }
466
467        }
468    //
469    }
470}
471
472#[cfg(feature = "littlefs")]
473#[macro_export]
474macro_rules! littlefs2_prince_filesystem {
475    ($Name:ident: (
476        $BASE_OFFSET:expr
477    )) => {
478        littlefs2_prince_filesystem!(
479            $Name: (
480                $BASE_OFFSET,
481                //     631.5KB
482                ((631 * 1024 + 512) - $BASE_OFFSET) / 512
483            )
484        );
485    };
486    ($Name:ident: (
487        $BASE_OFFSET:expr,
488        $BLOCK_COUNT:expr
489    )) => {
490        //
491        // Compile time assertion that $BASE_OFFSET is 512 byte aligned.
492        const _ZERO_SIZED_CHECK_0: usize = ((core::mem::size_of::<[u8; ($BASE_OFFSET % 512)]>() == 0) as usize) - 1;
493        // Compile time assertion that flash region does NOT spill over the 631.5KB boundary.
494        const _OVERFLOW_SIZE_CHECK_0: usize = ((
495            core::mem::size_of::<[u8; (($BASE_OFFSET + $BLOCK_COUNT * 512) <= (631 * 1024 + 512)) as usize]>() == 1) as usize) - 1;
496
497
498        pub struct $Name {
499            flash_gordon: $crate::drivers::flash::FlashGordon,
500            prince: $crate::peripherals::prince::Prince<$crate::typestates::init_state::Enabled>,
501        }
502
503        impl $Name {
504            const BASE_OFFSET: usize = $BASE_OFFSET;
505
506            pub fn new (
507                flash_gordon: $crate::drivers::flash::FlashGordon,
508                prince: $crate::peripherals::prince::Prince<$crate::typestates::init_state::Enabled>,
509            ) -> Self {
510                Self { flash_gordon, prince }
511            }
512        }
513
514        impl littlefs2::driver::Storage for $Name {
515            const READ_SIZE: usize = $crate::drivers::flash::littlefs_params::READ_SIZE;
516            const WRITE_SIZE: usize = $crate::drivers::flash::littlefs_params::WRITE_SIZE;
517            const BLOCK_SIZE: usize = $crate::drivers::flash::littlefs_params::BLOCK_SIZE;
518
519            const BLOCK_COUNT: usize = $BLOCK_COUNT;
520            const BLOCK_CYCLES: isize = $crate::drivers::flash::littlefs_params::BLOCK_CYCLES;
521
522            type CACHE_SIZE = $crate::drivers::flash::littlefs_params::CACHE_SIZE;
523            type LOOKAHEAD_SIZE = $crate::drivers::flash::littlefs_params::LOOKAHEAD_SIZE;
524
525
526            fn read(&mut self, off: usize, buf: &mut [u8]) -> littlefs2::io::Result<usize> {
527                self.prince.enable_region_2_for(||{
528                    let flash: *const u8 = (Self::BASE_OFFSET + off) as *const u8;
529                    for i in 0 .. buf.len() {
530                        buf[i] = unsafe{ *flash.offset(i as isize) };
531                    }
532                });
533                Ok(buf.len())
534            }
535
536            fn write(&mut self, off: usize, data: &[u8]) -> littlefs2::io::Result<usize> {
537                let prince = &mut self.prince;
538                let flash_gordon = &mut self.flash_gordon;
539                let ret = prince.write_encrypted(|prince| {
540                    prince.enable_region_2_for(||{
541                        <$crate::drivers::flash::FlashGordon as
542                            $crate::traits::flash::WriteErase<$crate::drivers::flash::U512, $crate::drivers::flash::U512>>
543                            ::write(flash_gordon, Self::BASE_OFFSET + off, data)
544                    })
545                });
546                ret
547                    .map(|_| data.len())
548                    .map_err(|_| littlefs2::io::Error::IO)
549            }
550
551            fn erase(&mut self, off: usize, len: usize) -> littlefs2::io::Result<usize> {
552                let first_page = (Self::BASE_OFFSET + off) / 512;
553                let pages = len / 512;
554                for i in 0..pages {
555                    <$crate::drivers::flash::FlashGordon as
556                        $crate::traits::flash::WriteErase<$crate::drivers::flash::U512, $crate::drivers::flash::U512>>
557                        ::erase_page(&mut self.flash_gordon, first_page + i)
558                        .map_err(|_| littlefs2::io::Error::IO)?;
559                }
560                Ok(512 * len)
561            }
562
563        }
564    //
565    }
566}
567
568// Example implementations using 0x8_0000 boundary to separate code and data.
569// This leaves 128KB for data and is covered by the last prince region (region 2).
570// ```
571// littlefs2_filesystem!(FilesystemGordon: (0x8_0000));
572// ```