NRF52832空中升級DFU

Secure DFU環境搭建

升級原理,加密原理在此不作描述,詳情參考http://www.cnblogs.com/iini/p/9314246.htmlhtml


 

1.工具一覽

  • gcc-arm-none-eabi編譯環境:GCC編譯環境

           https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloadspython

  • mingw 平臺(win版的Linux命令行)

          https://sourceforge.net/projects/mingw/files/latest/download?sourcegit

  • micro-ecc-master源碼

          https://github.com/kmackay/micro-eccgithub

  • python 安裝文件

          https://www.python.org/downloads/算法

  • pc-nrfutil

         https://github.com/NordicSemiconductor/pc-nrfutil/windows

  • nrfgo-studio
  • nrf connect app

 

2.安裝指導

Secure DFU須要micro-ecc庫進行簽名驗證,須要micro_ecc_lib_nrf52.lib,須要使用GCC編譯器生成。瀏覽器

2.1 gcc-arm-none-eabi安裝

gcc-arm-none-eabi-4_9-2015q3-20150921-win32.exe,直接雙擊安裝,注意使用默認安裝路徑,不要修改app

安裝完成less


 

2.2 mingw 平臺安裝

雙擊mingw-get-setup.exe,點擊install進行安裝,選擇默認路徑async

安裝好後彈出package包安裝界面MinGW Installation Manager,按下圖所示進行選擇

選擇後,點擊InstallationàApply Changes


 

2.3 mingw 環境變量配置

 安裝好MinGW,須要在系統環境變量Path添加路徑

平臺安裝驗證:

修改好系統環境變量後,重啓電腦,運行命令提示符,以下所示則安裝成功


2.4 micro-ecc庫生成

須要生成micro_ecc_lib_nrf52.lib,也可直接使用已經編譯好的文件micro-ecc_sdk14_15_newer.rar解壓後替換micro-ecc文件夾。

1.將micro-ecc-master源碼複製到SDK目錄下的external\micro-ecc中,並重命名爲micro-ecc

2.打開MinGW的命令行msys.bat

在批處理框裏輸入要生成庫的gcc算法路徑

cd E:/keil_workspace/NORDIC/nRF5_SDK_15.0.0_a53641a/external/micro-ecc/nrf52hf_keil/armgcc

 

以後輸入make

出現錯誤後,按照提示修改gcc的Makefile.windows文件以下

 

將gcc編譯器路徑更換爲實際路徑

#GNU_INSTALL_ROOT := C:/Program Files (x86)/GNU Tools ARM Embedded/6 2017-q2-update/bin/

GNU_INSTALL_ROOT := C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2015q3/bin/

#GNU_VERSION := 6.3.1

GNU_VERSION := 6.3.0

GNU_PREFIX := arm-none-eabi

 修改以後,編譯OK


 

2.5 python 安裝

1.雙擊python-2.7.14.amd64.msi安裝,注意使用默認路徑,安裝過程使用默認插件配置直接一直next。

2.系統環境變量添加

3.安裝驗證

修改環境變量後重啓電腦,命令行輸入python -V


 

2.6 nrfutil工具安裝

須要聯網

打開命令行,輸入pip install nrfutil安裝nrfutil

安裝完成後,輸入nrfutil version,以下則表示安裝成功


 

3.升級文件製做

爲便於調試與生產上的燒錄,編寫一些 bat 文件來操做nrfutil工具指令

工程在sdk中的目錄 E:\keil_workspace\NORDIC\nRF52832_htwh_sdk15.0\examples\ble_peripheral\ble_app_gnt_freertos-release

腳本文件目錄 E:\keil_workspace\NORDIC\nRF52832_htwh_sdk15.0\examples\ble_peripheral\ble_app_gnt_freertos-release\wh_Script_SDK15_S132_nRF52832_GNT

 3.1 密鑰生成文件

key_generate.bat

生成的 dfu_public_key.c 文件會拷貝到 dfu 文件夾下供 secure_bootloader 使用 

@echo off

pause
echo "執行以前須要確認文件路徑,修改完成後可註釋..."
pause


::1)經過nrfutil生產私鑰和公鑰文件
::generate private key
nrfutil keys generate priv.pem
::generate public key related with private key: priv.pem
nrfutil keys display --key pk --format code priv.pem --out_file dfu_public_key.c


