I am using a custom board based on nRF52840. Application is working perfectly, and then a new feature was requested. I need to count the number of minutes the application has been running, up to a small number.
I used the example fstorage code to find the end of flash, backed up a page and initialized fstorage to use that page. I use app_timer to set a 60-second timer, and when it fires I use nrf_fstorage_write to write 32 bits of zero to the previously erased flash.
When running with the debugger the 32-bit word is always written to zeros. But when I "free run" the board from power-up, and then later (minutes later) attach the debugger and have a look, I see that where I have written zeros the words in flash are not entirely zero.
This is not a crisis, as *some* of the bits are written to zero and I only need know on the next boot whether the words are non-0xffffffff. But I am bothered and a little puzzled.
The code, simplified, is essentially as below. Note that I just extracted this from my code and have not actually run this extract. If someone wishes to do so I can update the code to make it runnable.
NRF_FSTORAGE_DEF(nrf_fstorage_t fstorage) = { .end_addr = 0x100000, .start_addr = 0xfd000, .evt_handler = fstorage_evt_handler, }; static void fstorage_evt_handler(nrf_fstorage_evt_t * p_evt) { if (p_evt->result != NRF_SUCCESS) { NRF_LOG_INFO("--> Event received: ERROR while executing an fstorage operation."); return; } switch (p_evt->id) { case NRF_FSTORAGE_EVT_WRITE_RESULT: { NRF_LOG_INFO("\n--> Event received: wrote %d bytes at address 0x%x.", p_evt->len, p_evt->addr); } break; default: break; } } uint32_t g_minutes_used = 0; uint32_t g_minutes_left = MAX_RUNTIME_MINUTES; static void timer_runtime_event_handler(void* p_context) { UNUSED_PARAMETER(p_context); /* ** this handler is called every minute. */ const uint32_t zero_value = 0; nrf_fstorage_write(&fstorage, (uint32_t)&my_flash_start[g_minutes_used], &zero_value, sizeof(zero_value), NULL); NRF_LOG_INFO("\n Wrote zero to 0x%x. minutes left = %d.",(uint32_t)&my_flash_start[g_minutes_used],g_minutes_left); } #define MAX_RUNTIME_MINUTES 250 int fstorage_init(void) { ret_code_t rc; NRF_LOG_INFO("\nfstorage example started."); nrf_fstorage_api_t * p_fs_api; #ifdef SOFTDEVICE_PRESENT NRF_LOG_INFO("\nSoftDevice is present."); NRF_LOG_INFO("\nInitializing nrf_fstorage_sd implementation..."); /* Initialize an fstorage instance using the nrf_fstorage_sd backend. * nrf_fstorage_sd uses the SoftDevice to write to flash. This implementation can safely be * used whenever there is a SoftDevice, regardless of its status (enabled/disabled). */ p_fs_api = &nrf_fstorage_sd; #else NRF_LOG_INFO("\nSoftDevice not present."); NRF_LOG_INFO("\nInitializing nrf_fstorage_nvmc implementation..."); /* Initialize an fstorage instance using the nrf_fstorage_nvmc backend. * nrf_fstorage_nvmc uses the NVMC peripheral. This implementation can be used when the * SoftDevice is disabled or not present. * * Using this implementation when the SoftDevice is enabled results in a hardfault. */ p_fs_api = &nrf_fstorage_nvmc; #endif /* ** initialize flash storage code */ rc = nrf_fstorage_init(&fstorage, p_fs_api, NULL); APP_ERROR_CHECK(rc); /* ** count how many minutes we've used so far */ uint32_t ix; for (ix = 0; ix < MAX_RUNTIME_MINUTES;ix++) { if (0xffffffff == my_flash_start[ix]) { g_minutes_used = ix; // index into flash g_minutes_left = MAX_RUNTIME_MINUTES - g_minutes_used ; // number of minutes left break; } } /* ** check to see if we've used all our minutes */ if (ix >= MAX_RUNTIME_MINUTES) { g_minutes_used = MAX_RUNTIME_MINUTES; g_minutes_left = 0; } NRF_LOG_INFO("\nStartup: minutes used = %d.",g_minutes_used); NRF_LOG_INFO("\nStartup: minutes left = %d.",g_minutes_left); /* ** create the & start the runtime timer */ uint32_t err_code; #define TICKS_ONE_MINUTE APP_TIMER_TICKS(60000) err_code = app_timer_create(&m_runtime_timer_id, APP_TIMER_MODE_REPEATED, timer_runtime_event_handler); err_code = app_timer_start(m_runtime_timer_id,TICKS_ONE_MINUTE,NULL); }