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

fstorage write problems, reading back incorrect data

Using Softdevice s140 v6.1.0
nRF5 SDK v15.2.0

I am trying to write to the flash, here are my read and write functions:

//writes to the flash
uint32_t flash_write(uint32_t m_addr, uint32_t m_data)
{ 
    ret_code_t err_code;
    NRF_LOG_INFO("Writing \"%x\" to flash address \"%x\".", m_data, m_addr);
    err_code = nrf_fstorage_write(&fstorage, (FLASH_START_ADDR + (4*m_addr)), &m_data, sizeof(m_data), NULL);
    APP_ERROR_CHECK(err_code);
    // wait_for_flash_ready(&fstorage);

    return err_code;
}

//reads from the flash
uint32_t flash_read(uint32_t m_addr)
{ 
    ret_code_t err_code;
    uint32_t m_data;
    err_code = nrf_fstorage_read(&fstorage, (FLASH_START_ADDR + (4*m_addr)), &m_data, 4);
    APP_ERROR_CHECK(err_code);
    NRF_LOG_INFO("Read \"%x\" from flash address \"%x\".", m_data, m_addr);
    return m_data;
}

Two problems:

  1. The write function does not work unless i comment out the //wait_for_flash_ready(&fstorage);
  2. When writing 0x00000000 to an address, and then reading the same address back, I get a strange value: 0x2003FE50
    Yes, I am aware that you have to erase the page before writing, but I have checked that the data at that address was already 0xFFFFFFFF

Here's the rest of my flash related code:

#define FLASH_START_ADDR    0x70000
#define FLASH_LENGTH        0x10000
#define FLASH_LENGTH_32BIT  (FLASH_LENGTH/4)

static void fstorage_evt_handler(nrf_fstorage_evt_t * p_evt);
bool flashBusy = false;

NRF_FSTORAGE_DEF(nrf_fstorage_t fstorage) =
{
    /* Set a handler for fstorage events. */
    .evt_handler = fstorage_evt_handler,
    //start and end addresses
    .start_addr = FLASH_START_ADDR,
    .end_addr   = (FLASH_START_ADDR + FLASH_LENGTH - 1),
};

//Error Handler for fstorage events
static void fstorage_evt_handler(nrf_fstorage_evt_t * p_evt)
{
    if (p_evt->result != NRF_SUCCESS)
    {
        NRF_LOG_INFO("--> Event received: ERROR while executing an fstorage operation.");
        return;
    }

    switch (p_evt->id)
    {
        case NRF_FSTORAGE_EVT_WRITE_RESULT:
        {
            NRF_LOG_INFO("--> Event received: wrote %d bytes at address 0x%x.",
                         p_evt->len, p_evt->addr);
        } break;

        case NRF_FSTORAGE_EVT_ERASE_RESULT:
        {
            NRF_LOG_INFO("--> Event received: erased %d page from address 0x%x.",
                         p_evt->len, p_evt->addr);
        } break;

        default:
            break;
    }
}

//blocking function to wait for flash to be ready
void wait_for_flash_ready(nrf_fstorage_t const * p_fstorage)
{
    /* While fstorage is busy, sleep and wait for an event. */
    while (nrf_fstorage_is_busy(p_fstorage))
    {
        (void)sd_app_evt_wait();
    }
}

//function to set up the flash memory
void flash_init()
{   
    ret_code_t err_code;
    nrf_fstorage_api_t * p_fs_api;
    p_fs_api = &nrf_fstorage_sd;
    err_code = nrf_fstorage_init(&fstorage, p_fs_api, NULL);
    APP_ERROR_CHECK(err_code);
}

Parents
  • I realized that the 0x2003FE50 i was writing was the address of the data I wanted to write, rather than the data itself.

    Then I noticed that the nrf_fstorage_write() function requires a pointer to the data which is of type: void const * p_src

    Which for some reason doesn't like my &m_data (here my C knowledge is lacking)

    My new write function is:

    //writes to the flash
    uint32_t flash_write(uint32_t m_addr, void const * m_data)
    { 
        ret_code_t err_code;
        NRF_LOG_INFO("Writing \"%x\" to flash address \"%x\".", m_data, m_addr);
        err_code = nrf_fstorage_write(&fstorage, (FLASH_START_ADDR + (4*m_addr)), m_data, sizeof(m_data), NULL);
        APP_ERROR_CHECK(err_code);
        // wait_for_flash_ready(&fstorage);
    
        return err_code;
    }

    And when calling this function you pass the address of the data:

    flash_write(flash_addr, &flash_data);

    However the //wait_for_flash_ready(&fstorage); still needs to be commented out, which is contrary to the flash_fstorage example? Is this important if it is working without it?

