@@ -11,25 +11,34 @@ use crate::pac::NVMC;
1111#[ cfg( any( feature = "9160" , feature = "5340-app" ) ) ]
1212use crate :: pac:: NVMC_NS as NVMC ;
1313
14+ use core:: convert:: TryInto ;
1415use embedded_storage:: nor_flash:: { NorFlash , ReadNorFlash } ;
1516
17+ type WORD = u32 ;
18+ const WORD_SIZE : usize = core:: mem:: size_of :: < WORD > ( ) ;
19+ const PAGE_SIZE : usize = 4 * 1024 ;
20+
1621/// Interface to an NVMC instance.
1722pub struct Nvmc < T : Instance > {
1823 nvmc : T ,
19- storage : & ' static mut [ u32 ] ,
24+ storage : & ' static mut [ u8 ] ,
2025}
2126
2227impl < T > Nvmc < T >
2328where
2429 T : Instance ,
2530{
2631 /// Takes ownership of the peripheral and storage area.
27- 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 ) ;
2837 Self { nvmc, storage }
2938 }
3039
3140 /// Consumes `self` and returns back the raw peripheral and associated storage.
32- pub fn free ( self ) -> ( T , & ' static mut [ u32 ] ) {
41+ pub fn free ( self ) -> ( T , & ' static mut [ u8 ] ) {
3342 ( self . nvmc , self . storage )
3443 }
3544
@@ -67,28 +76,36 @@ where
6776
6877 #[ cfg( not( any( feature = "9160" , feature = "5340-app" ) ) ) ]
6978 #[ inline]
70- fn erase_page ( & mut self , offset : usize ) {
71- 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 ;
7281 self . nvmc . erasepage ( ) . write ( |w| unsafe { w. bits ( bits) } ) ;
7382 self . wait_ready ( ) ;
7483 }
7584
7685 #[ cfg( any( feature = "9160" , feature = "5340-app" ) ) ]
7786 #[ inline]
78- fn erase_page ( & mut self , offset : usize ) {
79- 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 ) ;
8089 self . wait_ready ( ) ;
8190 }
8291
8392 #[ inline]
84- fn write_word ( & mut self , offset : usize , word : u32 ) {
93+ fn write_word ( & mut self , word_offset : usize , word : u32 ) {
8594 #[ cfg( not( any( feature = "9160" , feature = "5340-app" ) ) ) ]
8695 self . wait_ready ( ) ;
8796 #[ cfg( any( feature = "9160" , feature = "5340-app" ) ) ]
8897 self . wait_write_ready ( ) ;
89- self . storage [ offset ] = word;
98+ self . direct_write_word ( word_offset , word) ;
9099 cortex_m:: asm:: dmb ( ) ;
91100 }
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+ }
92109}
93110
94111impl < T > ReadNorFlash for Nvmc < T >
@@ -97,89 +114,63 @@ where
97114{
98115 type Error = NvmcError ;
99116
100- const READ_SIZE : usize = 4 ;
117+ const READ_SIZE : usize = 1 ;
101118
102119 fn read ( & mut self , offset : u32 , bytes : & mut [ u8 ] ) -> Result < ( ) , Self :: Error > {
103120 let offset = offset as usize ;
104- let bytes_len = bytes. len ( ) ;
105- let read_len = bytes_len + ( Self :: READ_SIZE - ( bytes_len % Self :: READ_SIZE ) ) ;
106- let target_offset = offset + read_len;
107- if offset % Self :: READ_SIZE == 0 && target_offset <= self . capacity ( ) {
108- self . wait_ready ( ) ;
109- let last_offset = target_offset - Self :: READ_SIZE ;
110- for offset in ( offset..last_offset) . step_by ( Self :: READ_SIZE ) {
111- let word = self . storage [ offset >> 2 ] ;
112- bytes[ offset] = ( word >> 24 ) as u8 ;
113- bytes[ offset + 1 ] = ( word >> 16 ) as u8 ;
114- bytes[ offset + 2 ] = ( word >> 8 ) as u8 ;
115- bytes[ offset + 3 ] = ( word >> 0 ) as u8 ;
116- }
117- let offset = last_offset;
118- let word = self . storage [ offset >> 2 ] ;
119- let mut bytes_offset = offset;
120- if bytes_offset < bytes_len {
121- bytes[ bytes_offset] = ( word >> 24 ) as u8 ;
122- bytes_offset += 1 ;
123- if bytes_offset < bytes_len {
124- bytes[ bytes_offset] = ( word >> 16 ) as u8 ;
125- bytes_offset += 1 ;
126- if bytes_offset < bytes_len {
127- bytes[ bytes_offset] = ( word >> 8 ) as u8 ;
128- bytes_offset += 1 ;
129- if bytes_offset < bytes_len {
130- bytes[ bytes_offset] = ( word >> 0 ) as u8 ;
131- }
132- }
133- }
134- }
135- Ok ( ( ) )
136- } else {
137- Err ( NvmcError :: Unaligned )
121+ if bytes. len ( ) > self . capacity ( ) || offset > self . capacity ( ) - bytes. len ( ) {
122+ return Err ( NvmcError :: OutOfBounds ) ;
138123 }
124+ self . wait_ready ( ) ;
125+ bytes. copy_from_slice ( & self . storage [ offset..] [ ..bytes. len ( ) ] ) ;
126+ Ok ( ( ) )
139127 }
140128
141129 fn capacity ( & self ) -> usize {
142- self . storage . len ( ) << 2
130+ self . storage . len ( )
143131 }
144132}
145133
146134impl < T > NorFlash for Nvmc < T >
147135where
148136 T : Instance ,
149137{
150- const WRITE_SIZE : usize = 4 ;
138+ const WRITE_SIZE : usize = WORD_SIZE ;
151139
152- const ERASE_SIZE : usize = 4 * 1024 ;
140+ const ERASE_SIZE : usize = PAGE_SIZE ;
153141
154142 fn erase ( & mut self , from : u32 , to : u32 ) -> Result < ( ) , Self :: Error > {
155- if from as usize % Self :: ERASE_SIZE == 0 && to as usize % Self :: ERASE_SIZE == 0 {
156- self . enable_erase ( ) ;
157- for offset in ( from..to) . step_by ( Self :: ERASE_SIZE ) {
158- self . erase_page ( offset as usize >> 2 ) ;
159- }
160- self . enable_read ( ) ;
161- Ok ( ( ) )
162- } else {
163- Err ( NvmcError :: Unaligned )
143+ let ( from, to) = ( from as usize , to as usize ) ;
144+ if from > to || to > self . capacity ( ) {
145+ return Err ( NvmcError :: OutOfBounds ) ;
164146 }
147+ if from % PAGE_SIZE != 0 || to % PAGE_SIZE != 0 {
148+ return Err ( NvmcError :: Unaligned ) ;
149+ }
150+ let ( page_from, page_to) = ( from / PAGE_SIZE , to / PAGE_SIZE ) ;
151+ self . enable_erase ( ) ;
152+ for page_offset in page_from..page_to {
153+ self . erase_page ( page_offset) ;
154+ }
155+ self . enable_read ( ) ;
156+ Ok ( ( ) )
165157 }
166158
167159 fn write ( & mut self , offset : u32 , bytes : & [ u8 ] ) -> Result < ( ) , Self :: Error > {
168160 let offset = offset as usize ;
169- if offset % Self :: WRITE_SIZE == 0 && bytes. len ( ) % Self :: WRITE_SIZE == 0 {
170- self . enable_write ( ) ;
171- for offset in ( offset..( offset + bytes. len ( ) ) ) . step_by ( Self :: WRITE_SIZE ) {
172- let word = ( ( bytes[ offset] as u32 ) << 24 )
173- | ( ( bytes[ offset + 1 ] as u32 ) << 16 )
174- | ( ( bytes[ offset + 2 ] as u32 ) << 8 )
175- | ( ( bytes[ offset + 3 ] as u32 ) << 0 ) ;
176- self . write_word ( offset >> 2 , word) ;
177- }
178- self . enable_read ( ) ;
179- Ok ( ( ) )
180- } else {
181- Err ( NvmcError :: Unaligned )
161+ if bytes. len ( ) > self . capacity ( ) || offset as usize > self . capacity ( ) - bytes. len ( ) {
162+ return Err ( NvmcError :: OutOfBounds ) ;
163+ }
164+ if offset % WORD_SIZE != 0 || bytes. len ( ) % WORD_SIZE != 0 {
165+ return Err ( NvmcError :: Unaligned ) ;
166+ }
167+ let word_offset = offset / WORD_SIZE ;
168+ self . enable_write ( ) ;
169+ for ( word_offset, bytes) in ( word_offset..) . zip ( bytes. chunks_exact ( WORD_SIZE ) ) {
170+ self . write_word ( word_offset, u32:: from_ne_bytes ( bytes. try_into ( ) . unwrap ( ) ) ) ;
182171 }
172+ self . enable_read ( ) ;
173+ Ok ( ( ) )
183174 }
184175}
185176
@@ -214,4 +205,6 @@ mod sealed {
214205pub enum NvmcError {
215206 /// An operation was attempted on an unaligned boundary
216207 Unaligned ,
208+ /// An operation was attempted outside the boundaries
209+ OutOfBounds ,
217210}
0 commit comments