::2)複製dfu_public_key.c文件到dfu工程
::修改指定文件夾或文件本身修改ObjPath源文件位置,HexDestPath目標文件或文件夾位置
set ObjPath=dfu_public_key.c

set HexDestPath=E:\keil_workspace\NORDIC\nRF52832_htwh_sdk15.0\examples\dfu

::複製指定路徑指定文件或文件夾,至HexDestPath路徑文件夾
echo y | xcopy "%ObjPath%" /e /r /k "%HexDestPath%"
::xcopy /e/c/h/z "%~pd0*.*" "%out%"

pause

3.2 升級包製做bat文件

zip_generate.bat

文件中的工程目錄請根據實際路徑修改

@echo off

::1)複製工程hex文件到指定文件夾, 需設置文件地址
::修改指定文件夾或文件本身修改ObjPath源文件位置,HexDestPath目標文件或文件夾位置
set ObjPath=E:\keil_workspace\NORDIC\nRF52832_htwh_sdk15.0\examples\ble_peripheral\ble_app_gnt_freertos-release\pca10040\s132\arm5_no_packs\_build\gnt_app.hex

set HexDestPath=E:\keil_workspace\NORDIC\nRF52832_htwh_sdk15.0\examples\ble_peripheral\ble_app_gnt_freertos-release\wh_Script_SDK15_S132_nRF52832_GNT

::複製指定路徑指定文件或文件夾,至HexDestPath路徑文件夾
echo y | xcopy "%ObjPath%" /e /r /k "%HexDestPath%"
::xcopy /e/c/h/z "%~pd0*.*" "%out%"


::2)生成升級用zip文件
::nrfutil.exe pkg generate --hw-version 52 --application-version 1 --application gnt_app.hex --sd-req 0xA8 --key-file private.key gnt_app_Dfu15.zip

nrfutil pkg generate --hw-version 52 --application-version 1 --application gnt_app.hex --sd-req 0xA8 --key-file private.key gnt_app_Dfu15.zip


::pause 

3.2 生產燒錄文件製做bat文件

 會將應用gnt_app.hex、bootloader.hex、settings.hex、s132_nrf52_6.0.0_softdevice.hex這四個程序合爲whole.hex,用於生產燒錄;

 mergehex.bat

@echo off

::1)生成 settings page for current image: gnt_app.hex
::Bootloader settings存儲在Flash最後一個page,它將決定復位後芯片的行爲,好比是進入DFU模式仍是應用模式,同時它還包含image的CRC值和版本等信息。若是要求芯片復位後進入application,必須正確生成該bootloader settings hex

nrfutil settings generate --family NRF52 --application gnt_app.hex --application-version 1 --bootloader-version 1 --bl-settings-version 1 settings.hex


::2)合成一個hex用於生產燒錄
::merge bootloader and settings
mergehex.exe --merge bootloader.hex settings.hex --output bl_temp.hex
::merge bootloader, app and softdevice
mergehex.exe --merge bl_temp.hex gnt_app.hex s132_nrf52_6.0.0_softdevice.hex --output whole.hex

::pause 

::merge bootloader and settings

4.工程添加DFU服務

1.工程文件

工程文件添加

頭文件路徑包含

2.工程內容修改

在main.c中添加 DFU 服務支持

// 頭文件包含
#if (DFU_SUPPORT == 1)
#include "nrf_dfu_ble_svci_bond_sharing.h"
#include "nrf_svci_async_function.h"
#include "nrf_svci_async_handler.h"
#include "ble_dfu.h"
#include "nrf_power.h"
#include "nrf_bootloader_info.h"
#endif

#if (DFU_SUPPORT == 1)

// 進入DFU,應用關機以前的一些操做,註冊到power manager電源管理中
static bool app_shutdown_handler(nrf_pwr_mgmt_evt_t event)
{
    switch (event)
    {
        case NRF_PWR_MGMT_EVT_PREPARE_DFU:
            NRF_LOG_INFO("Power management wants to reset to DFU mode.");
            #if (GNT_WDT_EN == 1)
            my_wdt_feed();
            #endif
            
            break;

        default:
            // YOUR_JOB: Implement any of the other events available from the power management module:
            //      -NRF_PWR_MGMT_EVT_PREPARE_SYSOFF
            //      -NRF_PWR_MGMT_EVT_PREPARE_WAKEUP
            //      -NRF_PWR_MGMT_EVT_PREPARE_RESET
            return true;
    }

    NRF_LOG_INFO("Power management allowed to reset to DFU mode.");
    return true;
}

