Skip to content

Commit cae8c11

Browse files
committed
Add support for partial flash erase
Partial erase is a feature that allows to reduce time CPU is halted when using NVMC. It works by dividing page erase operation into multiple operations, in-between each operation CPU is resumed allowing interrupt handling.
1 parent 54c6586 commit cae8c11

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

nrf-hal-common/src/nvmc.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ use embedded_storage::nor_flash::{
1919
type WORD = u32;
2020
const WORD_SIZE: usize = core::mem::size_of::<WORD>();
2121
const PAGE_SIZE: usize = 4 * 1024;
22+
#[cfg(not(any(feature = "9160", feature = "5340-app")))]
23+
const PAGE_ERASE_TIME: u32 = 85;
2224

2325
/// Interface to an NVMC instance.
2426
pub struct Nvmc<T: Instance> {
@@ -44,6 +46,49 @@ where
4446
(self.nvmc, self.storage)
4547
}
4648

49+
#[cfg(not(any(feature = "9160", feature = "5340-app")))]
50+
/// Erases the given storage range using partial erase feature. This allows
51+
/// application to handle interrupts while erasing memory by dividing the
52+
/// time CPU is halted in smaller periods.
53+
///
54+
/// # Errors
55+
///
56+
/// Returns an error if the arguments are not aligned, out of bounds or when
57+
/// period is not in range from 1 to 127 inclusive.
58+
pub fn partial_erase(
59+
&mut self,
60+
from: u32,
61+
to: u32,
62+
period: u32,
63+
) -> Result<(), <Self as ErrorType>::Error> {
64+
let (from, to) = (from as usize, to as usize);
65+
if from > to || to > self.capacity() {
66+
return Err(NvmcError::OutOfBounds);
67+
}
68+
if from % PAGE_SIZE != 0 || to % PAGE_SIZE != 0 {
69+
return Err(NvmcError::Unaligned);
70+
}
71+
let (page_from, page_to) = (from / PAGE_SIZE, to / PAGE_SIZE);
72+
73+
if period & !0x7F != 0 || period == 0 {
74+
return Err(NvmcError::OutOfBounds);
75+
}
76+
77+
self.nvmc
78+
.erasepagepartialcfg
79+
.write(|w| unsafe { w.bits(period) });
80+
for page_offset in page_from..page_to {
81+
// According to nRF52840 manual (section 4.3.9.9) CONFIG.WEN must be
82+
// enabled before every partial erase and disabled after every
83+
// partial erase
84+
self.enable_erase();
85+
self.partial_erase_page(page_offset, period);
86+
self.enable_read();
87+
}
88+
89+
Ok(())
90+
}
91+
4792
fn enable_erase(&self) {
4893
#[cfg(not(any(feature = "9160", feature = "5340-app")))]
4994
self.nvmc.config.write(|w| w.wen().een());
@@ -91,6 +136,21 @@ where
91136
self.wait_ready();
92137
}
93138

139+
#[cfg(not(any(feature = "9160", feature = "5340-app")))]
140+
#[inline]
141+
fn partial_erase_page(&mut self, page_offset: usize, period: u32) {
142+
let bits = &mut (self.storage[page_offset * PAGE_SIZE]) as *mut _ as u32;
143+
let mut time_left = PAGE_ERASE_TIME;
144+
while time_left > 0 {
145+
self.nvmc
146+
.erasepagepartial
147+
.write(|w| unsafe { w.bits(bits) });
148+
self.wait_ready();
149+
150+
time_left = time_left.saturating_sub(period);
151+
}
152+
}
153+
94154
#[inline]
95155
fn write_word(&mut self, word_offset: usize, word: u32) {
96156
#[cfg(not(any(feature = "9160", feature = "5340-app")))]

0 commit comments

Comments
 (0)