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.

Parents
  • Hello,

    I just had a quick glance in the ble_zigbee_fynamic_door_lock_nus example, and I see that FDS_VIRTUAL_PAGES_RESERVED is set to:

    #define FDS_VIRTUAL_PAGES_RESERVED ((ZIGBEE_NVRAM_PAGE_SIZE * ZIGBEE_NVRAM_PAGE_COUNT + ZIGBEE_NVRAM_CONFIG_PAGE_SIZE * ZIGBEE_NVRAM_CONFIG_PAGE_COUNT)/(FDS_VIRTUAL_PAGE_SIZE * 4))

    Which in this case gives FDS_VIRTUAL_PAGES_RESERVED = 9

    While in your sdk_config.h it is set to 4. 

    Can you please try to use the macro from the ble_zigbee_dynamic_door_lock_nus example? If you can use the macros, then it will automatically adjust to your project, rather than just assuming it is 9 in your case as well.

    Based on your description above, you are stuck in flash_init() -> sd_app_evt_wait(), right?

    Where do you call flash_init() from? From your main() function, or an interrupt?

    I am also not sure about your implementation. What happens if you check fdsInitialized, which is false, and then you get the interrupt setting it to true right before you call sd_app_evt_wait()? You would have to wait for another interrupt then. Just for debugging purposes, try to comment out sd_app_evt_wait() in flash_init(). Does it behave the same?

    Also, could it be that you receive the FDS_EVT_INIT event, but the result != NRF_SUCCESS? Try to ignore the p_evt->result and see if it still behaves the same. 

    Do you have any logging from the FDS module? If so, does it say anything?

    BR,

    Edvin

  • Hi Edvin,

    Thank for your quick answer.

    I tried the macro you wrote but most of the ZIGBEE macro are not defined in my case. I tried with 9 instead of 4 but it did not solve the issue.

    My program seems indeed stuck into sd_app_evt_wait(). I do not know where exactly since it is a precompiled function. I just know when I stop the program, it does not show me where I am. (I am using keil uVision 5).

    flash_init() is called in the main, juste after ble_stack_init(). fdsInitialized is set to true, but I all the example I read wrote it that way.


    I do not know about the sd_app_evt_wait() called after fdsInitialized is set to true. It was impliemented like this in the example I have. And since it works all the time exept at the very first start of the device, I guess it is not the problem cause.
    I did try to comment sd_app_evt_wait(), and I still have the same issue.

    However, you were right about FDS_EVT_INIT event --> result != NRF_SUCCESS
    So i just added this :

    case FDS_EVT_INIT:
    					if (p_evt->result == FDS_SUCCESS){
    							 fdsInitialized = true;
    								#if defined(BOARD_PCA10056) || defined(BOARD_PCA10059)
    									m_light_changed(LIGHT_TOGGLE);
    								#endif
    					}
    					else{
    						fds_init();
    					}
    					break;

    and the issue seems corrected.
    I might change a bit my code not to call fds_init in fds_evt_handler() but I think we have a solution.

    Thanks a lot.
    Best regards

  • False alarm.

    In fact it does not work. I guess I was in the 4th try.

    It looks like no event is ever generated by the softdevice once the fds_init() has been called.

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

    Is there any way for me to reproduce this on a DK? Is it possible to zip the project and send it here? 

    I see that FDS is used in the example:

    SDK4.1.0\examples\multiprotocol\ble_zigbee\ble_zigbee_dynamic_door_lock_nus without modifications. 

    Can you please try one thing for me in the meantime:

    If you erase the chip completely (nrfjprog --eraseall), and then program the softdevice. Modify your application to not call storage_init(). Then run the application and read out the flash. You can use the command "nrfjprog --readcode my_flash_dump.hex", or the nRF Connect for Desktop --> Programmer application to get a visual representation. What I want to know is what kind of data, and mainly where it is stored. 

    E.g. if I comment out storage_init() in the ble_zigbee_dynamic_door_lock_nus example, it looks like this:

    While if I include storage_init(), it looks like this:

    As you can see, the last page of the FDS pages is from 0x000F6000->0x000F6FFF. The reason it is not starting at the top of the flash is that in this case 9 pages of 0x1000 (4096) bytes is reserved.

    So can you check without storage_init() what the flash looks like? Where is the bottom green line near the top of the flash starting?

    BR,
    Edvin

  • And in case you haven't tried, erase the chip completely before you program anything on it. Perhaps there is some old flash content in the flash area

  • 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

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

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