Secure DFU環境搭建
升級原理,加密原理在此不做描述,詳情參考http://www.cnblogs.com/iini/p/9314246.html
1.工具一覽
- gcc-arm-none-eabi編譯環境:GCC編譯環境
https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads
- mingw 平台(win版的Linux命令行)
https://sourceforge.net/projects/mingw/files/latest/download?source
- micro-ecc-master源碼
https://github.com/kmackay/micro-ecc
- python 安裝文件
https://www.python.org/downloads/
- pc-nrfutil
https://github.com/NordicSemiconductor/pc-nrfutil/
- 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,直接雙擊安裝,注意使用默認安裝路徑,不要修改
安裝完成
2.2 mingw 平台安裝
雙擊mingw-get-setup.exe,點擊install進行安裝,選擇默認路徑
安裝好后彈出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%時升級完成。