diff options
| author | Dan Halbert <halbert@halwitz.org> | 2019-03-18 09:11:40 -0400 |
|---|---|---|
| committer | Dan Halbert <halbert@halwitz.org> | 2019-03-18 09:11:40 -0400 |
| commit | 9cceea0d68492760524c1c3fd9c87d94066e6ccb (patch) | |
| tree | 96472cadc7435cc6379c9ced830cb6635fd2591a | |
| parent | 60f76941efabd579c28cddfd70218d6ef7c08067 (diff) | |
nrf: fix internal flash writes
| -rw-r--r-- | ports/nrf/bluetooth/ble_drv.c | 35 | ||||
| -rw-r--r-- | ports/nrf/bluetooth/ble_drv.h | 9 | ||||
| m--------- | ports/nrf/nrfx | 0 | ||||
| -rw-r--r-- | ports/nrf/supervisor/internal_flash.c | 84 |
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 |
