summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Halbert <halbert@halwitz.org>2019-03-18 09:11:40 -0400
committerDan Halbert <halbert@halwitz.org>2019-03-18 09:11:40 -0400
commit9cceea0d68492760524c1c3fd9c87d94066e6ccb (patch)
tree96472cadc7435cc6379c9ced830cb6635fd2591a
parent60f76941efabd579c28cddfd70218d6ef7c08067 (diff)
nrf: fix internal flash writes
-rw-r--r--ports/nrf/bluetooth/ble_drv.c35
-rw-r--r--ports/nrf/bluetooth/ble_drv.h9
m---------ports/nrf/nrfx0
-rw-r--r--ports/nrf/supervisor/internal_flash.c84
4 files changed, 84 insertions, 44 deletions
diff --git a/ports/nrf/bluetooth/ble_drv.c b/ports/nrf/bluetooth/ble_drv.c
index bb395ce4c..f6e575a8c 100644
--- a/ports/nrf/bluetooth/ble_drv.c
+++ b/ports/nrf/bluetooth/ble_drv.c
@@ -39,12 +39,16 @@
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)))
static uint8_t m_ble_evt_buf[sizeof(ble_evt_t) + (BLE_GATT_ATT_MTU_DEFAULT)];
void ble_drv_reset() {
// Linked list items will be gc'd.
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) {
@@ -85,22 +89,29 @@ extern void tusb_hal_nrf_power_event (uint32_t event);
void SD_EVT_IRQHandler(void) {
uint32_t evt_id;
while (sd_evt_get(&evt_id) != NRF_ERROR_NOT_FOUND) {
-// sd_evt_handler(evt_id);
-
switch (evt_id) {
// usb power event
- case NRF_EVT_POWER_USB_DETECTED:
- case NRF_EVT_POWER_USB_POWER_READY:
- case NRF_EVT_POWER_USB_REMOVED: {
- 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_REMOVED ) ? NRFX_POWER_USB_EVT_REMOVED : -1;
-
- tusb_hal_nrf_power_event(usbevt);
- }
+ case NRF_EVT_POWER_USB_DETECTED:
+ case NRF_EVT_POWER_USB_POWER_READY:
+ case NRF_EVT_POWER_USB_REMOVED: {
+ 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_REMOVED ) ? NRFX_POWER_USB_EVT_REMOVED : -1;
+
+ tusb_hal_nrf_power_event(usbevt);
+ }
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;
}
}
diff --git a/ports/nrf/bluetooth/ble_drv.h b/ports/nrf/bluetooth/ble_drv.h
index 8d3846a7b..cdb4c9b03 100644
--- a/ports/nrf/bluetooth/ble_drv.h
+++ b/ports/nrf/bluetooth/ble_drv.h
@@ -50,6 +50,15 @@
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 {
struct ble_drv_evt_handler_entry *next;
void *param;
diff --git a/ports/nrf/nrfx b/ports/nrf/nrfx
-Subproject b96950abf27229c2a3b1719d60691321246bfc9
+Subproject 3d268263be2390ab760f75a3da72689ef13031a
diff --git a/ports/nrf/supervisor/internal_flash.c b/ports/nrf/supervisor/internal_flash.c
index 4351f3da6..273213244 100644
--- a/ports/nrf/supervisor/internal_flash.c
+++ b/ports/nrf/supervisor/internal_flash.c
@@ -38,6 +38,7 @@
#include "nrf_nvmc.h"
#ifdef BLUETOOTH_SD
+#include "ble_drv.h"
#include "nrf_sdm.h"
#endif
@@ -71,26 +72,15 @@ uint32_t supervisor_flash_get_block_count(void) {
}
#ifdef BLUETOOTH_SD
-STATIC bool wait_for_flash_operation(void) {
- do {
+STATIC void sd_flash_operation_start(void) {
+ 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();
- uint32_t evt_id;
- uint32_t result = sd_evt_get(&evt_id);
- 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);
+ }
+ return sd_flash_operation_status;
}
#endif
@@ -101,27 +91,55 @@ void supervisor_flash_flush(void) {
if (memcmp(_flash_cache, (void *)_flash_page_addr, FL_PAGE_SZ) != 0) {
#ifdef BLUETOOTH_SD
- uint8_t sd_en = 0;
- (void) sd_softdevice_is_enabled(&sd_en);
-
- if (sd_en) {
- sd_flash_page_erase(_flash_page_addr / FL_PAGE_SZ);
- wait_for_flash_operation(); // TODO: handle error return.
- sd_flash_write((uint32_t *)_flash_page_addr, (uint32_t *)_flash_cache, FL_PAGE_SZ / sizeof(uint32_t));
- wait_for_flash_operation();
- } else {
+ uint8_t sd_en = 0;
+ (void) sd_softdevice_is_enabled(&sd_en);
+
+ if (sd_en) {
+ uint32_t err_code;
+ sd_flash_operation_status_t status;
+
+ sd_flash_operation_start();
+ 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
- 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_page_erase(_flash_page_addr);
+ nrf_nvmc_write_words(_flash_page_addr, (uint32_t *)_flash_cache, FL_PAGE_SZ / sizeof(uint32_t));
#ifdef BLUETOOTH_SD
- }
+ }
#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) {
+ // Must write out anything in cache before trying to read.
+ supervisor_flash_flush();
uint32_t src = lba2addr(block);
memcpy(dest, (uint8_t*) src, FILESYSTEM_BLOCK_SIZE*num_blocks);
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();
_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);
}
+ // 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);
// adjust for next run