1. 程式人生 > >【藍芽】CSR8670的DFU功能

【藍芽】CSR8670的DFU功能

本文介紹了CSR8670的DFU功能,從DFU升級過程、實現和DFU檔案生成做了詳細介紹。

地址:http://blog.csdn.net/wzz4420381/article/details/52371409

1. DFU簡介

DFU全稱是Device Firmware Upgrade,是一種通過USB升級裝置程式的機制,能用來升級以下軟體元件
韌體協議棧 VM應用程式 VM檔案系統內的其它檔案(語音提示音、額外語言包) PS Keys DFU協議被USB實施者論壇標準化為一個裝置類規範。CSR相容這個規範,且包含加密檢查。在製造時裝置燒錄的程式有RSA公鑰 DFU檔案用RSA私鑰加密,確保只有為此產品定製的DFU檔案能被終端使用者使用

2. DFU升級過程

這裡寫圖片描述

Loader是出廠時燒錄進晶片的 PS Keys儲存了系統的配置 Firmware是韌體協議棧 VM檔案系統包含了VM app和語音提示音

2.1. 詳細執行過程

這個章節列出了在使用DFU機制時的選擇和限制:

loader不能被升級
這使得DFU升級過程是安全的,loader總是存在且原封不動,因此在升級失敗後DFU過程仍可重複 韌體協議棧可以被升級(但不是必須的)
韌體協議棧可以不包含在DFU檔案裡,這種情況下韌體不會被更新。 如果預設boot模式沒有主機介面,必須包含韌體協議棧(否則產品只有協議棧,沒有VM,沒有主機介面,因此不能工作) 任何DFU檔案內的PS Keys都可以被修改 VM檔案系統可以被升級(但不是必須的)
如果VM檔案系統存在於DFU檔案內,VM檔案系統被替換成新的 不能單獨升級VM檔案系統內的檔案,檔案必須是連續的且沒有間隙

2.2. DFU升級工具

DFU升級工具有兩種:

DFUWizard:需要使用者安裝CSR DFU驅動才能開始DFU過程 HidDfu:不需要使用者安裝驅動,使用USB HID介面執行DFU

2.3. PS Keys

PS Keys的型別有很多種:

未保護韌體(FW)和虛擬機器(VM)Keys:
這些Keys不需要被簽名,但簽名也不會有任何問題 被保護FW Keys
這些Keys被儲存在loader內的FW公鑰認證 被保護VM Keys
這些Keys被儲存在被保護FW Keys內的VM公鑰認證 虛擬Keys,有著專門用途
這裡寫圖片描述

2.4. DFU事件序列

DFU事件序列如下:

裝置正常執行在獨立模式 USB插入,裝置被列舉成USB裝置 一個使用者USB命令或按鍵序列切換到DFU模式(這導致使用者在mode 0內reboot,使用者介面在這個模式內必須可用) DFUWizard命令裝置切換到Loader模式,裝置reboot且loader被啟用(當使用HidDfu時不需要這個步驟) DFU檔案被下載到裝置且由loader處理 裝置reboot回到mode 0(當使用HidDfu時不需要) 裝置reboot回到獨立模式 裝置檢測到到USB連線且列舉為一個USB裝置

3. 生成DFU檔案

官方手冊的步驟比較詳細,但每次生成程式碼需要手動操作。我寫了一個批處理檔案,實現了編譯、燒錄、生成DFU、生成release檔案一鍵操作。

3.1. 設定CSR安裝路徑

?
1 2 3 4 5 :: set CSR install path set dfutoolspath="C:\ADK4.0.0\tools\bin" set adkpath="C:\ADK4.0.0" set debugtransport=SPITRANS=USB SPIPORT=0 set adkversion=adk4.0.0

這裡的debugtransport指向USB-SPI偵錯程式,在執行批處理檔案過程中,確保PC與程式設計器已經連線。

3.2. 設定全域性變數

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 :: set project path set ReleasePath=released set ReleaseVersion=0.0.13 set ReleasePackageName=BT%ReleaseVersion% set ReleaseNoteName=ReleaseNote_BT%ReleaseVersion% set projectpath=parasol_v%ReleaseVersion% set projectmakefile=Speaker.parasol_released set projectname=speaker set projectpsr1=sink_system_csr8670 set projectpsr2=Speaker_with_TWS_CNS10001v4 set projectpsr3=Music5_bt_%ReleaseVersion% set dfupsrfw=example_DFU_fw_Music5_bt_%ReleaseVersion% set dfupsrvm=example_DFU_vm_Music5_bt_%ReleaseVersion%

