nrf51822-Add DFU service

Development environment: SDK9 is

based on the ble_app_uart example and adds dfu service to it.

The bootloader in the SDK provides two ways to enter the upgrade mode, one is to press the button, and the other is to click on the phone to upgrade. 

The relevant code in the bootloader code is as follows



If the mobile app is upgraded directly by clicking the icon, the value of the NRF_POWER->GPREGRET register will be set before the app jumps to the bootloader to upgrade. So the start of the bootloader code is to judge the value in this register to judge whether it is triggered by the phone to enter the DFU mode.

The following code will determine whether there is a button pressed on the device. If the button is pressed during the power-on process, it will also enter the DFU mode.

 

PS: Whether you enter the upgrade mode through the DFU icon on the phone or enter the upgrade mode through the buttons on the device, you need a bootloader. The two methods are just different in entering the upgrade mode.

First open the ble_app_uart project and add the following required modules in keil






Then add some DFU related processing code

Add in Main.c

 

#ifdef BLE_DFU_APP_SUPPORT

#include "ble_dfu.h"

#include "dfu_app_handler.h"

#endif

 

Modify IS_SRVC_CHANGED_CHARACT_PRESENT macro to 1


    

Add the following macro in Main.c



Add the following static variables in Main.c

#ifdef BLE_DFU_APP_SUPPORT   

static ble_dfu_t                         m_dfus;                                   

#endif


Add the following 3 functions to Main . c

Click ( here ) to collapse or open

  1. #ifdef BLE_DFU_APP_SUPPORT
  2. /**@brief Function for stopping advertising.
  3.  */
  4. static void advertising_stop(void)
  5. {
  6.     uint32_t err_code;

  7.     err_code = sd_ble_gap_adv_stop();
  8.     APP_ERROR_CHECK(err_code);

  9.     err_code = bsp_indication_set(BSP_INDICATE_IDLE);
  10.     APP_ERROR_CHECK(err_code);
  11. }


  12. /**@brief Function for loading application-specific context after establishing a secure connection.
  13.  *
  14.  * @details This function will load the application context and check if the ATT table is marked as 
  15.  * changed. If the ATT table is marked as changed, a Service Changed Indication
  16.  * is sent to the peer if the Service Changed CCCD is set to indicate.
  17.  *
  18.  * @param[in] p_handle The Device Manager handle that identifies the connection for which the context 
  19.  * should be loaded.
  20.  */
  21. static void app_context_load(dm_handle_t const * p_handle)
  22. {
  23.     uint32_t err_code;
  24.     static uint32_t context_data;
  25.     dm_application_context_t context;

  26.     context.len = sizeof(context_data);
  27.     context.p_data = (uint8_t *)&context_data;

  28.     err_code = dm_application_context_get(p_handle, &context);
  29.     if (err_code == NRF_SUCCESS)
  30.     {
  31.         // Send Service Changed Indication if ATT table has changed.
  32.         if ((context_data & (DFU_APP_ATT_TABLE_CHANGED << DFU_APP_ATT_TABLE_POS)) != 0)
  33.         {
  34.             err_code = sd_ble_gatts_service_changed(m_conn_handle, APP_SERVICE_HANDLE_START, BLE_HANDLE_MAX);
  35.             if ((err_code != NRF_SUCCESS) &&
  36.                 (err_code != BLE_ERROR_INVALID_CONN_HANDLE) &&
  37.                 (err_code != NRF_ERROR_INVALID_STATE) &&
  38.                 (err_code != BLE_ERROR_NO_TX_BUFFERS) &&
  39.                 (err_code != NRF_ERROR_BUSY) &&
  40.                 (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING))
  41.             {
  42.                 APP_ERROR_HANDLER(err_code);
  43.             }
  44.         }

  45.         err_code = dm_application_context_delete(p_handle);
  46.         APP_ERROR_CHECK(err_code);
  47.     }
  48.     else if (err_code == DM_NO_APP_CONTEXT)
  49.     {
  50.         // No context available. Ignore.
  51.     }
  52.     else
  53.     {
  54.         APP_ERROR_HANDLER(err_code);
  55.     }
  56. }


  57. / * *  @snippet  [ DFU BLE Reset prepare ]  * /
  58. /**@brief Function for preparing for system reset.
  59.  *
  60.  * @details This function implements @ref dfu_app_reset_prepare_t. It will be called by 
  61.  * @ref dfu_app_handler.c before entering the bootloader/DFU.
  62.  * This allows the current running application to shut down gracefully.
  63.  */
  64. static void reset_prepare(void)
  65. {
  66.     uint32_t err_code;

  67.     if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
  68.     {
  69.         // Disconnect from peer.
  70.         err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
  71.         APP_ERROR_CHECK(err_code);
  72.         err_code = bsp_indication_set(BSP_INDICATE_IDLE);
  73.         APP_ERROR_CHECK(err_code);
  74.     }
  75.     else
  76.     {
  77.         // If not connected, the device will be advertising. Hence stop the advertising.
  78.         advertising_stop();
  79.     }

  80.     err_code = ble_conn_params_stop();
  81.     APP_ERROR_CHECK(err_code);

  82.     nrf_delay_ms(500);
  83. }
  84. / * *  @snippet  [ DFU BLE Reset prepare ]  * /
  85. #endif // BLE_DFU_APP_SUPPORT

