Flash memory error : FDS_ERR_NO_PAGES

Hi DevZone !

I am using the nRF52840 for development and after some tests one of the chips could not access its memory flash in the function fds_init() in the library fds.c. I debugged it with Ozone and I saw the error FDS_ERR_NO_PAGES popping up. Can I repair the flash in some way ? Any suggestion on why it happened ?

Thank you !

Joel V.

Parents
  • Hi,

    fds_init() will return FDS_ERR_NO_PAGES If there is no space available in flash memory to install the file system. Which would imply that something in your application is consuming the memory. Do you see this on the other samples with the same application? Could you also elaborate a bit more on your application?

    regards

    Jared 

  • Hi,

    This is the only sample who did this but it has one main difference with the others is that this sample could have reboot more often than the others. The application is a mesh network capturing datas. I use the flash to store configurations for the nodes like its address, channel, etc. I am using only one page of the flash (a configuration page). I dont understand how it could have consume all the memory in flash. 

    Thanks

    Joel V.

  • Hi,

    Sorry for the poor explanation. Let me try again Slight smile

    The FDS module is an asynchronous module which means that operations doesn't complete when the function call is returned, a return with nRF_SUCESS only means that the operation was added successfully to the queue. You have to wait for the callback handler to be called with the appropriate event to be sure that the operation has completed. Updating or deleting a record does not free up the physical memory. It only invalidates the record. The physical memory is only freed once the garbage collector is called and frees up all of the invalidated memory. You therefore have to call the garbage collector before the memory is full.

    Assuming these two parts are the only FDS operations that you normally do in your application:

    1. Here you initialize the FDS module, run the garbage collector and read the record. Which is fine. You might want to wait for the garbage collector operation to complete first, but I don't think that it's crucial. 

    rc = fds_init();
    rc = fds_gc();
    APP_ERROR_CHECK(rc);
    
    
    fds_record_desc_t desc = {0};
    fds_find_token_t  tok  = {0};
    
    rc = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok);
    if (rc == NRF_SUCCESS){
        //rc = fds_record_delete(&desc);
        //APP_ERROR_CHECK(rc);
        fds_flash_record_t fds_config = {0};
    
        //Open the record and read its contents. 
        rc = fds_record_open(&desc, &fds_config);
        APP_ERROR_CHECK(rc);
    
        //Copy the configuration from flash into config.
        memcpy(&config, fds_config.p_data, sizeof(config_t));
    
        //Close the record when done reading.
        rc = fds_record_close(&desc);
        APP_ERROR_CHECK(rc); 

    2. Here you write a new record to the FDS. If it fails you run the garbage collector.

     fds_record_t config_record ={
                .file_id           = CONFIG_FILE,
                .key               = CONFIG_REC_KEY,
                .data.p_data       = &config,
                /* The length of a record is always expressed in 4-byte units (words). */
                .data.length_words = (sizeof(config_t)+3)/sizeof(uint32_t),
            };
            
    rc = fds_record_write(&desc, &config_record);
    if(rc != NRF_SUCCESS){
        rc = fds_gc();
        APP_ERROR_CHECK(rc);
        config_init(mesh_config);
    }
    APP_ERROR_CHECK(rc);

    Re-doing step 1 and 2 multiple times for example by reset the application will eventually fill up the flash. This is because you never invalidate a record by either deleting or updating a record, which means that the garbage collector will not do anything. Reset the application will effectively write a new record with the same record and same file ID to the FDS without deleting the old one, since FDS does not require uniqueness for file ID nor file record key. I would suggest that you try to use the fds_record_update() instead, which will invalidate the old record when you write a new record with the same record ID and record key. The garbage collector will then free up the memory when it's called. Note that you need to wait for the operation to be completed as stated earlier. 

    best regards

    Jared 

  • Hi Jared,

    I'm sorry but I understood correctly I was just searching for a solution to recover my processor which is not working because of the flash being full. I managed to do so with the nrfjprog.  :) 

    As for the step 1 and 2 mentionned here :

    Re-doing step 1 and 2 multiple times for example by reset the application will eventually fill up the flash.

    Step 1 will be done if the config page is already written (sucess when fds_record_find) 

    Step 2 will be done if the config page is not already written (fail when fds_record_find). In other words, this part of the function is never called at boot but when I just bought my nRF52840 and I first program it.

    So they wil never be done at same time and the Step 1 is usually done. 

    I changed the delete/write for an fds_record_update in my other function and it worked fine, i dont know why it didnt the first time. That should solve the problem if this function is not commented. 

    About this:

    You should also call the garbage collector at the start of main()

    One of your collegues already told me not to do so in a private ticket and I quote:

    « We highly discourage garbage collection on restart, because it will then do GC unnecessarily »

    Which one should I do ?

    Finally to solve the issues about the async module, what do you suggest as indicator to wait for before the fds_gc ?

  • Joel V said:

    I'm sorry but I understood correctly I was just searching for a solution to recover my processor which is not working because of the flash being full. I managed to do so with the nrfjprog.  :) 

    Aha, so you're were asking for how to erase the flash with nrfjprog --erase? 

    Joel V said:

    Step 1 will be done if the config page is already written (sucess when fds_record_find) 

    Step 2 will be done if the config page is not already written (fail when fds_record_find). In other words, this part of the function is never called at boot but when I just bought my nRF52840 and I first program it.

    So they wil never be done at same time and the Step 1 is usually done. 

    I changed the delete/write for an fds_record_update in my other function and it worked fine, i dont know why it didnt the first time. That should solve the problem if this function is not commented.

    I see, so you'll only write to the FDS once after programming the IC? How many resets before you get FDS_ERR_NO_PAGES from fds_init()? 

    I'm suspecting if you're getting alot of corrupted data that is caused by resetting the chip before the write operation has been completed. Also, if you're only writing to the chip if there is no found record then a fds_record_write() and fds_record_update() will do effectively do the same. 

    Joel V said:

    One of your collegues already told me not to do so in a private ticket and I quote:

    « We highly discourage garbage collection on restart, because it will then do GC unnecessarily »

    Which one should I do ?

    I read Terjes response to your other ticket and I do agree with him on a second thought. My understanding of your application was different then how I understand it now. 

    Joel V said:
    Finally to solve the issues about the async module, what do you suggest as indicator to wait for before the fds_gc ?

    FDS_EVT_GC will be generated by the callback handler. You can set a flag in the callback handler which you can wait for with a while(flag) {}  loop. 

    regards

    Jared 

  • I see, so you'll only write to the FDS once after programming the IC? How many resets before you get FDS_ERR_NO_PAGES from fds_init()? 

    Exactly Slight smile

    I couldn't count the number of resets but it may be a lot because this particuliar application is temporarly resetting a lot because I want to be sure it receives the mesh packets of the other applications because it is used as repeater. However right now it repeats only one other which may cause resets often. 

    I'm suspecting if you're getting alot of corrupted data that is caused by resetting the chip before the write operation has been completed.

    So the only reason that could explain this corrupted flash is that I did not comment the function that writes the flash at start ? Because like I said, in my final application, it is only supposed to read the flash at boot and never to write. Could it be corrupted in any way while reading ?

    I read Terjes response to your other ticket and I do agree with him on a second thought. My understanding of your application was different then how I understand it now.

    Perfect

    FDS_EVT_GC will be generated by the callback handler. You can set a flag in the callback handler which you can wait for with a while(flag) {}  loop. 

    I will try to do so.

    Thank you very much for your time, it is much appreciated,

    Joël V.

  • Joel V said:

    So the only reason that could explain this corrupted flash is that I did not comment the function that writes the flash at start ? Because like I said, in my final application, it is only supposed to read the flash at boot and never to write. Could it be corrupted in any way while reading ?

    You don't wait for the write operation to complete when you write to the flash the first time(step2). If you reset the application during the write operation then you can corrupted data. When the application then resets it will try to write to the flash again(step2) since the previous write didn't complete, but again the application will reset before the write completes and so on until the flash fills up with corrupted data. 

    I'm not excluding that the culprit could be something else, but this is my suspicion atm. An easy fix is to wait for the application to complete the write operation before the reset. Could you implement this in your application and see if you still get FDS_ERR_NO_PAGES?

    regards

    Jared 

Reply
  • Joel V said:

    So the only reason that could explain this corrupted flash is that I did not comment the function that writes the flash at start ? Because like I said, in my final application, it is only supposed to read the flash at boot and never to write. Could it be corrupted in any way while reading ?

    You don't wait for the write operation to complete when you write to the flash the first time(step2). If you reset the application during the write operation then you can corrupted data. When the application then resets it will try to write to the flash again(step2) since the previous write didn't complete, but again the application will reset before the write completes and so on until the flash fills up with corrupted data. 

    I'm not excluding that the culprit could be something else, but this is my suspicion atm. An easy fix is to wait for the application to complete the write operation before the reset. Could you implement this in your application and see if you still get FDS_ERR_NO_PAGES?

    regards

    Jared 

Children
No Data
Related