projectmakefile需要與工程的編譯檔案對應。

3.3. 建立release資料夾

?
1 2 3 4 5 6 :: create package dir rd /s /Q %ReleasePackageName% mkdir %ReleasePackageName% mkdir %ReleasePackageName%\"BT_Program file" mkdir %ReleasePackageName%\"BT_Source code" mkdir %ReleasePackageName%\"BT_Upgrade file"
首先刪除同名資料夾,再分別建立各資料夾 第一個資料夾存工廠燒錄檔案 第二個資料夾存原始碼(如果庫檔案被修改了,也要包含在內) 第三個資料夾存DFU檔案

3.4. 更新除錯介面

?
1 2 3 4 5 6 7 8 9 10 11 :: update debug transport in XIP files cscript //NoLogo //B xip_set_transport.vbs %adkpath%\apps\%projectpath%\%projectname%.xip "[%debugtransport%]" cscript //NoLogo //B xip_set_transport.vbs %adkpath%\kalimba\apps\a2dp_sink\sbc_decoder.xip "[%debugtransport%]" cscript //NoLogo //B xip_set_transport.vbs %adkpath%\kalimba\apps\a2dp_sink\aptx_decoder.xip "[%debugtransport%]" cscript //NoLogo //B xip_set_transport.vbs %adkpath%\kalimba\apps\a2dp_sink\aptx_acl_sprint_decoder.xip "[%debugtransport%]" cscript //NoLogo //B xip_set_transport.vbs %adkpath%\kalimba\apps\a2dp_sink\aac_decoder.xip "[%debugtransport%]" set origpath=%cd%

DSP工程的除錯介面需要設定,否則編譯時會報錯找不到偵錯程式。

3.5. 編譯DSP工程

?
1 2 3 4 5 6 7 8 9 10 11 12 echo. *** compile DSP app *** cd /D %adkpath%\kalimba\apps\a2dp_sink call %adkpath%\xide\bin\xipbuild.exe -f sbc_decoder.xip cd /D %adkpath%\kalimba\apps\a2dp_sink call %adkpath%\xide\bin\xipbuild.exe -f aptx_decoder.xip cd /D %adkpath%\kalimba\apps\a2dp_sink call %adkpath%\xide\bin\xipbuild.exe -f aptx_acl_sprint_decoder.xip cd /D %adkpath%\kalimba\apps\a2dp_sink call %adkpath%\xide\bin\xipbuild.exe -f aac_decoder.xip

每個VM工程包含一個主工程和多個DSP子工程。

3.6. 複製psr檔案

?
1 2 cd /D %origpath% call %adkpath%\tools\bin\copyfile %adkpath%\apps\%projectpath%\configurations\%projectpsr3%.psr %ReleasePackageName%\BT_Upgrade file\%projectpsr3%.psr"

這裡的psr3其實包含了三個部分:psr1、psr2、與專案有關的配置改動。

psr1和psr2是CSR預設的配置。

3.7. 生成未加密的工廠燒錄檔案

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 cd /D %adkpath%\apps\%projectpath% call %adkpath%\xide\bin\xipbuild.exe -f %projectname%.xip echo. *** erase board *** call %adkpath%\tools\bin\BlueFlashCmd.exe -TRANS "%debugtransport%" erase echo. *** delete the image directory before copying files into it *** echo. *** this will also flash the unsigned image onto the board echo. *** prevent voice file from delect *** call rmdir /S /Q headers_temp call rmdir /S /Q prompts_temp call rmdir /S /Q refname_temp del /f /s /Q audio_prompt_config_temp.csr mkdir headers_temp mkdir prompts_temp mkdir refname_temp xcopy /E image\headers headers_temp xcopy /E image\prompts prompts_temp xcopy /E image\refname refname_temp copy /b image\audio_prompt_config.csr audio_prompt_config_temp.csr call rmdir /S /Q image mkdir image xcopy /E headers_temp "image\headers\" xcopy /E prompts_temp "image\prompts\" xcopy /E refname_temp "image\refname\" copy /b audio_prompt_config_temp.csr "image\audio_prompt_config.csr" call rmdir /S /Q headers_temp call rmdir /S /Q prompts_temp call rmdir /S /Q refname_temp del /f /s /Q audio_prompt_config_temp.csr %adkpath%\tools\bin\make -R BLUELAB=%adkpath%\tools -f %projectmakefile%.mak flash cd /D %origpath% echo. *** merge psr file to board *** call %adkpath%\tools\bin\pscli.exe -TRANS "%debugtransport%" merge "%ReleasePackageName%\BT_Upgrade file\%projectpsr3%.psr"