The above codes are all included with the macro BLE_DFU_APP_SUPPORT, so after adding these codes, you need to add the definition of this macro in the project settings.

PS: There is a project with dfu in the official hrs example. Open that project and search for this macro globally to find the above code related to dfu. The code here is copied from there.

 

Add the code to create the dfu service at the end of the services_init function in Main.c

 

static void services_init(void)

{

         ………………………

         ……………………….

#ifdef BLE_DFU_APP_SUPPORT

    /** @snippet [DFU BLE Service initialization] */

    ble_dfu_init_t   dfus_init;

 

    // Initialize the Device Firmware Update Service.

    memset(&dfus_init, 0, sizeof(dfus_init));

 

  

 dfus_init.evt_handler   = dfu_app_on_dfu_evt;

    dfus_init.error_handler = NULL;

    dfus_init.evt_handler   = dfu_app_on_dfu_evt;

    dfus_init.revision      = DFU_REVISION;

 

    err_code = ble_dfu_init(&m_dfus, &dfus_init);

    APP_ERROR_CHECK(err_code);

 

    dfu_app_reset_prepare_set(reset_prepare);

    dfu_app_dm_appl_instance_set(m_app_handle);

         #endif // BLE_DFU_APP_SUPPORT

}

Add the event handling function of dfu and the event handling function of the device_manage module to the event dispatch function




Add the following function and code to Main.c




At this time, after compiling and downloading the program, use the official nordic software nrf master control panel to connect to the device and you can see a small DFU icon in the upper right corner. Click that to upgrade.

PS: Don't forget to burn the bootloader




Then how do you jump to the bootloader to enter the upgrade mode after clicking the dfu icon.

Earlier we added the creation of dfu service in service_init.

A callback function dfu_app_on_dfu_evt is set in the function



When the DFU icon is clicked, a start instruction will be sent, which will be processed in the dfu_app_on_dfu_evt function



The Bootloader_start function is to make some settings and then jump to the bootloader



The above sd_power_gpregret_set function is to set a flag, indicating that the bootloader is booted from the app.

Corresponds to the judgment at the beginning of the bootloader code mentioned earlier



The bootloader example in Sdk is based on 51422 of 32Kram. If you use 51822 of 16kram, you need to modify the following address

 



In addition, once the bootloader is burned, the startup sequence of the device is no longer protocol stack->app

But protocol stack->bootloader->app

The bootloader will judge whether the app is valid or not. The implementation in the sdk is that only the app upgraded through the DFU mode will be considered valid, and some related flags should be set after the DFU mode is upgraded. DFU judges whether the app is valid or not by judging these signs, so if you use burning software to burn the app, because some signs are not set, the bootloader will consider the app invalid and will not start the app.


But it can be achieved by modifying the variables. Even if the app is burned by the burning software, the bootloader can start the app normally.

Open the bootloader_settings.c file in the bootlaoder project and modify the following variables.




If the watchdog is used in the application, the dfu also needs to be fed to the dog. The watchdog of 51822 will always run after it is turned on.

It’s best to set the watchdog to stop the watchdog during sleep, which is convenient for processing. Just feed the dog after waking up. It doesn’t matter how long you sleep, because the watchdog will not count during sleep.

Set the following two values ​​to 0 directly.



Add dog feeding code to bootloader code



PS: If the SDK used is a higher version, and the program itself already has a custom base UUID, at this time adding DFU code needs to modify the number of base UUIDs allowed to be added, because the default is 1, the service itself has been added, and DFU The service also uses a custom base UUID. At this time , an error occurs when the  sd_ble_uuid_vs_add   function is called in the ble_dfu_init initialization function  . So modify the number of custom UUIDs allowed to be set. Modify as follows:

Guess you like

Origin blog.csdn.net/lilifang_2011/article/details/72876736