什么是OAD
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”文件,所以我们在下面的介绍文档中用ImageA来统称这三者合并之后的“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的时候会在编译完成的时候调用Python执行“hexmerge.py”脚本来将编译生成的三个hex文件合并成一个。
2.BIM和CC2640Stack的编译没有什么问题,我们不再讲述,下面重点来看一下CC2640App编译之后执行合成脚本的时候出现的问题,没有进行任何配置的情况下,会提示下面截图的信息:
这个错误是因为没有安装Python或者你安装的目录不是“C:\Python27\”下,导致找不到该执行文件,Python的安装过程可以参考下面链接中的博文:
Python安装完成并配置环境变量之后,我们还需要下载合成脚本,并复制到Python的安装目录下,合成脚本“hexmerge.py”的下载链接如下:
打开上述下载链接之后截图如下:
上面链接中列出了很多不同时期的版本,我下载的是上述截图中的红圈圈中的这个,下载到电脑上之后,解压缩显示如下:
我们需要的脚本在解压出来的文件夹的“scripts”目录下,将该目录下的所有py脚本都复制到“C:\Python27\Scripts”目录下。
3.重新编译“CC2640App”,但是这个时候又会出现下面的编译错误:
从上面截图中的编译错误提示,我们看不出什么原因,这个时候,我们可以将错误提示中的那些命令复制出来,删掉换行符和不必要的空格,剩下的内容如下:
python "C:\Python27\Scripts\hexmerge.py" -o "C:\ti\simplelink\ble_cc26xx_2_01_00_44423\Projects\ble\OADTarget\CC26xx\IAR\Application\CC2640\FlashROM\Exe\OAD_merge.hex" -r "0000:1FFFF" --overlap=error "C:\ti\simplelink\ble_cc26xx_2_01_00_44423\Projects\ble\OADTarget\CC26xx\IAR\Application\CC2640\FlashROM\Exe\OADTargetApp.hex":0100:1FFFF "C:\ti\simplelink\ble_cc26xx_2_01_00_44423\Projects\ble\OADTarget\CC26xx\IAR\Application\CC2640\..\..\..\..\..\util\BIM\CC26xx\FlashOnly\Exe\BIM.hex":0000:1F5FF "C:\ti\simplelink\ble_cc26xx_2_01_00_44423\Projects\ble\OADTarget\CC26xx\IAR\Application\CC2640\..\..\Stack\CC2640\FlashROM\Exe\OADTargetStackFlashROM.hex":F000:1EFFF
这其实就是合并文件的命令,而且是绝对路径的,那我们就可以在windows命令行中运行一下看看是否会提示更详细的错误信息,运行结果截图如下:
果然,不出所料的有更详细的提示信息,提示错误是导入“intelhex”模块的时候发现没有该模块,当然,我们也可以打开“hexmerge.py”脚本,然后看看错误提示中提到的139行的内容,来了解具体执行的地方,截图如下:
解决办法:将下载解压的“intelhex-2.1”文件夹下的“intelhex”文件夹整个复制到“C:\Python27”目录下,然后重新编译,这样就可以成功编译了,编译成功之后会在
“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。有的人觉得为了这个功能单独配置一个服务和特征值太浪费了,那我们可以将这个服务和特征值删掉,然后在你必须要保留的特征值中找一个带有写权限的,然后在主机通过该特征值写入某个命令的时候执行上述代码即可。
到这里,CC2640 OAD的整个过程就了解完了。
TI官方OAD文档
TI官方OAD文档在安装的协议栈中,在
“C:\ti\simplelink\ble_cc26xx_2_01_00_44423\Documents”目录下的“CC2640 BLE OAD User's Guide.pdf”文档中。