這裡完成了4件事:

編譯VM工程 擦除目標板 燒錄VM檔案系統到目標板 燒錄psr檔案到目標板

在執行第3部之前,需要首先刪除image資料夾。image資料夾的截圖如下:
這裡寫圖片描述

image資料夾由如下部分組成:

VM應用(vm.app) 各個DSP工程的映像(aac_decoder等幾個decoder) 語音提示音(headers、prompts、refname)

headers資料夾內的檔案數量與pskey中設定的語音提示音數量是對應的。

語音提示音資料夾是通過sink configuration tool生成的,然後通過編譯工程來新增到最終生成的image.fs檔案裡。所以在刪除image資料夾之前需要把相關內容快取一下,並在生成image之前再次放回到image資料夾。

把image和psr一起燒錄進目標板後,就可以讀出完整的工廠燒錄檔案。<喎�"/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;">echo. *** cold reset ***call %adkpath%\tools\bin\pscli.exe -TRANS "%debugtransport%" cold_resetecho. *** dump file from board ***cd /D %origpath%\%ReleasePackageName%\"BT_Program file"call %adkpath%\tools\bin\BlueFlashCmd.exe -TRANS "%debugtransport%" dump %projectpsr3%

?
1 2 3 4 5 6 7 8 9 10 11 echo. *** copy library file to BT_Source code *** cd /D %origpath% xcopy /E %adkversion% "%ReleasePackageName%\BT_Source code\BT_Source code\" echo. *** copy source file to BT_Source code *** xcopy /E %adkpath%\apps\%projectpath% "%ReleasePackageName%\BT_Source code\BT_Source code\Parasol_TWS_Code\" echo. *** compress code *** call "C:\Program Files\WinRAR\rar.exe" a -ep1 -o+ -ibck %ReleasePackageName%\"BT_Source code"\BT_SourceCode.rar "%ReleasePackageName% \BT_Source code\BT_Source code" rd /s /Q "%ReleasePackageName%\BT_Source code\BT_Source code\"

這裡首先把有修改的庫檔案和原始碼一起拷貝到目標資料夾下,然後呼叫了WinRAR提供的壓縮程式用來生成壓縮檔案。

3.11. 生成已加密的image檔案

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 echo. *** generate keys *** cd /D %origpath%\dfu_key copy /b keys.private.key %origpath%\%ReleasePackageName%\"BT_Upgrade file"\keys.private.key copy /b keys.public.key %origpath%\%ReleasePackageName%\"BT_Upgrade file"\keys.public.key cd /D %origpath%\%ReleasePackageName%\"BT_Upgrade file" :: call %dfutoolspath%\dfukeygenerate.exe -o keys echo. *** sign firmware *** copy /b %adkpath%\firmware\assisted\unified\gordon\loader_unsigned.xdv loader_unsigned.xdv copy /b %adkpath%\firmware\assisted\unified\gordon\loader_unsigned.xpv loader_unsigned.xpv copy /b %adkpath%\firmware\assisted\unified\gordon\stack_unsigned.xdv stack_unsigned.xdv copy /b %adkpath%\firmware\assisted\unified\gordon\stack_unsigned.xpv stack_unsigned.xpv call %dfutoolspath%\dfukeyinsert -v -o loader_signed -l loader_unsigned.xdv -ks keys.public.key call %dfutoolspath%\dfusign -v -o stack_signed -s stack_unsigned.xpv -ks keys.private.key echo. *** copy image.fs to BT_Upgrade file *** call %adkpath%\tools\bin\copyfile %adkpath%\apps\%projectpath%\image.fs app.fs echo. *** sign app *** call %dfutoolspath%\dfukeyinsert -v -o image_signed -ps %projectpsr3%.psr -ka keys.public.key call %dfutoolspath%\dfusign -v -o image_signed -h app.fs -ka keys.private.key echo. *** build binary *** call %adkpath%\tools\bin\vmbuilder -size 16064 merge.xpv stack_signed.xpv image_signed.fs

上述程式碼完成了如下幾件事:

生成金鑰,這個金鑰需要儲存好,後續release DFU檔案時需要用到 加密韌體,包括loader和stack 加密VM app和psr,生成加密後的image檔案

3.12. 生成已加密的工廠燒錄檔案

