Skip to content

Commit e5370c6

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 e5370c6

File tree

1 file changed

+59
-0
lines changed

1 file changed

+59
-0
lines changed

nrf-hal-common/src/nvmc.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ 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+
const PAGE_ERASE_TIME: u32 = 85;
2223

2324
/// Interface to an NVMC instance.
2425
pub struct Nvmc<T: Instance> {
@@ -44,6 +45,49 @@ where
4445
(self.nvmc, self.storage)
4546
}
4647

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

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

0 commit comments

Comments
 (0)