This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

flash not completely written with fstorage

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);

}

  • Here's what I'm seeing in flash at 0xFF000 through 0xff104. All zeros were written each time. 

    00000001 00000001 00000000 00000001 00000001 00000000 00000000 00000000
    00000000 00000000 00000001 00000001 002D4000 003C4000 004B4000 005A4000
    00694000 00784000 00874000 00964000 00A54000 00B44000 00C34000 00000000
    00E14000 00F04000 00000000 00000000 00000000 002C4000 003B4000 004A4000
    00594000 00684000 00774000 00864000 00954000 00A44000 00B34000 00C24000
    00000000 00E04000 00EF4000 00FE4000 000D4000 001C4000 002B4000 003A4000
    00494000 00584000 00674000 00764000 00854000 00000000 00A34000 00B24000
    00C14000 00D04000 00DF4000 00EE4000 00FD4000 000C4000 001B4000 002A4000
    00394000 00484000 

  • Hi Rob

    In general it is important to keep in mind that each page of the flash is only rated to 10000 erase cycles. If you only need to erase the page after 1024 writes you are probably OK, assuming you only write one 32-bit word a minute, but it is something to be aware of. 

    Do you have some way of logging errors when the debugger is not connected so you can see if the fstorage library returns successfully, and the data is written as normal?

    Having only parts of the bits cleared is not normal, and we should definitely try to pinpoint the cause. 

    What kind of voltage supply are you using during your test?
    Some kind of battery, or a lab supply?

    Best regards
    Torbjørn

  • Hej! 

    I don't ever erase the flash, except when re-programming the board with the jlink application. Inside my application I only write those 32-bit words, and that only one word every 60 seconds. 

    Since posting this I have run it on a development board and had the same result. So, powered by USB.

    There is no clean shutdown, though. At some point during the run power will vanish from the board and at some point after that power will return. This will only happen a few times though - and is why I'm trying to keep track of how many times the program has run. 


    I'm going to take my example and make it a runnable program and confirm that it does the same thing, and get you a complete project so you can try without waiting for feedback from me. Look for that Tomorrow (Friday the 28th of February)

    :) Rob

  • Hi Rob

    Sounds good, if you prepare a small example I can run on a DK without any extra hardware it will make it easy for me to reproduce the issue. Just let me know when you have something to share Slight smile

    Best regards
    Torbjørn

  • Unfortunately the project was canceled and then the pandemic happened. I'm not really in a position to do the promised small demo any more. Go ahead and close this if you wish.

Related