drivers/flash/nrfx: Enable partial erase of flash

When enabled, instead of erasing entire flash page at once, page will
be erased in defined time slices. Erasing single page stalls CPU
for significant time share (~80ms) and partial erase divides the
operation in to the shorter time periods, resuming CPU operation in
meantime and enabling better scheduling of time sensitive operations.

Signed-off-by: Dominik Ermel <dominik.ermel@nordicsemi.no>
This commit is contained in:
Dominik Ermel 2020-03-11 10:46:48 +00:00 committed by Anas Nashif
commit 143f9bfd4e
6 changed files with 78 additions and 7 deletions

View file

@ -27,6 +27,29 @@ config SOC_FLASH_NRF_RADIO_SYNC
help
Enable synchronization between flash memory driver and radio.
config SOC_FLASH_NRF_PARTIAL_ERASE
bool "Nordic nRFx flash driver partial erase"
depends on HAS_HW_NRF_NVMC_PE
help
Enable partial erase feature. Partial erase is performed in time
slices instead of blocking MCU, for the time it is needed to
complete operation over given area.
This allows interrupting flash erase between operations
to perform other task by MCU.
This feature may also be used for better syncing flash erase
operations, when compiled with SOC_FLASH_NRF_RADIO_SYNC,
with Bluetooth.
config SOC_FLASH_NRF_PARTIAL_ERASE_MS
int "Partial erase timeout in MS"
depends on SOC_FLASH_NRF_PARTIAL_ERASE
default 3
help
This is maximum time, in ms, that NVMC will use to erase part
of Flash, before stopping to let CPU resume operation.
Minimal timeout is 2ms maximum should not exceed half of
FLASH_PAGE_ERASE_MAX_TIME_US im ms.
config SOC_FLASH_NRF_UICR
bool "Access to UICR"
depends on !TRUSTED_EXECUTION_NONSECURE

View file

