如何为BLE 设备实现OTA DFU 空中升级功能(上)?
文章目錄
- 一、BLE peripheral 如何實(shí)現(xiàn)DFU?
- 1.1 Nordic Memory layout
- 1.2 Device Firmware Update process
- 二、如何實(shí)現(xiàn)Buttonless OTA DFU?
- 2.1 如何使用SDK 提供的Buttonless BLE DFU 示例?
- 2.2 如何執(zhí)行Buttonless BLE DFU 過程?
- 更多文章:
我們開發(fā)的BLE peripheral 設(shè)備通常都有代碼升級的需求,不管是解決先前的bug,還是增加新的功能。我們常用的PC 或手機(jī)都是直接聯(lián)網(wǎng)在線升級系統(tǒng)或軟件的,BLE 這類不直接接入互聯(lián)網(wǎng)且人機(jī)交互受限的嵌入式設(shè)備如何升級程序代碼呢?很多BLE peripheral 僅留出一個BLE 無線通訊接口,我們?nèi)绾瓮ㄟ^OTA 方式實(shí)現(xiàn)BLE 程序代碼的空中升級呢?我們?nèi)绾螌FU OTA 功能或服務(wù)作為一個模塊添加進(jìn)我們的工程中呢?
一、BLE peripheral 如何實(shí)現(xiàn)DFU?
在博文ARM 代碼燒錄方案與原理詳解 中談到,要實(shí)現(xiàn)DFU(Device Firmware Update) 功能一般需要bootloader 啟動引導(dǎo)代碼,且bootloader 與application 代碼是存儲在不同flash 區(qū)域的。
1.1 Nordic Memory layout
如果開發(fā)過Nordic 工程,我們知道藍(lán)牙協(xié)議棧softdevice 和application 代碼也是存儲在不同flash 區(qū)域的。DFU 實(shí)際上就是把新的程序代碼下載到本地設(shè)備,經(jīng)校驗通過后,搬移到原程序代碼存儲區(qū)的過程。我們要了解DFU 工作原理,需要先了解nordic memory 布局:
Nordic memory 主要分為四個部分:
- Application:我們實(shí)現(xiàn)業(yè)務(wù)邏輯的應(yīng)用程序代碼存放在該區(qū)域,用戶需要掉電保護(hù)的一些自定義數(shù)據(jù)存儲在Application data 區(qū)域,free 區(qū)域可用于暫存接收到的待升級固件代碼、也可用于暫存本設(shè)備產(chǎn)生的數(shù)據(jù);
- SoftDevice(BLE Protocol Stack):Nordic 以HEX 文件形式提供的BLE 協(xié)議棧代碼存放在該區(qū)域,我們根據(jù)芯片型號、SDK版本、業(yè)務(wù)需求等因素選擇合適的softdevice 版本;
- MBR(Master Boot Record):Nordic 引入MBR 主要是為了能借助DFU 更新Bootloader(我們可以借助Bootloader 將新的Application、Softdevice 或Bootloader 固件下載到某個Flash 空閑區(qū)域,完成校驗后使用新的固件代碼覆蓋原來的代碼,但bootloader 無法覆蓋自身,需要借助MBR 完成新bootloader 固件覆蓋舊代碼的任務(wù)), 系統(tǒng)上電都是從MBR 啟動的,所有的中斷異常也都是首先由MBR 處理再轉(zhuǎn)發(fā)給相應(yīng)的處理程序,因此MBR 也管理系統(tǒng)啟動流程,判斷是否有bootloader 代碼決定后續(xù)啟動bootloader 還是直接啟動application(MBR 代碼不可更新);
- MBR parameter storage:當(dāng)Bootloader 需要更新自身時,將新的bootloader 固件下載到本設(shè)備flash 空閑區(qū)域并完成校驗后,需要借助MBR 搬移新固件以覆蓋舊代碼。Bootloader 需要MBR 執(zhí)行哪些指令以及指令參數(shù)如何設(shè)置,這些信息都保存在MBR parameter storage 區(qū)域(由于從bootloader 切換到MBR 需系統(tǒng)重置,這些指令及參數(shù)需要保存在Flash 中而非RAM 中);
- Bootloader:主要用于更新固件代碼(比如application、softdevice、bootloader),當(dāng)我們有固件更新需求時,通過按鍵或者命令觸發(fā)設(shè)備進(jìn)入DFU 模式,bootloader 通過BLE、UART 或USB 方式將新的固件存儲到本設(shè)備空閑flash 內(nèi)(bootloader 可完全訪問softdevice 的API), 對新的固件進(jìn)行校驗(比如私鑰簽名校驗、Hash 完整性校驗、CRC 校驗等),校驗通過后搬移新的固件以覆蓋舊的固件(搬移bootloader 固件需借助MBR),然后激活新的固件,引導(dǎo)執(zhí)行 application;
- Bootloader settings:主要配合bootloader 完成DFU 過程,在Bootloader settings 區(qū)域記錄當(dāng)前固件的版本 / 大小 / CRC 值、設(shè)備廣播名與綁定信息、固件校驗信息(CRC32 值、SHA-256 哈希值、ECDSA_P256 數(shù)字簽名等)、固件更新進(jìn)度、固件激活進(jìn)度 等信息。為了防止在寫入 Bootloader settings(DFU 過程需要讀寫該區(qū)域信息) 時發(fā)生復(fù)位或掉電影響DFU 過程,SDK15 以后的版本引入了settings backup 機(jī)制(實(shí)際上就是復(fù)用了MBR parameter storage 區(qū)域),當(dāng)寫入Bootloader settings 時發(fā)生復(fù)位或掉電重啟后,可以從settings backup 區(qū)域讀取備份信息恢復(fù)DFU 過程。
由于MBR 需要知道Bootloader、MBR parameter storage、SoftDevice、Application 代碼的存儲地址,Bootloader 也需要知道Bootloader settings、MBR parameter storage 信息的存儲地址,上面每個存儲區(qū)域的地址范圍對于確定的Nordic 芯片和Softdevice 版本都有默認(rèn)值(主要是不同Nordic 芯片可供Application 使用得flash 空間大小不同,不同版本的softdevice 代碼占用flash 空間大小不同):
1.2 Device Firmware Update process
BLE 連接通信需要兩個設(shè)備BLE Peripheral / Slave 和BLE Central / Master,DFU 過程也需要兩個設(shè)備DFU target 和 DFU controller。DFU target 是要接收新的固件并升級固件的設(shè)備(比如手環(huán)、心率帶等),DFU controller 是發(fā)送新的固件并控制升級過程的設(shè)備(比如手機(jī)、網(wǎng)關(guān)等)。DFU 固件升級流程圖如下:
首先,進(jìn)入DFU mode 的方式有如下四種:
比較常用的是下面這兩種方式:
- 按鍵式ButtonPress DFU:DFU target 上電時長按某個按鍵進(jìn)入DFU 模式,適合有按鍵的設(shè)備使用;
- 非按鍵式Buttonless DFU:DFU target 接收到命令后自動進(jìn)入DFU 模式,整個升級過程DFU target 不需要任何人工干預(yù),適合完全封裝無按鍵的設(shè)備使用。該方式需要DFU target application 能夠接收并處理進(jìn)入DFU 模式的命令,Nordic SDK 示例工程 ble_app_buttonless_dfu 可以在接收到來自DFU controller 的升級命令后,將寄存器NRF_POWER->GPREGRET bit 0 設(shè)置為1,系統(tǒng)觸發(fā)軟件復(fù)位,從MBR 啟動Bootloader,Bootloader 檢測到滿足進(jìn)入DFU mode 的條件(NRF_POWER->GPREGRET 值為0xB1),便進(jìn)入DFU 模式開始固件升級過程。
DFU target 進(jìn)入DFU mode 后,開始等待接收數(shù)據(jù),這里分為兩個階段:
- Receive init packet and Prevalidation:DFU target 先接收到init packet,主要包含firmware 類型、大小、版本、hash 值、固件支持的硬件版本和softdevice ID、固件簽名類型及數(shù)字簽名等信息,DFU target 接收完init packet 后對這些信息進(jìn)行前期Prevalidation,主要是校驗待升級的固件是否由受信任方提供、是否跟當(dāng)前固件和硬件兼容等。如果預(yù)校驗通過,則更新Bootloader settings page 并準(zhǔn)備開始接收firmware;
- Receive firmware and Postvalidation:DFU target Prevalidation OK 后,開始接收firmware data,每接收4 KB 數(shù)據(jù)(也即1 page)回復(fù)一次CRC 校驗值,直到整個固件接收完畢,對其進(jìn)行Postvalidation,主要是Hash 完整性校驗。如果后期校驗通過,就會invalidate 無效化當(dāng)前固件,更新Bootloader settings page 并觸發(fā)軟件復(fù)位。
固件傳輸過程,根據(jù)傳輸方式的不同,可以分為有線升級和無線升級兩種:
- Wired DFU:通過有線通信方式來傳輸固件,比如UART、USB 等(目前Nordic SDK 僅對nRF52840 支持USB DFU);
- Wireless DFU(OTA DFU):通過無線通信方式來傳輸固件,比如BLE、ANT 等。
固件校驗過程,根據(jù)是否需要校驗數(shù)字簽名,也可分為開放升級和安全升級兩種:
- Open DFU:不對新的固件進(jìn)行數(shù)字簽名校驗(bootloader 除外),且優(yōu)先使用Single-bank 升級方式(目前Nordic SDK 僅支持通過USB 傳輸固件的方式進(jìn)行Open DFU);
- Secure DFU:需要對新的固件進(jìn)行數(shù)字簽名校驗,以防止惡意攻擊者偽造固件被接受并升級,特別是對OTA DFU 應(yīng)要求數(shù)字簽名校驗(Nordic SDK 建議對所有固件進(jìn)行數(shù)字簽名校驗)。
完成固件傳輸和校驗后,就開始進(jìn)行copy new firmware 的過程了,實(shí)際上就是使用新的固件覆蓋舊的固件。根據(jù)新固件和舊固件占用的存儲分區(qū)個數(shù),可分為雙分區(qū)升級和單分區(qū)升級兩種:
- Dual-bank DFU:將接收到的新固件先暫存在空閑存儲區(qū)Bank 1 中,完成數(shù)字簽名校驗和完整性校驗后,再擦除現(xiàn)有固件代碼(假設(shè)存儲在Bank 0 中),然后將Bank 1 中的新固件復(fù)制到Bank 0 處并激活(如果新固件校驗失敗,不影響現(xiàn)有固件的正常運(yùn)行)。雙分區(qū)升級需要足夠的空閑存儲區(qū)Bank 1 來存儲新固件,對存儲空間的要求較高,如果空閑存儲區(qū)不足以存儲新固件,則根據(jù)配置選擇是拒絕升級還是轉(zhuǎn)為單分區(qū)升級。下圖左邊展示了SoftDevice + Bootloader 的雙分區(qū)升級過程,右邊展示了Application 的雙分區(qū)升級過程:
- Single-bank DFU:進(jìn)入DFU 模式后先擦除當(dāng)前application 代碼,再把接收到的新固件存儲到原應(yīng)用所在的Bank 0 中(實(shí)際上相當(dāng)于直接使用新應(yīng)用替換舊應(yīng)用代碼),新固件接收完畢并通過校驗后直接激活(如果新固件校驗失敗,系統(tǒng)將保持DFU 模式繼續(xù)嘗試再次升級,因為原應(yīng)用程序已被擦除而不能再執(zhí)行)。單分區(qū)升級相比雙分區(qū)升級節(jié)省了一個Bank 空間,在系統(tǒng)資源比較緊張的情況下可以選用,Nordic SDK 默認(rèn)優(yōu)先使用雙分區(qū)升級方案。下圖左邊展示了SoftDevice + Bootloader 的單分區(qū)升級過程(因該過程會擦除application,完成SoftDevice + Bootloader 升級后還需要再進(jìn)行application 升級),右邊展示了Application 的單分區(qū)升級過程:
設(shè)備固件升級過程中,工程pca10040_s132_ble 中跟固件傳輸方式、固件版本校驗、固件簽名校驗、固件單雙區(qū)升級控制 等相關(guān)的宏變量配置如下:
// .\nRF5_SDK_17.0.2_d674dde\examples\dfu\secure_bootloader\pca10040_s132_ble\config\sdk_config.h// <e> NRF_DFU_TRANSPORT_BLE - BLE transport settings //========================================================== #define NRF_DFU_TRANSPORT_BLE 1 // <s> NRF_DFU_BLE_ADV_NAME - Default advertising name. #define NRF_DFU_BLE_ADV_NAME "DfuTarg"// <h> DFU security - nrf_dfu_validation - DFU validation //========================================================== // <q> NRF_DFU_APP_ACCEPT_SAME_VERSION - Whether to accept application upgrades with the same version as the current application. #define NRF_DFU_APP_ACCEPT_SAME_VERSION 1 // <q> NRF_DFU_APP_DOWNGRADE_PREVENTION - Check the firmware version and SoftDevice requirements of application (and SoftDevice) updates. #define NRF_DFU_APP_DOWNGRADE_PREVENTION 1 // <q> NRF_DFU_EXTERNAL_APP_VERSIONING - Require versioning for external applications. #define NRF_DFU_EXTERNAL_APP_VERSIONING 1 // <o> NRF_DFU_HW_VERSION - Device hardware version. #define NRF_DFU_HW_VERSION 52// <q> NRF_DFU_REQUIRE_SIGNED_APP_UPDATE - Require a valid signature to update the application or SoftDevice. #define NRF_DFU_REQUIRE_SIGNED_APP_UPDATE 1// <q> NRF_DFU_FORCE_DUAL_BANK_APP_UPDATES - Accept only dual-bank application updates. #define NRF_DFU_FORCE_DUAL_BANK_APP_UPDATES 0 // <q> NRF_DFU_SINGLE_BANK_APP_UPDATES - Place the application and the SoftDevice directly where they are supposed to be. #define NRF_DFU_SINGLE_BANK_APP_UPDATES 0// <h> BLE DFU security //========================================================== // <q> NRF_DFU_BLE_REQUIRES_BONDS - Require bond with peer. #define NRF_DFU_BLE_REQUIRES_BONDS 0Nordic SDK 提供的secure_bootloader 工程pca10040_s132_ble,默認(rèn)優(yōu)先采用Dual-bank DFU 方式,當(dāng)沒有足夠的空閑flash 空間時將切換到Single-bank DFU 方式,開發(fā)者可配置宏變量NRF_DFU_FORCE_DUAL_BANK_APP_UPDATES 為1 強(qiáng)制使用Dual-bank DFU (若空間不足則停止DFU 過程)。
Nordic SDK 默認(rèn)提供的是后臺式升級,對于工程ble_app_buttonless_dfu 來說,系統(tǒng)有兩段完全獨(dú)立的代碼:Application 和Bootloader,其中SoftDevice 是共用的,兩段獨(dú)立的程序都可以訪問SoftDevice API,也都有自己的藍(lán)牙廣播和藍(lán)牙連接。當(dāng)需要進(jìn)行DFU 時,在Application 中觸發(fā)進(jìn)入DFU mode,后面就交由Bootloader 完成固件的傳輸、校驗、激活過程。當(dāng)DFU target 從Application 跳轉(zhuǎn)到Bootloader 后,DFU controller 怎么判斷兩者是同一個設(shè)備呢?
DFU controller 可以通過相同的廣播名或設(shè)備地址來辨識出DFU target 的Application 連接和Bootloader 連接來自同一設(shè)備,但由于多數(shù)手機(jī)為了加快BLE 連接速度,常將首次連接發(fā)現(xiàn)的GATT Service 緩存到本地,下次連接若判斷為同一設(shè)備就會跳過服務(wù)發(fā)現(xiàn)過程直接從緩存讀取服務(wù)數(shù)據(jù),這就導(dǎo)致DFU controller 不能發(fā)現(xiàn)Bootloader 提供的DFU 服務(wù),也就無法順利完成DFU 過程。由此可見,DFU controller 應(yīng)不僅能辨識Application 連接和Bootloader 連接來自同一設(shè)備,還需要辨識當(dāng)前連接是Application 連接還是Bootloader 連接,這個問題該如何解決呢?
Nordic 為該問題提供了兩套方案:
- Unbonded DFU:DFU target 設(shè)備Application 和Bootloader 程序采用不同的藍(lán)牙設(shè)備地址,且Bootloader 程序的藍(lán)牙設(shè)備地址 = Application 程序的藍(lán)牙設(shè)備地址 + 1,這樣DFU controller 就可以區(qū)分Application 連接和Bootloader 連接,同時辨識出二者來自同一設(shè)備,由于藍(lán)牙設(shè)備地址不同,DFU controller 也會對Bootloader 連接執(zhí)行服務(wù)發(fā)現(xiàn)過程,發(fā)現(xiàn)Bootloader 提供的DFU 服務(wù),繼續(xù)進(jìn)行DFU 過程;
- Bonded DFU:DFU target 設(shè)備Application 和Bootloader 程序采用相同的藍(lán)牙設(shè)備地址,由于DFU target 和DFU controller 進(jìn)行了配對綁定過程,DFU target 可以主動向DFU controller 發(fā)送service changed indication,讓DFU controller 再執(zhí)行一次服務(wù)發(fā)現(xiàn)過程,讓DFU controller 可以發(fā)現(xiàn)Bootloader 提供的DFU 服務(wù),繼續(xù)進(jìn)行DFU 過程。
二、如何實(shí)現(xiàn)Buttonless OTA DFU?
對于BLE peripheral,通常都是電池供電,因此對其進(jìn)行固件升級通常都采用OTA DFU 方式(也即BLE DFU)。很多BLE peripheral 并沒有留出按鍵,需要人工干預(yù)的升級方式也不夠友好,因此BLE DFU 更多采用Buttonless DFU 方式升級固件。
本文使用的開發(fā)工具和示例工程如下:
- Development Kit:nRF52 DK;
- nRF5 SDK:nRF5_SDK_17.0.2_d674dde
- SoftDevice:s132_nrf52_7.2.0_softdevice.hex
- Bootloader:secure_bootloader_ble_s132_pca10040
- Application:ble_app_buttonless_dfu_pca10040_s132
- nRF Command Line Tools:nRF-Command-Line-Tools_10_10_0_Installer_64.exe(包含J-Link、nrfjprog、mergehex 命令集,可用于Nordic Soc 開發(fā)、燒錄 和調(diào)試)
- nRF Util:nrfutil-6.1.0.exe(提供nrfutil 命令集,可用于DFU package生成、Cryptographic key生成/管理/存儲、Bootloader settings 生成等),需Python 3.7 or later 支持
- Other Tools:Setup_EmbeddedStudio_ARM_v540b_win_x64.exe,nRF Connect-v4.24.3.apk,nRF Connect-setup-v3.6.1-ia32.exe,nRF.Toolbox.2.9.0.apk
2.1 如何使用SDK 提供的Buttonless BLE DFU 示例?
要實(shí)現(xiàn)無按鍵式的BLE 空中升級,需要往nRF52 DK 中燒錄SoftDevice(包含MBR)、Bootloader、Application 三部分。由于在DFU 過程中需要對新固件進(jìn)行Prevalidation 和Postvalidation,校驗過程主要是信息比對,Bootloader settings page 保存了當(dāng)前固件的屬性及校驗信息,init packet 包含了新固件的屬性及校驗信息。因此,首次向nRF52 DK 中燒錄Bootloader 和Application 時,也應(yīng)包含Bootloader settings page 信息(可由nrfutil 生成),制作DFU package 也應(yīng)包含固件版本及校驗信息(可由nrfutil 生成)。
首先,我們打開工程secure_bootloader_ble_s132_pca10040,編譯提示“uECC.h: No such file or directory”,我們在infocenter.nordicsemi.com 搜索關(guān)鍵詞“uECC” 得知micro_ecc backend 需要安裝(可能受限于版權(quán)要求,不能直接放到SDK 中),在.\nRF5_SDK_17.0.2_d674dde\external\micro-ecc 目錄下有自動化腳本build_all.bat,我們直接執(zhí)行該腳本即可自動安裝micro_ecc 密碼庫(需要電腦安裝Git、make 命令集和GCC compiler toolchain for ARM),安裝完成后會多一個micro-ecc 文件夾,里面就有uECC.h 文件和uECC.c 文件:
Nordic Cryptography library - nrf_crypto 分為nrf_crypto frontend 和nrf_crypto backends 兩部分,nrf_crypto frontend 對應(yīng)用程序提供統(tǒng)一的API,隱藏了不同nrf_crypto backends 的API 差異。我們可以根據(jù)硬件資源、版權(quán)等要求選擇合適的nrf_crypto backends,比如nRF52840 支持Arm CryptoCell CC310 cryptographic accelerator 建議選用CC310 backend(配合CryptoCell CC310 可以提高加解密效率),其它nRF52 芯片建議優(yōu)先選用micro-ecc backend(占用的存儲空間更小),若micro-ecc 無法滿足需求且不支持CryptoCell CC310 可選用mbed TLS backend(ARM 為嵌入式設(shè)備開發(fā)的支持TLS 協(xié)議的加解密算法,功能比micro-ecc 更強(qiáng)大):
工程secure_bootloader_ble_s132_pca10040 的sdk_config.h 中跟nrf_crypto 配置相關(guān)的宏變量如下(通過插件CMSIS_Configuration_Wizard.jar 查看sdk_config.h):
繼續(xù)編譯工程secure_bootloader_ble_s132_pca10040,提示#error “Debug public key not valid for production. Please see https://github.com/NordicSemiconductor/pc-nrfutil/blob/master/README.md to generate it”,大意是說dfu_public_key.c 文件中的公鑰是無效的,需要我們使用nrfutil 工具重新生成公私密鑰對。
如何利用nrfutil 生成公私密鑰對呢?我們可以查看Nordic 在線文檔Generating and displaying keys,也可以使用nrfutil keys --help 命令,獲知生成公私密鑰對的命令如下:
# Generate a private key and store it in a file named private.pem nrfutil keys generate private.pem# Display the public key that corresponds to the generated private key (in code format to be used with DFU) nrfutil keys display --key pk --format code private.pem# Write the public key that corresponds to the generated private key to the file public_key.c (in code format) nrfutil keys display --key pk --format code private.pem --out_file dfu_public_key.c該工程中的公鑰用于驗證DFU package 的數(shù)字簽名,與該公鑰配對的私鑰則用于為DFU package 進(jìn)行數(shù)字簽名。由于DFU 過程主要靠簽名校驗判斷固件升級包來源的可信性,為了保證DFU 過程的安全性,我們需要保管好生成的私鑰,后續(xù)每次升級固件都需要該私鑰對其簽名。
我們將生成的公鑰文件dfu_public_key.c 放到目錄.\nRF5_SDK_17.0.2_d674dde\examples\dfu 下并替換原有的同名文件。繼續(xù)編譯工程secure_bootloader_ble_s132_pca10040,這次工程順利編譯完成,將編譯生成的secure_bootloader_ble_s132_pca10040.hex 文件復(fù)制出來,這就是我們實(shí)現(xiàn)Buttonless BLE DFU 的Bootloader 程序代碼。
我們打開工程ble_app_buttonless_dfu_pca10040_s132,編譯完成后,將生成的ble_app_buttonless_dfu_pca10040_s132.hex 文件復(fù)制出來,這就是我們實(shí)現(xiàn)Buttonless BLE DFU 的Application 代碼。
SoftDevice 不需要我們編譯,Nordic SDK 直接提供的HEX 文件,我們從目錄.\nRF5_SDK_17.0.2_d674dde\components\softdevice\s132\hex 將s132_nrf52_7.2.0_softdevice.hex 文件復(fù)制出來,這就是我們實(shí)現(xiàn)Buttonless BLE DFU 的SoftDevice 代碼。
準(zhǔn)備好SoftDevice、Bootloader、Application 代碼文件,為方便后續(xù)DFU 過程的固件校驗,還需要生成包含固件版本等屬性信息的Bootloader settings 文件。
如何利用nrfutil 生成Bootloader settings 呢?我們可以查看Nordic 在線文檔Generating and displaying bootloader settings,也可以使用nrfutil settings generate --help 命令,獲知生成Bootloader settings的命令如下:
# Generate a bootloader settings page for an nRF52 device with the application ble_app_buttonless_dfu_pca10040_s132.hex installed, with application version string “1.0.0”, bootloader version 1, and bootloader settings version 2 (for SDK v17.0.2), and store it in a file named bl-settings.hex: nrfutil settings generate --family NRF52 --application ble_app_buttonless_dfu_pca10040_s132.hex --application-version-string "1.0.0" --bootloader-version 1 --bl-settings-version 2 bl-settings.hex# display the contents of the generated HEX file: nrfutil settings display bl-settings.hex生成實(shí)現(xiàn)Buttonless BLE DFU 功能的Bootloader settings 文件都包含哪些信息呢?我們可以查看生成的bl-settings.hex 文件內(nèi)容如下:
每個字段的含義都可以在struct nrf_dfu_settings_t 中查得,該數(shù)據(jù)結(jié)構(gòu)的聲明如下:
我們已經(jīng)生成了需要燒錄到nRF52 DK 中實(shí)現(xiàn)Buttonless BLE DFU 功能的四個程序文件,四個文件分別燒錄略繁瑣,我們可以先將其合并為一個hex 文件,再將其燒錄到目標(biāo)芯片中。
我們可以使用mergehex 命令實(shí)現(xiàn)多個hex 文件的合并,可以查看Nordic 在線文檔Merging files with mergehex,也可以使用mergehex --help 命令,獲知合并多個hex 文件的命令如下:
# Merge four HEX files into one file named all_ble_buttonless_dfu_nrf52832_s132.hexmergehex --merge s132_nrf52_7.2.0_softdevice.hex secure_bootloader_ble_s132_pca10040.hex bl-settings.hex ble_app_buttonless_dfu_pca10040_s132.hex --output all_ble_buttonless_dfu_nrf52832_s132.hex使用mergehex 命令將softdevice、bootloader、settings、application 合并為一個文件all_ble_buttonless_dfu_nrf52832_s132.hex 后,可以使用nrfjprog 命令將其燒錄到nRF52 DK 中(也可以使用nRF Connect for desktop --> Programmer 燒錄hex 文件)。我們可以查看Nordic 在線文檔Programming SoCs with nrfjprog,也可以使用nrfjprog --help 命令,獲知將hex 文件燒錄到目標(biāo)芯片中的命令如下:
# Erase all available user flash (including UICR) and program the file all_ble_buttonless_dfu_nrf52832_s132.hex to an nRF52 SoC nrfjprog --family NRF52 --program all_ble_buttonless_dfu_nrf52832_s132.hex --chiperase --verify --reset我們借助上面提供的nrfjprog 命令將合并后的代碼文件all_ble_buttonless_dfu_nrf52832_s132.hex 燒錄到nRF52 DK 中,系統(tǒng)正常啟動,我們可以通過nRF Connect 掃描并發(fā)現(xiàn)“Nordic_Buttonless” 設(shè)備。點(diǎn)擊“Connect” 連接成功后,可以看到“Secure DFU Service” 服務(wù),該服務(wù)包含“Buttonless DFU” Characteristic,下文嘗試使用該服務(wù)執(zhí)行BLE DFU 空中升級過程。
2.2 如何執(zhí)行Buttonless BLE DFU 過程?
要使用“Secure DFU Service” 進(jìn)行空中升級,還需要準(zhǔn)備DFU package。通常Bootloader 和Softdevice 更新頻率很低,Application 更新頻率較高,本文以空中升級application 固件為例,說明Buttonless BLE DFU 過程。
版本更新,最直觀的判斷標(biāo)識是版本號,工程ble_app_buttonless_dfu_pca10040_s132 暫不支持查詢軟件版本的命令,為了更直觀辨識新舊版本的差異,我們修改該工程的廣播名稱,原廣播名為"Nordic_Buttonless",我們修改為"Nordic_DFU_V110":
// .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_buttonless_dfu\main.c #define DEVICE_NAME "Nordic_DFU_V110" /**< Name of device. Will be included in the advertising data. */重新編譯工程,將生成的hex 文件添加版本號,修改后的app 文件為ble_app_buttonless_dfu_pca10040_s132_v110.hex,然后使用nrfutil 工具生成DFU package。
如何利用nrfutil 生成DFU package 呢?我們可以查看Nordic 在線文檔Generating DFU packages,也可以使用nrfutil pkg generate --help 命令,獲知生成DFU package 的命令如下:
# Generate a package called SDK1702_app_s132_v110.zip from the application file ble_app_buttonless_dfu_pca10040_s132_v110.hex with application version "1.1.0" that requires hardware version 52 and SoftDevice S132 v7.2.0 (0x0101) and is signed with the private key that is stored in private.pem nrfutil pkg generate --application ble_app_buttonless_dfu_pca10040_s132_v110.hex --application-version-string "1.1.0" --hw-version 52 --sd-req 0X0101 --key-file private.pem SDK1702_app_s132_v110.zip# Display the contents of the created dfu package SDK1702_app_s132_v110.zip nrfutil pkg display SDK1702_app_s132_v110.zip值得一提的是,nrfutil pkg generate 命令 “–sd-req” 參數(shù)需要制定SoftDevice firmware ID,幫助界面給出的列表并沒有包含s132_nrf52_7.2.0,我們該如何獲得s132_nrf52_7.2.0 的firmware ID 呢?到s132 所在的目錄 .\nRF5_SDK_17.0.2_d674dde\components\softdevice\s132\doc\s132_nrf52_7.2.0_release-notes.pdf,可以查得:
The Firmware ID of s132_nrf52_7.2.0 is 0x0101.
我們可以通過nrfutil pkg display ZIP_FILE 命令查看DFU package 的內(nèi)容,主要是 init packet file 和 firmware image file 相關(guān)的信息如下:
由于各部分hex 文件名都比較長,上面的命令也比較長,我們可以將其編輯進(jìn)shell 腳本里面(對于windows 系統(tǒng)就是.bat 批處理文件 ),后續(xù)制作DFU package 只需要執(zhí)行腳本即可:
- Unbonded BLE DFU procedure
有了DFU package(SDK1702_app_s132_v110.zip),我們就可以使用“Secure DFU Service” 進(jìn)行空中升級了,比如使用手機(jī)端nRF Connect for mobile 掃描發(fā)現(xiàn)并連接“Nordic_Buttonless” 設(shè)備 --> 點(diǎn)擊“DFU” 圖標(biāo) --> 選擇DFU package(SDK1702_app_s132_v110.zip)便開始DFU 過程(需將DFU package 傳到手機(jī)上),DFU 完成后設(shè)備廣播名變?yōu)?#34;Nordic_DFU_V110",說明固件升級成功了,操作圖示如下:
注意上圖“Nordic_Buttonless” 和“DFUTARG” 的藍(lán)牙設(shè)備地址關(guān)系,印證了前面介紹的Unbonded DFU 過程中DFU target 設(shè)備Bootloader 程序的藍(lán)牙設(shè)備地址 = Application 程序的藍(lán)牙設(shè)備地址 + 1,方便DFU controller 區(qū)分Application 連接和Bootloader 連接,發(fā)現(xiàn)Bootloader 提供的DFU 服務(wù)。
- Bonded BLE DFU procedure
Bootloader 如果啟用了NRF_DFU_BLE_REQUIRES_BONDS,則在執(zhí)行BLE DFU 前需要先執(zhí)行配對綁定過程,DFU target 拒絕來自未綁定DFU controller 的DFU 請求,Bonded DFU 安全性比Unbonded DFU 更高。我們在工程secure_bootloader_ble_s132_pca10040 中均啟用NRF_DFU_BLE_REQUIRES_BONDS 如下:
// .\nRF5_SDK_17.0.2_d674dde\examples\dfu\secure_bootloader\pca10040_s132_ble\config\sdk_config.h // <h> BLE DFU security //========================================================== // <q> NRF_DFU_BLE_REQUIRES_BONDS - Require bond with peer. #define NRF_DFU_BLE_REQUIRES_BONDS 1編譯工程,提示“#error NRF_DFU_BLE_REQUIRES_BONDS requires NRF_SDH_BLE_SERVICE_CHANGED. Please update the SoftDevice BLE stack configuration in sdk_config.h”。前面我們提到,Bonded DFU 過程中,DFU target 需要主動向DFU controller 發(fā)送service changed indication,讓DFU controller 可以發(fā)現(xiàn)Bootloader 提供的DFU 服務(wù),因此還需要啟用NRF_SDH_BLE_SERVICE_CHANGED 如下:
// .\nRF5_SDK_17.0.2_d674dde\examples\dfu\secure_bootloader\pca10040_s132_ble\config\sdk_config.h //========================================================== // <q> NRF_SDH_BLE_SERVICE_CHANGED - Include the Service Changed characteristic in the Attribute Table. #define NRF_SDH_BLE_SERVICE_CHANGED 1重新編譯工程,順利完成,我們將生成的secure_bootloader_ble_s132_pca10040.hex 文件復(fù)制出來(也可以添加_bond 以區(qū)別與前面的unbond)。然后,在工程ble_app_buttonless_dfu_pca10040_s132 中啟用NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS 如下:
// .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_buttonless_dfu\pca10040\s132\config\sdk_config.h // <h> ble_dfu - Device Firmware Update //========================================================== // <q> NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS - Buttonless DFU supports bonds. #define NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS 1重新編譯工程,順利完成,我們將生成的ble_app_buttonless_dfu_pca10040_s132.hex 文件復(fù)制出來(也可以添加_bond 以區(qū)別與前面的unbond),執(zhí)行前面介紹的生成Bootloader settings、合并燒錄hex 文件的過程,nRF52 DK 系統(tǒng)正常啟動,通過nRF Connect 連接“Nordic_Buttonless” 設(shè)備可以看到“Secure DFU Service” 服務(wù)。
我們將工程ble_app_buttonless_dfu_pca10040_s132 的DEVICE_NAME 改為“Nordic_DFU_V120”:
// .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_buttonless_dfu\main.c #define DEVICE_NAME "Nordic_DFU_V120" /**< Name of device. Will be included in the advertising data. */重新編譯工程,將生成的hex 文件改為ble_app_buttonless_dfu_pca10040_s132_v120.hex,執(zhí)行前面介紹的生成生成DFU package 過程,獲得DFU 升級包SDK1702_app_s132_v120.zip,將其傳到手機(jī)上用于DFU 升級。
手機(jī)端nRF Connect 執(zhí)行DFU 的操作跟前面Unbonded BLE DFU 類似,主要區(qū)別是在進(jìn)行DFU 之前需要先執(zhí)行配對綁定操作,圖示如下(點(diǎn)擊“DFU” 圖標(biāo)選擇DFU package 的過程跟前面完全一致,這里省略了):
Bonded BLE DFU procedure 不再出現(xiàn)“DFUTARG” 設(shè)備了,這樣印證了前面說到的,Bonded DFU 過程中DFU target 設(shè)備Application 和Bootloader 程序采用相同的藍(lán)牙設(shè)備地址,配對綁定后DFU target 可以主動向DFU controller 發(fā)送service changed indication,讓DFU controller 可以發(fā)現(xiàn)Bootloader 提供的DFU 服務(wù),繼續(xù)執(zhí)行DFU 過程。
本工程源碼下載地址:https://github.com/StreamAI/Nordic_nRF5_Project/tree/main/BLE_Buttonless_DFU。
更多文章:
- 《如何為BLE 設(shè)備添加OTA DFU 空中升級服務(wù)(下)?》
- 《如何實(shí)現(xiàn)BLE 最大數(shù)據(jù)吞吐率并滿足設(shè)計功耗要求?》
- 《如何抓包分析BLE 空口報文(GAP + GATT + LESC)?》
- 《如何實(shí)現(xiàn)掃碼連接BLE 設(shè)備的功能?》
- 《Nordic_nRF5_Project》
- 《Nordic nRF5 SDK documentation》
- 《BLE 技術(shù)(五)— Generic Access Profile + Pairing and Bonding》
- 《BLE 技術(shù)(六)— GATT Profile + Security Manager Protocol》
- 《Bluetooth Core Specification_v5.2》
總結(jié)
以上是生活随笔為你收集整理的如何为BLE 设备实现OTA DFU 空中升级功能(上)?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 创业基础(第六章:创业资源及其管理) 来
- 下一篇: 2PC、3PC