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

BLE transport for DFU in application

Hello,

We are using nRF52840 with SDK 15.2.0, a bootloader and the SoftDevice. We communicate with another microcontroller (a STM) with I2C. The nRF52840 is the master.

Currently we are able to perform (separately) a DFU for the two microcontrollers:

  • For the nRF5284, we use the nRF Connect application on a smartphone and we launch the DFU process with a .zip file containing the new firmware. Or we can use a cellular modem then jump to the bootloader.
  • For the STM, we download the new firmware from a cellular modem to the nRF52840 Flash memory, then we send it via I2C to the STM bootloader which perform DFU.

Now, we would like to be able to perform a DFU for the STM with nRF Connect on smartphone, as we do for the nRF5284. So the idea is to create the .zip file containing the STM firmware, like we currently do with the nRF5284 firmware. Then the process for the user will be the same for the two targets: connect the nRF5284 to the smartphone, select the .zip file, launch the DFU process, and when data is stored in Flash memory we check the target (with a parameter in the .dat file):

  • If it is the nRF5284 firmware, we jump to the bootloader (like it is already done currently).
  • If it is the STM firmware, the DFU is finished on the nRF5284 side (no reset) and we send it to STM via I2C.

To do that, we need to move the BLE DFU mechanism from the bootloader to the application. I have found some information in other topics and I have searched in the source code of the bootloader and the example given here. I am not sure, but I think we need the DFU Control Point and DFU Packet Characteristics, and the BLE transport layer. We don’t need to create a custom transport, we want to do exactly like how it is done in the bootloader.

We are in SDK 15.2 and not in 15.3 so is it a problem? I have read that DFU in application was improved in 15.3.

What we have done is to add the following code from the bootloader in our application during the BLE init:

scheduler_init();

err_code = nrf_dfu_settings_init(true);
APP_ERROR_CHECK(err_code);

err_code = nrf_dfu_init(m_user_observer);
APP_ERROR_CHECK(err_code);

The BLE transport layer is not modified, in the file nrf_dfu_ble.c:

DFU_TRANSPORT_REGISTER(nrf_dfu_transport_t const ble_dfu_transport) =
{
    .init_func  = ble_dfu_transport_init,
    .close_func = ble_dfu_transport_close,
};

Now we can see in nRF Connect the same BLE characteristics with the bootloader and with the application. But if we launch the DFU from the smartphone, the process is blocked during the first data write, without answer from the application.

The problem occurs in the ble_evt_handler in the file nrf_dfu_ble.c for the case BLE_GATTS_EVT_WRITE in the function on_write(&m_dfu, p_ble_evt);

The function begins with the code

ble_gatts_evt_write_t const * const p_write_evt = &p_ble_evt->evt.gatts_evt.params.write;

if (p_write_evt->handle != p_dfu->dfu_pkt_handles.value_handle)
{
    return;
}

And the if condition is false so the data is not stored.

I don't know if this is the main problem or only the result of another problem. Is it the good way to move the DFU process in the application? Or perhaps you have a good example for us? We try to do the less modifications as possible in the code because we only want to reproduce what the bootloader do.

Thanks for your help!

