如何为BLE 设备实现OTA DFU 空中升级功能(上)?
文章目錄
- 一、BLE peripheral 如何實現DFU?
- 1.1 Nordic Memory layout
- 1.2 Device Firmware Update process
- 二、如何實現Buttonless OTA DFU?
- 2.1 如何使用SDK 提供的Buttonless BLE DFU 示例?
- 2.2 如何執行Buttonless BLE DFU 過程?
- 更多文章:
我們開發的BLE peripheral 設備通常都有代碼升級的需求,不管是解決先前的bug,還是增加新的功能。我們常用的PC 或手機都是直接聯網在線升級系統或軟件的,BLE 這類不直接接入互聯網且人機交互受限的嵌入式設備如何升級程序代碼呢?很多BLE peripheral 僅留出一個BLE 無線通訊接口,我們如何通過OTA 方式實現BLE 程序代碼的空中升級呢?我們如何將DFU OTA 功能或服務作為一個模塊添加進我們的工程中呢?
一、BLE peripheral 如何實現DFU?
在博文ARM 代碼燒錄方案與原理詳解 中談到,要實現DFU(Device Firmware Update) 功能一般需要bootloader 啟動引導代碼,且bootloader 與application 代碼是存儲在不同flash 區域的。
1.1 Nordic Memory layout
如果開發過Nordic 工程,我們知道藍牙協議棧softdevice 和application 代碼也是存儲在不同flash 區域的。DFU 實際上就是把新的程序代碼下載到本地設備,經校驗通過后,搬移到原程序代碼存儲區的過程。我們要了解DFU 工作原理,需要先了解nordic memory 布局:
Nordic memory 主要分為四個部分:
- Application:我們實現業務邏輯的應用程序代碼存放在該區域,用戶需要掉電保護的一些自定義數據存儲在Application data 區域,free 區域可用于暫存接收到的待升級固件代碼、也可用于暫存本設備產生的數據;
- SoftDevice(BLE Protocol Stack):Nordic 以HEX 文件形式提供的BLE 協議棧代碼存放在該區域,我們根據芯片型號、SDK版本、業務需求等因素選擇合適的softdevice 版本;
- MBR(Master Boot Record):Nordic 引入MBR 主要是為了能借助DFU 更新Bootloader(我們可以借助Bootloader 將新的Application、Softdevice 或Bootloader 固件下載到某個Flash 空閑區域,完成校驗后使用新的固件代碼覆蓋原來的代碼,但bootloader 無法覆蓋自身,需要借助MBR 完成新bootloader 固件覆蓋舊代碼的任務), 系統上電都是從MBR 啟動的,所有的中斷異常也都是首先由MBR 處理再轉發給相應的處理程序,因此MBR 也管理系統啟動流程,判斷是否有bootloader 代碼決定后續啟動bootloader 還是直接啟動application(MBR 代碼不可更新);
- MBR parameter storage:當Bootloader 需要更新自身時,將新的bootloader 固件下載到本設備flash 空閑區域并完成校驗后,需要借助MBR 搬移新固件以覆蓋舊代碼。Bootloader 需要MBR 執行哪些指令以及指令參數如何設置,這些信息都保存在MBR parameter storage 區域(由于從bootloader 切換到MBR 需系統重置,這些指令及參數需要保存在Flash 中而非RAM 中);
- Bootloader:主要用于更新固件代碼(比如application、softdevice、bootloader),當我們有固件更新需求時,通過按鍵或者命令觸發設備進入DFU 模式,bootloader 通過BLE、UART 或USB 方式將新的固件存儲到本設備空閑flash 內(bootloader 可完全訪問softdevice 的API), 對新的固件進行校驗(比如私鑰簽名校驗、Hash 完整性校驗、CRC 校驗等),校驗通過后搬移新的固件以覆蓋舊的固件(搬移bootloader 固件需借助MBR),然后激活新的固件,引導執行 application;
- Bootloader settings:主要配合bootloader 完成DFU 過程,在Bootloader settings 區域記錄當前固件的版本 / 大小 / CRC 值、設備廣播名與綁定信息、固件校驗信息(CRC32 值、SHA-256 哈希值、ECDSA_P256 數字簽名等)、固件更新進度、固件激活進度 等信息。為了防止在寫入 Bootloader settings(DFU 過程需要讀寫該區域信息) 時發生復位或掉電影響DFU 過程,SDK15 以后的版本引入了settings backup 機制(實際上就是復用了MBR parameter storage 區域),當寫入Bootloader settings 時發生復位或掉電重啟后,可以從settings backup 區域讀取備份信息恢復DFU 過程。
由于MBR 需要知道Bootloader、MBR parameter storage、SoftDevice、Application 代碼的存儲地址,Bootloader 也需要知道Bootloader settings、MBR parameter storage 信息的存儲地址,上面每個存儲區域的地址范圍對于確定的Nordic 芯片和Softdevice 版本都有默認值(主要是不同Nordic 芯片可供Application 使用得flash 空間大小不同,不同版本的softdevice 代碼占用flash 空間大小不同):
1.2 Device Firmware Update process
BLE 連接通信需要兩個設備BLE Peripheral / Slave 和BLE Central / Master,DFU 過程也需要兩個設備DFU target 和 DFU controller。DFU target 是要接收新的固件并升級固件的設備(比如手環、心率帶等),DFU controller 是發送新的固件并控制升級過程的設備(比如手機、網關等)。DFU 固件升級流程圖如下:
首先,進入DFU mode 的方式有如下四種:
比較常用的是下面這兩種方式:
- 按鍵式ButtonPress DFU:DFU target 上電時長按某個按鍵進入DFU 模式,適合有按鍵的設備使用;
- 非按鍵式Buttonless DFU:DFU target 接收到命令后自動進入DFU 模式,整個升級過程DFU target 不需要任何人工干預,適合完全封裝無按鍵的設備使用。該方式需要DFU target application 能夠接收并處理進入DFU 模式的命令,Nordic SDK 示例工程 ble_app_buttonless_dfu 可以在接收到來自DFU controller 的升級命令后,將寄存器NRF_POWER->GPREGRET bit 0 設置為1,系統觸發軟件復位,從MBR 啟動Bootloader,Bootloader 檢測到滿足進入DFU mode 的條件(NRF_POWER->GPREGRET 值為0xB1),便進入DFU 模式開始固件升級過程。
DFU target 進入DFU mode 后,開始等待接收數據,這里分為兩個階段:
- Receive init packet and Prevalidation:DFU target 先接收到init packet,主要包含firmware 類型、大小、版本、hash 值、固件支持的硬件版本和softdevice ID、固件簽名類型及數字簽名等信息,DFU target 接收完init packet 后對這些信息進行前期Prevalidation,主要是校驗待升級的固件是否由受信任方提供、是否跟當前固件和硬件兼容等。如果預校驗通過,則更新Bootloader settings page 并準備開始接收firmware;
- Receive firmware and Postvalidation:DFU target Prevalidation OK 后,開始接收firmware data,每接收4 KB 數據(也即1 page)回復一次CRC 校驗值,直到整個固件接收完畢,對其進行Postvalidation,主要是Hash 完整性校驗。如果后期校驗通過,就會invalidate 無效化當前固件,更新Bootloader settings page 并觸發軟件復位。
固件傳輸過程,根據傳輸方式的不同,可以分為有線升級和無線升級兩種:
- Wired DFU:通過有線通信方式來傳輸固件,比如UART、USB 等(目前Nordic SDK 僅對nRF52840 支持USB DFU);
- Wireless DFU(OTA DFU):通過無線通信方式來傳輸固件,比如BLE、ANT 等。
固件校驗過程,根據是否需要校驗數字簽名,也可分為開放升級和安全升級兩種:
- Open DFU:不對新的固件進行數字簽名校驗(bootloader 除外),且優先使用Single-bank 升級方式(目前Nordic SDK 僅支持通過USB 傳輸固件的方式進行Open DFU);
- Secure DFU:需要對新的固件進行數字簽名校驗,以防止惡意攻擊者偽造固件被接受并升級,特別是對OTA DFU 應要求數字簽名校驗(Nordic SDK 建議對所有固件進行數字簽名校驗)。
完成固件傳輸和校驗后,就開始進行copy new firmware 的過程了,實際上就是使用新的固件覆蓋舊的固件。根據新固件和舊固件占用的存儲分區個數,可分為雙分區升級和單分區升級兩種:
- Dual-bank DFU:將接收到的新固件先暫存在空閑存儲區Bank 1 中,完成數字簽名校驗和完整性校驗后,再擦除現有固件代碼(假設存儲在Bank 0 中),然后將Bank 1 中的新固件復制到Bank 0 處并激活(如果新固件校驗失敗,不影響現有固件的正常運行)。雙分區升級需要足夠的空閑存儲區Bank 1 來存儲新固件,對存儲空間的要求較高,如果空閑存儲區不足以存儲新固件,則根據配置選擇是拒絕升級還是轉為單分區升級。下圖左邊展示了SoftDevice + Bootloader 的雙分區升級過程,右邊展示了Application 的雙分區升級過程:
- Single-bank DFU:進入DFU 模式后先擦除當前application 代碼,再把接收到的新固件存儲到原應用所在的Bank 0 中(實際上相當于直接使用新應用替換舊應用代碼),新固件接收完畢并通過校驗后直接激活(如果新固件校驗失敗,系統將保持DFU 模式繼續嘗試再次升級,因為原應用程序已被擦除而不能再執行)。單分區升級相比雙分區升級節省了一個Bank 空間,在系統資源比較緊張的情況下可以選用,Nordic SDK 默認優先使用雙分區升級方案。下圖左邊展示了SoftDevice + Bootloader 的單分區升級過程(因該過程會擦除application,完成SoftDevice + Bootloader 升級后還需要再進行application 升級),右邊展示了Application 的單分區升級過程:
設備固件升級過程中,工程pca10040_s132_ble 中跟固件傳輸方式、固件版本校驗、固件簽名校驗、固件單雙區升級控制 等相關的宏變量配置如下:
// .\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,默認優先采用Dual-bank DFU 方式,當沒有足夠的空閑flash 空間時將切換到Single-bank DFU 方式,開發者可配置宏變量NRF_DFU_FORCE_DUAL_BANK_APP_UPDATES 為1 強制使用Dual-bank DFU (若空間不足則停止DFU 過程)。
Nordic SDK 默認提供的是后臺式升級,對于工程ble_app_buttonless_dfu 來說,系統有兩段完全獨立的代碼:Application 和Bootloader,其中SoftDevice 是共用的,兩段獨立的程序都可以訪問SoftDevice API,也都有自己的藍牙廣播和藍牙連接。當需要進行DFU 時,在Application 中觸發進入DFU mode,后面就交由Bootloader 完成固件的傳輸、校驗、激活過程。當DFU target 從Application 跳轉到Bootloader 后,DFU controller 怎么判斷兩者是同一個設備呢?
DFU controller 可以通過相同的廣播名或設備地址來辨識出DFU target 的Application 連接和Bootloader 連接來自同一設備,但由于多數手機為了加快BLE 連接速度,常將首次連接發現的GATT Service 緩存到本地,下次連接若判斷為同一設備就會跳過服務發現過程直接從緩存讀取服務數據,這就導致DFU controller 不能發現Bootloader 提供的DFU 服務,也就無法順利完成DFU 過程。由此可見,DFU controller 應不僅能辨識Application 連接和Bootloader 連接來自同一設備,還需要辨識當前連接是Application 連接還是Bootloader 連接,這個問題該如何解決呢?
Nordic 為該問題提供了兩套方案:
- Unbonded DFU:DFU target 設備Application 和Bootloader 程序采用不同的藍牙設備地址,且Bootloader 程序的藍牙設備地址 = Application 程序的藍牙設備地址 + 1,這樣DFU controller 就可以區分Application 連接和Bootloader 連接,同時辨識出二者來自同一設備,由于藍牙設備地址不同,DFU controller 也會對Bootloader 連接執行服務發現過程,發現Bootloader 提供的DFU 服務,繼續進行DFU 過程;
- Bonded DFU:DFU target 設備Application 和Bootloader 程序采用相同的藍牙設備地址,由于DFU target 和DFU controller 進行了配對綁定過程,DFU target 可以主動向DFU controller 發送service changed indication,讓DFU controller 再執行一次服務發現過程,讓DFU controller 可以發現Bootloader 提供的DFU 服務,繼續進行DFU 過程。
二、如何實現Buttonless OTA DFU?
對于BLE peripheral,通常都是電池供電,因此對其進行固件升級通常都采用OTA DFU 方式(也即BLE DFU)。很多BLE peripheral 并沒有留出按鍵,需要人工干預的升級方式也不夠友好,因此BLE DFU 更多采用Buttonless DFU 方式升級固件。
本文使用的開發工具和示例工程如下:
- 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 開發、燒錄 和調試)
- 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 示例?
要實現無按鍵式的BLE 空中升級,需要往nRF52 DK 中燒錄SoftDevice(包含MBR)、Bootloader、Application 三部分。由于在DFU 過程中需要對新固件進行Prevalidation 和Postvalidation,校驗過程主要是信息比對,Bootloader settings page 保存了當前固件的屬性及校驗信息,init packet 包含了新固件的屬性及校驗信息。因此,首次向nRF52 DK 中燒錄Bootloader 和Application 時,也應包含Bootloader settings page 信息(可由nrfutil 生成),制作DFU package 也應包含固件版本及校驗信息(可由nrfutil 生成)。
首先,我們打開工程secure_bootloader_ble_s132_pca10040,編譯提示“uECC.h: No such file or directory”,我們在infocenter.nordicsemi.com 搜索關鍵詞“uECC” 得知micro_ecc backend 需要安裝(可能受限于版權要求,不能直接放到SDK 中),在.\nRF5_SDK_17.0.2_d674dde\external\micro-ecc 目錄下有自動化腳本build_all.bat,我們直接執行該腳本即可自動安裝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 對應用程序提供統一的API,隱藏了不同nrf_crypto backends 的API 差異。我們可以根據硬件資源、版權等要求選擇合適的nrf_crypto backends,比如nRF52840 支持Arm CryptoCell CC310 cryptographic accelerator 建議選用CC310 backend(配合CryptoCell CC310 可以提高加解密效率),其它nRF52 芯片建議優先選用micro-ecc backend(占用的存儲空間更小),若micro-ecc 無法滿足需求且不支持CryptoCell CC310 可選用mbed TLS backend(ARM 為嵌入式設備開發的支持TLS 協議的加解密算法,功能比micro-ecc 更強大):
工程secure_bootloader_ble_s132_pca10040 的sdk_config.h 中跟nrf_crypto 配置相關的宏變量如下(通過插件CMSIS_Configuration_Wizard.jar 查看sdk_config.h):
繼續編譯工程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 的數字簽名,與該公鑰配對的私鑰則用于為DFU package 進行數字簽名。由于DFU 過程主要靠簽名校驗判斷固件升級包來源的可信性,為了保證DFU 過程的安全性,我們需要保管好生成的私鑰,后續每次升級固件都需要該私鑰對其簽名。
我們將生成的公鑰文件dfu_public_key.c 放到目錄.\nRF5_SDK_17.0.2_d674dde\examples\dfu 下并替換原有的同名文件。繼續編譯工程secure_bootloader_ble_s132_pca10040,這次工程順利編譯完成,將編譯生成的secure_bootloader_ble_s132_pca10040.hex 文件復制出來,這就是我們實現Buttonless BLE DFU 的Bootloader 程序代碼。
我們打開工程ble_app_buttonless_dfu_pca10040_s132,編譯完成后,將生成的ble_app_buttonless_dfu_pca10040_s132.hex 文件復制出來,這就是我們實現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 文件復制出來,這就是我們實現Buttonless BLE DFU 的SoftDevice 代碼。
準備好SoftDevice、Bootloader、Application 代碼文件,為方便后續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生成實現Buttonless BLE DFU 功能的Bootloader settings 文件都包含哪些信息呢?我們可以查看生成的bl-settings.hex 文件內容如下:
每個字段的含義都可以在struct nrf_dfu_settings_t 中查得,該數據結構的聲明如下:
我們已經生成了需要燒錄到nRF52 DK 中實現Buttonless BLE DFU 功能的四個程序文件,四個文件分別燒錄略繁瑣,我們可以先將其合并為一個hex 文件,再將其燒錄到目標芯片中。
我們可以使用mergehex 命令實現多個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 文件燒錄到目標芯片中的命令如下:
# 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 中,系統正常啟動,我們可以通過nRF Connect 掃描并發現“Nordic_Buttonless” 設備。點擊“Connect” 連接成功后,可以看到“Secure DFU Service” 服務,該服務包含“Buttonless DFU” Characteristic,下文嘗試使用該服務執行BLE DFU 空中升級過程。
2.2 如何執行Buttonless BLE DFU 過程?
要使用“Secure DFU Service” 進行空中升級,還需要準備DFU package。通常Bootloader 和Softdevice 更新頻率很低,Application 更新頻率較高,本文以空中升級application 固件為例,說明Buttonless BLE DFU 過程。
版本更新,最直觀的判斷標識是版本號,工程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” 參數需要制定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 的內容,主要是 init packet file 和 firmware image file 相關的信息如下:
由于各部分hex 文件名都比較長,上面的命令也比較長,我們可以將其編輯進shell 腳本里面(對于windows 系統就是.bat 批處理文件 ),后續制作DFU package 只需要執行腳本即可:
- Unbonded BLE DFU procedure
有了DFU package(SDK1702_app_s132_v110.zip),我們就可以使用“Secure DFU Service” 進行空中升級了,比如使用手機端nRF Connect for mobile 掃描發現并連接“Nordic_Buttonless” 設備 --> 點擊“DFU” 圖標 --> 選擇DFU package(SDK1702_app_s132_v110.zip)便開始DFU 過程(需將DFU package 傳到手機上),DFU 完成后設備廣播名變為"Nordic_DFU_V110",說明固件升級成功了,操作圖示如下:
注意上圖“Nordic_Buttonless” 和“DFUTARG” 的藍牙設備地址關系,印證了前面介紹的Unbonded DFU 過程中DFU target 設備Bootloader 程序的藍牙設備地址 = Application 程序的藍牙設備地址 + 1,方便DFU controller 區分Application 連接和Bootloader 連接,發現Bootloader 提供的DFU 服務。
- Bonded BLE DFU procedure
Bootloader 如果啟用了NRF_DFU_BLE_REQUIRES_BONDS,則在執行BLE DFU 前需要先執行配對綁定過程,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 發送service changed indication,讓DFU controller 可以發現Bootloader 提供的DFU 服務,因此還需要啟用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 文件復制出來(也可以添加_bond 以區別與前面的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 文件復制出來(也可以添加_bond 以區別與前面的unbond),執行前面介紹的生成Bootloader settings、合并燒錄hex 文件的過程,nRF52 DK 系統正常啟動,通過nRF Connect 連接“Nordic_Buttonless” 設備可以看到“Secure DFU Service” 服務。
我們將工程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,執行前面介紹的生成生成DFU package 過程,獲得DFU 升級包SDK1702_app_s132_v120.zip,將其傳到手機上用于DFU 升級。
手機端nRF Connect 執行DFU 的操作跟前面Unbonded BLE DFU 類似,主要區別是在進行DFU 之前需要先執行配對綁定操作,圖示如下(點擊“DFU” 圖標選擇DFU package 的過程跟前面完全一致,這里省略了):
Bonded BLE DFU procedure 不再出現“DFUTARG” 設備了,這樣印證了前面說到的,Bonded DFU 過程中DFU target 設備Application 和Bootloader 程序采用相同的藍牙設備地址,配對綁定后DFU target 可以主動向DFU controller 發送service changed indication,讓DFU controller 可以發現Bootloader 提供的DFU 服務,繼續執行DFU 過程。
本工程源碼下載地址:https://github.com/StreamAI/Nordic_nRF5_Project/tree/main/BLE_Buttonless_DFU。
更多文章:
- 《如何為BLE 設備添加OTA DFU 空中升級服務(下)?》
- 《如何實現BLE 最大數據吞吐率并滿足設計功耗要求?》
- 《如何抓包分析BLE 空口報文(GAP + GATT + LESC)?》
- 《如何實現掃碼連接BLE 設備的功能?》
- 《Nordic_nRF5_Project》
- 《Nordic nRF5 SDK documentation》
- 《BLE 技術(五)— Generic Access Profile + Pairing and Bonding》
- 《BLE 技術(六)— GATT Profile + Security Manager Protocol》
- 《Bluetooth Core Specification_v5.2》
總結
以上是生活随笔為你收集整理的如何为BLE 设备实现OTA DFU 空中升级功能(上)?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 创业基础(第六章:创业资源及其管理) 来
- 下一篇: 2PC、3PC