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

Flash FDS initialization failure until 4 reset with nRF5 SDK for Thread and Zigbee v4.1.0

Hi everyone.

I have an application using BLE and OpenThread dynamicaly.
I am working with nRF52840 chip with nRF5 SDK for Thread and Zigbee v4.1.0 (Release Date: Week 18, 2020)

In order to store the advertising data and some mesh parameters, I need to use the flash.
I first try to implement a solution with nrf_fstorage module, but I had a lot of issues with it so I changed for FDS module.

I manage to implement a working solution exept that the first time the chip is programmed (after a full erase), I need to do 3 to 4 resets befor the program starts.

I have been investigating in debug mode. It seems I am stuck somewhere into sd_app_evt_wait();
Here is my code to init the flash :

static bool volatile fdsInitialized;
static bool writeTerminated;

/************************************* fds_evt_handler ***************************************/
/** 
* @Brief Simple event handler to handle errors during initialization. 
*/
static void fds_evt_handler(fds_evt_t const * p_evt)
{
		switch (p_evt->id){
			case FDS_EVT_INIT:
					if (p_evt->result == FDS_SUCCESS){
						 fdsInitialized = true;
					}
					break;
			case FDS_EVT_WRITE:
					if (p_evt->result == FDS_SUCCESS){
						 writeTerminated = true;
					}
					break;
			case FDS_EVT_UPDATE:
					if (p_evt->result == FDS_SUCCESS){
						 writeTerminated = true;
						 if(netStr2Save.netReset == 1){
								//Restar tne Mesh Network with the new name		
								NVIC_SystemReset();
						 }
					}
					break;
			case FDS_EVT_DEL_RECORD:
					if (p_evt->result == FDS_SUCCESS){    
					}
				break;
			
			 case FDS_EVT_GC:
					if (p_evt->result == FDS_SUCCESS){
						 flash_save_config(&netStr2Save);
					}
					break;
			default:
					break;
    }
}

void flash_init(void){

	ret_code_t ret = fds_register(fds_evt_handler);
	if (ret != FDS_SUCCESS)
	{
    	return ret;
	}

	ret = fds_init();	
	if (ret != FDS_SUCCESS)
	{
		return ret;
	}
    
    while (!fdsInitialized){
        sd_app_evt_wait();
    }
	writeTerminated = true;
}


The flash init function is called after ble_stack_init in the main.

Here is the SDK config I  have got :
/ <e> FDS_ENABLED - fds - Flash data storage module
//==========================================================
#ifndef FDS_ENABLED
#define FDS_ENABLED 1
#endif
// <h> Pages - Virtual page settings

// <i> Configure the number of virtual pages to use and their size.
//==========================================================
// <o> FDS_VIRTUAL_PAGES - Number of virtual flash pages to use. 
// <i> One of the virtual pages is reserved by the system for garbage collection.
// <i> Therefore, the minimum is two virtual pages: one page to store data and one page to be used by the system for garbage collection.
// <i> The total amount of flash memory that is used by FDS amounts to @ref FDS_VIRTUAL_PAGES * @ref FDS_VIRTUAL_PAGE_SIZE * 4 bytes.

#ifndef FDS_VIRTUAL_PAGES
#define FDS_VIRTUAL_PAGES 3
#endif

// <o> FDS_VIRTUAL_PAGE_SIZE  - The size of a virtual flash page.
 

// <i> Expressed in number of 4-byte words.
// <i> By default, a virtual page is the same size as a physical page.
// <i> The size of a virtual page must be a multiple of the size of a physical page.
// <1024=> 1024 
// <2048=> 2048 

#ifndef FDS_VIRTUAL_PAGE_SIZE
#define FDS_VIRTUAL_PAGE_SIZE 1024
#endif

// <o> FDS_VIRTUAL_PAGES_RESERVED - The number of virtual flash pages that are used by other modules. 
// <i> FDS module stores its data in the last pages of the flash memory.
// <i> By setting this value, you can move flash end address used by the FDS.
// <i> As a result the reserved space can be used by other modules.