// 註冊應用關機事件處理函數(經常使用於關機前須要進行的一些操做:如flash操做,控制模塊的關閉等)
NRF_PWR_MGMT_HANDLER_REGISTER(app_shutdown_handler, 0);

static void buttonless_dfu_sdh_state_observer(nrf_sdh_state_evt_t state, void * p_context)
{
    if (state == NRF_SDH_EVT_STATE_DISABLED)
    {
        NRF_LOG_INFO("NRF_SDH_EVT_STATE_DISABLED to DFU mode.");
        // Softdevice was disabled before going into reset. Inform bootloader to skip CRC on next boot.
        nrf_power_gpregret2_set(BOOTLOADER_DFU_SKIP_CRC);

        //Go to system off.
        nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
    }
}

/* nrf_sdh state observer. */
NRF_SDH_STATE_OBSERVER(m_buttonless_dfu_state_obs, 0) =
{
    .handler = buttonless_dfu_sdh_state_observer,
};

#endif


#if (DFU_SUPPORT == 1)
/**@brief Function for handling dfu events from the Buttonless Secure DFU service
 *
 * @param[in]   event   Event from the Buttonless Secure DFU service.
 */
static void ble_dfu_evt_handler(ble_dfu_buttonless_evt_type_t event)
{
    switch (event)
    {
        case BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE:
            NRF_LOG_INFO("Device is preparing to enter bootloader mode.");
            // YOUR_JOB: Disconnect all bonded devices that currently are connected.
            //           This is required to receive a service changed indication
            //           on bootup after a successful (or aborted) Device Firmware Update.
            break;

        case BLE_DFU_EVT_BOOTLOADER_ENTER:
            // YOUR_JOB: Write app-specific unwritten data to FLASH, control finalization of this
            //           by delaying reset by reporting false in app_shutdown_handler
            NRF_LOG_INFO("Device will enter bootloader mode.");
            break;

        case BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED:
            NRF_LOG_ERROR("Request to enter bootloader mode failed asynchroneously.");
            // YOUR_JOB: Take corrective measures to resolve the issue
            //           like calling APP_ERROR_CHECK to reset the device.
            break;

        case BLE_DFU_EVT_RESPONSE_SEND_ERROR:
            NRF_LOG_ERROR("Request to send a response to client failed.");
            // YOUR_JOB: Take corrective measures to resolve the issue
            //           like calling APP_ERROR_CHECK to reset the device.
            APP_ERROR_CHECK(false);
            break;

        default:
            NRF_LOG_ERROR("Unknown event from ble_dfu_buttonless.");
            break;
    }
}
#endif


static void services_init(void)
{
    ret_code_t         err_code;
    nrf_ble_qwr_init_t qwr_init = {0};

    // Initialize Queued Write Module.
    qwr_init.error_handler = nrf_qwr_error_handler;

    err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
    APP_ERROR_CHECK(err_code);
    
    
    // 添加GPS_NB_TAG服務
    ble_gnts_init_t     gnts_init;
    
    memset(&gnts_init, 0, sizeof(gnts_init));
    gnts_init.data_handler = gnts_data_handler;

    err_code = ble_gnts_init(&m_gnts, &gnts_init);
    APP_ERROR_CHECK(err_code);  
    
#if (DFU_SUPPORT == 1)
    ble_dfu_buttonless_init_t dfus_init = {0};
    // Initialize the async SVCI interface to bootloader.
    err_code = ble_dfu_buttonless_async_svci_init();
    APP_ERROR_CHECK(err_code);

    dfus_init.evt_handler = ble_dfu_evt_handler;

    err_code = ble_dfu_buttonless_init(&dfus_init);
    APP_ERROR_CHECK(err_code);
#endif
    
}

3. sdk_config.h 文件設置


 

 

 另外 bootloader 工程中須要設置進入boot方式

 

 5. 實際測試

用keil編譯工程以後,運行bat文件生成升級用 zip 包

鏈接設備藍牙

1.使能Buttonless DFU的CCCD項;

2.點擊按鍵2

 

點擊SEND,設備進入boot模式,關閉當前鏈接,進入掃描項SCAN,鏈接DfuTrag

點擊右上角的DFU小圖標,選擇ZIP文件(SDK12以後僅支持ZIP格式升級),點擊OK,進入文件瀏覽器選擇升級文件後自動開始升級,到100%時升級完成。

相關文章
相關標籤/搜索