This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Problems using fstorage to write to flash (using it alongside mesh sdk)

Hi, currently I am using fstorage alongside ble-mesh to store some data in flash. Currently however, writing with fstorage seems to be successful only about 50% of the time, with the other failing 50% giving me a timeout error (error code 13, NRF_TIMEOUT_ERROR). The memory areas between the mesh data and the fstorage do not overlap. Reading using fstorage so far works just fine. Are there any ideas to what might be causing this issue?

I suspect perhaps the fstorage operations might be competing with the mesh events in some sort of scheduler but I am not sure.

Thanks in advance

PS. I am aware that the mesh SDK offer its own thing for managing flash data (flash manager) but i used fstorage due to my greater familiarity with it plus the fact that there are no flash manager examples in the SDK, so I would prefer if i can stick with my current fstorage solution, however if this issue is unfixable I am open to trying out the mesh SDK's flash manager.

Parents
  • Hi Jeffe, 

    It's possible to have both fstorage and flash_manager at the same time. For example you can find that in the ble_app_proximity_coexist example we provide. 

    Which fstorage backend did you use ? I assume you are using nrf_fstorage_sd.c ? 

  • An update of what I have been doing:

    I look at the ble_app_promixty_coexist example and I do not seem to be missing anything.

    What I did though was took my .c file that contains all my fstorage code (since the code is almost standalone with very few dependencies from the overall mesh program), and tested it by itself, in an non-mesh setting and it worked just fine.

    Here is my fstorage source code and header if it helps, as I can't seem to find anything that would make it break if using alongside mesh

    #include "simple_flash_storage.h"
    
    #include <stdint.h>
    #include <string.h>
    
    #include "app_error.h"
    #include "nrf_fstorage_sd.h"
    
    //#include "nrf_log.h"
    //#include "nrf_log_ctrl.h"
    //#include "nrf_log_default_backends.h"
    #include "log.h"
    
    static uint32_t first_empty_addr;
    
    nrf_fstorage_t fstorage;
    
    static void fstorage_evt_handler(nrf_fstorage_evt_t * p_evt) {
        if (p_evt->result != NRF_SUCCESS)
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_ERROR, "--> Event received: ERROR while executing an fstorage operation: code %d \n", 
    	    p_evt->result);
    	//NRF_LOG_INFO("--> Event received: ERROR while executing an fstorage operation: code %d \n", p_evt->result);
            return;
        }
    
        switch (p_evt->id)
        {
            case NRF_FSTORAGE_EVT_WRITE_RESULT:
            {
                __LOG(LOG_SRC_APP, LOG_LEVEL_DBG1, "--> Success: wrote %d bytes at address 0x%x. \n",
                             p_evt->len, p_evt->addr);
    	    //NRF_LOG_INFO("--> Success: wrote %d bytes at address 0x%x. \n", p_evt->len, p_evt->addr);
            } break;
    
            case NRF_FSTORAGE_EVT_ERASE_RESULT:
            {
                __LOG(LOG_SRC_APP, LOG_LEVEL_DBG1, "--> Success: erased %d page from address 0x%x. \n",
                             p_evt->len, p_evt->addr);
    	    //NRF_LOG_INFO("--> Success: erased %d page from address 0x%x. \n", p_evt->len, p_evt->addr)
            } break;
    
            default:
                break;
        }
    }
    
    ret_code_t flash_store_data(const level_t * values) {
        ret_code_t rc;
        static flash_entry_t data_to_store;
        data_to_store.label = 0xFACE;
        memcpy(data_to_store.channel_vals, values, NUM_CHANNELS);
        
        if (first_empty_addr >= fstorage.end_addr) {
    	flash_clean_data();
        }
    
        rc = nrf_fstorage_write(&fstorage, first_empty_addr, &data_to_store, ENTRY_SIZE, NULL);
        if (rc != NRF_SUCCESS) {
    	__LOG(LOG_SRC_APP, LOG_LEVEL_ERROR, "Error occured when writing to persistent storage: code %d \n", rc);
    	//NRF_LOG_INFO("Error occured when writing to persistent storage: code %d \n", rc);
        }
    
        first_empty_addr += ENTRY_SIZE;
        return rc;
    }
    
    ret_code_t flash_retrieve_data(level_t * values) {
        ret_code_t rc;
        flash_entry_t data_to_retrieve;
        
        uint32_t addr_to_read = first_empty_addr - ENTRY_SIZE;
        if (first_empty_addr == fstorage.start_addr) {
    	addr_to_read = 1 + fstorage.end_addr - ENTRY_SIZE;
        }
    
        rc = nrf_fstorage_read(&fstorage, addr_to_read, &data_to_retrieve, ENTRY_SIZE);
        if (rc != NRF_SUCCESS) {
    	__LOG(LOG_SRC_APP, LOG_LEVEL_ERROR, "Error occured when reading persistent storage: code %d \n", rc);
    	//NRF_LOG_INFO("Error occured when reading persistent storage: code %d \n", rc);
        } else {
    	memcpy(values, data_to_retrieve.channel_vals, NUM_CHANNELS);
        }
    
        return rc;
    }
    
    ret_code_t flash_clean_data() {
        ret_code_t rc;
        rc = nrf_fstorage_erase(&fstorage, fstorage.start_addr, NUM_PAGES, NULL);
        if (rc != NRF_SUCCESS) {
            __LOG(LOG_SRC_APP, LOG_LEVEL_ERROR, "Error occured when cleaning persistent storage: code %d \n", rc);
    	//NRF_LOG_INFO("Error occured when cleaning persistent storage: code %d \n", rc);
        }
        first_empty_addr = fstorage.start_addr;
    
        return rc;
    }
    
    uint32_t flash_addr_pointer() {
        return first_empty_addr;
    }
    
    void flash_init() {
        nrf_fstorage_api_t * p_fs_api;
        p_fs_api = &nrf_fstorage_sd;
        
        fstorage.evt_handler = fstorage_evt_handler;
        fstorage.start_addr = START_ADDRESS;
        fstorage.end_addr = END_ADDRESS;
    
        APP_ERROR_CHECK(nrf_fstorage_init(&fstorage, p_fs_api, NULL));
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Simple flash storage module enabled \n");
        //NRF_LOG_INFO("Simple flash storage module enabled \n");
        
        __LOG(LOG_SRC_APP, LOG_LEVEL_DBG1, "Read Address 0x%x \n", fstorage.start_addr);
        //NRF_LOG_INFO("Read Address 0x%x \n", fstorage.start_addr);
    
        flash_entry_t latest_data;
        APP_ERROR_CHECK(nrf_fstorage_read(&fstorage, fstorage.start_addr, &latest_data, ENTRY_SIZE));
        __LOG(LOG_SRC_APP, LOG_LEVEL_DBG1, "Read Address 0x%x \n", fstorage.start_addr);
        //NRF_LOG_INFO("Read Address 0x%x \n", fstorage.start_addr);
        first_empty_addr = fstorage.start_addr;
        while (latest_data.label != 0xffff) {
    	first_empty_addr += ENTRY_SIZE;
    	if (first_empty_addr >= fstorage.end_addr) {
    	    break;
    	} 
    	else {
    	    APP_ERROR_CHECK(nrf_fstorage_read(&fstorage, first_empty_addr, &latest_data, ENTRY_SIZE));
    	    __LOG(LOG_SRC_APP, LOG_LEVEL_DBG1, "Read Address 0x%x \n", first_empty_addr);
    	    //NRF_LOG_INFO("Read Address 0x%x \n", first_empty_addr);
    	}
    
        }
    
    }
    simple_flash_storage.h

  • Hi Jeffe, 
    I suspect that the mesh stack timeslot scheduling may be the cause. 
    So basically the way the mesh stack works is to request timeslot from the softdevice and continue to extend it until it reach the limit (128s) then it will request another timeslot. 

    If you are inside an timeslot and calling a softdevice flash API , it may get delayed until the timeslot next extending period. It's mentioned here in our documentation in the earlier nRF5 Mesh SDK documentation (look for fstorage).

    The reason the ble_app_proximity works fine could be that flash operation only occurred when the chip is handling BLE activities (bonding), when it may not be the case with your application. 

    I think the best solution here would be to use the flash manager module from mesh. Or you would need to pause mesh before you execute flash operation in fstorage and then continue back on. 

