OFF CHIP OTA UPDATE using external flash

I am working on this project off chip ota update on nRF5_SDK  using ecample/thread/dfu

by now, i have done changes in these functions on_data_obj_create_request() and on_data_obj_write_request(). initially these functions were erasing and writing data in internal flash which I changed to qspi functions like nrf_drv_qspi_erase() and nrf_drv_qspi_write(). and it works perfectly.

Later i changed functions for hash verification which is also working but i am not sure about what should be the next step so that bootloader changes the earlier application with the new firmware image.

Parents
  • Hi,

    Unfortunately our experts on this matter are out-of-office today. We expect to get back to you beginning of next week. If you have any progress in the mean time then please update this ticket with your findings.

    Regards,
    Terje

  • I have made three changes in code 

    1: in flash erase i have changed it to erase external flash using QSPI.

    static void on_data_obj_create_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
    {
        NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_CREATE (data)");
    
        if (!nrf_dfu_validation_init_cmd_present())
        {
            /* Can't accept data because DFU isn't initialized by init command. */
            NRF_LOG_ERROR("Cannot create data object without valid init command");
            p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
            return;
        }
    
        if (p_req->create.object_size == 0)
        {
            NRF_LOG_ERROR("Object size cannot be 0.")
            p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
            return;
        }
    
        if (  ((p_req->create.object_size & (CODE_PAGE_SIZE - 1)) != 0)
            && (s_dfu_settings.progress.firmware_image_offset_last + p_req->create.object_size != m_firmware_size_req))
        {
            NRF_LOG_ERROR("Object size must be page aligned");
            ota_error_code = 1;
            p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
            return;
        }
    
        if (p_req->create.object_size > DATA_OBJECT_MAX_SIZE)
        {
            /* It is impossible to handle the command because the size is too large */
            NRF_LOG_ERROR("Invalid size for object (too large)");
            p_res->result = NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES;
            return;
        }
    
        if ((s_dfu_settings.progress.firmware_image_offset_last + p_req->create.object_size) >
            m_firmware_size_req)
        {
            NRF_LOG_ERROR("Creating the object with size 0x%08x would overflow firmware size. "
                          "Offset is 0x%08x and firmware size is 0x%08x.",
                          p_req->create.object_size,
                          s_dfu_settings.progress.firmware_image_offset_last,
                          m_firmware_size_req);
    
            p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
            ota_error_code = 2;
            return;
        }
    
        s_dfu_settings.progress.data_object_size      = p_req->create.object_size;
        s_dfu_settings.progress.firmware_image_crc    = s_dfu_settings.progress.firmware_image_crc_last;
        s_dfu_settings.progress.firmware_image_offset = s_dfu_settings.progress.firmware_image_offset_last;
        s_dfu_settings.write_offset                   = s_dfu_settings.progress.firmware_image_offset_last;
    
        /* Erase the page we're at. */
        if (nrf_dfu_flash_erase((m_firmware_start_addr + s_dfu_settings.progress.firmware_image_offset),
                                CEIL_DIV(p_req->create.object_size, CODE_PAGE_SIZE), NULL) != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Erase operation failed");
            p_res->result = NRF_DFU_RES_CODE_INVALID_OBJECT;
            return;
        }
    
        NRF_LOG_DEBUG("Creating object with size: %d. Offset: 0x%08x, CRC: 0x%08x",
                     s_dfu_settings.progress.data_object_size,
                     s_dfu_settings.progress.firmware_image_offset,
                     s_dfu_settings.progress.firmware_image_crc);
        
       NRF_LOG_INFO("Creating object with size: %d.  Offset: 0x%08x, CRC: 0x%08x\r\n",
                     s_dfu_settings.progress.data_object_size,
                     s_dfu_settings.progress.firmware_image_offset,
                     s_dfu_settings.progress.firmware_image_crc);
    
    
          /* check if flash is enabled */
            if(is_flash_enable() == false)
            {
              NRF_LOG_INFO("Flash in sleep state. Reinintialising\r\n");
    
              Enable_Flash();
            }
    
            if(nrf_drv_qspi_erase(NRF_QSPI_ERASE_LEN_4KB, FIRMWARE_FLASH_ADDR + (s_dfu_settings.progress.firmware_image_offset)) != NRFX_SUCCESS)
            {
              NRF_LOG_INFO("Failed to rrase data blocks in Ext Flash.\r\n");
            }
            else
            {
              NRF_LOG_INFO("Succsessfully Erased Ext Flash block at: 0x%X\r\n\r\n",FIRMWARE_FLASH_ADDR + (s_dfu_settings.progress.firmware_image_offset));
              WAIT_FOR_PERIPH();
              nrf_delay_ms(500);
            }
    
    
    }
     

    2: in flash store I have changed to write the code in external flash using QSPI.

    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_ERROR_BASE_NUM;
          //ret_code_t ret =
          //  nrf_dfu_flash_store(write_addr, p_req->write.p_data, p_req->write.len, p_req->callback.write);
    
            
            /* check if flash is enabled */
            if(is_flash_enable() == false)
            {
              NRF_LOG_INFO("Flash in sleep state. Reinintialising\r\n");
    
              Enable_Flash();
            }
            
            
            if(nrf_drv_qspi_write(p_req->write.p_data, p_req->write.len,FIRMWARE_FLASH_ADDR + s_dfu_settings.write_offset) != NRFX_SUCCESS)
            {
              NRF_LOG_INFO("\r\nFailed storing data blocks in Ext Flash.\r\n");
            }
            else
            {
              NRF_LOG_INFO("Succsessfully storing data block at: 0x%X\r\n\r\n",FIRMWARE_FLASH_ADDR + s_dfu_settings.write_offset);
              WAIT_FOR_PERIPH();
              p_req->callback.write((void*)p_req->write.p_data);
              ret = NRF_SUCCESS;
            }
    
        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;
    }

    3: in calculate hash i have changed it to copy data from QSPI and update the hash accordingly.

    ret_code_t nrf_crypto_hash_calculate(nrf_crypto_hash_context_t    * const p_context,
                                         nrf_crypto_hash_info_t       const * p_info,
                                         uint8_t                      const * p_data,
                                         size_t                               data_size,
                                         uint8_t                            * p_digest,
                                         size_t                       * const p_digest_size)
    {
        ret_code_t                      ret_val;
        nrf_crypto_hash_context_t     * p_ctx  = (nrf_crypto_hash_context_t *)p_context;
        void                          * p_allocated_context = NULL;
    
    // Internal allocation of context not available for CC310_BL in order to save code size.
    #if defined(NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256_ENABLED) && (NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256_ENABLED == 1)
        
        // Do nothing
        
    #elif defined(NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256_ENABLED) && (NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256_ENABLED == 0)
        
        // Validate input. Only validate input parameters that are used locally, others are validated
        // in the init, update and/or finalize functions.
        VERIFY_TRUE(p_info != NULL, NRF_ERROR_CRYPTO_INPUT_NULL);
    
        // Allocate context if needed (not provided by the user).
        if (p_context == NULL)
        {
            p_allocated_context = NRF_CRYPTO_ALLOC(p_info->context_size);
            if (p_allocated_context == NULL)
            {
                return NRF_ERROR_CRYPTO_ALLOC_FAILED;
            }
            p_ctx = (nrf_crypto_hash_context_t *)p_allocated_context;
        }
        
    #else
    
        #warning NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256_ENABLED define not found in sdk_config.h (Is the sdk_config.h valid?).
        
    #endif // NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256_ENABLED
    
        ret_val = nrf_crypto_hash_init(p_ctx, p_info);
        NRF_CRYPTO_VERIFY_SUCCESS_DEALLOCATE(ret_val, p_allocated_context);
    
    
        if(validation_state == 0)
        {
            ret_val = nrf_crypto_hash_update(p_ctx, p_data, data_size);
            NRF_CRYPTO_VERIFY_SUCCESS_DEALLOCATE(ret_val, p_allocated_context);
            validation_state = 1;
        }
        else
        {
            uint16_t firmware_blocks = data_size / FIRMWARE_BLOCK_SIZE;
            uint8_t rest_block = data_size % FIRMWARE_BLOCK_SIZE;
    
    
            printf("data_size: %d", data_size);
            printf("firmware_blocks: %d", firmware_blocks);
            printf("rest_block: %d", rest_block);
    
    
            for(uint16_t i=0; i <= firmware_blocks; i++)
            {
              /* check if flash is enabled */
                if(is_flash_enable() == false)
                {
                    printf("Flash in sleep state. Reinintialising\r\n");
    
                    Enable_Flash();
                }
            
                uint8_t m_buffer_rx[FIRMWARE_BLOCK_SIZE];
    
                if(i == firmware_blocks)
                {
                    if(nrf_drv_qspi_read(m_buffer_rx, rest_block,FIRMWARE_FLASH_ADDR + (FIRMWARE_BLOCK_SIZE * i)) != NRFX_SUCCESS)
                    {
                       printf("\r\nFailed read data blocks in Ext Flash.\r\n");
                    }
                    else
                    {
                       printf("Succsessfully read rest_block data block from: 0x%X\r\n\r\n",FIRMWARE_FLASH_ADDR + (FIRMWARE_BLOCK_SIZE * i));
                       WAIT_FOR_PERIPH();
                       ret_val = nrf_crypto_hash_update(p_ctx, m_buffer_rx, rest_block);
                       NRF_CRYPTO_VERIFY_SUCCESS_DEALLOCATE(ret_val, p_allocated_context);
                    }
                }
                else
                {
                    if(nrf_drv_qspi_read(m_buffer_rx, FIRMWARE_BLOCK_SIZE,FIRMWARE_FLASH_ADDR + (FIRMWARE_BLOCK_SIZE * i)) != NRFX_SUCCESS)
                    {
                        printf("\r\nFailed read data blocks in Ext Flash.\r\n");
                    }
                    else
                    {
                        printf("Succsessfully read data block %d from: 0x%X\r\n\r\n", i ,FIRMWARE_FLASH_ADDR + (FIRMWARE_BLOCK_SIZE * i));
                        WAIT_FOR_PERIPH();
                        ret_val = nrf_crypto_hash_update(p_ctx, m_buffer_rx, FIRMWARE_BLOCK_SIZE);
                        NRF_CRYPTO_VERIFY_SUCCESS_DEALLOCATE(ret_val, p_allocated_context);
                    }
                }            
            }
            validation_state = 0;
        }
    
        ret_val = nrf_crypto_hash_finalize(p_ctx, p_digest, p_digest_size);
        NRF_CRYPTO_VERIFY_SUCCESS_DEALLOCATE(ret_val, p_allocated_context);
    
    #if !NRF_MODULE_ENABLED(NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256)
        // Free context if allocated internally
        if (p_allocated_context != NULL)
        {
            NRF_CRYPTO_FREE(p_allocated_context);
        }
    #endif // !NRF_MODULE_ENABLED(NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256)
    
        return NRF_SUCCESS;
    }
    
    #endif // NRF_MODULE_ENABLED(NRF_CRYPTO_HASH)
    
    #endif // NRF_MODULE_ENABLED(NRF_CRYPTO)

    and after that few more changes to get notified that hash has been verified and also to find out flow of the code 

    1

    #if NRF_DFU_IN_APP
            res.result = nrf_dfu_validation_post_data_execute(m_firmware_start_addr, m_firmware_size_req);
            printf("Post Validation Error Code: %d\r\n",res.result );
    
            #else
            res.result = nrf_dfu_validation_activation_prepare(m_firmware_start_addr, m_firmware_size_req);
            #endif

    2 and in this this change i didn't find the output after this  if (!is_trusted). may be this piece of code is not executing or something

    nrf_dfu_result_t postvalidate(uint32_t data_addr, uint32_t data_len, bool is_trusted)
    {
        nrf_dfu_result_t           ret_val = NRF_DFU_RES_CODE_SUCCESS;
        dfu_init_command_t const * p_init  = mp_init;
    
        if (!fw_hash_ok(p_init, data_addr, data_len))
        {
            ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_VERIFICATION_FAILED);
        }
        else
        {
            printf("postvalidate Hash ok\r\n");
          
            if (p_init->type == DFU_FW_TYPE_APPLICATION)
            {
                if (!postvalidate_app(p_init, data_addr, data_len, is_trusted))
                {
                    ret_val = NRF_DFU_RES_CODE_INVALID_OBJECT;
                    printf("postvalidate fun error: postvalidate_app %d\r\n",ret_val);
                }
                else
                {
                  printf("postvalidate fun success\r\n");
                }
            }
    #if NRF_DFU_SUPPORTS_EXTERNAL_APP
            else if (p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
            {
                if (!is_trusted)
                {
                    // This function must be implemented externally
                    ret_val = nrf_dfu_validation_post_external_app_execute(p_init, is_trusted);
                }
                else
                {
                    s_dfu_settings.bank_1.bank_code = NRF_DFU_BANK_VALID_EXT_APP;
                }
            }
    #endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
            else
            {
                bool with_sd = p_init->type & DFU_FW_TYPE_SOFTDEVICE;
                bool with_bl = p_init->type & DFU_FW_TYPE_BOOTLOADER;
    
                if (!postvalidate_sd_bl(p_init, with_sd, with_bl, data_addr, data_len, is_trusted))
                {
                    ret_val = NRF_DFU_RES_CODE_INVALID_OBJECT;
                    if (is_trusted && with_sd && !DFU_REQUIRES_SOFTDEVICE &&
                        (data_addr == nrf_dfu_softdevice_start_address()))
                    {
                        nrf_dfu_softdevice_invalidate();
                    }
                }
            }
        }
    
        if (!is_trusted)
        {
            if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
            {
                    printf("\r\nSet DFU setting current bank.\r\n");
    
                s_dfu_settings.bank_current = NRF_DFU_CURRENT_BANK_1;
            }
            else
            {
                printf("nrf_dfu_settings_progress_reset if !is_trusted\r\n");
    
                nrf_dfu_settings_progress_reset();
            }
        }
        else
        {
            if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
            {
            printf("Mark the update as complete and valid.\r\n");
                // Mark the update as complete and valid.
                s_dfu_settings.bank_1.image_crc  = crc32_compute((uint8_t *)data_addr, data_len, NULL);
                s_dfu_settings.bank_1.image_size = data_len;
            }
            else
            {
                nrf_dfu_bank_invalidate(&s_dfu_settings.bank_1);
                        printf("Mark the update as Invalid. : %d\r\n",ret_val);
    
            }
    
            printf("nrf_dfu_settings_progress_reset if is_trusted\r\n");
    
            nrf_dfu_settings_progress_reset();
            s_dfu_settings.progress.update_start_address = data_addr;
        }
    
        return ret_val;
    }
    

    3

    static bool nrf_dfu_validation_hash_ok(uint8_t const * p_hash, uint32_t src_addr, uint32_t data_len, bool little_endian)
    {
        ret_code_t err_code;
        bool       result   = true;
        uint8_t    hash_be[NRF_CRYPTO_HASH_SIZE_SHA256];
        size_t     hash_len = NRF_CRYPTO_HASH_SIZE_SHA256;
    
        nrf_crypto_hash_context_t hash_context = {0};
    
        crypto_init();
    
        if (little_endian)
        {
            // Convert to hash to big-endian format for use in nrf_crypto.
            nrf_crypto_internal_swap_endian(hash_be,
                                            p_hash,
                                            NRF_CRYPTO_HASH_SIZE_SHA256);
            p_hash = hash_be;
        }
    
        NRF_LOG_DEBUG("Hash verification. start address: 0x%x, size: 0x%x",
                      src_addr,
                      data_len);
    
       NRF_LOG_INFO("Hash verification. start address: 0x%x, size: 0x%x",
                      src_addr,
                      data_len);
    
    
        err_code = nrf_crypto_hash_calculate(&hash_context,
                                             &g_nrf_crypto_hash_sha256_info,
                                             (uint8_t*)src_addr,
                                             data_len,
                                             m_fw_hash,
                                             &hash_len);
    
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Could not run hash verification (err_code 0x%x).", err_code);
            result = false;
        }
        else if (memcmp(m_fw_hash, p_hash, NRF_CRYPTO_HASH_SIZE_SHA256) != 0)
        {
            NRF_LOG_WARNING("Hash verification failed.");
            NRF_LOG_INFO("Hash verification failed.");
            NRF_LOG_DEBUG("Expected FW hash:")
            NRF_LOG_INFO("Expected FW hash:")
            NRF_LOG_HEXDUMP_DEBUG(p_hash, NRF_CRYPTO_HASH_SIZE_SHA256);
            NRF_LOG_DEBUG("Actual FW hash:")
            NRF_LOG_INFO("Actual FW hash:")
            NRF_LOG_HEXDUMP_DEBUG(m_fw_hash, NRF_CRYPTO_HASH_SIZE_SHA256);
            NRF_LOG_FLUSH();
    
            result = false;
        }
    
        return result;
    }

  • Hi 

    I have solved the above problems. from last conversation to till today 

    1: now both size matches 

    2: download is complete.

    3: Hash verification and crc is completed and it working fine

    4: i have started log in bootloader  so now i am able to see the problem of bootloader reset.

    i have changed the image_copy function and in logs i can see it is working and writes my image completely .

    static uint32_t image_copy(uint32_t dst_addr,
                               uint32_t src_addr,
                               uint32_t size,
                               uint32_t progress_update_step)
    {
        if (src_addr == dst_addr)
        {
            NRF_LOG_DEBUG("No copy needed");
            return NRF_SUCCESS;
        }
    
        ASSERT(src_addr >= dst_addr);
        ASSERT(progress_update_step > 0);
        ASSERT((dst_addr % CODE_PAGE_SIZE) == 0);
    
        uint32_t max_safe_progress_upd_step = (src_addr - dst_addr)/CODE_PAGE_SIZE;
        ASSERT(max_safe_progress_upd_step > 0);
    
        uint32_t ret_val = NRF_SUCCESS;
        uint32_t pages_left = CEIL_DIV(size, CODE_PAGE_SIZE);
    
        //Firmware copying is time consuming operation thus watchdog handling is started
        nrf_bootloader_wdt_init();
    
        progress_update_step = MIN(progress_update_step, max_safe_progress_upd_step);
    
        while (size > 0)
        {
            uint32_t pages;
            uint32_t bytes;
            if (pages_left <= progress_update_step)
            {
                pages = pages_left;
                bytes = size;
            }
            else
            {
                pages = progress_update_step;
                bytes = progress_update_step * CODE_PAGE_SIZE;
            }
            // Erase the target pages
            ret_val = nrf_dfu_flash_erase(dst_addr, pages, NULL);
            if (ret_val != NRF_SUCCESS)
            {
                return ret_val;
            }
    
            // Flash one page
    
            uint32_t m_buffer_rx[bytes];
    
            if(nrf_drv_qspi_read(m_buffer_rx, bytes,firmware_flash_addr ) != NRFX_SUCCESS)
            {
              NRF_LOG_INFO("Failed read application for bootloader reset in Ext Flash.\r\n");
            }
            else
            {
              NRF_LOG_INFO("Succsessfully read application for bootloader reset from: 0x%lX\r\n",firmware_flash_addr);
              WAIT_FOR_PERIPH();
              NRF_LOG_DEBUG("Copying 0x%x to 0x%x, size: 0x%x", src_addr, dst_addr, bytes);
              ret_val = nrf_dfu_flash_store(dst_addr,
                                          (uint32_t *)m_buffer_rx,
                                          ALIGN_NUM(sizeof(uint32_t), bytes),
                                          NULL);
            }
            //NRF_LOG_DEBUG("Copying 0x%x to 0x%x, size: 0x%x", src_addr, dst_addr, bytes);
            //ret_val = nrf_dfu_flash_store(dst_addr,
            //                              (uint32_t *)src_addr,
            //                              ALIGN_NUM(sizeof(uint32_t), bytes),
            //                              NULL);
    
    
            if (ret_val != NRF_SUCCESS)
            {
                return ret_val;
            }
            else
            {
              NRF_LOG_INFO("flash store successfull...\r\n");
            }
    
            pages_left  -= pages;
            size        -= bytes;
            dst_addr    += bytes;
            src_addr    += bytes;
            s_dfu_settings.write_offset += bytes;
            firmware_flash_addr += bytes; 
    
            //store progress in flash on every successful chunk write
            ret_val = nrf_dfu_settings_write_and_backup(NULL);
            if (ret_val != NRF_SUCCESS)
            {
                NRF_LOG_ERROR("Failed to write image copying progress to settings page.");
                return ret_val;
            }
        }
    
        return ret_val;
    }

    here is the log of that 

    but after this in app_activate() function there is crc calculation on bank 0 and  crc calculation fails and there is an error.

    the code of app_activate() function

    static uint32_t app_activate(void)
    {
        // This function is only in use when new app is present in Bank 1
        uint32_t const image_size  = s_dfu_settings.bank_1.image_size;
    
        uint32_t src_addr    = s_dfu_settings.progress.update_start_address;
        uint32_t ret_val     = NRF_SUCCESS;
        uint32_t target_addr = nrf_dfu_bank0_start_addr() + s_dfu_settings.write_offset;
        uint32_t length_left = (image_size - s_dfu_settings.write_offset);
        uint32_t crc;
    
        NRF_LOG_DEBUG("Enter nrf_dfu_app_continue");
    
        src_addr += s_dfu_settings.write_offset;
    
        if (src_addr == target_addr)
        {
            length_left = 0;
        }
    
        ret_val = image_copy(target_addr, src_addr, length_left, NRF_BL_FW_COPY_PROGRESS_STORE_STEP);
        if (ret_val != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Failed to copy firmware.");
            return ret_val;
        }
    
        // Check the CRC of the copied data. Enable if so.
        crc = crc32_compute((uint8_t*)nrf_dfu_bank0_start_addr(), image_size, NULL);
    
        if (crc == s_dfu_settings.bank_1.image_crc)
        {
            NRF_LOG_DEBUG("Setting app as valid");
            s_dfu_settings.bank_0.bank_code = NRF_DFU_BANK_VALID_APP;
            s_dfu_settings.bank_0.image_crc = crc;
            s_dfu_settings.bank_0.image_size = image_size;
        }
        else
        {
            NRF_LOG_ERROR("CRC computation failed for copied app: "
                          "src crc: 0x%08x, res crc: 0x%08x",
                          s_dfu_settings.bank_1.image_crc,
                          crc);
        }
    
        return ret_val;
    }
    



    i want to know why this crc calculation fails because before bootloader reset same crc calculation is correct. 

    here is more log which is from bootloader

    0> 
    00> <debug> app: Copying 0xBE000 to 0x59000, size: 0x8000
    00> 
    00> <debug> nrf_dfu_flash: nrf_fstorage_write(addr=0x00059000, src=0x2001FED8, len=32768 bytes), queue usage: 1
    00> 
    00> <debug> nrf_dfu_flash: Flash write success: addr=0x00059000, pending 0
    00> 
    00> <info> app: flash store successfull...
    00> 
    00> 
    00> 
    00> <debug> nrf_dfu_settings: Writing settings...
    00> 
    00> <debug> nrf_dfu_settings: Erasing old settings at: 0x000FF000
    00> 
    00> <debug> nrf_dfu_flash: nrf_fstorage_erase(addr=0x0x000FF000, len=1 pages), queue usage: 1
    00> 
    00> <debug> nrf_dfu_flash: Flash erase success: addr=0x000FF000, pending 0
    00> 
    00> <debug> nrf_dfu_flash: nrf_fstorage_write(addr=0x000FF000, src=0x200012EC, len=896 bytes), queue usage: 1
    00> 
    00> <debug> nrf_dfu_flash: Flash write success: addr=0x000FF000, pending 0
    00> 
    00> <info> nrf_dfu_settings: Backing up settings page to address 0xFE000.
    00> 
    00> <debug> nrf_dfu_settings: Writing settings...
    00> 
    00> <debug> nrf_dfu_settings: Erasing old settings at: 0x000FE000
    00> 
    00> <debug> nrf_dfu_flash: nrf_fstorage_erase(addr=0x0x000FE000, len=1 pages), queue usage: 1
    00> 
    00> <debug> nrf_dfu_flash: Flash erase success: addr=0x000FE000, pending 0
    00> 
    00> <debug> nrf_dfu_flash: nrf_fstorage_write(addr=0x000FE000, src=0x20000F68, len=896 bytes), queue usage: 1
    00> 
    00> <debug> nrf_dfu_flash: Flash write success: addr=0x000FE000, pending 0
    00> 
    00> <debug> nrf_dfu_flash: nrf_fstorage_erase(addr=0x0x00061000, len=5 pages), queue usage: 1
    00> 
    00> <debug> nrf_dfu_flash: Flash erase success: addr=0x00061000, pending 0
    00> 
    00> <info> app: Succsessfully read application for bootloader reset from: 0x160000
    00> 
    00> 
    00> 
    00> <debug> app: Copying 0xC6000 to 0x61000, size: 0x4F30
    00> 
    00> <debug> nrf_dfu_flash: nrf_fstorage_write(addr=0x00061000, src=0x2002C218, len=20272 bytes), queue usage: 1
    00> 
    00> <debug> nrf_dfu_flash: Flash write success: addr=0x00061000, pending 0
    00> 
    00> <info> app: flash store successfull...
    00> 
    00> 
    00> 
    00> <debug> nrf_dfu_settings: Writing settings...
    00> 
    00> <debug> nrf_dfu_settings: Erasing old settings at: 0x000FF000
    00> 
    00> <debug> nrf_dfu_flash: nrf_fstorage_erase(addr=0x0x000FF000, len=1 pages), queue usage: 1
    00> 
    00> <debug> nrf_dfu_flash: Flash erase success: addr=0x000FF000, pending 0
    00> 
    00> <debug> nrf_dfu_flash: nrf_fstorage_write(addr=0x000FF000, src=0x200012EC, len=896 bytes), queue usage: 1
    00> 
    00> <debug> nrf_dfu_flash: Flash write success: addr=0x000FF000, pending 0
    00> 
    00> <info> nrf_dfu_settings: Backing up settings page to address 0xFE000.
    00> 
    00> <debug> nrf_dfu_settings: Writing settings...
    00> 
    00> <debug> nrf_dfu_settings: Erasing old settings at: 0x000FE000
    00> 
    00> <debug> nrf_dfu_flash: nrf_fstorage_erase(addr=0x0x000FE000, len=1 pages), queue usage: 1
    00> 
    00> <debug> nrf_dfu_flash: Flash erase success: addr=0x000FE000, pending 0
    00> 
    00> <debug> nrf_dfu_flash: nrf_fstorage_write(addr=0x000FE000, src=0x20000F68, len=896 bytes), queue usage: 1
    00> 
    00> <debug> nrf_dfu_flash: Flash write success: addr=0x000FE000, pending 0
    00> 
    00> <error> app: CRC computation failed for copied app: src crc: 0xBF28E606, res crc: 0x5B2DA0B8
    00> 
    00> <debug> nrf_dfu_settings: Writing settings...
    00> 
    00> <debug> nrf_dfu_settings: Erasing old settings at: 0x000FF000
    00> 
    00> <debug> nrf_dfu_flash: nrf_fstorage_erase(addr=0x0x000FF000, len=1 pages), queue usage: 1
    00> 
    00> <debug> nrf_dfu_flash: Flash erase success: addr=0x000FF000, pending 0
    00> 
    00> <debug> nrf_dfu_flash: nrf_fstorage_write(addr=0x000FF000, src=0x200012EC, len=896 bytes), queue usage: 1
    00> 
    00> <debug> nrf_dfu_flash: Flash write success: addr=0x000FF000, pending 0
    00> 
    00> <info> nrf_dfu_settings: Backing up settings page to address 0xFE000.
    00> 
    00> <debug> nrf_dfu_settings: Writing settings...
    00> 
    00> <debug> nrf_dfu_settings: Erasing old settings at: 0x000FE000
    00> 
    00> <debug> nrf_dfu_flash: nrf_fstorage_erase(addr=0x0x000FE000, len=1 pages), queue usage: 1
    00> 
    00> <debug> nrf_dfu_flash: Flash erase success: addr=0x000FE000, pending 0
    00> 
    00> <debug> nrf_dfu_flash: nrf_fstorage_write(addr=0x000FE000, src=0x20000F68, len=896 bytes), queue usage: 1
    00> 
    00> <debug> nrf_dfu_flash: Flash write success: addr=0x000FE000, pending 0
    00> 
    00> <debug> app: Resetting bootloader.
    00> 
    00> <info> nrf_dfu_settings: B<info> app: Inside main
    00> 
    00> 
    00> 
    00> <debug> app: In nrf_bootloader_init
    00> 
    00> <debug> nrf_dfu_settings: Calling nrf_dfu_settings_init()...
    00> 
    00> <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    00> 
    00> <debug> nrf_dfu_settings: Using settings page.
    00> 
    00> <debug> nrf_dfu_settings: Copying forbidden parts from backup page.
    00> 
    00> <debug> nrf_dfu_settings: Destination settings are identical to source, write not needed. Skipping.
    00> 
    00> <info> nrf_dfu_settings: Backing up settings page to address 0xFE000.
    00> 
    00> <debug> nrf_dfu_settings: Destination settings are identical to source, write not needed. Skipping.
    00> 
    00> <debug> app: Enter nrf_bootloader_fw_activate
    00> 
    00> <info> app: No firmware to activate.
    00> 
    00>  feeding watchdog.
    00> 
    00> <debug> app: timer_activate (0x20000018)
    00> 
    00> <debug> app: in weak nrf_dfu_init_user
    00> 
    00> <debug> app: timer_stop (0x20000008)
    00> 
    00> <debug> app: timer_activate (0x20000008)
    00> 
    00> <info> app: Entering DFU mode.
    00> 
    00> <debug> app: Initializing transports (found: 0)
    00> 
    00> <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    00> 
    00> <debug> app: Enter main loop
    00> 

  • Are you copying the image from bank 1 in external flash? I can't tell from your code snippet where the image is copied from.

  • Bank 1 is the temporary address where the app was initially supposed to be downloaded, but I changed it to external flash.

    Bank 0 is the address in the internal flash where the app runs after the download completes. In the bootloader, we erase the old image from bank 0 and replace it with bank 1 (in this case, external flash) after performing a CRC check.

  • Yes, but you are not showing how you adapted the copy function to read the image from external flash.

  • i have changed the image_copy function and in logs i can see it is working and writes my image completely

    after this i have shared a code snippet of image_copy() inside that i have changed this

    // Flash one page

    uint32_t m_buffer_rx[bytes];

    if(nrf_drv_qspi_read(m_buffer_rx, bytes,firmware_flash_addr ) != NRFX_SUCCESS)
    {
    NRF_LOG_INFO("Failed read application for bootloader reset in Ext Flash.\r\n");
    }
    else
    {
    NRF_LOG_INFO("Succsessfully read application for bootloader reset from: 0x%lX\r\n",firmware_flash_addr);
    WAIT_FOR_PERIPH();
    NRF_LOG_DEBUG("Copying 0x%x to 0x%x, size: 0x%x", src_addr, dst_addr, bytes);
    ret_val = nrf_dfu_flash_store(dst_addr,
    (uint32_t *)m_buffer_rx,
    ALIGN_NUM(sizeof(uint32_t), bytes),
    NULL);
    }

    and code which was earlier copying the image is here:


    //NRF_LOG_DEBUG("Copying 0x%x to 0x%x, size: 0x%x", src_addr, dst_addr, bytes);
    //ret_val = nrf_dfu_flash_store(dst_addr,
    // (uint32_t *)src_addr,
    // ALIGN_NUM(sizeof(uint32_t), bytes),
    // NULL);