?
1 2 3 4 5 6 7 8 9 10 11 12 13 echo. *** merge signed xpv file to board *** call %adkpath%\tools\bin\BlueFlashCmd.exe -TRANS "%debugtransport%" erase call %adkpath%\tools\bin\BlueFlashCmd.exe -TRANS "%debugtransport%" merge echo. *** merge signed psr file to board *** call %adkpath%\tools\bin\pscli.exe -TRANS "%debugtransport%" merge image_signed.psr echo. *** cold reset *** call %adkpath%\tools\bin\pscli.exe -TRANS "%debugtransport%" cold_reset echo. *** dump signed file from board *** cd /D %origpath%\%ReleasePackageName%\"BT_Program file" call %adkpath%\tools\bin\BlueFlashCmd.exe -TRANS "%debugtransport%" dump %projectpsr3%_signed
首先把已加密的image檔案merge到目標板 然後merge已加密的psr檔案 最後dump出已加密的工廠燒錄檔案

如果裝置出廠時燒錄的是已加密的燒錄檔案,後續DFU升級就可以更改被保護的PS Keys,否則只能更改未被保護的PS Keys。

3.13. 生成DFU檔案

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 echo. *** sign PSKEYs to be included in the DFU image *** cd /D %origpath%\%ReleasePackageName%\"BT_Upgrade file" copy %origpath%\%dfupsrvm%.psr app_vm.psr copy %origpath%\%dfupsrfw%.psr app_fw.psr call %dfutoolspath%\dfusign -v -o dfu_vm_signed -pa app_vm.psr -ka keys.private.key call %dfutoolspath%\dfusign -v -o dfu_fw_signed -ps app_fw.psr -ks keys.private.key echo. *** generate the DFU file *** call %dfutoolspath%\dfubuild -v -pedantic -f %projectpsr3%.dfu -uv 0x0a12 -up 0x0001 -ui "ADK DFU" -s stack_signed.xpv -d stack_signed.xdv -h image_signed.fs -p3 . dfu_fw_signed.stack.psr dfu_vm_signed.app.psr echo. *** delete middle files *** cd /D %origpath%\%ReleasePackageName%\"BT_Upgrade file" del /f /s /Q dfu_fw_signed.stack.psr del /f /s /Q dfu_vm_signed.app.psr del /f /s /Q image_signed.fs del /f /s /Q image_signed.psr del /f /s /Q loader_signed.xdv del /f /s /Q loader_unsigned.xdv del /f /s /Q merge.xdv del /f /s /Q stack_signed.xdv del /f /s /Q stack_unsigned.xdv del /f /s /Q loader_signed.xpv del /f /s /Q loader_unsigned.xpv del /f /s /Q merge.xpv del /f /s /Q stack_signed.xpv del /f /s /Q stack_unsigned.xpv

DFU檔案由以下部分組成:

已加密的stack 已加密的image 已加密的psr,包括vm和fw兩部分

DFU檔案中的psr會覆蓋掉裝置原有的psr。

3.14. 打包release檔案

?
1 2 3 4 5 6 echo. *** copy release note *** copy %origpath%\%ReleaseNoteName%.xlsx %ReleaseNoteName%.xlsx echo. *** package all files *** cd /D %origpath% call "C:\Program Files\WinRAR\rar.exe" a -ep1 -o+ -ibck %ReleasePackageName%.rar %ReleasePackageName%

4. 總結

DFUWizard只支援windows平臺,別的平臺需要另行開發。 loader最好要加密,且生成的金鑰需要妥善儲存。如果金鑰丟失會導致後續DFU升級都不能成功,只能重新生成金鑰並重新燒錄loader。 如果裝置中的loader是未加密的,在跨ADK版本升級時(4.0.0升級到4.0.1),即使DFU升級過程完成了,新的程式也無法正常執行,原因就是被保護PS Keys沒有升級成功,導致程式崩潰。 如果啟用了UART口,進入DFU模式時晶片會reboot失敗,因為UART和USB口功能衝突。這種情況下,DFU模式需要從reboot mode 1啟動,且確保在reboot mode 1內把host interface設成USB。 ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 // --------MODE0-------------------------------------------------------- // BOOTMODE_KEY_LIST_0: Overwrite : //                                HOST_INTRFACE  (1F9) //                                USB PRODUCT ID (2bf) &04B0 = 01F9 02BF // BOOTMODE_KEY_TABLE_0+0: PSKEY_HOST_INTERFACE = USB &04B8 = 0002 //  BOOTMODE_KEY_TABLE_0+1: USB PID = 0xffff (DFU) &04B9 = ffff // PSKEY_INITIAL_BOOTMODE &03cd = 0001
如果PC識別不到裝置,需要檢查PS Keys是否符合以下設定:
PSKEY_USB_PIO_VBUS:開發板需要設定成VDD_CHG PSKEY_USB_DFU_PRODUCT_ID=0xffff