nRF Connect SDK (NCS) / Zephyr固件升級(jí),主要包括MCUboot和藍(lán)牙空中升級(jí)。
隨著nRF Connect SDK(NCS)/Zephyr固件升級(jí),近期不少朋友在后臺(tái)給Nordic君發(fā)來(lái)不少疑問(wèn): 為此,Nordic君特地找到一篇來(lái)自 Nordic 中國(guó)區(qū) FAE 經(jīng)理 Kevin 艾的原創(chuàng)博客文章對(duì)以上問(wèn)題進(jìn)行解答。目錄
CONTENT
1.概述2. NCS中的Bootloader 2.1 nRF5 SDK Bootloader 2.2 MCUboot 2.3 B0,亦稱nRF Secure Immutable Bootloader(NSIB)3. DFU協(xié)議 3.1 概述 3.2 SMP DFU協(xié)議 3.2.1 SMP包頭和命令 3.2.2 SMP包payload和CBOR編碼 3.2.3 SMP包詳細(xì)解析示例 3.2.4 SMP DFU流程 3.3 nrf dfu協(xié)議4. NCS DFU升級(jí)步驟說(shuō)明 4.1 SMP DFU升級(jí)步驟說(shuō)明 4.2 nrf_dfu升級(jí)步驟說(shuō)明 4.3 存儲(chǔ)器分區(qū)(多image情況)5. 移植SMP DFU功能到peripheral_uart(NUS)6. 手機(jī)端DFU參考代碼 ●1、概述 ●DFU概念
DFU(Device Firmware Update),就是設(shè)備固件升級(jí)的意思。OTA概念
OTA(Over The Air)是實(shí)現(xiàn)DFU的一種方式而已,準(zhǔn)確說(shuō),OTA的全稱應(yīng)該是OTA DFU,即通過(guò)空中無(wú)線方式實(shí)現(xiàn)設(shè)備固件升級(jí)。只不過(guò)大家為了方便起見(jiàn),直接用OTA來(lái)指代固件空中升級(jí)(有時(shí)候大家也將OTA稱為FOTA,即Firmware OTA,這種稱呼意思更明了一些)。 只要是通過(guò)無(wú)線通信方式實(shí)現(xiàn)DFU的,都可以叫OTA,比如4G/WiFi/藍(lán)牙/NFC/Zigbee/NB-IoT,他們都支持OTA。DFU除了可以通過(guò)無(wú)線方式(OTA)進(jìn)行升級(jí),也可以通過(guò)有線方式進(jìn)行升級(jí),比如通過(guò)UART,USB或者SPI通信接口來(lái)升級(jí)設(shè)備固件。 不管采用OTA方式還是有線通信方式,DFU包括后臺(tái)式(background)和非后臺(tái)式兩種模式。 1、后臺(tái)式DFU,又稱靜默式DFU(Silent DFU),在升級(jí)的時(shí)候,新固件在后臺(tái)悄悄下載,即新固件下載屬于應(yīng)用程序功能的一部分,在新固件下載過(guò)程中,應(yīng)用可以正常使用,也就是說(shuō)整個(gè)下載過(guò)程對(duì)用戶來(lái)說(shuō)是無(wú)感的,下載完成后,系統(tǒng)再跳到BootLoader程序,由BootLoader完成新老固件拷貝操作,至此整個(gè)升級(jí)過(guò)程結(jié)束。比如智能手機(jī)升級(jí)Android或者iOS系統(tǒng)都是采用后臺(tái)式DFU方式,新系統(tǒng)下載過(guò)程中,手機(jī)可以正常使用哦。 2、非后臺(tái)式DFU,在升級(jí)的時(shí)候,系統(tǒng)需要先從應(yīng)用程序跳到BootLoader程序,由BootLoader進(jìn)行新固件下載工作,下載完成后BootLoader繼續(xù)完成新老固件拷貝操作,至此升級(jí)結(jié)束。早先的功能機(jī)就是采用非后臺(tái)式 DFU來(lái)升級(jí)操作系統(tǒng)的,即用戶需要先長(zhǎng)按某些按鍵進(jìn)入bootloader模式,然后再進(jìn)行升級(jí),整個(gè)升級(jí)過(guò)程中手機(jī)正常功能都無(wú)法使用。 下面再講雙區(qū)(2 Slot)DFU和單區(qū)(1 Slot)DFU,雙區(qū)或者單區(qū)DFU是新固件覆蓋老固件的兩種方式。 后臺(tái)式DFU必須采用雙區(qū)模式進(jìn)行升級(jí),即老系統(tǒng)(老固件)和新系統(tǒng)(新固件)各占一塊Slot(存儲(chǔ)區(qū)),假設(shè)老固件放在Slot0中,新固件放在Slot1中,升級(jí)的時(shí)候,應(yīng)用程序先把新固件下載到Slot1中,只有當(dāng)新固件下載完成并校驗(yàn)成功后,系統(tǒng)才會(huì)跳入BootLoader程序,然后擦除老固件所在的Slot0區(qū),并把新固件拷貝到Slot0中,或者把Slot0和Slot1兩者的image進(jìn)行交換。 非后臺(tái)式DFU可以采用雙區(qū)也可以采用單區(qū)模式,與后臺(tái)式DFU相似,雙區(qū)模式下新老固件各占一塊Slot(老固件為Slot0,新固件為Slot1),升級(jí)時(shí),系統(tǒng)先跳入BootLoader程序,然后BootLoader程序把新固件下載到Slot1中,只有新固件下載完成并校驗(yàn)成功后,才會(huì)去擦除老固件所在的Slot0區(qū),并把新固件拷貝到Slot0區(qū)。 單區(qū)模式的非后臺(tái)式DFU只有一個(gè)Slot0,老固件和新固件分享這一個(gè)Slot0,升級(jí)的時(shí)候,進(jìn)入bootloader程序DFU模式后立馬擦除老固件,然后直接把新固件下載到同一個(gè)Slot中,下載完成后校驗(yàn)新固件的有效性,新固件有效升級(jí)完成,否則要求重來(lái)。 跟非后臺(tái)式DFU雙區(qū)模式相比,單區(qū)模式節(jié)省了一個(gè)Slot的Flash空間,在系統(tǒng)資源比較緊張的時(shí)候,單區(qū)模式是一個(gè)不錯(cuò)的選擇。不管是雙區(qū)模式還是單區(qū)模式,升級(jí)過(guò)程出現(xiàn)問(wèn)題后,都可以進(jìn)行二次升級(jí),都不會(huì)出現(xiàn)“變磚”情況。 不過(guò)雙區(qū)模式有一個(gè)好處,如果升級(jí)過(guò)程中出現(xiàn)問(wèn)題或者新固件有問(wèn)題,它還可以選擇之前的老固件老系統(tǒng)繼續(xù)執(zhí)行而不受其影響。而單區(qū)模式碰到這種情況就只能一直待在bootloader中,然后等待二次或者多次升級(jí)嘗試,此時(shí)設(shè)備的正常功能已無(wú)法使用,從用戶使用這個(gè)角度來(lái)說(shuō),你的確可以說(shuō)此時(shí)設(shè)備已經(jīng)“變磚”了。 所以說(shuō),雖然雙區(qū)模式犧牲了很多存儲(chǔ)空間,但是換來(lái)了更好的升級(jí)體驗(yàn)。 可參考下面三個(gè)圖來(lái)理解上述過(guò)程![afd70038-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/5F/wKgaomTm_UWAYPs3AADhOLsY3z0823.png)
Bootloader首先需要判斷是進(jìn)入正常應(yīng)用程序啟動(dòng)流程還是DFU流程。
要啟動(dòng)應(yīng)用image,Bootloader必須知道啟動(dòng)image的啟動(dòng)向量表在哪里。 要校驗(yàn)一個(gè)image,Bootloader必須知道這個(gè)image正確的校驗(yàn)值存在哪里。 要完成升級(jí),Bootloader必須知道新image所在位置和老image所在位置,并執(zhí)行一定的拷貝算法。 啟動(dòng)向量表可以放在image的最開(kāi)始處,也可以放在其他地方,這就涉及到image的格式。 Image正確的校驗(yàn)值可以跟image合在一塊存放,也可以單獨(dú)放在一個(gè)flash page里面。如果image的校驗(yàn)值是跟image本身合在一塊存放的,這里再次涉及到image的格式。 關(guān)于新image和老image存放位置,這就涉及到存儲(chǔ)器分區(qū)問(wèn)題。Bootloader的實(shí)現(xiàn)將直接決定image的格式,以及存儲(chǔ)器的結(jié)構(gòu)劃分。 NCS支持MCUboot,B0和nRF5 Bootloader三種Bootloader,三個(gè)Bootloader選其一即可,一般推薦大家使用MCUboot。 由于很多讀者對(duì)Nordic老的SDK,即nRF5 SDK比較熟悉,我們先以這個(gè)nRF5 Bootloader為例來(lái)講解他們的Flash分區(qū)以及image格式,然后再講MCUboot和B0,看看他們又是如何分區(qū)和定義image格式的。 注意:如果你只對(duì)其中某一個(gè)具體的Bootloader感興趣,可以跳過(guò)其他章節(jié),直接閱讀相關(guān)章節(jié),比如如果你只對(duì)MCUboot感興趣,可以只看2.2節(jié)。2.1 nRF5 SDK Bootloader介紹
nRF5 Bootloader 是指:nRF5_SDK_17.1.0_ddde560examplesdfusecure_bootloader 這里面定義的Bootloader。 如果你的DFU想使用這個(gè)Bootloader,那么nRF5 SDK的存儲(chǔ)區(qū)劃分(雙bank)是下面這樣的:![aff31854-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/5F/wKgaomTm_UWAKOwWAAB9PxTDyRA020.png)
![b013240a-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/5F/wKgaomTm_UWAFcmDAABTdByMt0g615.png)
![b043fb8e-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/5F/wKgaomTm_UWACxQFAAD9FTwn9EQ723.png)
- 特定按鍵是否按下
- 保持寄存器GPREGRET1是否為0xB1
- Settings page里面當(dāng)前bank是否為Bank1
- 上次DFU過(guò)程是否還在進(jìn)行中
- 應(yīng)用程序校驗(yàn)是否通過(guò)
- 我們是通過(guò)把Settings page里面的當(dāng)前bank設(shè)置為Bank1來(lái)觸發(fā)DFU模式的。
- 由于是后臺(tái)式DFU,我們只把DFU進(jìn)度信息保存在RAM里面,沒(méi)有將其保存在Settings page這個(gè)Flash頁(yè)面中。
![b05b1b34-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/5F/wKgaomTm_UWAWpyBAAEZG6oRgTU377.png)
2.2 MCUboot
MCUboot位于如下目錄:bootloader/mcuboot/boot/zephyr 在NCS中做DFU的時(shí)候,一般都推薦使用MCUboot。 MCUboot功能強(qiáng)大,兼容的芯片平臺(tái)多,而且是一個(gè)久經(jīng)考驗(yàn)的第三方開(kāi)源Bootloader。 MCUboot把存儲(chǔ)區(qū)劃分為Primary slot和Secondary slot,而且primary slot跟secondary slot兩者大小是一樣的,程序默認(rèn)在Primary slot中執(zhí)行。 有一點(diǎn)需要大家注意,NCS對(duì)MCUboot進(jìn)行了定制,在NCS中,程序只能在Primary slot中執(zhí)行,Secondary slot只是用來(lái)存儲(chǔ)新image,而且Secondary slot可以放在內(nèi)部Flash,也可以放在外部Flash,這樣在NCS中,存儲(chǔ)器分區(qū)有如下兩種典型情況:![b08cceae-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/5F/wKgaomTm_UaAUr0YAABI02AjeLQ565.png)
![b0b7bb1e-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/5F/wKgaomTm_UaAfKJJAABmvEn4yeY552.png)
- 啟動(dòng)image
![b1123030-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/5F/wKgaomTm_UaAcH2_AARhUvjtyQo778.png)
![b1602510-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/5F/wKgaomTm_UaAOQJOAATtxyO1lT8126.png)
![b1c0d734-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/5F/wKgaomTm_UeAT6rBAAJ-epuBgEg455.png)
![b20cbf28-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/5F/wKgaomTm_UeACsrQAAIN9sc_ghk561.png)
![b2459686-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/5F/wKgaomTm_UeAaIA_AAARiq3N7Ro111.png)
- BOOT_SWAP_TYPE_TEST。MCUboot將進(jìn)入DFU模式,而且為test目的的DFU。跟下面的BOOT_SWAP_TYPE_ PERM模式相比,BOOT_SWAP_TYPE_TEST的DFU過(guò)程與之一模一樣,也就是說(shuō)BOOT_SWAP_TYPE_TEST就是進(jìn)行正常的真正DFU,只不過(guò)DFU完成后,MCUboot跳到新app,這個(gè)時(shí)候新app必須把secondary slot里面的image_ok字段寫(xiě)為1,即調(diào)用boot_write_img_confirmed()這個(gè)API來(lái)完成,否則再次復(fù)位進(jìn)入MCUboot的時(shí)候,MCUboot會(huì)認(rèn)為新image有問(wèn)題(沒(méi)有確認(rèn)),從而執(zhí)行回滾操作,重新把老image換到primary slot,然后繼續(xù)跑老image(此時(shí)升級(jí)應(yīng)該算失?。?/span>
- BOOT_SWAP_TYPE_ PERM。如前所述,BOOT_SWAP_TYPE_ PERM跟BOOT_SWAP_TYPE_TEST DFU過(guò)程一模一樣,唯一區(qū)別的是,一旦設(shè)為PERM(永久)模式,哪怕新image沒(méi)有去寫(xiě)image_ok字段,再次復(fù)位進(jìn)入MCUboot,MCUboot也不會(huì)去執(zhí)行回滾操作,而強(qiáng)制認(rèn)為升級(jí)已成功。
- BOOT_SWAP_TYPE_ REVERT,回滾操作。前述的回滾操作,swap_type就是BOOT_SWAP_TYPE_ REVERT。一旦檢測(cè)到BOOT_SWAP_TYPE_ REVERT,MCUboot將進(jìn)行回滾操作。
- BOOT_SWAP_TYPE_ NONE。正常啟動(dòng)模式,MCUboot將直接跳到app,而不是進(jìn)入DFU模式。
- BOOT_SWAP_TYPE_ FAIL。當(dāng)MCUboot校驗(yàn)primary slot里面的image失敗時(shí),就會(huì)報(bào)BOOT_SWAP_TYPE_ FAIL,此時(shí)程序?qū)⑺涝贛CUboot里面。
- BOOT_SWAP_TYPE_ PANIC。當(dāng)MCUboot啟動(dòng)過(guò)程中出現(xiàn)了致命錯(cuò)誤,就會(huì)報(bào)BOOT_SWAP_TYPE_ PANIC,此時(shí)程序?qū)⑺涝贛CUboot里面。
![b2646656-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/5F/wKgaomTm_UeAKgJIAADqwN87EYs140.png)
![b2ea9438-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/5F/wKgaomTm_UiAWl_BAADZ3mGXcDM487.png)
2.3B0=nRF Secure Immutable Bootloader(NSIB)
NSIB(nRF Secure Immutable Bootloader),亦稱B0,位于nrf/samples/bootloader,這個(gè)是Nordic自己開(kāi)發(fā)的一個(gè)不可升級(jí)的Bootloader。 b0把存儲(chǔ)區(qū)劃分成slot0和slot1,并且slot0大小等于slot1大小,s0_image跑在slot0,s1_image跑在slot1,B0根據(jù)s0_image和s1_image的版本號(hào)來(lái)決定跑哪一個(gè)image,如果s0_image的版本號(hào)高于或等于s1_image的版本號(hào),那么B0啟動(dòng)的時(shí)候就會(huì)跳到s0_image;反之,如果s1_image的版本號(hào)高于s0_image的版本號(hào),那么B0啟動(dòng)的時(shí)候就會(huì)跳到s1_image。 由于s0_image和s1_image都有可能被執(zhí)行,所以s0_image和s1_image必須都放置在內(nèi)部Flash,也就是說(shuō)slot0和slot1必須都在nRF設(shè)備內(nèi)部Flash中。 B0將存儲(chǔ)區(qū)劃分成如下模樣:![b30d7782-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/5F/wKgaomTm_UiABiaXAAAi1vXw8EE975.png)
![b32fcc10-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UiAd0dkAAGt9gfaiHI943.png)
![b35a5944-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UiAYBkYAALCBVcOKbE660.png)
![b3a708c0-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UmAOR3uAASS0MbjkTY112.png)
![b43a3050-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UmAfXhfAAIBnPLsN3g767.png)
![b43a3050-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UmAfXhfAAIBnPLsN3g767.png)
![b4ace26c-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UmAB2SmAADR-sTf0q4467.png)
![b4d88b60-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UmATLuBAACxytqa48Y610.png)
![b509c28e-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UmAKhLfAAFMbXtvz4k982.png)
![b53888d0-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UmAQKeRAAC20HNoSMw775.png)
- 0,正數(shù)
- 1,負(fù)數(shù)
- 2,字節(jié)串(byte string)
- 3,UTF-8字符串(text string)
- 4,數(shù)組
- 5,map(又稱字典)
- 6,tag(這個(gè)用得少)
- 7,浮點(diǎn)數(shù)或者特殊類型,其中特殊類型將short count 20–23定義為 false, true, null和undefined
-
如果長(zhǎng)度為0–23,則直接用short count的5 bits來(lái)表示,從第2個(gè)字節(jié)開(kāi)始表示data payload
-
如果short count為24(0x18),則表示第2個(gè)字節(jié)代表長(zhǎng)度,從第3個(gè)字節(jié)開(kāi)始表示data payload
-
如果short count為25(0x19),則表示第2和第3個(gè)字節(jié)合起來(lái)表示長(zhǎng)度,從第4個(gè)字節(jié)開(kāi)始表示data payload
-
如果short count為26(0x1A),則表示第2,第3,第4和第5個(gè)字節(jié)合起來(lái)表示長(zhǎng)度,從第6個(gè)字節(jié)開(kāi)始表示data payload
-
如果short count為27(0x1B),則表示第2至第9個(gè)字節(jié)合起來(lái)表示長(zhǎng)度,從第10個(gè)字節(jié)開(kāi)始表示data payload
-
如果short count為31(0x1F),則表示長(zhǎng)度為未定義,從第2個(gè)字節(jié)開(kāi)始表示data payload,直到遇到停止符:0xFF
- 00 00 00 02 00 01 00 00 bf ff
![b557d9a6-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UqATxitAAByK-3SCbA973.png)
![b5744d0c-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UqAXeanAAErFV89NVY668.png)
![b5e7bd82-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UqAVVPXAACqqfEPHG8121.png)
![b62d60a8-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UqAAhxdAACsZOBmyDM830.png)
- int img_mgmt_state_read(struct mgmt_ctxt *ctxt)
-
簽名升級(jí)image。注:app_update.bin已經(jīng)是簽過(guò)名的image了
-
上傳image,即把a(bǔ)pp_update.bin傳送到目標(biāo)設(shè)備
-
列出image以獲得image的hash值
-
測(cè)試image,即寫(xiě)magic字段,以讓MCUboot進(jìn)入DFU模式
-
復(fù)位設(shè)備,以重新進(jìn)入MCUboot,從而MCUboot進(jìn)入DFU模式,并執(zhí)行相應(yīng)的swap操作,并完成兩個(gè)slot image之間的交換或者拷貝動(dòng)作
-
Confirm image,即新image啟動(dòng)成功后,對(duì)其image_ok字段進(jìn)行置1操作
-
mcumgr conn add myCOM type="serial" connstring="dev=COM13,baud=115200,mtu=256" (Note: change the COM if needed)
-
mcumgr -c myCOM image upload app_update.bin
-
mcumgr -c myCOM image list
-
mcumgr -c myCOM image test
-
mcumgr -c myCOM reset
-
mcumgr -c myCOM image confirm
藍(lán)牙DFU流程解讀
當(dāng)采用BLE作為傳輸層的時(shí)候,上面命令都被手機(jī)app打包成二進(jìn)制數(shù)據(jù)包直接下發(fā)給設(shè)備端,但解析出來(lái)之后,你會(huì)發(fā)現(xiàn)藍(lán)牙DFU流程跟上面說(shuō)明的流程基本上一模一樣。比如前面的00 00 00 02 00 01 00 00 bf ff,就是手機(jī)發(fā)給設(shè)備的第一條DFU命令或者說(shuō)請(qǐng)求(request)。 我們?cè)倥e一個(gè)例子:上傳image命令(request),它的第一個(gè)數(shù)據(jù)包示例如下所示:![b698dc02-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UqASmsqAAFRKs29PkM405.png)
- img_mgmt_upload(struct mgmt_ctxt *ctxt)
![b6d820f6-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UqAcbF8AACkZxUP4fY691.png)
![b724dac2-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UuAfVPmAAAZddaq2O8030.png)
![b7563df6-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UuAO7mSAAAoejbkYsE899.png)
- 03 00 00 0d 00 01 00 01 bf 62 72 63 00 63 6f 66 66 19 09 40 ff
- 02 00 00 32 00 01 00 00 BF 67 63 6F 6E 66 69 72 6D F4 64 68 61 73 68 58 20 47 7C C8 4B 52 27 23 03 DA 27 41 F1 1D 38 46 0F 11 AE DB 5E 75 A2 D3 25 0C 6E DE EF 15 84 24 49 FF,大家可以仿照上面的做法來(lái)解析一下這個(gè)數(shù)據(jù)包,它解析的結(jié)果是:調(diào)用img_mgmt_state_write,并寫(xiě)入magic字段,同時(shí)將swap類型設(shè)為BOOT_SWAP_TYPE_TEST
- 02 00 00 02 00 00 00 05 BF FF,這個(gè)包解析的結(jié)果是:調(diào)用os_mgmt_reset,對(duì)設(shè)備進(jìn)行復(fù)位
3.3 nrf dfu協(xié)議
nrf dfu協(xié)議就是nRF5 SDK使用的DFU協(xié)議,相信很多讀者都很熟悉它。 nrf dfu協(xié)議定義了兩個(gè)角色:controller和target,controller發(fā)request,target回response,一來(lái)一往,完成DFU傳輸過(guò)程。 nrf dfu定義了如下request命令以及他們的response。![b78298e2-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_UuAZdc8AAJnpWw8wMU296.png)
- 選擇對(duì)象(NRF_DFU_OP_OBJECT_SELECT),用來(lái)選擇init包或者image包
- 創(chuàng)建對(duì)象(NRF_DFU_OP_OBJECT_CREATE),用來(lái)創(chuàng)建init包或者一個(gè)image 4kB塊
- 寫(xiě)對(duì)象(NRF_DFU_OP_OBJECT_WRITE),即傳輸實(shí)際數(shù)據(jù)。由于藍(lán)牙將命令和數(shù)據(jù)分成兩個(gè)不同characteristic,寫(xiě)對(duì)象其實(shí)就是寫(xiě)數(shù)據(jù),是一個(gè)專門的characteristic:packet characteristic,因此發(fā)送寫(xiě)對(duì)象命令時(shí),就沒(méi)有必要加上Opcode,而是直接把數(shù)據(jù)寫(xiě)到packet characteristic上。由于串口只有一個(gè)RX線,因此通過(guò)串口DFU的時(shí)候,寫(xiě)對(duì)象命令還是有Opcode的。
- 獲取對(duì)象的CRC(NRF_DFU_OP_CRC_GET),用來(lái)獲取前面init包或者4kB image塊的CRC值
- 執(zhí)行對(duì)象(NRF_DFU_OP_OBJECT_EXECUTE),即把數(shù)據(jù)真正寫(xiě)入Flash中
- 選擇init對(duì)象
- 創(chuàng)建init對(duì)象
- 執(zhí)行init對(duì)象
- 選擇image data對(duì)象
- 建第一個(gè)4kB data對(duì)象
- 寫(xiě)對(duì)象,即設(shè)備(target)循環(huán)接收主機(jī)發(fā)過(guò)來(lái)的image chunk,直至4kB
- 計(jì)算4kB image塊的CRC,并返回給主機(jī)(controller)以供其校驗(yàn)
- 執(zhí)行4kB image塊對(duì)象,即將其寫(xiě)入到Flash中
- 循環(huán)往復(fù),直至整個(gè)image寫(xiě)入完畢
- 寫(xiě)DFU標(biāo)志,并復(fù)位設(shè)備
- 復(fù)位后進(jìn)入Bootloader DFU模式,Bootloader完成后續(xù)的拷貝工作,至此整個(gè)DFU過(guò)程宣告結(jié)束
- 進(jìn)入項(xiàng)目目錄:cd zephyrsamplessubsysmgmtmcumgrsmp_svr
- 編譯:west build -b nrf52840dk_nrf52840 -d build_nrf52840dk_nrf52840 -p -- -DOVERLAY_CONFIG="overlay-bt.conf"(根據(jù)你自己手上的板子情況,把nrf52840dk_nrf52840換成其他DK,比如nrf5340dk_nrf5340_cpuapp)
-
燒寫(xiě):west flash -d build_nrf52840dk_nrf52840,此時(shí)設(shè)備將廣播“Zephyr”
-
修改原始工程,比如廣播名字(CONFIG_BT_DEVICE_NAME="NEW_DFU"放在overlay-bt.conf中)再重新編譯,然后拷貝以下字段到手機(jī)版nRF Connect“build_nrf52840dk_nrf52840/zephyr/app_update.bin"
-
用手機(jī)nRF Connect連接設(shè)備,成功后,點(diǎn)擊右上角的“DFU”圖標(biāo),選擇前面的“app_update.bin”文件,然后選擇“Test and Confirm”,DFU開(kāi)始
-
升級(jí)文件傳輸完畢,系統(tǒng)將重啟
-
MCUboot完成swap操作,并跳到新app,廣播將變成“NEW_DFU”
- 手機(jī)nRF Connect連接新app,并發(fā)送confirm命令
- 至此整個(gè)升級(jí)結(jié)束
- 準(zhǔn)備。a. 安裝PC版nrfutil。nrfutil安裝有兩種方式,一種是直接下載exe文件,一種是以Python的方式進(jìn)行安裝。nrfutil.exe直接下載鏈接為:https://github.com/NordicSemiconductor/pc-nrfutil/releases,記得把nrfutil.exe所在目錄放在Windows環(huán)境變量中。Python方式安裝nrfutil步驟如下所示: i. 安裝Python,下載地址//www.python.org/downloads/,安裝成功后請(qǐng)確保Windows環(huán)境變量包含Python目錄 ii. 通過(guò)pip安裝最新版的nrfutil,即打開(kāi)Windows命令行工具CMD,輸入如下命令:pip install nrfutil,即可以完成nrfutil的安裝。安裝完成后,在Windows命令行工具輸入:nrfutil version,如果可以正確顯示版本信息,說(shuō)明安裝已經(jīng)成功對(duì)于Windows用戶,nrfutil運(yùn)行需要幾個(gè)特殊的DLL庫(kù),而這幾個(gè)庫(kù)有些Windows機(jī)器是沒(méi)有的,如此,可往:https://www.microsoft.com/en-us/download/details.aspx?id=40784下載b. 進(jìn)入nrf_dfu/ble_intFlash/sdk_change目錄,選擇你的SDK版本。比如ncs_v1.8.0,把nrf_dfu/ble_intFlash/sdk_change/ncs_v1.8.x下面內(nèi)容直接覆蓋nrf倉(cāng)庫(kù)目錄c. 建議大家對(duì)照例子里面的readme看一下還有沒(méi)有其他準(zhǔn)備工作
- 進(jìn)入項(xiàng)目目錄:cd nrf_dfu/ble_intFlash
- 編譯:west build -b nrf52840dk_nrf52840 -d build_nrf52840dk_nrf52840 -p(根據(jù)你自己手上的板子情況,把nrf52840dk_nrf52840換成其他DK,比如nrf5340dk_nrf5340_cpuapp)
-
燒寫(xiě):west flash -d build_nrf52840dk_nrf52840此時(shí)設(shè)備將廣播“Nordic_DFU”
-
修改原始工程:比如廣播名字(CONFIG_BT_DEVICE_NAME="NEW_DFU"),再重新編譯,然后拷貝“build_nrf52840dk_nrf52840/zephyr/ app_signed.hex”到update目錄
-
雙擊update目錄中的zip_generate.bat,將生成ble_intFlash.zip,將ble_intFlash.zip拷貝到手機(jī)nRF Connect中
-
用手機(jī)nRF Connect連接設(shè)備,成功后,點(diǎn)擊右上角的“DFU”圖標(biāo),選擇前面的“ble_intFlash.zip”文件
-
升級(jí)文件傳輸完畢,系統(tǒng)將重啟
-
MCUboot完成swap操作,并跳到新app,新app自動(dòng)完成image confirm操作
-
此時(shí)廣播已經(jīng)變成“NEW_DFU”,至此整個(gè)升級(jí)結(jié)束
![bb834e64-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_U-AAAyrAAJcKzJ9ZUU520.png)
![bba18e7e-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_U-AYVKMAAEYVZ1qXjg010.png)
![bbee52e0-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_U-ABMa7AADSfOmVbjM645.png)
![bc3157fc-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_U-AAMqpAAB5DBDcEdg187.png)
![bc4d4f7a-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_VCAJ5_aAACqcvMvMjs504.png)
![bc725dd8-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_VCAOnj1AAKfeGyIp30906.png)
![bcebb48a-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_VCAM44PAAFs0xxb6_I833.png)
- mcuboot_primary大小必須等于mcuboot_secondary,而且CONFIG_BOOT_MAX_IMG_SECTORS最好也等于他們大小/4096
-
如果使用了一個(gè)region(flash_primary這個(gè)region除外),那么這個(gè)region每一塊區(qū)域都要屬于一個(gè)分區(qū)名字,不能出現(xiàn)某塊區(qū)域沒(méi)有分區(qū)名字情況。比如上面重新定義了external_flash region,根據(jù)regions.yml文件定義,external_flash總共有8Mbytes,那么這8Mbytes都必須有一個(gè)分區(qū)名字,而我們定義的littlefs_storage和mcuboot_secondary兩個(gè)分區(qū)的確包含了全部8MB區(qū)域。如果我們定義littlefs_storage所在區(qū)域?yàn)?x0~0x700000,而mcuboot_secondary所在區(qū)域?yàn)?x710000~0x800000,那么系統(tǒng)就會(huì)報(bào)錯(cuò),因?yàn)檫@里還有一個(gè)空隙(gap):0x700000~0x710000是沒(méi)有取分區(qū)名字的。解決這個(gè)問(wèn)題有兩個(gè)辦法:一個(gè)就是上面的方法把0x700000~0x710000劃到littlefs_storage分區(qū),一個(gè)就是給這塊區(qū)域?qū)iT取一個(gè)名字,比如:my_unused_area(見(jiàn)下面示意),也是可以解決問(wèn)題的。
對(duì)于flash_primary這個(gè)region,由于系統(tǒng)默認(rèn)認(rèn)為必須要有一個(gè)“app”分區(qū),所以它可以存在而且只能存在一個(gè)空隙(gap),這樣系統(tǒng)默認(rèn)這個(gè)gap就是“app”分區(qū)。當(dāng)然你也可以把flash_primary所有區(qū)域都分好區(qū),包括“app”分區(qū)。
- regions.yml文件里面各個(gè)存儲(chǔ)器的物理大小必須符合實(shí)際,這個(gè)通過(guò)修改dts文件來(lái)保證的。這里面最容易出錯(cuò)的就是external_flash,external_flash的大小在regions.yml文件里面是以字節(jié)為單位(在kconfig文件里面也是以字節(jié)為單位的),但是external_flash對(duì)應(yīng)的設(shè)備樹(shù),比如MX25R64,它在dts文件里面是以bit為單位的,所以當(dāng)大家使用其他外部Flash的時(shí)候,請(qǐng)仔細(xì)檢查這些size對(duì)不對(duì)
- settings_storage,即settings使用的分區(qū),大家可以將分區(qū)名改成:storage,這是其一,其二settings系統(tǒng)最終使用的最大flash區(qū)域大小是由CONFIG_PM_PARTITION_SIZE_SETTINGS_STORAGE決定,而不是settings_storage分區(qū)本身大小決定,所以建議大家把CONFIG_PM_PARTITION_SIZE_SETTINGS_STORAGE的值設(shè)為settings_storage分區(qū)大小。
- 至于RAM分區(qū),道理也是一樣的。這里需要注意的是,RAM各個(gè)分區(qū)的大小大家可以直接到dts文件里面去調(diào)整,而無(wú)需在pm_static.yml文件里面調(diào)整。當(dāng)然,大家在pm_static.yml里面調(diào)整也是可以的,殊途同歸,達(dá)到目的就好了。對(duì)于nRF52系列,只有一個(gè)sram_primary分區(qū),這個(gè)沒(méi)什么好講的;對(duì)于nRF53系列,除了sram_primary這個(gè)分區(qū),它還有rpmsg_nrf53_sram分區(qū)以及pcd_sram分區(qū),其中rpmsg_nrf53_sram是用來(lái)藍(lán)牙協(xié)議棧host和controller之間進(jìn)行雙核通訊的,而pcd_sram是用來(lái)升級(jí)網(wǎng)絡(luò)核image的。
![bd4eeb68-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_VCAa2I3AAGfB4jCtmI275.png)
![bdb37e70-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_VCACeggAAD2rYfGnNs970.png)
大家可以下載下來(lái)參考或者測(cè)試一下。 從上述例子我們可以看出,在NCS中移植一個(gè)例子非常方便,它不需要去添加c文件和頭文件,也不需要去修改編譯選項(xiàng),還不需要去修改傳統(tǒng)的頭文件進(jìn)行配置,僅僅修改conf文件和初始化函數(shù),就輕輕松松完成了整個(gè)移植,這也是NCS非常大的一個(gè)好處。 https://github.com/aiminhua/ncs_samples/tree/master/smp_dfu其實(shí)鏈接下面包含的例子都同時(shí)具備smp和nus兩個(gè)服務(wù),并且區(qū)分各種不同情形下的DFU情況,比如secondary slot在外部Flash,通過(guò)串口傳輸image等,同時(shí)其對(duì)peripheral_uart例子進(jìn)行了小小改動(dòng),以更符合某些實(shí)際應(yīng)用場(chǎng)景,建議大家好好看一下,相信對(duì)大家理解MCUboot和SMP會(huì)幫助不少。 ●6、手機(jī)端DFU參考代碼 ● Nordic不僅提供設(shè)備端的DFU參考代碼,同時(shí)提供手機(jī)端的參考代碼。Nordic分別開(kāi)發(fā)了Android版和iOS版的DFU庫(kù),大家可以直接拿過(guò)來(lái)使用,集成到自己的移動(dòng)端app中,這兩個(gè)庫(kù)都放在github上,其中smp dfu對(duì)應(yīng)的DFU庫(kù)鏈接如下所示:
- Android版SMP DFU庫(kù):https://github.com/NordicSemiconductor/Android-nRF-Connect-Device-Manager
- iOS版SMP DFU庫(kù):https://github.com/JuulLabs-OSS/mcumgr-ios
- Android版nrf dfu庫(kù):https://github.com/NordicSemiconductor/Android-DFU-Library
- iOS版nrf dfu庫(kù):https://github.com/NordicSemiconductor/IOS-DFU-Library
- Android版nRF Toolbox源代碼及開(kāi)發(fā)說(shuō)明請(qǐng)參考:https://github.com/NordicSemiconductor/Android-nRF-Toolbox
- iOS版nRF Toolbox源代碼及開(kāi)發(fā)說(shuō)明請(qǐng)參考:https://github.com/NordicSemiconductor/IOS-nRF-Toolbox
![bdf1acb8-d0e0-11ec-bce3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/95/60/wKgaomTm_VGAdt88AAIDAjforow966.png)
原文標(biāo)題:【Nordic博文分享系列】nRF Connect SDK(NCS)/Zephyr固件升級(jí)詳解來(lái)啦!
文章出處:【微信公眾號(hào):Nordic半導(dǎo)體】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
-
固件升級(jí)
+關(guān)注
關(guān)注
0文章
34瀏覽量
12154 -
NCS
+關(guān)注
關(guān)注
1文章
8瀏覽量
9117 -
Nordic
+關(guān)注
關(guān)注
9文章
174瀏覽量
47410
原文標(biāo)題:【Nordic博文分享系列】nRF Connect SDK(NCS)/Zephyr固件升級(jí)詳解來(lái)啦!
文章出處:【微信號(hào):nordicsemi,微信公眾號(hào):Nordic半導(dǎo)體】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
如何實(shí)現(xiàn)自己的DFU
轉(zhuǎn):利用 USB DFU實(shí)現(xiàn) IAP功能
求助 STM32F205 DFU升級(jí)問(wèn)題
stm32如何進(jìn)入dfu模式
STM32芯片的DFU編程
關(guān)于Atmel AVR XMEGA USB CDC與DFU的特點(diǎn)介紹
基于DfuSe工具從APP跳轉(zhuǎn)到DFU模式
![基于DfuSe工具從APP跳轉(zhuǎn)到<b class='flag-5'>DFU</b>模式](https://file.elecfans.com/web1/M00/81/EB/pIYBAFwzH76ABmrXAAALmr-kNl4124.png)
megawin_USB_DFU_v1.22升級(jí)
![megawin_USB_<b class='flag-5'>DFU</b>_v1.22<b class='flag-5'>升級(jí)</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
如何使用CubeMx生成一個(gè)DFU工程
AN3156_基于STM32微控制器引導(dǎo)程序的USB_DFU協(xié)議應(yīng)用手冊(cè)
![AN3156_基于STM32微控制器引導(dǎo)程序的USB_<b class='flag-5'>DFU</b><b class='flag-5'>協(xié)議</b>應(yīng)用手冊(cè)](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
AN3156_STM32 引導(dǎo)加載程序中使用的 USB DFU 協(xié)議
![AN3156_STM32 引導(dǎo)加載程序中使用的 USB <b class='flag-5'>DFU</b> <b class='flag-5'>協(xié)議</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
評(píng)論