Reply
  • I realized that the 0x2003FE50 i was writing was the address of the data I wanted to write, rather than the data itself.

    Then I noticed that the nrf_fstorage_write() function requires a pointer to the data which is of type: void const * p_src

    Which for some reason doesn't like my &m_data (here my C knowledge is lacking)

    My new write function is:

    //writes to the flash
    uint32_t flash_write(uint32_t m_addr, void const * m_data)
    { 
        ret_code_t err_code;
        NRF_LOG_INFO("Writing \"%x\" to flash address \"%x\".", m_data, m_addr);
        err_code = nrf_fstorage_write(&fstorage, (FLASH_START_ADDR + (4*m_addr)), m_data, sizeof(m_data), NULL);
        APP_ERROR_CHECK(err_code);
        // wait_for_flash_ready(&fstorage);
    
        return err_code;
    }

    And when calling this function you pass the address of the data:

    flash_write(flash_addr, &flash_data);

    However the //wait_for_flash_ready(&fstorage); still needs to be commented out, which is contrary to the flash_fstorage example? Is this important if it is working without it?

Children
  • The difference between the fstorage example and your example is: 

    //fstorage example
    rc = nrf_fstorage_write(&fstorage, 0x3e000, &m_data, sizeof(m_data), NULL);
    
    //your code
    err_code = nrf_fstorage_write(&fstorage, (FLASH_START_ADDR + (4*m_addr)), m_data, sizeof(m_data), NULL);

    Are you certain that (FLASH_START_ADDR + (4*m_addr)) works? Have you checked what err_code is returned from nrf_fstorage_write() ?

    /**@brief   Function for writing data to flash.
     *
     * Write @p len bytes from @p p_src to @p dest.
     *
     * When using @ref nrf_fstorage_sd, the data is written by several calls to @ref sd_flash_write if
     * the length of the data exceeds @ref NRF_FSTORAGE_SD_MAX_WRITE_SIZE bytes.
     * Only one event is sent upon completion.
     *
     * @note The data to be written to flash must be kept in memory until the operation has
     *       terminated and an event is received.
     *
     * @param[in]   p_fs        The fstorage instance.
     * @param[in]   dest        Address in flash memory where to write the data.
     * @param[in]   p_src       Data to be written.
     * @param[in]   len         Length of the data (in bytes).
     * @param[in]   p_param     User-defined parameter passed to the event handler (may be NULL).
     *
     * @retval  NRF_SUCCESS                 If the operation was accepted.
     * @retval  NRF_ERROR_NULL              If @p p_fs or @p p_src is NULL.
     * @retval  NRF_ERROR_INVALID_STATE     If the module is not initialized.
     * @retval  NRF_ERROR_INVALID_LENGTH    If @p len is zero or not a multiple of the program unit,
     *                                      or if it is otherwise invalid.
     * @retval  NRF_ERROR_INVALID_ADDR      If the address @p dest is outside the flash memory
     *                                      boundaries specified in @p p_fs, or if it is unaligned.
     * @retval  NRF_ERROR_NO_MEM            If no memory is available to accept the operation.
     *                                      When using the @ref nrf_fstorage_sd, this error
     *                                      indicates that the internal queue of operations is full.
     */

  • Yeah it works, that is just to get the address 32bit-justified.

    The problem is actually in the wait_for_flash_ready(&fstorage) function as supplied in the example, there is this code:

    void wait_for_flash_ready(nrf_fstorage_t const * p_fstorage)
    {
        /* While fstorage is busy, sleep and wait for an event. */
        while (nrf_fstorage_is_busy(p_fstorage))
        {
            power_manage();
        }
    }
    
    /**@brief   Sleep until an event is received. */
    static void power_manage(void)
    {
    #ifdef SOFTDEVICE_PRESENT
        (void) sd_app_evt_wait();
    #else
        __WFE();
    #endif
    }

    which calls the function sd_app_evt_wait(); while the flash is busy doing the work. I'm *guessing* this causes the program to crash at this point because I called the flash_write() from a bluetooth event, instead of from the main loop like in the example.

    What I have chosen to do is to remove the wait_for_flash_ready(&fstorage); function and implement my own flagging system which is cleared after the flash event, to prevent any other flash operations from happening:

    bool flashBusy = false;
    
    //Error Handler for fstorage events
    static void fstorage_evt_handler(nrf_fstorage_evt_t * p_evt)
    {
        if (p_evt->result != NRF_SUCCESS)
        {
            NRF_LOG_INFO("--> Event received: ERROR while executing an fstorage operation.");
            return;
        }
    
        switch (p_evt->id)
        {
            case NRF_FSTORAGE_EVT_WRITE_RESULT:
            {
                NRF_LOG_INFO("--> Event received: wrote %d bytes at address 0x%x.",
                             p_evt->len, p_evt->addr);
                flashBusy = false;
                CMD_RESULT = CMD_SUCCESS;
            } break;
    
            case NRF_FSTORAGE_EVT_ERASE_RESULT:
            {
                NRF_LOG_INFO("--> Event received: erased %d page(s) from address 0x%x.",
                             p_evt->len, p_evt->addr);
                flashBusy = false;
                CMD_RESULT = CMD_SUCCESS;
            } break;
    
            default:
                break;
        }
    }

  • Yes, I think you are onto something. 

    When calling the flash_write() within a Bluetooth event, the issue is caused by the priority. The Bluetooth event has a higher priority. I would recommend keeping the wait_for_flash_ready() as this will ensure that the application is done writing to flash before reading.

    Have you tried to add a flag instead of flash_write in the Bluetooth event and then check the flag in the main context? If true, then write flash and clear flag?

Related