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.

  • Hi,

    The application signals the bootloader that a new update is available by setting the .bank_current value in the bootloader settings to NRF_DFU_CURRENT_BANK_1. The bootloader then validates the image based on the data stored in the settings page and subsequently runs the nrf_bootloader_fw_activate() to copy the image from bank 1 to its destination.

    This post discusses which part of the settings page can be updated by the application: RE: App-based DFU, changing bank#1 address? 

     With regards to logging, I recommend you try the 'debug' variant of the bootloader project. This project has logging over RTT enabled by default. 

    Best regards,

    Vidar

  • The application signals the bootloader that a new update is available by setting the .bank_current value in the bootloader settings to NRF_DFU_CURRENT_BANK_1.

    we are writing our app in external flash . NRF_DFU_CURRENT_BANK_1 is not set by our code what else we need to change after that. and what changes we are suppose to make in that red lined postvalidate() function.

    till now i have made some changes in my code to write magic number in external flash to trigger  bootloader about new application in external flash which is also working 

    1:in nrf_dfu_valodation.c file inside nrf_dfu_validation_signature_check() function: after image verification i have erased an address in external flash for magic number.

    // Function to perform signature check if required.
    static nrf_dfu_result_t nrf_dfu_validation_signature_check(dfu_signature_type_t signature_type,
                                                               uint8_t      const * p_signature,
                                                               uint32_t             signature_len,
                                                               uint8_t      const * p_data,
                                                               uint32_t             data_len)
    {
        ret_code_t err_code;
        size_t     hash_len = NRF_CRYPTO_HASH_SIZE_SHA256;
    
        nrf_crypto_hash_context_t         hash_context   = {0};
        nrf_crypto_ecdsa_verify_context_t verify_context = {0};
    
        crypto_init();
    
        NRF_LOG_INFO("Signature required. Checking signature.")
        if (p_signature == NULL)
        {
            NRF_LOG_WARNING("No signature found.");
            return EXT_ERR(NRF_DFU_EXT_ERROR_SIGNATURE_MISSING);
        }
    
        if (signature_type != DFU_SIGNATURE_TYPE_ECDSA_P256_SHA256)
        {
            NRF_LOG_INFO("Invalid signature type");
            return EXT_ERR(NRF_DFU_EXT_ERROR_WRONG_SIGNATURE_TYPE);
        }
    
        NRF_LOG_INFO("Calculating hash (len: %d)", data_len);
        err_code = nrf_crypto_hash_calculate(&hash_context,
                                             &g_nrf_crypto_hash_sha256_info,
                                             p_data,
                                             data_len,
                                             m_sig_hash,
                                             &hash_len);
        if (err_code != NRF_SUCCESS)
        {
            return NRF_DFU_RES_CODE_OPERATION_FAILED;
        }
    
        if (sizeof(m_signature) != signature_len)
        {
            return NRF_DFU_RES_CODE_OPERATION_FAILED;
        }
    
        // Prepare the signature received over the air.
        memcpy(m_signature, p_signature, signature_len);
    
        // Calculate the signature.
        NRF_LOG_INFO("Verify signature");
    
        // The signature is in little-endian format. Change it to big-endian format for nrf_crypto use.
        nrf_crypto_internal_double_swap_endian_in_place(m_signature, sizeof(m_signature) / 2);
    
        err_code = nrf_crypto_ecdsa_verify(&verify_context,
                                           &m_public_key,
                                           m_sig_hash,
                                           hash_len,
                                           m_signature,
                                           sizeof(m_signature));
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Signature failed (err_code: 0x%x)", err_code);
            NRF_LOG_DEBUG("Signature:");
            NRF_LOG_HEXDUMP_DEBUG(m_signature, sizeof(m_signature));
            NRF_LOG_DEBUG("Hash:");
            NRF_LOG_HEXDUMP_DEBUG(m_sig_hash, hash_len);
            NRF_LOG_DEBUG("Public Key:");
            NRF_LOG_HEXDUMP_DEBUG(pk, sizeof(pk));
            NRF_LOG_FLUSH();
    
            return NRF_DFU_RES_CODE_INVALID_OBJECT;
        }
    
        NRF_LOG_INFO("Image verified");
    
        if(nrf_drv_qspi_erase(NRF_QSPI_ERASE_LEN_4KB, MAGIC_NUMBER_ADDR) != NRFX_SUCCESS)
        {
          NRF_LOG_INFO("\r\nFailed to errase data blocks in Ext Flash for magic number.\r\n");
        }
        else
        {
          NRF_LOG_INFO("Succsessfully Erased Ext Flash block for magic number at: 0x%X\r\n\r\n",MAGIC_NUMBER_ADDR);
          WAIT_FOR_PERIPH();
        }
    
    
        return NRF_DFU_RES_CODE_SUCCESS;
    }

    2:in nrf_dfu_valodation.c file inside postvalidate() function: I have written the magic number in external flash .

    #include "nrf_drv_qspi.h"
    
    #define MAGIC_NUMBER_ADDR 0x200000  // block no. 32
    uint8_t MAGIC_NUMBER[]="12112345";
    
    
    
    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_drv_qspi_write(MAGIC_NUMBER, sizeof(MAGIC_NUMBER),MAGIC_NUMBER_ADDR) != NRFX_SUCCESS)
                  {
                    printf("Failed to store magic number in Ext Flash.\r\n");
                  }
                  else
                  {
                    printf("Succsessfully storing magic number at: 0x%X\r\n\r\n",MAGIC_NUMBER_ADDR);
                    WAIT_FOR_PERIPH();
                  }
    
                }
            }

    3:in nrf_bootloader.c file inside nrf_bootloader_init() function: i have made changes to read that magic number again from external flash to verify the new firmware.


    #include "nrf_drv_qspi.h"
    
    #define DFU_QSPI_BANK_ADDR 0x200000  // block no. 32
    uint8_t DEFAULT_DFU_QSPI_BANK[8]= "12112345";
    uint8_t DFU_QSPI_BANK[8];
    uint8_t DFU_QSPI_BANK_SIZE = sizeof(DEFAULT_DFU_QSPI_BANK);
    
    
    
    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();
        }
    
        ret_val = nrf_dfu_settings_init(false);
        if (ret_val != NRF_SUCCESS)
        {
            return NRF_ERROR_INTERNAL;
        }
    
        #if NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
    
        if(nrf_drv_qspi_read(DFU_QSPI_BANK, DFU_QSPI_BANK_SIZE,DFU_QSPI_BANK_ADDR) != NRFX_SUCCESS)
        {
          printf("\r\nFailed read DFU_QSPI_BANK.\r\n");
        }
        else
        {
          printf("Succsessfully read DFU_QSPI_BANK from: 0x%X\r\n\r\n",DFU_QSPI_BANK_ADDR);
          WAIT_FOR_PERIPH();
        }
    
        //compare data 
    
        // Postvalidate if DFU has signaled that update is ready.
        if (s_dfu_settings.bank_current == NRF_DFU_CURRENT_BANK_1)
        {
            postvalidate();
        }
        #endif
    
        // Check if an update needs to be activated and activate it.
        activation_result = nrf_bootloader_fw_activate();

    above all works but i am still not sure about changes in bootloader because app_activate(),sd_activate() and bl_activate() all are using the same uint32_t         src_addr = s_dfu_settings.progress.update_start_address; to find the updated address and also how to chnage the image size  uint32_t const image_size = s_dfu_settings.bank_1.image_size; there are multiple queries related to this. will you please, guide me with step by step changes .

    here is the output the changes i have made




  • I recommend you try the 'debug' variant of the bootloader project. This project has logging over RTT enabled by default

    I am using examples\thread\dfu\bootloader example for bootloader and there is not option of 'debug' variant in that project. should i change this bootloader example.

  • and also after including qspi and other files in boootloader there is is error in firmware size and the firmware size request and also because of this error the dfu download process in external flash not getting completed.

    firmware size requested from nrf_dfu_req_handler.c is different than the firmware size in background_dfu_state.c . 

       

    this error is same but not the same time but error is common

  • It looks like the problem is that you are creating a 0x1000 byte object when there is only 0xE20 bytes left to send.

Related