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

DFU: nRF51822 OTA bootloader jams after reset_prepare()

I managed to upload my application OTA DFU when there was only the bootloader running. After my application is there, I can start DFU and my application runs thru reset_prepare() function as expected. However, it seems that it never enters the bootloader although DfuTarg seems to appear as an available BLE device. So I cannot upload my application another time :(

Any ideas what could be wrong? Why my application does not start bootloader (correctly) after reset_prepare()?

EDIT: The bootloader enters event loop and jams there, see the code below (from bootloader.c/nRF51_SDK_8.0.0_5fc2c3a). The DFU loader at phone side says "disconnected" (mostly, sometimes it jams). I cannot reconnect although DfuTarg is visible.

for (;;)
{
    // Wait in low power state for any events.
    uint32_t err_code = sd_app_evt_wait();
    APP_ERROR_CHECK(err_code);

	myLedIndication(); // This shows me bootloader is running here very busy

    // Event received. Process it from the scheduler.
    app_sched_execute();

    if ((m_update_status == BOOTLOADER_COMPLETE) ||
        (m_update_status == BOOTLOADER_TIMEOUT)  ||
        (m_update_status == BOOTLOADER_RESET))
    {
        // When update has completed or a timeout/reset occured we will return.
        return;
    }
}

And the reset_prepare() looks like:

static void reset_prepare(void)
{
	uint32_t err_code;
	if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
	{
		// Disconnect from peer.
		err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
		APP_ERROR_CHECK(err_code);
		//err_code = bsp_indication_set(BSP_INDICATE_IDLE);
		//APP_ERROR_CHECK(err_code);
	}
	else
	{
		// If not connected, the device will be advertising. Hence stop the advertising.
		advertising_stop();
	}
	err_code = ble_conn_params_stop();
	APP_ERROR_CHECK(err_code);
}
  • Both. Those are in bootloader side. bootloader_util_arm.c is also in application side, but not the bootloader_settings_arm.c.

  • Hi, are you working with a nRF51 DK kit? Reason I ask is that we have different chip variants in case you're working on a custom board. Some with 16K and 32K of RAM and 128 or 256K of flash (chip variants). DK kit has 256/32 respectively which the examples are based on. So linker settings need to be adjusted accordingly for other variants.

    Generally when adding DFU support to an application such as the ble_app_hrs_dfu example you need to follow the instructions given here in the SDK documenation to allow buttonless entry to DFU mode. I guess you have followed those already considering you have implemented at least some of it in the code you posted. Unfortunately, there are two things missing from from these instructions (has been reported internally):

    1. Add loading of service changed flag as shown in the reference example (ble_app_hrs_dfu)
    2. set device_manager_cnfg.h->DEVICE_MANAGER_APP_CONTEXT_SIZE to a multiple of word size. I.e., 4 or more. This is used to store the ATT table changed flag.

    I'd suggest to closely compare the ble_app_hrs_dfu example with yours to see if there are any differences releated to DFU implemenation.

  • I am now using a dirty hack to get rid of bootloader jamming. The modification is at the bootloader's main.c, and it makes the bootloader to reset after it first enters from application, and only after that, it enters the actual bootloader code. However, two upload tries is now needed from nRFTools, so the solution is not optimal.

    bool app_reset = (NRF_POWER->GPREGRET == BOOTLOADER_DFU_START);
    bool app_reset2 = (NRF_POWER->GPREGRET == ~BOOTLOADER_DFU_START);
    
    if (app_reset)
    {
        NRF_POWER->GPREGRET = ~BOOTLOADER_DFU_START;
        NVIC_SystemReset();
    }
    else if (app_reset2)
    {
        NRF_POWER->GPREGRET = 0;
    }
    

    In addition, few other changes are needed to support "app_reset2" (several places at main). At least it works now somehow. But it is really a dirty hack as I said...

  • The assembly routine in bootloader_util_app_start() does jump from application to bootloader, but it doesn't do a system reset like NVIC_SystemReset, power on reset or a pin reset resulting in the softdevice already being invoked going from application to bootloader. This is the reason for the "app reset" check in ble_stack_init() as SD_MBR_COMMAND_INIT_SD can't be issued when SD is already invoked. In other words, only issue the SD_MBR_COMMAND_INIT_SD command if a system reset has been performed.

    Reason for not doing a system reset in the example is to support sharing of bond information between the application and bootlaoder to keep the same encrypted link while doing DFU (bond sharing). If this feature is not needed you can call NVIC_SystemReset(); in your application and always invoke the Softdevice in ble_stack_init().

Related