Reply
  • i have changed the image_copy function and in logs i can see it is working and writes my image completely

    after this i have shared a code snippet of image_copy() inside that i have changed this

    // Flash one page

    uint32_t m_buffer_rx[bytes];

    if(nrf_drv_qspi_read(m_buffer_rx, bytes,firmware_flash_addr ) != NRFX_SUCCESS)
    {
    NRF_LOG_INFO("Failed read application for bootloader reset in Ext Flash.\r\n");
    }
    else
    {
    NRF_LOG_INFO("Succsessfully read application for bootloader reset from: 0x%lX\r\n",firmware_flash_addr);
    WAIT_FOR_PERIPH();
    NRF_LOG_DEBUG("Copying 0x%x to 0x%x, size: 0x%x", src_addr, dst_addr, bytes);
    ret_val = nrf_dfu_flash_store(dst_addr,
    (uint32_t *)m_buffer_rx,
    ALIGN_NUM(sizeof(uint32_t), bytes),
    NULL);
    }

    and code which was earlier copying the image is here:


    //NRF_LOG_DEBUG("Copying 0x%x to 0x%x, size: 0x%x", src_addr, dst_addr, bytes);
    //ret_val = nrf_dfu_flash_store(dst_addr,
    // (uint32_t *)src_addr,
    // ALIGN_NUM(sizeof(uint32_t), bytes),
    // NULL);