@ -26,18 +26,33 @@
#define FLASH_RADIO_ABORT_DELAY_US 1500
#define FLASH_RADIO_WORK_DELAY_US 200
#define FLASH_SLOT_ERASE FLASH_PAGE_ERASE_MAX_TIME_US
#define FLASH_INTERVAL_ERASE (FLASH_RADIO_ABORT_DELAY_US + \
FLASH_RADIO_WORK_DELAY_US + \
FLASH_SLOT_ERASE)
#define FLASH_INTERVAL_WRITE 7500
#define FLASH_SLOT_WRITE (FLASH_INTERVAL_WRITE - \
FLASH_RADIO_ABORT_DELAY_US - \
FLASH_RADIO_WORK_DELAY_US)
#define FLASH_INTERVAL_WRITE 7500
#if defined(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE)
/* The timeout is multiplied by 1.5 because switching tasks may take
* significant portion of time.
*/
#define FLASH_TIMEOUT_MS ((FLASH_PAGE_ERASE_MAX_TIME_US) * \
(FLASH_PAGE_MAX_CNT) / 1000 * 15 / 10)
#define FLASH_SLOT_ERASE (MAX(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE_MS * 1000, \
7500))
#else
#define FLASH_TIMEOUT_MS ((FLASH_PAGE_ERASE_MAX_TIME_US) * \
(FLASH_PAGE_MAX_CNT) / 1000)
#define FLASH_SLOT_ERASE FLASH_PAGE_ERASE_MAX_TIME_US
#endif /* CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE */
#define FLASH_TIMEOUT_MS ((FLASH_PAGE_ERASE_MAX_TIME_US)\
* (FLASH_PAGE_MAX_CNT) / 1000)
#endif /* CONFIG_SOC_FLASH_NRF_RADIO_SYNC */
#define FLASH_OP_DONE (0) /* 0 for compliance with the driver API. */
@ -52,6 +67,9 @@ struct flash_context {
u32_t interval; /* timeslot interval. */
u32_t slot; /* timeslot length. */
#endif /* CONFIG_SOC_FLASH_NRF_RADIO_SYNC */
#if defined(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE)
u32_t flash_addr_next;
#endif /* CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE */
}; /*< Context type for f. @ref write_op @ref erase_op */
#if defined(CONFIG_SOC_FLASH_NRF_RADIO_SYNC)
@ -426,7 +444,10 @@ static int erase_in_timeslice(u32_t addr, u32_t size)
.len = size,
.enable_time_limit = 1, /* enable time limit */
.interval = FLASH_INTERVAL_ERASE,
.slot = FLASH_SLOT_ERASE
.slot = FLASH_SLOT_ERASE,
#if defined(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE)
.flash_addr_next = addr
#endif
};
struct flash_op_desc flash_op_desc = {
@ -481,10 +502,23 @@ static int erase_op(void *context)
#endif
do {
(void)nrfx_nvmc_page_erase(e_ctx->flash_addr);
#if defined(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE)
if (e_ctx->flash_addr == e_ctx->flash_addr_next) {
nrfx_nvmc_page_partial_erase_init(e_ctx->flash_addr,
CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE_MS);
e_ctx->flash_addr_next += pg_size;
}
if (nrfx_nvmc_page_partial_erase_continue()) {
e_ctx->len -= pg_size;
e_ctx->flash_addr += pg_size;
}
#else
(void)nrfx_nvmc_page_erase(e_ctx->flash_addr);
e_ctx->len -= pg_size;
e_ctx->flash_addr += pg_size;
#endif /* CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE */
#if defined(CONFIG_SOC_FLASH_NRF_RADIO_SYNC)
i++;
@ -597,8 +631,11 @@ static int erase(u32_t addr, u32_t size)
.flash_addr = addr,
.len = size,
#if defined(CONFIG_SOC_FLASH_NRF_RADIO_SYNC)
.enable_time_limit = 0 /* disable time limit */
.enable_time_limit = 0, /* disable time limit */
#endif /* CONFIG_SOC_FLASH_NRF_RADIO_SYNC */
#if defined(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE)
.flash_addr_next = addr
#endif
};
return erase_op(&context);

View file

@ -78,6 +78,10 @@ config HAS_HW_NRF_MWU
config HAS_HW_NRF_NFCT
bool
# NVMC supports partial erase
config HAS_HW_NRF_NVMC_PE
bool
config HAS_HW_NRF_PDM
bool

View file

@ -15,6 +15,7 @@ config SOC_NRF52810
select HAS_HW_NRF_EGU1
select HAS_HW_NRF_GPIO0
select HAS_HW_NRF_GPIOTE
select HAS_HW_NRF_NVMC_PE
select HAS_HW_NRF_PDM
select HAS_HW_NRF_POWER
select HAS_HW_NRF_PPI
@ -56,6 +57,7 @@ config SOC_NRF52811
select HAS_HW_NRF_EGU1
select HAS_HW_NRF_GPIO0
select HAS_HW_NRF_GPIOTE
select HAS_HW_NRF_NVMC_PE
select HAS_HW_NRF_PDM
select HAS_HW_NRF_POWER
select HAS_HW_NRF_PPI
@ -179,6 +181,7 @@ config SOC_NRF52833
select HAS_HW_NRF_LPCOMP
select HAS_HW_NRF_MWU
select HAS_HW_NRF_NFCT
select HAS_HW_NRF_NVMC_PE
select HAS_HW_NRF_PDM
select HAS_HW_NRF_POWER
select HAS_HW_NRF_PPI
@ -252,6 +255,7 @@ config SOC_NRF52840
select HAS_HW_NRF_LPCOMP
select HAS_HW_NRF_MWU
select HAS_HW_NRF_NFCT
select HAS_HW_NRF_NVMC_PE
select HAS_HW_NRF_PDM
select HAS_HW_NRF_POWER
select HAS_HW_NRF_PPI

View file

@ -25,6 +25,7 @@ config SOC_NRF5340_CPUAPP
select HAS_HW_NRF_I2S
select HAS_HW_NRF_IPC
select HAS_HW_NRF_NFCT
select HAS_HW_NRF_NVMC_PE
select HAS_HW_NRF_PDM
select HAS_HW_NRF_POWER
select HAS_HW_NRF_PWM0
@ -75,6 +76,7 @@ config SOC_NRF5340_CPUNET
select HAS_HW_NRF_GPIO1
select HAS_HW_NRF_GPIOTE
select HAS_HW_NRF_IPC
select HAS_HW_NRF_NVMC_PE
select HAS_HW_NRF_POWER
select HAS_HW_NRF_RADIO_BLE_CODED
select HAS_HW_NRF_RADIO_IEEE802154

View file

@ -19,6 +19,7 @@ config SOC_NRF9160
select HAS_HW_NRF_GPIOTE
select HAS_HW_NRF_I2S
select HAS_HW_NRF_IPC
select HAS_HW_NRF_NVMC_PE
select HAS_HW_NRF_PDM
select HAS_HW_NRF_POWER
select HAS_HW_NRF_PWM0