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

}

Parents
  • 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

Reply
  • 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

Children
  • 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.

  • I am sorry to hear that Rob. 

    If the project is canceled I guess you no longer need to investigate this issue. I will close the ticket then. 

    Thanks for the update. 

    Best regards
    Torbjørn

  • Yeah - the software portion of the project was working perfectly, except for this minor bug which did not affect the functioning of the application. But, as with many projects, a lot of management mistakes were made and the project died thanks to them. This is my life, as a consultant. I am always rushing to get as much of the software done (and get paid!) as soon as possible, because so many projects are canceled. 

    Maybe one day the project will rise from the ashes and I'll get to address this issue. 

    Or, just for fun if I'm ever between contracts, I might pull out an eval card and get you the promised example. 

Related