nrf: fix internal flash writes
This commit is contained in:
parent
60f76941ef
commit
9cceea0d68
@ -39,12 +39,16 @@
|
|||||||
|
|
||||||
nrf_nvic_state_t nrf_nvic_state = { 0 };
|
nrf_nvic_state_t nrf_nvic_state = { 0 };
|
||||||
|
|
||||||
|
// Flag indicating progress of internal flash operation.
|
||||||
|
sd_flash_operation_status_t sd_flash_operation_status;
|
||||||
|
|
||||||
__attribute__((aligned(4)))
|
__attribute__((aligned(4)))
|
||||||
static uint8_t m_ble_evt_buf[sizeof(ble_evt_t) + (BLE_GATT_ATT_MTU_DEFAULT)];
|
static uint8_t m_ble_evt_buf[sizeof(ble_evt_t) + (BLE_GATT_ATT_MTU_DEFAULT)];
|
||||||
|
|
||||||
void ble_drv_reset() {
|
void ble_drv_reset() {
|
||||||
// Linked list items will be gc'd.
|
// Linked list items will be gc'd.
|
||||||
MP_STATE_VM(ble_drv_evt_handler_entries) = NULL;
|
MP_STATE_VM(ble_drv_evt_handler_entries) = NULL;
|
||||||
|
sd_flash_operation_status = SD_FLASH_OPERATION_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ble_drv_add_event_handler(ble_drv_evt_handler_t func, void *param) {
|
void ble_drv_add_event_handler(ble_drv_evt_handler_t func, void *param) {
|
||||||
@ -85,22 +89,29 @@ extern void tusb_hal_nrf_power_event (uint32_t event);
|
|||||||
void SD_EVT_IRQHandler(void) {
|
void SD_EVT_IRQHandler(void) {
|
||||||
uint32_t evt_id;
|
uint32_t evt_id;
|
||||||
while (sd_evt_get(&evt_id) != NRF_ERROR_NOT_FOUND) {
|
while (sd_evt_get(&evt_id) != NRF_ERROR_NOT_FOUND) {
|
||||||
// sd_evt_handler(evt_id);
|
|
||||||
|
|
||||||
switch (evt_id) {
|
switch (evt_id) {
|
||||||
// usb power event
|
// usb power event
|
||||||
case NRF_EVT_POWER_USB_DETECTED:
|
case NRF_EVT_POWER_USB_DETECTED:
|
||||||
case NRF_EVT_POWER_USB_POWER_READY:
|
case NRF_EVT_POWER_USB_POWER_READY:
|
||||||
case NRF_EVT_POWER_USB_REMOVED: {
|
case NRF_EVT_POWER_USB_REMOVED: {
|
||||||
int32_t usbevt = (evt_id == NRF_EVT_POWER_USB_DETECTED ) ? NRFX_POWER_USB_EVT_DETECTED:
|
int32_t usbevt = (evt_id == NRF_EVT_POWER_USB_DETECTED ) ? NRFX_POWER_USB_EVT_DETECTED:
|
||||||
(evt_id == NRF_EVT_POWER_USB_POWER_READY) ? NRFX_POWER_USB_EVT_READY :
|
(evt_id == NRF_EVT_POWER_USB_POWER_READY) ? NRFX_POWER_USB_EVT_READY :
|
||||||
(evt_id == NRF_EVT_POWER_USB_REMOVED ) ? NRFX_POWER_USB_EVT_REMOVED : -1;
|
(evt_id == NRF_EVT_POWER_USB_REMOVED ) ? NRFX_POWER_USB_EVT_REMOVED : -1;
|
||||||
|
|
||||||
tusb_hal_nrf_power_event(usbevt);
|
tusb_hal_nrf_power_event(usbevt);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: break;
|
// Set flag indicating that a flash operation has finished.
|
||||||
|
case NRF_EVT_FLASH_OPERATION_SUCCESS:
|
||||||
|
sd_flash_operation_status = SD_FLASH_OPERATION_DONE;
|
||||||
|
break;
|
||||||
|
case NRF_EVT_FLASH_OPERATION_ERROR:
|
||||||
|
sd_flash_operation_status = SD_FLASH_OPERATION_ERROR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +50,15 @@
|
|||||||
|
|
||||||
typedef void (*ble_drv_evt_handler_t)(ble_evt_t*, void*);
|
typedef void (*ble_drv_evt_handler_t)(ble_evt_t*, void*);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SD_FLASH_OPERATION_DONE,
|
||||||
|
SD_FLASH_OPERATION_IN_PROGRESS,
|
||||||
|
SD_FLASH_OPERATION_ERROR,
|
||||||
|
} sd_flash_operation_status_t;
|
||||||
|
|
||||||
|
// Flag indicating progress of internal flash operation.
|
||||||
|
extern sd_flash_operation_status_t sd_flash_operation_status;
|
||||||
|
|
||||||
typedef struct ble_drv_evt_handler_entry {
|
typedef struct ble_drv_evt_handler_entry {
|
||||||
struct ble_drv_evt_handler_entry *next;
|
struct ble_drv_evt_handler_entry *next;
|
||||||
void *param;
|
void *param;
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit b96950abf27229c2a3b1719d60691321246bfc94
|
Subproject commit 3d268263be2390ab760f75a3da72689ef13031a4
|
@ -38,6 +38,7 @@
|
|||||||
#include "nrf_nvmc.h"
|
#include "nrf_nvmc.h"
|
||||||
|
|
||||||
#ifdef BLUETOOTH_SD
|
#ifdef BLUETOOTH_SD
|
||||||
|
#include "ble_drv.h"
|
||||||
#include "nrf_sdm.h"
|
#include "nrf_sdm.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -71,26 +72,15 @@ uint32_t supervisor_flash_get_block_count(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BLUETOOTH_SD
|
#ifdef BLUETOOTH_SD
|
||||||
STATIC bool wait_for_flash_operation(void) {
|
STATIC void sd_flash_operation_start(void) {
|
||||||
do {
|
sd_flash_operation_status = SD_FLASH_OPERATION_IN_PROGRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC sd_flash_operation_status_t sd_flash_operation_wait_until_done(void) {
|
||||||
|
while (sd_flash_operation_status == SD_FLASH_OPERATION_IN_PROGRESS) {
|
||||||
sd_app_evt_wait();
|
sd_app_evt_wait();
|
||||||
uint32_t evt_id;
|
}
|
||||||
uint32_t result = sd_evt_get(&evt_id);
|
return sd_flash_operation_status;
|
||||||
if (result == NRF_SUCCESS) {
|
|
||||||
switch (evt_id) {
|
|
||||||
case NRF_EVT_FLASH_OPERATION_SUCCESS:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case NRF_EVT_FLASH_OPERATION_ERROR:
|
|
||||||
return false;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Some other event. Wait for a flash event.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} while (true);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -101,27 +91,55 @@ void supervisor_flash_flush(void) {
|
|||||||
if (memcmp(_flash_cache, (void *)_flash_page_addr, FL_PAGE_SZ) != 0) {
|
if (memcmp(_flash_cache, (void *)_flash_page_addr, FL_PAGE_SZ) != 0) {
|
||||||
|
|
||||||
#ifdef BLUETOOTH_SD
|
#ifdef BLUETOOTH_SD
|
||||||
uint8_t sd_en = 0;
|
uint8_t sd_en = 0;
|
||||||
(void) sd_softdevice_is_enabled(&sd_en);
|
(void) sd_softdevice_is_enabled(&sd_en);
|
||||||
|
|
||||||
if (sd_en) {
|
if (sd_en) {
|
||||||
sd_flash_page_erase(_flash_page_addr / FL_PAGE_SZ);
|
uint32_t err_code;
|
||||||
wait_for_flash_operation(); // TODO: handle error return.
|
sd_flash_operation_status_t status;
|
||||||
sd_flash_write((uint32_t *)_flash_page_addr, (uint32_t *)_flash_cache, FL_PAGE_SZ / sizeof(uint32_t));
|
|
||||||
wait_for_flash_operation();
|
sd_flash_operation_start();
|
||||||
} else {
|
err_code = sd_flash_page_erase(_flash_page_addr / FL_PAGE_SZ);
|
||||||
|
if (err_code != NRF_SUCCESS) {
|
||||||
|
mp_raise_OSError_msg_varg(translate("Flash erase failed to start, err 0x%04x"), err_code);
|
||||||
|
}
|
||||||
|
status = sd_flash_operation_wait_until_done();
|
||||||
|
if (status == SD_FLASH_OPERATION_ERROR) {
|
||||||
|
mp_raise_OSError_msg(translate("Flash erase failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Divide a full page into parts, because writing a full page causes an assertion failure.
|
||||||
|
// See https://devzone.nordicsemi.com/f/nordic-q-a/40088/sd_flash_write-cause-nrf_fault_id_sd_assert/
|
||||||
|
const size_t BLOCK_PARTS = 2;
|
||||||
|
size_t words_to_write = FL_PAGE_SZ / sizeof(uint32_t) / BLOCK_PARTS;
|
||||||
|
for (size_t i = 0; i < BLOCK_PARTS; i++) {
|
||||||
|
sd_flash_operation_start();
|
||||||
|
err_code = sd_flash_write(((uint32_t *)_flash_page_addr) + i * words_to_write,
|
||||||
|
(uint32_t *)_flash_cache + i * words_to_write,
|
||||||
|
words_to_write);
|
||||||
|
if (err_code != NRF_SUCCESS) {
|
||||||
|
mp_raise_OSError_msg_varg(translate("Flash write failed to start, err 0x%04x"), err_code);
|
||||||
|
}
|
||||||
|
status = sd_flash_operation_wait_until_done();
|
||||||
|
if (status == SD_FLASH_OPERATION_ERROR) {
|
||||||
|
mp_raise_OSError_msg(translate("Flash write failed"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
#endif
|
#endif
|
||||||
nrf_nvmc_page_erase(_flash_page_addr);
|
nrf_nvmc_page_erase(_flash_page_addr);
|
||||||
nrf_nvmc_write_words(_flash_page_addr, (uint32_t *)_flash_cache, FL_PAGE_SZ / sizeof(uint32_t));
|
nrf_nvmc_write_words(_flash_page_addr, (uint32_t *)_flash_cache, FL_PAGE_SZ / sizeof(uint32_t));
|
||||||
#ifdef BLUETOOTH_SD
|
#ifdef BLUETOOTH_SD
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_flash_page_addr = NO_CACHE;
|
|
||||||
}
|
}
|
||||||
|
_flash_page_addr = NO_CACHE;
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_uint_t supervisor_flash_read_blocks(uint8_t *dest, uint32_t block, uint32_t num_blocks) {
|
mp_uint_t supervisor_flash_read_blocks(uint8_t *dest, uint32_t block, uint32_t num_blocks) {
|
||||||
|
// Must write out anything in cache before trying to read.
|
||||||
|
supervisor_flash_flush();
|
||||||
uint32_t src = lba2addr(block);
|
uint32_t src = lba2addr(block);
|
||||||
memcpy(dest, (uint8_t*) src, FILESYSTEM_BLOCK_SIZE*num_blocks);
|
memcpy(dest, (uint8_t*) src, FILESYSTEM_BLOCK_SIZE*num_blocks);
|
||||||
return 0; // success
|
return 0; // success
|
||||||
@ -139,9 +157,11 @@ mp_uint_t supervisor_flash_write_blocks(const uint8_t *src, uint32_t lba, uint32
|
|||||||
supervisor_flash_flush();
|
supervisor_flash_flush();
|
||||||
|
|
||||||
_flash_page_addr = page_addr;
|
_flash_page_addr = page_addr;
|
||||||
|
// Copy the current contents of the entire page into the cache.
|
||||||
memcpy(_flash_cache, (void *)page_addr, FL_PAGE_SZ);
|
memcpy(_flash_cache, (void *)page_addr, FL_PAGE_SZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Overwrite part or all of the page cache with the src data.
|
||||||
memcpy(_flash_cache + (addr & (FL_PAGE_SZ - 1)), src, count * FILESYSTEM_BLOCK_SIZE);
|
memcpy(_flash_cache + (addr & (FL_PAGE_SZ - 1)), src, count * FILESYSTEM_BLOCK_SIZE);
|
||||||
|
|
||||||
// adjust for next run
|
// adjust for next run
|
||||||
|
Loading…
Reference in New Issue
Block a user