Reply
  • Hi Jeffe, 
    I suspect that the mesh stack timeslot scheduling may be the cause. 
    So basically the way the mesh stack works is to request timeslot from the softdevice and continue to extend it until it reach the limit (128s) then it will request another timeslot. 

    If you are inside an timeslot and calling a softdevice flash API , it may get delayed until the timeslot next extending period. It's mentioned here in our documentation in the earlier nRF5 Mesh SDK documentation (look for fstorage).

    The reason the ble_app_proximity works fine could be that flash operation only occurred when the chip is handling BLE activities (bonding), when it may not be the case with your application. 

    I think the best solution here would be to use the flash manager module from mesh. Or you would need to pause mesh before you execute flash operation in fstorage and then continue back on. 

Children
  • Thank you for your response.

    It seems like I am forced to use flash manager in this case then, as I do not think i can temporarily pause the mesh without interfering with receiving more incoming data from the mesh network.

    Do you know of any examples that directly use the flash manager for mesh then that is similar to what I am doing with the fstorage here, as that will help very much.

    Also just out of curiousity, do you know why the flash manager of the mesh SDK is not affected by the timeslot scheduling, but fstorage is, since at the end both of them still use the softdevice? If so can you explain because I am interested in the technical issue here.

    Again thank you a lot for your help

  • Hi Jeffe, 

    If you have a look at the mesh_flash module you can find that the flash is accessed directly via NVMC not via softdevice. The flash activity occurs inside mesh timeslot can access flash directly via NVMC. 

    A good example of using the flash manager is in the enocean_switch example where we store the enocean information to flash. This documentation is also very useful.

  • Oh, so the flash manager of the mesh SDK doesn't actually use the softdevice by directly uses the NVMC - and by extension any flash storage implementation that directly use the NVMC and skip the softdevice should also work?

    I will take a good look at stuff you recommended, thanks!

  • Hi Jeffe, 
    I'm checking with the mesh team on what should be the best way of doing this. But as it's suggested in the documentation here:

    It's preferred to use Flash Manager. Note that the reason it can access flash directly without using softdevice API is because it's running inside Mesh timeslots. If you use your own flash library that access flash via NVMC there is a risk that it operates outside Mesh timeslots. This will cause a fault. 

  • I see, so that is why flash manager is the best option. I have went ahead and decided to use that via mesh_config. Thank you for all the help

Related