NO_SWAP error from pages_init() when initializing FDS

I'm using SDK 14.2, S132, and the NRF52832

This problem occurs during the pm_init() function when initializing the soft device. Investigating further has led to the pages_init() function which returns NO_SWAP.

If I erase the flash of the device first and then load the program afterwards, this problem doesn't happen. If I try to use buttonless DFU however, this problem starts to occur.

The firmware that's on the device originally has the following settings:

FDS_VIRTUAL_PAGES 14

FDS_VIRTUAL_PAGE_SIZE 1024

The firmware that's used during DFU has these settings:

FDS_VIRTUAL_PAGES 4

FDS_VIRTUAL_PAGE_SIZE 1024

Everything else should be the same so I feel like this issue is occurring because of the difference in FDS pages. Also, if I use buttonless DFU but there is data stored on the device using FDS, does this data get overwritten?

EDIT: So I think the proper way to go about this would be to erase all the FDS pages that were allocated by the firmware currently on the device so that the new FDS can basically start fresh?

EDIT2: I tried adding logic in the DFU section so that when the device is preparing to enter DFU, it would use sd_flash_page_erase and loop through the FDS_VIRTUAL_PAGES. This immediately returns NRF_ERROR_FORBIDDEN when calling it for page 0 however.

EDIT3: I'm almost at the point of just using fstorage directly and not using FDS at all at this point. I can't find a simple way with the FDS API to erase pages so I just decided to use sd_flash_erase_page directly. I'm calling this function from the main context and I'm setting a flag in nrf_fstorage_sys_evt_handler on the NRF_EVT_FLASH_OPERATION_SUCCESS event so that I can then call the next erase. I've used sd_app_evt_wait() and __WFE() to wait for the flag to be set and they never are set. I also tried to just overwrite the word after 0xDEADC0DE (with sd_flash_write) which is used to identify the page as data to 0xFFFFFFFF in an attempt to just let the FDS clean those pages up when it initializes at boot-up but I get the same problem (NRF_EVT_FLASH_OPERATION_SUCCESS never happens). I can't find anything on the forums that explains why I'm not getting this event.

  • Hello,

    I am sorry for the late reply.

    Can you confirm whether your pages_init() function actually returns NO_SWAP, or if it returns NO_PAGES (since there is no break; between these cases in the switch after pages_init();

     

    Can you check which one(s) of the returns that are added in static fds_init_opts_t pages_init(void) in fds.c, starting from line 632 (if not modified)?

    The reason I ask is that the return FDS_ERR_NO_PAGES means that pages_init() returns 0x00 or 0x02. 

    This means that either, the return stays the same as it is initialized in pages_init: ret = NO_PAGES, or it is ret |= PAGE_DATA.

     

    Can you check what lines that ret is changed inside pages_init()?

     

    Best regards,

    Edvin

     

     

  • Can you also check the first and second word on the pages that you try to initialize, before you run pages_init()?

    See here to see the descriptions. is word0 0xDEADC0DE and word1 either 0xF11E0FF or 0xF11E0FE?

     

    BR,

    Edvin

  • Hi Edvin,

    pages_init returns 0x02. If I set a breakpoint in the loop when all of the pages are initialized, all them are "FDS_PAGE_DATA" and I believe aren't able to be garbage collected which is why the initialization fails.

    All four pages (from 0x74000 - 0x77000) show: 0xDEADC0DE 0xF11E01FE

    This makes sense if we're getting FDS_PAGE_DATA during the page intialization.

    What I want to implement is some way to just deallocate or completely erase the area used by FDS in between DFU updates. I can't seem to find a straightforward way to do this using only FDS however.

  • Alright so I managed to get something working. It's not a clean solution by any means but it seems to get the job done. For anyone else that happens to have this problem this is what I did:

    1. Set a flag in the main loop when you want to do a DFU (in my case I had a custom BLE service that I could just write to and set the flag)

    2. Call a function to erase the flash pages used by using sd_flash_page_erase

    2a. I wasn't able to get NRF_EVT_FLASH_OPERATION_SUCCESS events reliably at all so instead of checking for it, I just implemeneted the following loop:

      ret_code_t err_code;
      uint32_t event_type;
    
      for (int i = 0; i < FDS_VIRTUAL_PAGES; i++)
      {
        // address will look like 0x6A000 and we just want 0x6A so shift the
        // lower bits out
        err_code = sd_flash_page_erase((m_fs.start_addr >> 12) + i);
    
        // if sd is busy then wait for another sd event before trying again
        while(err_code == NRF_ERROR_BUSY)
        {
          sd_app_evt_wait();
          err_code = sd_flash_page_erase((m_fs.start_addr >> 12) + i);
        }
    
        // fetch events in queue until there are none left which should include
        // the flash event
        while(sd_evt_get(&event_type) == NRF_SUCCESS);
      }

    Now the pages used for FDS should be erased and you can run DFU and the device will initialize normally. I have no idea whether this is a safe way to implement this but again I don't see any erase way to do it through the FDS API.

  • I fixed this with a similar approach as senorwigglez by wiping out the old data.  I did it by modifying fds_init() to wipe out the data and let FDS re-init.

    I added a parameter force_wipe so the caller can demand a clean start.  If it encountered NO_PAGES or NO_SWAP, then I changed init_opts to FRESH_INSTALL, and let it continue and wipe out the storage rather than failing by returning FDS_ERR_NO_PAGES.  Seems to work so far.

    switch (init_opts)
        {
            case NO_PAGES:
            case NO_SWAP:
                if(eInitMode == FDS_INIT_FORCE_REDO)
                {
                    // they want to force a fresh filesystem on us
                    init_opts = FRESH_INSTALL;
                }
                else
                {
                    return FDS_ERR_NO_PAGES;
                }
    
            case ALREADY_INSTALLED:
            {
                // No initialization is necessary. Notify the application immediately.
                m_flags.initialized  = true;
                m_flags.initializing = false;
                event_send(&evt_success);
                return FDS_SUCCESS;
            }
    
            default:
                break;
        }

Related