Children
  • It looks like you are using the QSPI flash API correctly. Could you please read out the image stored in the QSPI flash and compare it to the image stored in Bank 1 to see if they match?

  • To read from the external flash, a specific command is required by the nrfprog tool. Unfortunately, while retrieving data from the external flash, this command appends the address to each line, thereby impeding the direct comparison between the data retrieved from the internal and external flash sources.

    Furthermore, regarding the progress of the DFU process, I'd like to inform you that we have reached the final stages:

    1. The application has been successfully downloaded to the external flash.
    2. Hash verification has been completed without any issues.
    3. DFU bank 1 has been appropriately configured.
    4. The bootloader has been reset as per the protocol.
    5. The bootloader is effectively replacing the entire code from the external flash to the internal flash.
    6. Upon replacement, a CRC computation over the image in the internal flash is conducted. However, this step encounters failure, and despite diligent efforts, the root cause behind this failure remains elusive.
  • You can use regex or a text processing tool like 'awk' to filter out the address column from the output.

    Example of using regex in Vs code:

  • hey I tried all possible commands to read external qspi flash, but as I am using custom board none of them worked. 

    so i tried another way. even though crc calculation fails, i jumped to start the app directly buy changing the code in nrf_bootloader_init() function and my dfu is complete after this.

    return NRF_ERROR_INTERNAL; // Should not reach this.

    case ACTIVATION_ERROR:
    default:
    return NRF_ERROR_INTERNAL;
    }

    if (dfu_enter)
    {
    nrf_bootloader_app_start();
    nrf_bootloader_wdt_init();
    scheduler_init();
    dfu_enter_flags_clear();

    // Call user-defined init function if implemented
    ret_val = nrf_dfu_init_user();
    if (ret_val != NRF_SUCCESS)
    {
    return NRF_ERROR_INTERNAL;
    }

    nrf_bootloader_dfu_inactivity_timer_restart(initial_timeout, inactivity_timeout);

    in above juggad code nrf_bootloader_app_start(); function is used to start the app code. and it works and my app version 2 is working perfectlly.

    my device sends Payloads on server and on the server i can see the update and ota version as well.

    in this payload you can see at the last 2 is wrrten which represents the app version.

    and in another payload ota done message is visible.

    and also in j link it is visible 

    even this ota is done but still why that crc calculation fails? and if let this run then without crc verification this ota process is just like the single bank dfu process. 

    so please help me in this crc calculation

  • I would still like you to verify that the updated binary stored in the bank 0 matches the binary you uploaded through DFU. Since you are not able to read data from your external flash, you can program the hex file of your new application to the device, then read out the memory. Then, repeat the same steps but when loading the image through DFU and not via the debug interface.

    If the images are identical, then that suggests that the CRC computed by the application and the one computed by the bootloader were not computed over the same area.

Related