Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

DFU with external QSPI memory

Hi,

   I am working on project, in which we using nordic nRF52840 chip. We need to flash the app+SD+BL image file in external QSPI memory.

After prevalidation, the DFU controller starts to send flash image package, we need to receive this and need to save in external QSPI memory. Once the postvalidation is successful, then read all the flash image package stored in external QSPI memory and write it to internal flash memory.

For that we use secure bootloader example code as reference file. I need to know where i need to modify the secure bootloader code.

I noticed that after prevalidation, the flash is erased in on_data_obj_create_request() function in nrf_dfu_req_handler.c file, and flash is written in on_data_obj_write_request() under the same c file. Is that right?

Thanks & Regards

Mohammad Gouse

Parents
  • Hi Hung Bui,

      I have modified the files nrf_fstorage_nvmc.c, nrf_flash.c, nrf_dfu_flash.c (with their corresponding header file) to have external qspi memory interface.

    Once the device enter into DFU mode, it initialize the nrf_dfu_req_handler_init(), so I modified this function by adding nrf_dfu_qspi_init() in it.

      In this project, MX25R6435F used as external QSPI memory. The memory map of this will be same as Nordic system memory map, but without MBR and Bootloader (In our case bootloader in internal flash memory).

    Step 1: After pre-validation, I need to copy the image file (SD + APP) to external QSPI. Now I need to know where I need to change the code to proceed to next step.

  • Hi Mohammad, 

    I assume you are familiar with the DFU procedure as described here

    After you pass the pre-validation (received the init packet and then got the NRF_DFU_OP_OBJECT_WRITE to execute it), you will receive the data objects. 

    They will be handled inside nrf_dfu_data_req(). It will start with the NRF_DFU_OP_OBJECT_CREATE and the page will be erased with the call to nrf_dfu_flash_erase() inside on_data_obj_create_request(). You would need to modify that function to erase the QSPI flash page instead. 

    Next is NRF_DFU_OP_OBJECT_WRITE , which handled in on_data_obj_write_request(). You need to modify nrf_dfu_flash_store() to store on QSPI. And so on. 

    I'm not 100% sure why you would need to make the addressing on QSPI the same as on the internal chip. But it's up to you. You can have a look at our discussion with TomWS above to know about other stuff you need to modify. 

  • Hello Mohammad,

    I'm starting with exactly the same task on the nRF52840. I will retrieve the DFU files via a cellular path and would like to save the files in external flash. Then I would like to continue the DFU from the external flash.
    It would be very helpful for me if I could start with a sample project that demonstrates the principles of the DFU from external storage.
    So I would like to ask you if there is a way to share a demo project or similar helpful things to get you started faster.
    Thank you and best regards
    Maik

  • Hi Maik,

    I am trying to implement the same. Let me know if you got any luck on this?

  • Hi Mohammad & TomWS,

    I am trying to implement the same thing.

    It would be very helpful for me if I could start with a sample project that demonstrates the principles of the DFU from external storage.

    Please guide us!

    Dipak

     

  • Hi

    Is there somebody who can share the sample project which is running?
    Thank you so much for any feedback.

    Regards

  • Hi Tom

    Can you tell me how you implemented the callback of the SPI (I'm using QSPI but it will be smilar)

    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?

Reply
  • Hi Tom

    Can you tell me how you implemented the callback of the SPI (I'm using QSPI but it will be smilar)

    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?

Children
No Data
Related