#ifndef FDS_VIRTUAL_PAGES_RESERVED
#define FDS_VIRTUAL_PAGES_RESERVED 4
#endif

// </h> 
//==========================================================

// <h> Backend - Backend configuration

// <i> Configure which nrf_fstorage backend is used by FDS to write to flash.
//==========================================================
// <o> FDS_BACKEND  - FDS flash backend.
 

// <i> NRF_FSTORAGE_SD uses the nrf_fstorage_sd backend implementation using the SoftDevice API. Use this if you have a SoftDevice present.
// <i> NRF_FSTORAGE_NVMC uses the nrf_fstorage_nvmc implementation. Use this setting if you don't use the SoftDevice.
// <1=> NRF_FSTORAGE_NVMC 
// <2=> NRF_FSTORAGE_SD 

#ifndef FDS_BACKEND
#define FDS_BACKEND 2
#endif


I found a few posts on the forum about similar issues, but none of them solved mine.
Would you have any ideas where it could come from ?

Best regards.

  • This means that every ~4 times you reset the device, it works, and the FDS event handler is called with FDS_INIT status OK?

    Yes, after erasing all the chip I need to do 4 reset until it works.
    After that it works well.
    I can compile and program a new .hex without issues exept if I do a full erase.

    I 've prepared a zip keil project with only the FDS part of my project, event with it and my custom board it does not work. I tried with the nRF52840 dongle, same issue, I guess you can also try with the nRF52840 DK.
    You can download the archive here https://we.tl/t-gHRwu5GXTW

  • Ok, I looked at this for far to long on Friday, without any progress. I noticed first today that you were using the scheduler, but you don't process the scheduler. 

    Typically, you would process the scheduler in the main loop, but another challenge is that you are waiting in the flash_init() function before you allow the main loop to be executed. I removed your power_manage() from wait_for_fds_ready() quite early, for debugging purposes. But I ended up replacing it by app_sched_execute(). Then I also added app_sched_execute() to your main-loop, before anything else. I don't remember if you had anything there at all, but I added an NRF_LOG_PROCESS() aswell. 

    Anyway: Adding the app_sched_execute seemed to solve it. If you are curious, the reason that you had to reset 4 times was that the fds could only initialize one FDS page on every run, because the FDS was not processed by the scheduler. Hence, you would see:

    1st reset: First FDS page initialized (Swap page)

    2nd reset: Second FDS page initalized (Data page)

    3rd reset: Third FDS page initialized (Data page)

    4th reset: FDS event handler was triggered, because all the pages were set.

    I also did some cleanup in your n_flash_interface.c. I don't remember what your fdsInitialized (and writeTerminated) was declared as, but they should be "volatile bool fdsInitialized;". 

    I also commented out a large part of your functions that were not used, to reduce the amount of compiler warnings, just to see if there were any critical ones. 

    Please compare the file to your own. Of course, you should include the things that I commented out, if you intend to use them. 

    /*
     * n_flash_interface.c
     *
     * Airstar
     * Author: Simon EMBERGER
     * Created: 07/05/2019
     * Functions created for the RF application base on the FDS librairy
     *
     *
     * IMPORTANT : THE FLASH ADDRESS SETTING IS DONE MANUALY IN THE FUNCTION flash_bounds_set 
     *             TO AVOID ERASING THE BOOTLOADER OF THE DONGLE
     *
     * 
    */ 
    
    #include "sdk_config.h"
    #include "n_flash_interface.h"
    
    #include "nrf_fstorage.h"
    #include "nrf_soc.h"
    
    #include "crc32.h"
    
    #include "string.h"
    
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    #include "nrf_log.h"
    
    #include "app_scheduler.h"
    
    #ifdef SOFTDEVICE_PRESENT
    #include "nrf_fstorage_sd.h"
    #endif
    
    
    #include "fds.h"
    
    
    #define FILE_ID       0x0001  /* The ID of the file to write the records into. */
    #define RECORD_KEY    0x1111  /* A key for the first record. */
    #define FDS_SUCCESS NRF_SUCCESS
     
    
    
    volatile bool fdsInitialized;
    volatile bool writeTerminated;
    
    uint8_t array[12] = {0};
    
    //static 	fds_record_t  netRecord = {	
    //								.file_id           = FILE_ID,
    //								.key               = RECORD_KEY,
    //								.data.p_data       = &array,
    //								.data.length_words = (sizeof(array) + 3) /sizeof(uint32_t),   /* one word is four bytes. */
    //};
    
    
    //static fds_record_desc_t   record_desc = {0};
    
    
    
    
    
    /************************************* fds_evt_handler ***************************************/
    /** 
    * @Brief Simple event handler to handle errors during initialization. 
    */
    static void fds_evt_handler(fds_evt_t const * p_evt)
    {
    		switch (p_evt->id){
    			case FDS_EVT_INIT:
                        NRF_LOG_INFO("FDS_EVT_INIT, result: 0x%02x", p_evt->result);
    					if (p_evt->result == FDS_SUCCESS){
    							 fdsInitialized = true;
    					}
    					else{	
    						fds_init();	
    					}
    					break;
    
    			case FDS_EVT_WRITE:
                        NRF_LOG_INFO("FDS_EVT_WRITE, result: 0x%02x", p_evt->result);
    					if (p_evt->result == FDS_SUCCESS){
    						 writeTerminated = true;
    					}
    					break;
    					
    			case FDS_EVT_UPDATE:
                        NRF_LOG_INFO("FDS_EVT_UPDATE, result: 0x%02x", p_evt->result);
    					if (p_evt->result == FDS_SUCCESS){
    						 writeTerminated = true;
    					}
    					break;
    					
    			case FDS_EVT_DEL_RECORD:
                        NRF_LOG_INFO("FDS_EVT_DEL_RECORD, result: 0x%02x", p_evt->result);
    					if (p_evt->result == FDS_SUCCESS){    
    					}
    				break;
    			
    			 case FDS_EVT_GC:
                        NRF_LOG_INFO("FDS_EVT_GC, result: 0x%02x", p_evt->result);
    					if (p_evt->result == FDS_SUCCESS){
    					}
    					break;
    			default:
                        NRF_LOG_INFO("Default FDS event 0x%02x", p_evt->id);
    					break;
        }
    }
    
    
    /************************************* power_manage ***************************************/
    //static void power_manage(void)
    //{
    //#ifdef SOFTDEVICE_PRESENT
    //    if (NRF_LOG_PROCESS() == false)
    //    {
    //        //(void) sd_app_evt_wait();
    //    }
    //#else
    //    __WFE();
    //#endif
    //}
    
    
    
    /************************************* wait_for_fds_ready ***************************************/
    /**@brief   Wait for fds to initialize. */
    static void wait_for_fds_ready(void){
        while (fdsInitialized == false){
            //NRF_LOG_INFO("not ready, %02x", fdsInitialized);
            //power_manage();
            app_sched_execute();
        }
    }
    
    
    /************************************* flash_init ***************************************/
    void flash_init(void){
        NRF_LOG_INFO("inside flash_init");
    	ret_code_t ret = fds_register(fds_evt_handler);
    	if (ret != FDS_SUCCESS){
    	}
    
    	ret = fds_init();	
        NRF_LOG_INFO("fds_init ret = 0x%02x", ret);
    	APP_ERROR_CHECK(ret);
    	
    	wait_for_fds_ready();
    	writeTerminated = true;
    }
    

    Best regards,

    Edvin

  • Oh I understand, thanks a lot, it seems to work well now at the first try.
    I use app_sched_execute() in the while of my main, I just removed everything to give you a project with the minimum needed to recreate the bug.

    So I did what you advise, replacing power_manage() by app_sched_execute() and it works.

Related