nrf_dfu_flash_store change to QSPI function -> callback issue in nrfx_qspi_write

Hi

I'm chnaging the Secure Bootloader to an external falsh for bank1, connected with QSPI.

In the function on_data_obj_write_request is the call for nrf_dfu_flash_store (file nrf_dfu_req_handler.c

static void on_data_obj_write_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
    NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_WRITE (data)");

    if (!nrf_dfu_validation_init_cmd_present())
    {
        /* Can't accept data because DFU isn't initialized by init command. */
        p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
        return;
    }

    uint32_t const data_object_offset = s_dfu_settings.progress.firmware_image_offset -
                                        s_dfu_settings.progress.firmware_image_offset_last;

    if ((p_req->write.len + data_object_offset) > s_dfu_settings.progress.data_object_size)
    {
        /* Can't accept data because too much data has been received. */
        NRF_LOG_ERROR("Write request too long");
        p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
        return;
    }

    uint32_t const write_addr = m_firmware_start_addr + s_dfu_settings.write_offset;
    /* CRC must be calculated before handing off the data to fstorage because the data is
     * freed on write completion.
     */
    uint32_t const next_crc =
        crc32_compute(p_req->write.p_data, p_req->write.len, &s_dfu_settings.progress.firmware_image_crc);

    ASSERT(p_req->callback.write);

    ret_code_t ret =
        nrf_dfu_flash_store(write_addr, p_req->write.p_data, p_req->write.len, p_req->callback.write);

    if (ret != NRF_SUCCESS)
    {
        /* When nrf_dfu_flash_store() fails because there is no space in the queue,
         * stop processing the request so that the peer can detect a CRC error
         * and retransmit this object. Remember to manually free the buffer !
         */
        p_req->callback.write((void*)p_req->write.p_data);
        return;
    }

    /* Update the CRC of the firmware image. */
    s_dfu_settings.write_offset                   += p_req->write.len;
    s_dfu_settings.progress.firmware_image_offset += p_req->write.len;
    s_dfu_settings.progress.firmware_image_crc     = next_crc;

    /* This is only used when the PRN is triggered and the 'write' message
     * is answered with a CRC message and these field are copied into the response.
     */
    p_res->write.crc    = s_dfu_settings.progress.firmware_image_crc;
    p_res->write.offset = s_dfu_settings.progress.firmware_image_offset;
}

There is a callback which is needed:

ret_code_t ret =
        nrf_dfu_flash_store(write_addr, p_req->write.p_data, p_req->write.len, p_req->callback.write);

inside this function I use the QSPI function:

hal_qspi_write(&p_src, len, (dest & EXTERNAL_FLASH_ADDRESS_LOWER_BYTES), (void*)callback))

which at the end is calling the nrfx function nrfx_qspi_write. 

Here I should have a callback, but I don't know what I should implement.

The original callback in the nrf_fstorage_write is implemented like this:
return (p_fs->p_api)->write(p_fs, dest, p_src, len, p_context);

ret_code_t nrf_fstorage_write(nrf_fstorage_t const * p_fs,
                              uint32_t               dest,
                              void           const * p_src,
                              uint32_t               len,
                              void                 * p_context)
{
    NRF_FSTORAGE_PARAM_CHECK(p_fs,        NRF_ERROR_NULL);
    NRF_FSTORAGE_PARAM_CHECK(p_src,       NRF_ERROR_NULL);
    NRF_FSTORAGE_PARAM_CHECK(p_fs->p_api, NRF_ERROR_INVALID_STATE);
    NRF_FSTORAGE_PARAM_CHECK(len,         NRF_ERROR_INVALID_LENGTH);

    /* Length must be a multiple of the program unit. */
    NRF_FSTORAGE_PARAM_CHECK(!(len % p_fs->p_flash_info->program_unit), NRF_ERROR_INVALID_LENGTH);

    /* Source and destination addresses must be word-aligned. */
    NRF_FSTORAGE_PARAM_CHECK(addr_is_aligned32(dest),                NRF_ERROR_INVALID_ADDR);
    NRF_FSTORAGE_PARAM_CHECK(addr_is_aligned32((uint32_t)p_src),     NRF_ERROR_INVALID_ADDR);
    NRF_FSTORAGE_PARAM_CHECK(addr_is_within_bounds(p_fs, dest, len), NRF_ERROR_INVALID_ADDR);

    return (p_fs->p_api)->write(p_fs, dest, p_src, len, p_context);
}

Now the DFU is strating on bank1 but the App is generating an error because data is missing because of this callack I guess?

I was following this topic:

https://devzone.nordicsemi.com/f/nordic-q-a/48961/dfu-with-external-qspi-memory

  • NB: I will be out of office next week, so if you reply, this will be assigned to someone else. I hope you get it working, and if not, your questions will be handled by one of my colleagues.

    Best regards,

    Edvin

  • Hi Edvin

    It's working!!!

    I had to update also the function nrf_crypto_hash_calculate to read in parts the QSPI flash and loop the update function (read to RAM, nrf_crypto_hash_update, loop again until size is finished)

    Thank you so much, I'm in vacation also, now its even sweeter to go :-)

  • Hello,

    That is awsome! Nothing like taking a vacation after you got everything working! 

    Then let's hope it is case closed for now. If any related questions should pop up during July, I suggest you create a new ticket, where you can link to this one for background information. 

    If something pops up in August or later, then you can use this one.

    Have a nice summer!

    Best regards,

    Edvin

  • Thank you, have a nice time aswell

    just for information for others: I check the additional bootloader flag here line 33:

    ret_code_t nrf_bootloader_init(nrf_dfu_observer_t observer)
    {
    	NRF_LOG_DEBUG("In nrf_bootloader_init");
    	ret_code_t                            ret_val;
    	nrf_bootloader_fw_activation_result_t activation_result;
    	uint32_t                              initial_timeout;
    	bool                                  dfu_enter = false;
    	m_user_observer = observer;
    
    	if (NRF_BL_DEBUG_PORT_DISABLE)
    	{
    		nrf_bootloader_debug_port_disable();
    	}
    
    #if NRF_BL_DFU_ENTER_METHOD_BUTTON
    	dfu_enter_button_init();
    #endif
    	ret_val = nrf_dfu_settings_init(false);
    
    	if (ret_val != NRF_SUCCESS)
    	{
    		return NRF_ERROR_INTERNAL;
    	}
    
    #if NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
    
    	// Postvalidate if DFU has signaled that update is ready.
    	if (s_dfu_settings.bank_current == NRF_DFU_CURRENT_BANK_1)
    	{
    		postvalidate();
    	}
    
        if (NRF_BL_DFU_ENTER_METHOD_GPREGRET &&
    	        ((nrf_power_gpregret_get() & BOOTLOADER_QSPI_START_MASK) == BOOTLOADER_QSPI_START))
    	{
            init_package_qspi_handle();
    		dfu_enter_flags_clear();
    	}
    
    #endif
    	// Check if an update needs to be activated and activate it.
    	activation_result = nrf_bootloader_fw_activate();
    
    	switch (activation_result)

  •  

    After testing I recognized that the Update is working if I do a software reset, meaning the nrf52 is still under power. If I do a hardware reset, the update is not starting, but I don't know why. because the new application is still in the external flash and the start Bit setted with the function sd_power_gpregret_set should be avilable even after power loss or am I wrong? Or is the eason maybe because the bootloader didin't checked the bank0 and bank1 valid flags?

    Any idea?

Related