本文源自:https://blog.csdn.net/wzz4420381/article/details/52371409

作者:RyomaWang

申明:为了保持原作者内容,这里不进行任何修改,后续另写一篇随笔,作为补充和说明。

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安装路径

:: 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. 设置全局变量

:: 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文件夹

:: 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. 更新调试接口

:: 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工程

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文件

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. 生成未加密的工厂烧录文件

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一起烧录进目标板后,就可以读出完整的工厂烧录文件。

echo. *** cold reset ***
call %adkpath%\tools\bin\pscli.exe -TRANS "%debugtransport%" cold_reset echo. *** dump file from board ***
cd /D %origpath%\%ReleasePackageName%\"BT_Program file"
call %adkpath%\tools\bin\BlueFlashCmd.exe -TRANS "%debugtransport%" dump %projectpsr3%

3.10. 压缩源码

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文件

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. 生成已加密的工厂烧录文件

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文件

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文件

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。
// --------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

[转发]CSR8670的DFU功能的更多相关文章

  1. 十、CSR8670的DFU功能[补充]

    前一篇转载的博文很清楚,全面的介绍了DFU功能的实现步骤.关于DFU功能,你还需要知道以下信息: 一.image.fs,firmware,loader,psr之间的关系 图1-1 image.fs示意 ...

  2. 定向转发和重定向实现 <select >下拉表单数据传送

    定向转发的特点:   (1). 实行转发时浏览器上的网址不变  (如果你这点忽视了,那你就要接受我无尽的鄙视吧! 哇咔咔~~~)    (2). 实行转发时 :   只有一次请求.  不信,看这下面的 ...

  3. SSH有端口映射功能(访问本地端口=访问远程端口)

    大部分SSH连接软件都有SSH通道转发功能,就是用这个实现的. 如果Delphi在代码上实现的话,用libSSH 或者 SecureBridge都可以. 代码基本不用帖,思路给大家讲一下吧. SSH有 ...

  4. SSH端口转发详解及实例

    一.SSH端口转发简介 SSH会自动加密和解密所有SSH客户端与服务端之间的网络数据.但是,SSH还能够将其他TCP端口的网络数据通SSH链接来转发,并且自动提供了相应的加密及解密服务.这一过程也被叫 ...

  5. ServletRequest HttpServletRequest 请求方法 获取请求参数 请求转发 请求包含 请求转发与重定向区别 获取请求头字段

      ServletRequest 基本概念 JavaWeb中的 "Request"对象  实际为   HttpServletRequest  或者  ServletRequest, ...

  6. SSH端口转发详解及实例-转载

    作者:珂儿吖 出处:http://www.cnblogs.com/keerya/ 目录 1.1 SSH端口转发的两大功能 实验一:实现SSH端口转发——本地转发 实验二.实现SSH端口转发——远程转发 ...

  7. Linux 网卡驱动学习(九)(层二转发)

    1.mac 地址表的自学习过程 port1上的A计算机要与port2上的B计算机通信时,A发到交换机上,交换机收到信息后,交换机先记录发port1所相应的a的mac地址并记录在自己的mac表中,然后再 ...

  8. 6tunnel数据转发

    6tunnel 一条命令实现端口映射.数据转发,实现代理服务器功能. 安装脚本 #!/bin/bash DIR=/opt/software INSTALL=6tunnel-master.tar.gz ...

  9. Qt编写气体安全管理系统15-网络转发

    一.前言 在本系统中网络转发是个什么功能含义呢,其实就是将本地采集设备的所有数据打包发送到指定的网络地址,默认采用UDP的形式,无连接开销小,我也是看到很多的组态软件有这个功能,其实现有的很多的气体探 ...

随机推荐

  1. 小白学 Python(7):基础流程控制(上)

    人生苦短,我选Python 前文传送门 小白学 Python(1):开篇 小白学 Python(2):基础数据类型(上) 小白学 Python(3):基础数据类型(下) 小白学 Python(4):变 ...

  2. 如果有人问你 MySql 怎么存取 Emoji,把这篇文章扔给他

    01.前言 Emoji 在我们生活中真的是越来越常见了,几乎每次发消息的时候不带个 Emoji,总觉得少了点什么,似乎干巴巴的文字已经无法承载我们丰富的感情了.对于我们开发者来说,如何将 Emoji ...

  3. 百万年薪python之路 -- 模块

    1.自定义模块 1.1.1 模块是什么? 模块就是文件,存放一堆常用的函数和变量的程序文件(.py)文件 1.1.2 为什么要使用模块? 1.避免写重复代码,从文件级别组织程序,更方便管理 2.可以多 ...

  4. 百万年薪python之路 -- 装饰器

    装饰器 1.1 开放封闭原则 开放封闭原则具体定义是这样: 1.对扩展是开放的 我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改.所以我们必须允许代码扩展.添加新 ...

  5. Helm神器,让管理Kubernetes像yum安装包一样简单

    目录 一.什么是Helm 二.安装 1.安装helm客户端 2.安装Tiller 3.创建服务端 4.给Tiller授权 5.为 Tiller 设置帐号 6.验证Tiller是否安装成功 三.Helm ...

  6. Linux常用命令(1)

      常用命令(1)   1.系统相关命令 su 切换用户 hostname 查看主机名 who 查看登录到系统的用户 whoami 确认自己身份 history 查看运行命令的历史 ifconfig ...

  7. 完美解决Python与anaconda之间的冲突问题

    anaconda指的是一个开源的Python发行版本,其包含了conda.Python等180多个科学包及其依赖项.因为包含了大量的科学包,Anaconda 的下载文件比较大(约 515 MB),如果 ...

  8. 【IDEA】IDEA自动生成文档注释的设置方法

    Digest:今天和大家分享一下如何使用IntelliJ IDEA快速生成文档注释 IntelliJ IDEA创建自定义文档注释模板 1.打开IntelliJ IDEA,依次点击 File --> ...

  9. Mui 微信支付、支付宝支付

    利用mui 发起手机微信和支付宝支付 payStatement :调起微信支付接口的参数 参考文档: https://pay.weixin.qq.com/wiki/doc/api/app/app.ph ...

  10. 新的服务器安装的mysql使用navcat连接不上

    首先出现问题 然后在防火墙添加3306端口 /sbin/iptables -I INPUT -p tcp --dport 3306 -j ACCEPT 又出现了问题 ERROR 1130: Host ...