【藍芽】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升級過程
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介面執行DFU2.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"
|
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%
原始碼">3.10. 壓縮原始碼
?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
|
如果裝置出廠時燒錄的是已加密的燒錄檔案,後續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
|
PSKEY_USB_PIO_VBUS:開發板需要設定成VDD_CHG PSKEY_USB_DFU_PRODUCT_ID=0xffff