CC2640之OAD韌體升級(內建Flash)
OAD是TI在BLE協議棧基礎上擴充套件的一種無線更新技術。OAD使用客戶端-伺服器的機制工作。需要韌體更新的目標晶片叫做OAD Target/Client,用來管理OAD功能的一端叫做OAD Manager/Server。
配置OAD的目標裝置,如果需要更新軟體的話,不用連線模擬器,通過BLE無線就可以更新軟體,方便使用者升級。
有些人會覺得OAD很複雜,其實並不複雜,本質就是OAD Manager/Server端將需要升級的bin檔案位元組流取出來,然後按照特定的長度(因為BLE每個包的長度是受限的)通過write方法,將資料通過帶有寫許可權的特徵值傳送給OAD Target/Client端,然後OAD Target/Client 端將收到的資料寫到特定的flash地址上。
CC2640的OAD韌體升級支援內建Flash和外接Flash兩種,我們先來了解下內建Flash的OAD配置方式,至於外接Flash的情況,後期再繼續更新。
CC2640內建Flash OAD
內建Flash的OAD韌體升級配置之後,整個Flash中地址分配情況如下圖:
下面,我們來具體瞭解一下內建Flash的裝置配置OAD的方法。
編譯ImageA
ImageA在官方文件中是指OAD Target Application,因為CC2640的工程燒錄的時候是將BIM、BLE STACK和OAD Target Application這三者hex檔案合併成“OAD_merge.hex
下面,我們一起來看看編譯的方法和編譯過程中出現的問題及解決辦法:
1.先開啟IAR開發工具,然後將
“C:\ti\simplelink\ble_cc26xx_2_01_00_44423\Projects\ble\OADTarget\CC26xx\IAR”
目錄下的“OADTarget.eww”拖到IAR的左側工作區,開啟“OADTarget”工程,開啟之後顯示如下:
我們可以看到,開啟的工程包含了BIM、CC2640App和CC2640Stack,編譯過程為:首先編譯BIM,然後編譯CC2640Stack,最後編譯CC2640App,編譯CC2640App的時候會在編譯完成的時候呼叫
2.BIM和CC2640Stack的編譯沒有什麼問題,我們不再講述,下面重點來看一下CC2640App編譯之後執行合成指令碼的時候出現的問題,沒有進行任何配置的情況下,會提示下面截圖的資訊:
Python安裝完成並配置環境變數之後,我們還需要下載合成指令碼,並複製到Python的安裝目錄下,合成指令碼“hexmerge.py”的下載連結如下:
開啟上述下載連結之後截圖如下:
下載解壓之後將檔案複製到C:\ti\simplelink\ble_cc26xx_2_00_00_42893\Projects\ble\OADTarget\CC26xx\IAR\Application\CC2640目錄中即可
這樣就可以成功編譯了,編譯成功之後會在
“C:\ti\simplelink\ble_cc26xx_2_01_00_44423\Projects\ble\OADTarget\CC26xx\IAR\Application\
CC2640\FlashROM\Exe”
目錄下生成“OAD_merge.hex”檔案,這就是我們需要的ImageA的hex檔案。
注意:用這個ImageA升級ImageB的話,如果用PC端的BLE Device Monitor或者安卓手機端的APP都會出現連線失敗,或者搜尋不到服務,或者搜尋到服務之後過一會就斷開,或者升級過程中斷開連線等問題,這個問題的主要原因是ImageA的CC2640App開啟了BLE連線成功之後自動申請修改連線引數的功能,在
“C:\ti\simplelink\ble_cc26xx_2_01_00_44423\Projects\ble\OADTarget\CC26xx\Source\Application”目錄下的“oadTargetApp.c”檔案中,相關程式碼截圖如下:
自動申請的連線引數最小是80,最大是800,這個連線間隔太長,會影響升級,所以我們將“DEFAULT_ENABLE_UPDATE_REQUEST”的值改為“FALSE”來關閉自動申請連線引數更新,進而用預設的連線引數進行升級。這樣PC端的BLE Device Monitor才能正常連線並進行升級。如果為了提高升級的速度,需要將連線間隔縮小,那用PC端的BLE Device Monitor的話可以用該工具進行設定;若用手機端進行升級的話,可以將需要的連線間隔通過某個特徵值發給從機,由從機來重新申請。
燒錄ImageA
將開發板通過XDS模擬器連結到電腦上,連線的方法、Flash Programmer工具以及驅動的安裝我們這裡不再講述,準備好之後,開啟Flash Programmer 工具,然後按照下圖進行操作:
成功燒錄之後,我們用PC端的BLE Device Monitor工具進行搜尋和連線,之後可以看到相應的服務和特徵值,截圖如下:
此處有一點需要注意,就是ImageA中固定了Mac地址,也就是,如果用協議棧中的Demo編譯ImageA,其Mac地址都是“0A:D0:AD:0A:D0:AD”,而後面編譯的ImageB用的是晶片本身的Mac地址,這樣可以避免用安卓手機等方式升級時,因為藍芽快取的原因導致裝置名、服務和特性沒有改變的問題。
當然ImageA的Mac地址也可以根據自己的需求進行修改,但是要保證跟現有的已經分配的Mac地址不衝突,所以除非必須改,否則不要動這個地方。程式碼中設定的地方截圖如下:
編譯ImageB
我們先用TI協議棧中的Demo進行測試和整個流程的熟悉。如何在一個沒有配置過OAD的工程中配置OAD ImageB的相關內容在另一篇博文中講解,連結如下所示:
1.開啟協議棧中的“SimpleBLEPeripheral”工程,“CC2640App”選擇“FlashOnly_OAD_ImgB”,截圖如下:
2.首先編譯“CC2640Stack”,然後編譯“CC2640App”,成功編譯之後,會在
“C:\ti\simplelink\ble_cc26xx_2_01_00_44423\Projects\ble\SimpleBLEPeripheral\CC26xx\IAR\Application\
CC2640\FlashOnly_OAD_ImgB\Exe”
目錄下生成“OADbin.bin”檔案,這個就是ImageB的bin檔案。
3.用PC端的BLE Device Monitor工具或者安卓手機端工具將該檔案更新到裝置端之後,會發現裝置端重啟之後不再廣播,程式跑不起來,如果出現這種情況,開啟
“C:\ti\simplelink\ble_cc26xx_2_01_00_44423\Projects\ble\SimpleBLEPeripheral\CC26xx\IAR\Config”
目錄下的“appBLE.cfg”檔案,將開頭的如下兩行程式碼遮蔽掉:
- //var ROM = xdc.useModule('ti.sysbios.rom.ROM');
- //ROM.romName = ROM.CC2650;
操作截圖如下:
至於這個地方為什麼要這樣,TI官方文件其實有說明。官方文件中的說明如下:
升級ImageB
ImageB用PC端BLE Device Monitor工具升級過程如下:
1.用BLE Device Monitor工具,搜尋並連線我們要升級的裝置,然後點選選單欄上的“File”,在下拉選單中選擇“Program(OAD)”,操作截圖如下:
2.點選“Program(OAD)”之後,會彈出如下所示的框框:
“File Image”裡面要選擇的檔案就是我們要更新的韌體,我的是在
“C:/ti/simplelink/ble_cc26xx_2_01_00_44423/Projects/ble/SimpleBLEPeripheral/CC26xx/IAR/Application/
CC2640/FlashOnly_OAD_ImgB/Exe/OADbin.bin”目錄下的該檔案,選擇之後,點選“Start”進行升級,升級過程如下:
待進度條走完,升級就完成了,該提示框會自動消隱。
3.升級完成之後,然後重新用PC端的BLE Device Monitor工具進行搜尋和連線(如果搜尋不到,就重啟下裝置然後再試試),截圖如下:
ImageB的裝置名我特意進行了修改,目的是與ImageA的進行區分,並且看右側跟之前ImageA的相比較也明顯能看出服務和特性都不一樣了,證明我們的升級成功了。
4.到了這一步,ImageB的韌體就升級到我們的目標裝置上了,但是ImageB本身不帶升級功能,所以沒有辦法來升級ImageA,有人會問,那我們要更新ImageB怎麼辦呢?也就是我們如何從ImageB切換到ImageA,然後重新升級新的韌體ImageB呢?
TI考慮到了這一點,所以增加了一個UUID為“FFD0”的服務和UUID為“FFD1”的特徵值,使用者可以向該特徵值寫入任意值,裝置端就會切換回ImageA,截圖如下:
重新搜尋裝置,就會發現裝置切換到ImageA了。
因為本人是個愛學習的小學生,所以我們再一起來看看上述切換的實現程式碼及原理,實現程式碼在
“C:\ti\simplelink\ble_cc26xx_2_01_00_44423\Projects\ble\Profiles\OAD\CC26xx”
目錄下的“oadResetService.c”檔案中,原始碼截圖如下:
關鍵的部分就是紅圈裡面的內容,原始碼如下:
- uint16_t crc[2] = {0x0000, 0x0000};
- // Invalidate the image.
- OADTarget_writeFlash(OAD_IMG_R_PAGE, OAD_IMG_R_OSET + OAD_IMG_CRC_OSET,
- (uint8_t *)crc, 4);
- // Reset.
- HAL_SYSTEM_RESET();
從上述程式碼中不難看出,所謂的ImageB切換回ImageA,其實就是將Flash中ImageB校驗位元組寫成0,因為重啟裝置的時候執行到BIM中會先去判斷ImageB的校驗位元組,如果全為0,就認為ImageB不完整或者沒有,然後去判斷ImageA的校驗位元組,如果ImageA的校驗位元組完整非0,就去執行ImageA。有的人覺得為了這個功能單獨配置一個服務和特徵值太浪費了,那我們可以將這個服務和特徵值刪掉,然後在你必須要保留的特徵值中找一個帶有寫許可權的,然後在主機通過該特徵值寫入某個命令的時候執行上述程式碼即可。