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

debug bootloader for thread examples

Hi,

I wonder if there exists a debug bootloader for thread examples. There is a bootloader in the secure DFU example, but it is not for debugging. "examples/thread/dfu/bootloader" . I appreciate if you can point me to the right direction.

Best regards,

Ozan

Parents
  • Hi Edvin,

    I made some tests, but no success with bootloader in debug mode. Anyways, I continue to work on DFU. The thing is that DFU update library gives fatal error and resets the device. I appreciate if you can check the following log:

    <info> COAP_DFU: DFU trigger request received
    <info> background_dfu: DFU trigger: init (sz=140, crc=3CE37F4) image (sz=357152, crc=76D6FA45)
    <info> background_dfu: state=DFU_DOWNLOAD_TRIG event=DFU_EVENT_TRANSFER_COMPLETE
    <warning> background_dfu: Installed image CRC is different
    <error> nrf_dfu_validation: Failed to decode init packet
    <error> background_dfu: Init commad has changed
    <info> background_dfu: Init complete. Multicast Mode.
    <info> background_dfu: state=DFU_DOWNLOAD_INIT_CMD event=DFU_EVENT_TRANSFER_CONTINUE
    <info> COAP_DFU: DFU trigger request received
    <error> background_dfu: Validate trigger: DFU already in progress (s:DFU_DOWNLOAD_INIT_CMD).
    <info> COAP_DFU: DFU trigger request received
    <error> background_dfu: Validate trigger: DFU already in progress (s:DFU_DOWNLOAD_INIT_CMD).
    <info> background_dfu: Storing block (b:0 c:0).
    <info> background_dfu: state=DFU_DOWNLOAD_INIT_CMD event=DFU_EVENT_TRANSFER_CONTINUE
    <info> background_dfu: Storing block (b:1 c:1).
    <info> background_dfu: state=DFU_DOWNLOAD_INIT_CMD event=DFU_EVENT_TRANSFER_CONTINUE
    <info> background_dfu: Storing block (b:2 c:2).
    <info> nrf_dfu_validation: Signature required. Checking signature.
    <info> nrf_dfu_validation: Calculating init packet hash (init packet len: 63)
    <info> nrf_dfu_validation: Verify signature
    <info> nrf_dfu_validation: Image verified
    <info> background_dfu: state=DFU_DOWNLOAD_INIT_CMD event=DFU_EVENT_TRANSFER_COMPLETE
    <info> background_dfu: state=DFU_DOWNLOAD_FIRMWARE event=DFU_EVENT_TRANSFER_CONTINUE
    <info> background_dfu: Storing block (b:0 c:0).
    
    <info> app: Thread version: OPENTHREAD/20180926-00368-gf01e3f34; NRF52840; Feb 28 2019 11:11:40
    <info> COAP_DFU: Endpoints initialized
    <info> background_dfu: Current DFU Diag version: Mar 18 2019 16:39:48, 0x99E68F38
    <warning> COAP_DFU: Image data received in invalid state: (m:0 s:5).
    <warning> COAP_DFU: Image data received in invalid state: (m:0 s:5).
    <warning> COAP_DFU: Image data received in invalid state: (m:0 s:5).
    <warning> COAP_DFU: Image data received in invalid state: (m:0 s:5).
    <warning> COAP_DFU: Image data received in invalid state: (m:0 s:5).
    <warning> COAP_DFU: Image data received in invalid state: (m:0 s:5).
    <warning> COAP_DFU: Image data received in invalid state: (m:0 s:5).
    <warning> COAP_DFU: Image data received in invalid state: (m:0 s:5).
    <warning> COAP_DFU: Image data received in invalid state: (m:0 s:5).
    

    I followed the steps in the thread dfu example

    #initial client
    nrfutil settings generate --family NRF52840 --application tnode.hex --application-version 1 --bootloader-version 1 --bl-settings-version 1 settings.hex
    mergehex -m tnode.hex settings.hex -o dfu_client.hex
    
    nrfjprog -f nrf52 -r --program dfu_data/mbr.hex --snr 683612867 --chiperase
    nrfjprog -f nrf52 -r --program dfu_data/bootloader.hex --snr 683612867 --sectoranduicrerase
    nrfjprog -f nrf52 -r --program ./dfu_client.hex --snr 683612867 --sectorerase
    
    #new firmware
    nrfutil pkg generate --hw-version 52 --sd-req 0x00 --application-version 2 --application tnode.hex --key-file dfu_data/priv.pem app_dfu_package_2.zip
    nrfutil --output /dev/stdout dfu thread -pkg app_dfu_package_2.zip -p /dev/ttyACM1 -r 10 -rs 5000 -a FF03::1 -sp 5685
    

    Related parts of the project file:

    c_preprocessor_definitions="BOARD_PCA10056;CONFIG_GPIO_AS_PINRESET;FLOAT_ABI_HARD;FREERTOS;INITIALIZE_USER_SECTIONS;NO_VTOR_CONFIG;NRF52840_XXAA;NRF_DFU_NO_TRANSPORT;NRF_DFU_SETTINGS_VERSION=1;OPENTHREAD_ENABLE_APPLICATION_COAP;SVC_INTERFACE_CALL_AS_NORMAL_FUNCTION;SWI_DISABLE0;uECC_ENABLE_VLI_API=0;uECC_OPTIMIZATION_LEVEL=3;uECC_SQUARE_FUNC=0;uECC_SUPPORT_COMPRESSED_POINT=0;uECC_VLI_NATIVE_LITTLE_ENDIAN=1;"
    
      <configuration
        Name="Release"
        linker_section_placement_file="flash_placement-release.xml"
        linker_section_placement_macros="FLASH_PH_START=0x0;FLASH_PH_SIZE=0x100000;RAM_PH_START=0x20000000;RAM_PH_SIZE=0x40000;FLASH_START=0x1000;FLASH_SIZE=0xfb000;RAM_START=0x20000008;RAM_SIZE=0x3fff8"
        linker_section_placements_segments="FLASH RX 0x0 0x100000;RAM RWX 0x20000000 0x40000;ot_flash_data RX 0x000f4000 0x4000;uicr_bootloader_start_address RX 0x10001014 0x4;bootloader_settings_page RX 0x000FF000 0x1000;uicr_mbr_params_page RX 0x10001018 0x4;mbr_params_page RX 0x000FE000 0x1000"
        c_preprocessor_definitions="NDEBUG"
        gcc_optimization_level="Optimize For Size" />

    And flash placement file (not the same with the example since I added different components in to the project, but merged):

    <!DOCTYPE Linker_Placement_File>
    <Root name="Flash Section Placement">
      <MemorySegment name="FLASH" start="$(FLASH_PH_START)" size="$(FLASH_PH_SIZE)">
        <ProgramSection load="no" name=".reserved_flash" start="$(FLASH_PH_START)" size="$(FLASH_START)-$(FLASH_PH_START)" />
        <ProgramSection alignment="0x100" load="Yes" name=".vectors" start="$(FLASH_START)" />
        <ProgramSection alignment="4" load="Yes" name=".init" />
        <ProgramSection alignment="4" load="Yes" name=".init_rodata" />
        <ProgramSection alignment="4" load="Yes" name=".text" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".crypto_data" inputsections="*(SORT(.crypto_data*))" address_symbol="__start_crypto_data" end_symbol="__stop_crypto_data" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".nrf_queue" inputsections="*(.nrf_queue*)" address_symbol="__start_nrf_queue" end_symbol="__stop_nrf_queue" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_const_data" inputsections="*(SORT(.log_const_data*))" address_symbol="__start_log_const_data" end_symbol="__stop_log_const_data" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_backends" inputsections="*(SORT(.log_backends*))" address_symbol="__start_log_backends" end_symbol="__stop_log_backends" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".nrf_balloc" inputsections="*(.nrf_balloc*)" address_symbol="__start_nrf_balloc" end_symbol="__stop_nrf_balloc" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".dfu_trans" inputsections="*(SORT(.dfu_trans*))" address_symbol="__start_dfu_trans" end_symbol="__stop_dfu_trans" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections" address_symbol="__start_nrf_sections" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".fs_data"  inputsections="*(.fs_data*)" runin=".fs_data_run"/>
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_dynamic_data"  inputsections="*(SORT(.log_dynamic_data*))" runin=".log_dynamic_data_run"/>
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_filter_data"  inputsections="*(SORT(.log_filter_data*))" runin=".log_filter_data_run"/>
        <ProgramSection alignment="4" load="Yes" name=".dtors" />
        <ProgramSection alignment="4" load="Yes" name=".ctors" />
        <ProgramSection alignment="4" load="Yes" name=".rodata" />
        <ProgramSection alignment="4" load="Yes" name=".ARM.exidx" address_symbol="__exidx_start" end_symbol="__exidx_end" />
        <ProgramSection alignment="4" load="Yes" runin=".fast_run" name=".fast" />
        <ProgramSection alignment="4" load="Yes" runin=".data_run" name=".data" />
        <ProgramSection alignment="4" load="Yes" runin=".tdata_run" name=".tdata" />
        <ProgramSection alignment="4" load="No"  name=".mev_data" start="0xf3000" size="0x1000" />
      </MemorySegment>
      <MemorySegment name="RAM" start="$(RAM_PH_START)" size="$(RAM_PH_SIZE)">
        <ProgramSection load="no" name=".reserved_ram" start="$(RAM_PH_START)" size="$(RAM_START)-$(RAM_PH_START)" />
        <ProgramSection alignment="0x100" load="No" name=".vectors_ram" start="$(RAM_START)" address_symbol="__app_ram_start__"/>
        <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections_run" address_symbol="__start_nrf_sections_run" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".fs_data_run" address_symbol="__start_fs_data" end_symbol="__stop_fs_data" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".log_dynamic_data_run" address_symbol="__start_log_dynamic_data" end_symbol="__stop_log_dynamic_data" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".log_filter_data_run" address_symbol="__start_log_filter_data" end_symbol="__stop_log_filter_data" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections_run_end" address_symbol="__end_nrf_sections_run" />
        <ProgramSection alignment="4" load="No" name=".fast_run" />
        <ProgramSection alignment="4" load="No" name=".data_run" />
        <ProgramSection alignment="4" load="No" name=".tdata_run" />
        <ProgramSection alignment="4" load="No" name=".bss" />
        <ProgramSection alignment="4" load="No" name=".tbss" />
        <ProgramSection alignment="4" load="No" name=".non_init" />
        <ProgramSection alignment="4" size="__HEAPSIZE__" load="No" name=".heap" />
        <ProgramSection alignment="8" size="__STACKSIZE__" load="No" place_from_segment_end="Yes" name=".stack"  address_symbol="__StackLimit" end_symbol="__StackTop"/>
        <ProgramSection alignment="8" size="__STACKSIZE_PROCESS__" load="No" name=".stack_process" />
      </MemorySegment>
      <MemorySegment name="ot_flash_data" start="0x000f4000" size="0x4000">
        <ProgramSection alignment="4" keep="Yes" load="No" name=".ot_flash_data" address_symbol="__start_ot_flash_data" end_symbol="__stop_ot_flash_data" start = "0x000f4000" size="0x4000" />
      </MemorySegment>
      <MemorySegment name="bootloader_settings_page" start="0x000FF000" size="0x1000">
        <ProgramSection alignment="4" keep="Yes" load="No" name=".bootloader_settings_page" address_symbol="__start_bootloader_settings_page" end_symbol="__stop_bootloader_settings_page" start = "0x000FF000" size="0x1000" />
      </MemorySegment>
      <MemorySegment name="mbr_params_page" start="0x000FE000" size="0x1000">
        <ProgramSection alignment="4" keep="Yes" load="No" name=".mbr_params_page" address_symbol="__start_mbr_params_page" end_symbol="__stop_mbr_params_page" start = "0x000FE000" size="0x1000" />
      </MemorySegment>
      <MemorySegment name="uicr_bootloader_start_address" start="0x10001014" size="0x4">
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".uicr_bootloader_start_address" address_symbol="__start_uicr_bootloader_start_address" end_symbol="__stop_uicr_bootloader_start_address" start = "0x10001014" size="0x4" />
      </MemorySegment>
      <MemorySegment name="uicr_mbr_params_page" start="0x10001018" size="0x4">
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".uicr_mbr_params_page" address_symbol="__start_uicr_mbr_params_page" end_symbol="__stop_uicr_mbr_params_page" start = "0x10001018" size="0x4" />
      </MemorySegment>
    </Root>

    And the code where DFU monitored and processed:

    static void thread_stack_task(void * arg)
    {
        UNUSED_PARAMETER(arg);
    
        uint32_t now, before = otPlatAlarmMilliGetNow();
    
        while (1)
        {
    #ifdef NDEBUG
            coap_dfu_process();
            thread_process();
    
            now = otPlatAlarmMilliGetNow();
            if (now - before > 1000)
            {
                coap_time_tick();
                before = now;
            }
    
            if (m_app.trigger_dfu)
            {
                m_app.trigger_dfu = false;
                coap_dfu_trigger(NULL);
            }
    #else
            thread_process();
    #endif
    
            UNUSED_VARIABLE(ulTaskNotifyTake(pdTRUE, portMAX_DELAY));
        }
    }
    

    Any help is highly appreciated! I think I am doing wrong with the flash placement, but I just merged the example with my current version of placement file.

    I know that this info may not be enough to pinpoint the problem, but if you can give me some clues/checkpoints then I can continue. 

    Best regards,

    Vedat

  • I am not sure what that needs to be changed in the flash placement file. I don't think you need to change anything in this file, to be honest. What you should do is to change your nrf_bootloader_init() to something like this:

    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_DFU_ENTER_METHOD_BUTTON)
        {
            dfu_enter_button_init();
        }
    
        ret_val = nrf_dfu_settings_init(false);
        if (ret_val != NRF_SUCCESS)
        {
            return NRF_ERROR_INTERNAL;
        }
    
        // Check if an update needs to be activated and activate it.
        activation_result = nrf_bootloader_fw_activate();
    
        switch (activation_result)
        {
            case ACTIVATION_NONE:
                initial_timeout = NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS);
                dfu_enter       = dfu_enter_check();
                break;
    
            case ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE:
                initial_timeout = NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_CONTINUATION_TIMEOUT_MS);
                dfu_enter       = true;
                break;
    
            case ACTIVATION_SUCCESS:
                bootloader_reset();
                NRF_LOG_ERROR("Should never come here: After bootloader_reset()");
                return NRF_ERROR_INTERNAL; // Should not reach this.
    
            case ACTIVATION_ERROR:
            default:
                return NRF_ERROR_INTERNAL;
        }
    
        //if (dfu_enter)
        if (false)               //This will always start application, regardless of the state of dfu_enter.
        {
            nrf_bootloader_wdt_init();
    
            scheduler_init();
    
            // Clear all DFU stop flags.
            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);
    
            ret_val = nrf_dfu_init(dfu_observer);
            if (ret_val != NRF_SUCCESS)
            {
                return NRF_ERROR_INTERNAL;
            }
    
            NRF_LOG_DEBUG("Enter main loop");
            loop_forever(); // This function will never return.
            NRF_LOG_ERROR("Should never come here: After looping forever.");
        }
        else
        {
            // Erase additional data like peer data or advertisement name
            ret_val = nrf_dfu_settings_additional_erase();
            if (ret_val != NRF_SUCCESS)
            {
                return NRF_ERROR_INTERNAL;
            }
    
            m_flash_write_done = false;
            nrf_dfu_settings_backup(flash_write_callback);
            ASSERT(m_flash_write_done);
    
            nrf_bootloader_app_start();
            NRF_LOG_ERROR("Should never come here: After nrf_bootloader_app_start()");
        }
    
        // Should not be reached.
        return NRF_ERROR_INTERNAL;
    }

    You can see that I changed the "if (dfu_enter)" to "if (false)".

    Note that with this very simple approach, it will never enter bootloader mode, but always start the application.

    If you want to filter on your own premises, e.g. work as a normal bootloader, but not check the CRC, you need to study the bootloader project found in examples\thread\dfu\bootloader.

    Inside the nrf_bootloader_init() there is a state machine:

    nrf_bootloader_fw_activate checks whether it has received any new application that it needs to move around. If not, it will return ACTIVATION_NONE. In this case, it will check dfu_enter_check(). If you want to disable the CRC here, just comment out the first check inside. nrf_dfu_app_is_valid(). If you skip this check, you should be able to debug your application, because the bootloader skips the CRC check. However, the rest of the bootloader and DFU procedure requires the keys as normal.

    Best regards,

    Edvin

