@@ -14,23 +14,31 @@ use crate::pac::NVMC_NS as NVMC;
1414use core:: convert:: TryInto ;
1515use embedded_storage:: nor_flash:: { NorFlash , ReadNorFlash } ;
1616
17+ type WORD = u32 ;
18+ const WORD_SIZE : usize = core:: mem:: size_of :: < WORD > ( ) ;
19+ const PAGE_SIZE : usize = 4 * 1024 ;
20+
1721/// Interface to an NVMC instance.
1822pub struct Nvmc < T : Instance > {
1923 nvmc : T ,
20- storage : & ' static mut [ u32 ] ,
24+ storage : & ' static mut [ u8 ] ,
2125}
2226
2327impl < T > Nvmc < T >
2428where
2529 T : Instance ,
2630{
2731 /// Takes ownership of the peripheral and storage area.
28- pub fn new ( nvmc : T , storage : & ' static mut [ u32 ] ) -> Nvmc < T > {
32+ ///
33+ /// The storage area must be page-aligned.
34+ pub fn new ( nvmc : T , storage : & ' static mut [ u8 ] ) -> Nvmc < T > {
35+ assert ! ( storage. as_ptr( ) as usize % PAGE_SIZE == 0 ) ;
36+ assert ! ( storage. len( ) % PAGE_SIZE == 0 ) ;
2937 Self { nvmc, storage }
3038 }
3139
3240 /// Consumes `self` and returns back the raw peripheral and associated storage.
33- pub fn free ( self ) -> ( T , & ' static mut [ u32 ] ) {
41+ pub fn free ( self ) -> ( T , & ' static mut [ u8 ] ) {
3442 ( self . nvmc , self . storage )
3543 }
3644
@@ -68,28 +76,36 @@ where
6876
6977 #[ cfg( not( any( feature = "9160" , feature = "5340-app" ) ) ) ]
7078 #[ inline]
71- fn erase_page ( & mut self , offset : usize ) {
72- let bits = & mut ( self . storage [ offset as usize >> 2 ] ) as * mut _ as u32 ;
79+ fn erase_page ( & mut self , page_offset : usize ) {
80+ let bits = & mut ( self . storage [ page_offset * PAGE_SIZE ] ) as * mut _ as u32 ;
7381 self . nvmc . erasepage ( ) . write ( |w| unsafe { w. bits ( bits) } ) ;
7482 self . wait_ready ( ) ;
7583 }
7684
7785 #[ cfg( any( feature = "9160" , feature = "5340-app" ) ) ]
7886 #[ inline]
79- fn erase_page ( & mut self , offset : usize ) {
80- self . storage [ offset as usize >> 2 ] = 0xffffffff ;
87+ fn erase_page ( & mut self , page_offset : usize ) {
88+ self . direct_write_word ( page_offset * PAGE_SIZE , 0xffffffff ) ;
8189 self . wait_ready ( ) ;
8290 }
8391
8492 #[ inline]
85- fn write_word ( & mut self , offset : usize , word : u32 ) {
93+ fn write_word ( & mut self , word_offset : usize , word : u32 ) {
8694 #[ cfg( not( any( feature = "9160" , feature = "5340-app" ) ) ) ]
8795 self . wait_ready ( ) ;
8896 #[ cfg( any( feature = "9160" , feature = "5340-app" ) ) ]
8997 self . wait_write_ready ( ) ;
90- self . storage [ offset ] = word;
98+ self . direct_write_word ( word_offset , word) ;
9199 cortex_m:: asm:: dmb ( ) ;
92100 }
101+
102+ #[ inline]
103+ fn direct_write_word ( & mut self , word_offset : usize , word : u32 ) {
104+ let target: & mut [ u8 ] = & mut self . storage [ word_offset * WORD_SIZE ..] [ ..WORD_SIZE ] ;
105+ let target: & mut [ u8 ; WORD_SIZE ] = target. try_into ( ) . unwrap ( ) ;
106+ let target: & mut u32 = unsafe { core:: mem:: transmute ( target) } ;
107+ * target = word;
108+ }
93109}
94110
95111impl < T > ReadNorFlash for Nvmc < T >
@@ -100,62 +116,41 @@ where
100116
101117 const READ_SIZE : usize = 1 ;
102118
103- fn read ( & mut self , offset : u32 , mut bytes : & mut [ u8 ] ) -> Result < ( ) , Self :: Error > {
104- let mut offset = offset as usize ;
119+ fn read ( & mut self , offset : u32 , bytes : & mut [ u8 ] ) -> Result < ( ) , Self :: Error > {
120+ let offset = offset as usize ;
105121 if bytes. len ( ) > self . capacity ( ) || offset > self . capacity ( ) - bytes. len ( ) {
106122 return Err ( NvmcError :: OutOfBounds ) ;
107123 }
108124 self . wait_ready ( ) ;
109- if offset & 3 != 0 {
110- let word = self . storage [ offset >> 2 ] . to_ne_bytes ( ) ;
111- let start = offset & 3 ;
112- let length = 4 - start;
113- if length > bytes. len ( ) {
114- bytes. copy_from_slice ( & word[ start..start + bytes. len ( ) ] ) ;
115- return Ok ( ( ) ) ;
116- }
117- bytes[ ..length] . copy_from_slice ( & word[ start..] ) ;
118- offset = offset + length;
119- bytes = & mut bytes[ length..] ;
120- }
121- let mut word_offset = offset >> 2 ;
122- let mut chunks = bytes. chunks_exact_mut ( 4 ) ;
123- for bytes in & mut chunks {
124- bytes. copy_from_slice ( & self . storage [ word_offset] . to_ne_bytes ( ) ) ;
125- word_offset += 1 ;
126- }
127- let bytes = chunks. into_remainder ( ) ;
128- if !bytes. is_empty ( ) {
129- bytes. copy_from_slice ( & self . storage [ word_offset] . to_ne_bytes ( ) [ ..bytes. len ( ) ] ) ;
130- }
125+ bytes. copy_from_slice ( & self . storage [ offset..] [ ..bytes. len ( ) ] ) ;
131126 Ok ( ( ) )
132127 }
133128
134129 fn capacity ( & self ) -> usize {
135- self . storage . len ( ) << 2
130+ self . storage . len ( )
136131 }
137132}
138133
139134impl < T > NorFlash for Nvmc < T >
140135where
141136 T : Instance ,
142137{
143- const WRITE_SIZE : usize = 4 ;
138+ const WRITE_SIZE : usize = WORD_SIZE ;
144139
145- const ERASE_SIZE : usize = 4 * 1024 ;
140+ const ERASE_SIZE : usize = PAGE_SIZE ;
146141
147142 fn erase ( & mut self , from : u32 , to : u32 ) -> Result < ( ) , Self :: Error > {
148- let from = from as usize ;
149- let to = to as usize ;
143+ let ( from, to) = ( from as usize , to as usize ) ;
150144 if from > to || to > self . capacity ( ) {
151145 return Err ( NvmcError :: OutOfBounds ) ;
152146 }
153- if from % Self :: ERASE_SIZE != 0 || to % Self :: ERASE_SIZE != 0 {
147+ if from % PAGE_SIZE != 0 || to % PAGE_SIZE != 0 {
154148 return Err ( NvmcError :: Unaligned ) ;
155149 }
150+ let ( page_from, page_to) = ( from / PAGE_SIZE , to / PAGE_SIZE ) ;
156151 self . enable_erase ( ) ;
157- for offset in ( from..to ) . step_by ( Self :: ERASE_SIZE ) {
158- self . erase_page ( offset ) ;
152+ for page_offset in page_from..page_to {
153+ self . erase_page ( page_offset ) ;
159154 }
160155 self . enable_read ( ) ;
161156 Ok ( ( ) )
@@ -166,15 +161,13 @@ where
166161 if bytes. len ( ) > self . capacity ( ) || offset as usize > self . capacity ( ) - bytes. len ( ) {
167162 return Err ( NvmcError :: OutOfBounds ) ;
168163 }
169- if offset % Self :: WRITE_SIZE != 0 || bytes. len ( ) % Self :: WRITE_SIZE != 0 {
164+ if offset % WORD_SIZE != 0 || bytes. len ( ) % WORD_SIZE != 0 {
170165 return Err ( NvmcError :: Unaligned ) ;
171166 }
167+ let word_offset = offset / WORD_SIZE ;
172168 self . enable_write ( ) ;
173- let mut word_offset = offset >> 2 ;
174- for bytes in bytes. chunks_exact ( 4 ) {
175- // The unwrap is correct because chunks_exact always returns the correct size.
169+ for ( word_offset, bytes) in ( word_offset..) . zip ( bytes. chunks_exact ( WORD_SIZE ) ) {
176170 self . write_word ( word_offset, u32:: from_ne_bytes ( bytes. try_into ( ) . unwrap ( ) ) ) ;
177- word_offset += 1 ;
178171 }
179172 self . enable_read ( ) ;
180173 Ok ( ( ) )
0 commit comments