DFU observer doesn't notify NRF_DFU_EVT_DFU_COMPLETED event

Hello,

In my application (using sdk 16.0.0) I have a bootloader that allows to upload a new firmware through either BLE or UART. The Bootloader is initialized as usual:

ret_val = nrf_bootloader_init(dfu_observer);

where:

static void dfu_observer(nrf_dfu_evt_type_t evt_type)
{
switch (evt_type)
{

.....

case NRF_DFU_EVT_DFU_STARTED:
sd_power_gpregret_set(0,0x4); // not correct but works!
bsp_board_led_on(BSP_BOARD_LED_0); // green
bsp_board_led_on(BSP_BOARD_LED_2); // red
break;


case NRF_DFU_EVT_OBJECT_RECEIVED: // DFU data object received
break;

case NRF_DFU_EVT_DFU_FAILED:
case NRF_DFU_EVT_DFU_ABORTED:
bsp_board_led_off(BSP_BOARD_LED_0); // green
bsp_board_led_on(BSP_BOARD_LED_2); // red
break;

case NRF_DFU_EVT_DFU_COMPLETED:
sd_power_gpregret_set(0,0x4); // set bit of GPREGRET register to remember DFU was ok after reset
bsp_board_led_on(BSP_BOARD_LED_0); // green
bsp_board_led_off(BSP_BOARD_LED_2); // red
break;

default:
break;
}
}

Now, what I would like to do is to write a bit of the GPREGRET register upon a successful DFU operation (NRF_DFU_EVT_DFU_COMPLETED) to notify the application that there has been a DFU after reset. However it looks like that state of the switch/case statement is never reached. The operations within the NRF_DFU_EVT_DFU_STARTED case (led blinking, GPREGRET writing) are instead executed, even though writing the register upon the "STARTED" event is not what I want as I am not sure at that point that the DFU operation will be successful.

Is there something I should do to enable the NRF_DFU_EVT_DFU_COMPLETED event to be processed? Is it possible that immediately after a successful DFU the bootloader resets and the new firmware is loaded, thus bypassing what is in that switch/case statement state? If so, what should I do to prevent an early reset?

Thanks.

Regards,

Stefano

Parents
  • Hello,

    I am not sure whether the NRF_DFU_EVT_DFU_COMPLETED is used in the later bootloaders. This is due to the way that the bootloader resets a couple of times during the procedure to do different tasks. Perhaps you can hook onto some other event?

    Try hooking onto the ACTIVATION_SUCCESS event in nrf_bootloader.c -> nrf_bootloader_init().

    I suggest that you ensure that the register is written before you call bootloader_reset(true); inside the ACTIVATION_SUCCESS event:

            case ACTIVATION_SUCCESS:
                uint8_t my_custom_value;
                uint8_t old_value = nrf_power_gpregret_get();
                nrf_power_gpregret_set(my_custom_value & old_value);    // Avoid deleting old bits that are set.
                while (nrf_power_gpregret_get() & my_custom_value != my_custom_value)
                {
                    // Wait until the register is properly written before we reset.
                }
                
                bootloader_reset(true);
                NRF_LOG_ERROR("Unreachable");
                return NRF_ERROR_INTERNAL; // Should not reach this.

    Best regards,

    Edvin

  • Dear Edvin,

    Thank you for your answer. I am using a SoftDevice, so I guess I should use sd_power_gpregret_* instead of nrf_power_gpregret_* (by the way, this duality is really confusing, couldn't this be handled inside the function instead of splitting in two sets?). Ok I will try, but these two states are conceptually different (one is the end of the DFU process, the other is a success in the activation. If I want to send feedbacks to a custom app during the process I will need to use the states of nrf_dfu_evt_type_t). In general which are the states of nrf_dfu_evt_type_t which are used and which are not? I can clearly see that NRF_DFU_EVT_DFU_STARTED is taken into account, but I am not sure about the others.

    Thanks,

    Stefano

Reply
  • Dear Edvin,

    Thank you for your answer. I am using a SoftDevice, so I guess I should use sd_power_gpregret_* instead of nrf_power_gpregret_* (by the way, this duality is really confusing, couldn't this be handled inside the function instead of splitting in two sets?). Ok I will try, but these two states are conceptually different (one is the end of the DFU process, the other is a success in the activation. If I want to send feedbacks to a custom app during the process I will need to use the states of nrf_dfu_evt_type_t). In general which are the states of nrf_dfu_evt_type_t which are used and which are not? I can clearly see that NRF_DFU_EVT_DFU_STARTED is taken into account, but I am not sure about the others.

    Thanks,

    Stefano

Children
  • ste2108 said:
    I guess I should use sd_power_gpregret_* instead of nrf_power_gpregret_* (by the way, this duality is really confusing, couldn't this be handled inside the function instead of splitting in two sets?)

    You need to use sd_power_gpregret instead of nrf_power_gpregret when the softdevice is enabled, because it restricts the access to this register. However, in this case, the softdevice is not enabled, as far as I can tell (I didn't test this now). The softdevice is only enabled if the bootloader is told to enter DFU mode (checked with dfu_enter_check()) and you are using a BLE bootloader.

    When the transfer is complete, the image is checked and verified (and moved if it is dual bank), and then it is reset. After this, it will enter ACTIVATION_SUCCESS, so the softdevice should not be enabled in this case. 

    ste2108 said:
    If I want to send feedbacks to a custom app during the process I will need to use the states of nrf_dfu_evt_type_t

    What do you mean? If you are using single bank, then you have no app to send these states to, and in general, the application will not be started between these events. The chip will remain in the bootloader until the DFU is complete. 

    If you want to see what events that occur, you can add some logging in the dfu_observer() callback function in nrf_bootloader.c that prints the events.

    Best regards,

    Edvin

Related