Reply
  • I am not sure what that needs to be changed in the flash placement file. I don't think you need to change anything in this file, to be honest. What you should do is to change your nrf_bootloader_init() to something like this:

    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_DFU_ENTER_METHOD_BUTTON)
        {
            dfu_enter_button_init();
        }
    
        ret_val = nrf_dfu_settings_init(false);
        if (ret_val != NRF_SUCCESS)
        {
            return NRF_ERROR_INTERNAL;
        }
    
        // Check if an update needs to be activated and activate it.
        activation_result = nrf_bootloader_fw_activate();
    
        switch (activation_result)
        {
            case ACTIVATION_NONE:
                initial_timeout = NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS);
                dfu_enter       = dfu_enter_check();
                break;
    
            case ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE:
                initial_timeout = NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_CONTINUATION_TIMEOUT_MS);
                dfu_enter       = true;
                break;
    
            case ACTIVATION_SUCCESS:
                bootloader_reset();
                NRF_LOG_ERROR("Should never come here: After bootloader_reset()");
                return NRF_ERROR_INTERNAL; // Should not reach this.
    
            case ACTIVATION_ERROR:
            default:
                return NRF_ERROR_INTERNAL;
        }
    
        //if (dfu_enter)
        if (false)               //This will always start application, regardless of the state of dfu_enter.
        {
            nrf_bootloader_wdt_init();
    
            scheduler_init();
    
            // Clear all DFU stop flags.
            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);
    
            ret_val = nrf_dfu_init(dfu_observer);
            if (ret_val != NRF_SUCCESS)
            {
                return NRF_ERROR_INTERNAL;
            }
    
            NRF_LOG_DEBUG("Enter main loop");
            loop_forever(); // This function will never return.
            NRF_LOG_ERROR("Should never come here: After looping forever.");
        }
        else
        {
            // Erase additional data like peer data or advertisement name
            ret_val = nrf_dfu_settings_additional_erase();
            if (ret_val != NRF_SUCCESS)
            {
                return NRF_ERROR_INTERNAL;
            }
    
            m_flash_write_done = false;
            nrf_dfu_settings_backup(flash_write_callback);
            ASSERT(m_flash_write_done);
    
            nrf_bootloader_app_start();
            NRF_LOG_ERROR("Should never come here: After nrf_bootloader_app_start()");
        }
    
        // Should not be reached.
        return NRF_ERROR_INTERNAL;
    }

    You can see that I changed the "if (dfu_enter)" to "if (false)".

    Note that with this very simple approach, it will never enter bootloader mode, but always start the application.

    If you want to filter on your own premises, e.g. work as a normal bootloader, but not check the CRC, you need to study the bootloader project found in examples\thread\dfu\bootloader.

    Inside the nrf_bootloader_init() there is a state machine:

    nrf_bootloader_fw_activate checks whether it has received any new application that it needs to move around. If not, it will return ACTIVATION_NONE. In this case, it will check dfu_enter_check(). If you want to disable the CRC here, just comment out the first check inside. nrf_dfu_app_is_valid(). If you skip this check, you should be able to debug your application, because the bootloader skips the CRC check. However, the rest of the bootloader and DFU procedure requires the keys as normal.

    Best regards,

    Edvin

Children
Related