@@ -14,23 +14,31 @@ use crate::pac::NVMC_NS as NVMC;
14
14
use core:: convert:: TryInto ;
15
15
use embedded_storage:: nor_flash:: { NorFlash , ReadNorFlash } ;
16
16
17
+ type WORD = u32 ;
18
+ const WORD_SIZE : usize = core:: mem:: size_of :: < WORD > ( ) ;
19
+ const PAGE_SIZE : usize = 4 * 1024 ;
20
+
17
21
/// Interface to an NVMC instance.
18
22
pub struct Nvmc < T : Instance > {
19
23
nvmc : T ,
20
- storage : & ' static mut [ u32 ] ,
24
+ storage : & ' static mut [ u8 ] ,
21
25
}
22
26
23
27
impl < T > Nvmc < T >
24
28
where
25
29
T : Instance ,
26
30
{
27
31
/// 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 ) ;
29
37
Self { nvmc, storage }
30
38
}
31
39
32
40
/// 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 ] ) {
34
42
( self . nvmc , self . storage )
35
43
}
36
44
@@ -68,28 +76,36 @@ where
68
76
69
77
#[ cfg( not( any( feature = "9160" , feature = "5340-app" ) ) ) ]
70
78
#[ 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 ;
73
81
self . nvmc . erasepage ( ) . write ( |w| unsafe { w. bits ( bits) } ) ;
74
82
self . wait_ready ( ) ;
75
83
}
76
84
77
85
#[ cfg( any( feature = "9160" , feature = "5340-app" ) ) ]
78
86
#[ 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 ) ;
81
89
self . wait_ready ( ) ;
82
90
}
83
91
84
92
#[ inline]
85
- fn write_word ( & mut self , offset : usize , word : u32 ) {
93
+ fn write_word ( & mut self , word_offset : usize , word : u32 ) {
86
94
#[ cfg( not( any( feature = "9160" , feature = "5340-app" ) ) ) ]
87
95
self . wait_ready ( ) ;
88
96
#[ cfg( any( feature = "9160" , feature = "5340-app" ) ) ]
89
97
self . wait_write_ready ( ) ;
90
- self . storage [ offset ] = word;
98
+ self . direct_write_word ( word_offset , word) ;
91
99
cortex_m:: asm:: dmb ( ) ;
92
100
}
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
+ }
93
109
}
94
110
95
111
impl < T > ReadNorFlash for Nvmc < T >
@@ -100,62 +116,41 @@ where
100
116
101
117
const READ_SIZE : usize = 1 ;
102
118
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 ;
105
121
if bytes. len ( ) > self . capacity ( ) || offset > self . capacity ( ) - bytes. len ( ) {
106
122
return Err ( NvmcError :: OutOfBounds ) ;
107
123
}
108
124
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 ( ) ] ) ;
131
126
Ok ( ( ) )
132
127
}
133
128
134
129
fn capacity ( & self ) -> usize {
135
- self . storage . len ( ) << 2
130
+ self . storage . len ( )
136
131
}
137
132
}
138
133
139
134
impl < T > NorFlash for Nvmc < T >
140
135
where
141
136
T : Instance ,
142
137
{
143
- const WRITE_SIZE : usize = 4 ;
138
+ const WRITE_SIZE : usize = WORD_SIZE ;
144
139
145
- const ERASE_SIZE : usize = 4 * 1024 ;
140
+ const ERASE_SIZE : usize = PAGE_SIZE ;
146
141
147
142
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 ) ;
150
144
if from > to || to > self . capacity ( ) {
151
145
return Err ( NvmcError :: OutOfBounds ) ;
152
146
}
153
- if from % Self :: ERASE_SIZE != 0 || to % Self :: ERASE_SIZE != 0 {
147
+ if from % PAGE_SIZE != 0 || to % PAGE_SIZE != 0 {
154
148
return Err ( NvmcError :: Unaligned ) ;
155
149
}
150
+ let ( page_from, page_to) = ( from / PAGE_SIZE , to / PAGE_SIZE ) ;
156
151
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 ) ;
159
154
}
160
155
self . enable_read ( ) ;
161
156
Ok ( ( ) )
@@ -166,15 +161,13 @@ where
166
161
if bytes. len ( ) > self . capacity ( ) || offset as usize > self . capacity ( ) - bytes. len ( ) {
167
162
return Err ( NvmcError :: OutOfBounds ) ;
168
163
}
169
- if offset % Self :: WRITE_SIZE != 0 || bytes. len ( ) % Self :: WRITE_SIZE != 0 {
164
+ if offset % WORD_SIZE != 0 || bytes. len ( ) % WORD_SIZE != 0 {
170
165
return Err ( NvmcError :: Unaligned ) ;
171
166
}
167
+ let word_offset = offset / WORD_SIZE ;
172
168
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 ) ) {
176
170
self . write_word ( word_offset, u32:: from_ne_bytes ( bytes. try_into ( ) . unwrap ( ) ) ) ;
177
- word_offset += 1 ;
178
171
}
179
172
self . enable_read ( ) ;
180
173
Ok ( ( ) )
0 commit comments