Skip to content

Commit 1392ec8

Browse files
committed
Change Nvmc backing storage to [u8]
1 parent 96df9c4 commit 1392ec8

File tree

3 files changed

+44
-54
lines changed

3 files changed

+44
-54
lines changed

examples/nvmc-demo/memory.x

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ MEMORY
22
{
33
/* NOTE 1 K = 1 KiB = 1024 bytes */
44
FLASH : ORIGIN = 0x00000000, LENGTH = 1024K - 16K
5-
/* We use 4 pages of 4 KiB each, so 16 KiB */
6-
CONFIG : ORIGIN = ORIGIN(FLASH) + LENGTH(FLASH), LENGTH = 16K
5+
/* We use 6 pages of 4 KiB each */
6+
CONFIG : ORIGIN = ORIGIN(FLASH) + LENGTH(FLASH), LENGTH = 6 * 4K
77
RAM : ORIGIN = 0x20000000, LENGTH = 256K
88
}
99

examples/nvmc-demo/src/main.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,12 @@ use hal::pac::NVMC;
1414
use panic_probe as _;
1515
use rtt_target::{rprintln, rtt_init_print};
1616

17-
// We use 4 pages to use non-zero offsets.
17+
const NUM_PAGES: usize = 6;
1818
const PAGE_SIZE: u32 = 4 * 1024;
1919
const LAST_PAGE: u32 = 3 * PAGE_SIZE;
20-
const CONFIG_SIZE: usize = 4 * PAGE_SIZE as usize / 4;
2120
extern "C" {
2221
#[link_name = "_config"]
23-
static mut CONFIG: [u32; CONFIG_SIZE];
22+
static mut CONFIG: [u8; NUM_PAGES * PAGE_SIZE as usize];
2423
}
2524

2625
// To run this example:
@@ -88,9 +87,7 @@ fn read<const LENGTH: usize>(nvmc: &mut Nvmc<NVMC>, offset: u32) -> [u8; LENGTH]
8887
}
8988

9089
unsafe fn direct_read<const LENGTH: usize>(offset: u32) -> [u8; LENGTH] {
91-
let ptr = &CONFIG as *const u32 as *const u8;
92-
let slice = core::slice::from_raw_parts(ptr, CONFIG_SIZE * 4);
93-
slice[offset as usize..][..LENGTH].try_into().unwrap()
90+
CONFIG[offset as usize..][..LENGTH].try_into().unwrap()
9491
}
9592

9693
fn erase_if_needed(nvmc: &mut Nvmc<NVMC>, offset: u32) {

nrf-hal-common/src/nvmc.rs

Lines changed: 39 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,31 @@ use crate::pac::NVMC_NS as NVMC;
1414
use core::convert::TryInto;
1515
use 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.
1822
pub struct Nvmc<T: Instance> {
1923
nvmc: T,
20-
storage: &'static mut [u32],
24+
storage: &'static mut [u8],
2125
}
2226

2327
impl<T> Nvmc<T>
2428
where
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

95111
impl<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

139134
impl<T> NorFlash for Nvmc<T>
140135
where
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

Comments
 (0)