@@ -11,25 +11,34 @@ use crate::pac::NVMC;
11
11
#[ cfg( any( feature = "9160" , feature = "5340-app" ) ) ]
12
12
use crate :: pac:: NVMC_NS as NVMC ;
13
13
14
+ use core:: convert:: TryInto ;
14
15
use embedded_storage:: nor_flash:: { NorFlash , ReadNorFlash } ;
15
16
17
+ type WORD = u32 ;
18
+ const WORD_SIZE : usize = core:: mem:: size_of :: < WORD > ( ) ;
19
+ const PAGE_SIZE : usize = 4 * 1024 ;
20
+
16
21
/// Interface to an NVMC instance.
17
22
pub struct Nvmc < T : Instance > {
18
23
nvmc : T ,
19
- storage : & ' static mut [ u32 ] ,
24
+ storage : & ' static mut [ u8 ] ,
20
25
}
21
26
22
27
impl < T > Nvmc < T >
23
28
where
24
29
T : Instance ,
25
30
{
26
31
/// 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 ) ;
28
37
Self { nvmc, storage }
29
38
}
30
39
31
40
/// 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 ] ) {
33
42
( self . nvmc , self . storage )
34
43
}
35
44
@@ -67,28 +76,36 @@ where
67
76
68
77
#[ cfg( not( any( feature = "9160" , feature = "5340-app" ) ) ) ]
69
78
#[ 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 ;
72
81
self . nvmc . erasepage ( ) . write ( |w| unsafe { w. bits ( bits) } ) ;
73
82
self . wait_ready ( ) ;
74
83
}
75
84
76
85
#[ cfg( any( feature = "9160" , feature = "5340-app" ) ) ]
77
86
#[ 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 ) ;
80
89
self . wait_ready ( ) ;
81
90
}
82
91
83
92
#[ inline]
84
- fn write_word ( & mut self , offset : usize , word : u32 ) {
93
+ fn write_word ( & mut self , word_offset : usize , word : u32 ) {
85
94
#[ cfg( not( any( feature = "9160" , feature = "5340-app" ) ) ) ]
86
95
self . wait_ready ( ) ;
87
96
#[ cfg( any( feature = "9160" , feature = "5340-app" ) ) ]
88
97
self . wait_write_ready ( ) ;
89
- self . storage [ offset ] = word;
98
+ self . direct_write_word ( word_offset , word) ;
90
99
cortex_m:: asm:: dmb ( ) ;
91
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
+ }
92
109
}
93
110
94
111
impl < T > ReadNorFlash for Nvmc < T >
@@ -97,89 +114,63 @@ where
97
114
{
98
115
type Error = NvmcError ;
99
116
100
- const READ_SIZE : usize = 4 ;
117
+ const READ_SIZE : usize = 1 ;
101
118
102
119
fn read ( & mut self , offset : u32 , bytes : & mut [ u8 ] ) -> Result < ( ) , Self :: Error > {
103
120
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 ) ;
138
123
}
124
+ self . wait_ready ( ) ;
125
+ bytes. copy_from_slice ( & self . storage [ offset..] [ ..bytes. len ( ) ] ) ;
126
+ Ok ( ( ) )
139
127
}
140
128
141
129
fn capacity ( & self ) -> usize {
142
- self . storage . len ( ) << 2
130
+ self . storage . len ( )
143
131
}
144
132
}
145
133
146
134
impl < T > NorFlash for Nvmc < T >
147
135
where
148
136
T : Instance ,
149
137
{
150
- const WRITE_SIZE : usize = 4 ;
138
+ const WRITE_SIZE : usize = WORD_SIZE ;
151
139
152
- const ERASE_SIZE : usize = 4 * 1024 ;
140
+ const ERASE_SIZE : usize = PAGE_SIZE ;
153
141
154
142
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 ) ;
164
146
}
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 ( ( ) )
165
157
}
166
158
167
159
fn write ( & mut self , offset : u32 , bytes : & [ u8 ] ) -> Result < ( ) , Self :: Error > {
168
160
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 ( ) ) ) ;
182
171
}
172
+ self . enable_read ( ) ;
173
+ Ok ( ( ) )
183
174
}
184
175
}
185
176
@@ -214,4 +205,6 @@ mod sealed {
214
205
pub enum NvmcError {
215
206
/// An operation was attempted on an unaligned boundary
216
207
Unaligned ,
208
+ /// An operation was attempted outside the boundaries
209
+ OutOfBounds ,
217
210
}
0 commit comments