Parents
  • Hi,

    I have never seen anyone use the BLE transport from the bootloader in the application and do be honest I do not have a full overview of what modifications you need in order to get it to work. So in order to make suggestions I need to know more specifically what you have done and what issues you face when debugging and what results you see from debugging.

    More generally I am not sure if you need to move the transport to the application at all? That may be the case, but you could perhaps also keep the transport in the bootloader and use the (partial) support for external applications that was introduced in SDK 15.3. That was never used except for in the nRF5 SDK for Thread and Zigbee though so it is not complete, but it allows you to transfer an image to the nRF using normal DFU procedure, placing the image in bank 1. If the image is tagged as an external application the bootloader will not do more about it, but you can then implement the rest of the mechanism in you application, for updating the external MCU. There are very few examples of use here, but there is one thread on it.

    Einar

  • Hi Einar, thanks for your answer.

    I will try to explain what I have done and where I see the problem in my current solution.

    Previously, our BLE init task had this code:

    ble_stack_init();
    gap_params_init();
    gatt_init();
    advertising_init();
    services_init();
    conn_params_init();
    peer_manager_init();

    Based on the bootloader code, I have changed it for this new code:

    scheduler_init();
    err_code = nrf_dfu_settings_init(true);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_dfu_init(m_user_observer);
    APP_ERROR_CHECK(err_code);
    gatt_init();
    services_init();
    conn_params_init();
    peer_manager_init();
    
    // Now ble_stack_init(), gap_params_init() and advertising_init() are done in the ble_dfu_transport_init() function

    We can see the correct BLE attributes with nRF Connect (the DFU service, DFU Control Point and DFU Packet). We have the same result with the bootloader.

    If I launch the DFU process, it is stopped after writing data to the Control Point without answer, and nothing happens after that, as you can see in the logs of nRF Connect:

         

    From the application's debug logs, we receive the following data:

    <debug> nrf_ble_gatt: Requesting to update ATT MTU to 63 bytes on connection 0x0.
    <debug> nrf_dfu_ble: Connected
    <debug> nrf_ble_gatt: ATT MTU updated to 63 bytes on connection 0x0 (response).
    <debug> nrf_dfu_ble: Received BLE_GAP_EVT_CONN_PARAM_UPDATE
    <debug> nrf_dfu_ble: max_conn_interval: 12
    <debug> nrf_dfu_ble: min_conn_interval: 12
    <debug> nrf_dfu_ble: slave_latency: 0
    <debug> nrf_dfu_ble: conn_sup_timeout: 600
    <debug> nrf_dfu_ble: Received BLE_GAP_EVT_PHY_UPDATE (RX:2, TX:2, status:0)
    <debug> nrf_ble_gatt: Peer on connection 0x0 requested a data length of 251 bytes.
    <debug> nrf_ble_gatt: Updating data length to 27 on connection 0x0.
    <debug> nrf_dfu_ble: Received BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST.
    <debug> nrf_ble_gatt: Data length updated to 67 on connection 0x0.
    <debug> nrf_ble_gatt: max_rx_octets: 67
    <debug> nrf_ble_gatt: max_tx_octets: 67
    <debug> nrf_ble_gatt: max_rx_time: 2120
    <debug> nrf_ble_gatt: max_tx_time: 2120
    <debug> nrf_dfu_ble: Received BLE_GAP_EVT_DATA_LENGTH_UPDATE (67, max_rx_time 2120).
    <debug> nrf_dfu_ble: Received BLE_GAP_EVT_CONN_PARAM_UPDATE
    <debug> nrf_dfu_ble: max_conn_interval: 12
    <debug> nrf_dfu_ble: min_conn_interval: 12
    <debug> nrf_dfu_ble: slave_latency: 0
    <debug> nrf_dfu_ble: conn_sup_timeout: 600

    So it seems the DFU process is stopped just before sending the firmware to the nRF52840. So perhaps it is a problem in the BLE transport layer?


    Concerning the SDK 15.3 with external application support, thanks for the suggestion. Perhaps we will try this solution if we can't solve this current problem, but it's not the best solution for us because we prefer if possible to not reset the nRF52840 application if the DFU is only for the STM.

  • Hi,

    I think you need to do a bit more to merge this with your application code. It looks like the BLE event handler of the bootloader code is not run on a BLE event, doesn't it? So you would need to the same as the ble_evt_handler() in nrf_dfu_ble.c. You probably need to integrate that with your existing BLE event handling so you do not handle events duplicatly (connected etc.)

  • The ble_evt_handler() in nrf_dfu_ble.c is running correctly on a BLE event, and our own handler is running too. I have updated our handler to not have duplicated event already handled by nrf_dfu_ble.c, but the result is the same.

Reply Children
  • Finally we will try your solution of external application with SDK 15.3. If we have some problems or questions we will inform you, thanks.

  • Hi,

    Now we are on SDK 15.3 with SoftDevice 6.1.1 and the secure bootloader from the example in SDK. We have set the flags NRF_BL_DFU_ALLOW_UPDATE_FROM_APP and NRF_DFU_SUPPORTS_EXTERNAL_APP in sdk_config.h for the bootloader.

    We are able to do exactly what we want, the external firmware is written in Flash and when the application is restarted we perform the DFU of the other microcontroller and we invalidate the bank 1 in memory. So thank you for your help for this part.

    But now we have another problem with the bootloader: thanks to this previous thread, we were able to do a DFU after using our own firmware download process in Flash and modifying the bootloader settings. With this new bootloader, the application data swap in memory is correctly done but after that, the app is not started and the bootloader seems to be stuck in a faulty state because we can not detect it in BLE. So we have no way to retreive the app without reprogramming the nRF52840.

    If something is wrong with our data or the bootloader settings, the bootloader must abort the DFU and keep the current application in bank 0. But we can see the swap of bank 1 in bank 0 in memory so it is strange to not start correctly the new application after that.

    We can see the settings management is not exactly the same with SDK 15.3, have you any idea to solve our problem? Thanks for your help.

  • Hi,

    Is it possible to use RTT logging to see what happens in the bootloader? Without knowing more I suspect that you may be getting problems with the bootloader settings backup. Perhaps you could add all fields to settings_forbidden_parts_copy_from_backup() and see if that does anything (effectively omitting the setting backup feature)?

  • With the help of this thread we have found our problem. You are right, it was the settings backup. We have bypassed it in the bootloader and we have updated the settings in version 2 in the application.

    Now it works as expected, we can perform a DFU with BLE or modem, and for the two microcontrollers.

    Thank you, the problem is solved!

Related