c语言空中升级协议,BLE的空中升级(OTA)
BLE的OTA可以用来更新固件程序。本文以BlueNRG-1芯片为例,分析OTA实现方案细节。
1. 架构
一个OTA方案至少包括三个部分:
程序类型
描述
当前用户程序
当前正在运行的固件程序
新版用户程序
接收的更新后的固件程序
引导程序
芯片上电先进入引导程序,再跳转到新版程序运行
BlueNRG-1对160kB的内部Flash进行了逻辑分区,分别存放这三个部分程序:
这颗芯片的Flash地址区间为0x10040000 – 0x10068000,共160kB。上图中,最下面的Bootloader为引导程序,随后是两个程序空间,NVM中存放一些关键信息,最后一部分为预留空间,不使用。
APP_A和APP_B地位平等,如果当前程序在APP_A处,则将新版程序写入APP_B,反之亦然。
图中标注了各部分空间的大小,APP_A和APP_B的空间数值是根据总空间160kB减去其他几部分空间再除以2得到的。由此可知,用户更新的程序Flash大小应小于76kB。
芯片复位时直接进入引导程序,引导程序检测当前程序的位置,然后跳转至相应的程序空间。
2. 协议
在对BLE设备执行OTA升级过程,需要约定双方的行为规范。
2.1 从机GATT服务
OTA行为需要在一个专有的GATT服务上进行。该服务的GATT结构如下:
OTA Service
Current Image Char [Read]
New Image Info Char [Write | Read]
New Image Data Char [Write_Without_Response]
Expected Data Block Sequence Number Char [Notify]
该服务共四个特征项。
第一个特征项,用于主机读取从机的有效Flash空间地址和边界。
第二个特征项,用于主机向从机写入新版程序二进制文件的基地址和大小。
第三个特征项,用于主机向从机分块写入新版程序二进制文件的内容,每块共19个字节,包括16个字节文件数据,1字节校验信息,2字节块序号(Block Sequence)。
第四个特征项,用于从机向主机发送期望的块序号,配合第三个特征项,实现一个简单的流程控制功能,以保证二进制文件传输的完整性。
2.2 从机广播数据
可以在从机的广播包中加入特殊字段,以方便主机快速识别从机。
在从机的广播包中,加入Device Name内容。
在从机的扫描响应包中,加入OTA Service UUID内容。
2.3 时序
基本时序如下所示:
3. 引导程序
引导程序完成两个任务:
检测当前程序的位置
跳转到当前程序
在程序的Flash空间基地址,存放的是中断向量表,向量表的第一个元素为_INITIAL_SP,其内容为栈顶的地址,即MSP指针;第二个元素为复位处理函数(Reset_Handler),执行该句柄将执行程序初始化操作并跳转进入C代码的main函数。
所以,引导程序需要做的是检测到当前程序的中断向量表,并执行它的复位处理函数。
中断向量表在程序空间的位置如下图所示:
中断向量表的第五个元素OTA_APP_TAG是自定义的中断向量,它并不响应任何中断,仅仅记录当前程序空间的有效性。
OTA更新成功时,会将新版程序的OTA_APP_TAG设为0xAA5555AA,旧版程序的OTA_APP_TAG设为0x00000000。
引导程序检测两块Flash空间的OTA_APP_TAG值,如果检测到有效值,则设置该空间的程序为有效程序,并擦除旧程序。检测程序伪代码如下:
#define TAG_VALUE(addr) (* ((volatile uint32_t*) ((addr) + OTA_TAG_VECTOR_TABLE_ENTRY_OFFSET)))
if ((TAG_VALUE(APP_A_ADDRESS) == 0xAA5555AA) && (TAG_VALUE(APP_B_ADDRESS) == 0x00000000)) {
// 1. Set APP_A Availability
// 2. Erase APP_B Flash
}
else {
// 1. Set APP_B Availability
// 2. Erase APP_A Flash
}
执行复位处理函数通常在芯片复位时自动执行,然后再进入main函数。由于现在是手动引导用户程序,所以也需要手动执行复位处理函数。
基本思路是:(1)将中断向量表的第一个元素所指向的内容赋给MSP。(2)将中断向量表的第二个元素所指向的内容转换成函数并执行。
其代码如下:
/* 设置MSP */
__set_MSP(*(__IO uint32_t*) appAddress);
/* 执行Reset_Handler */
uint32_t JumpAddress = *(__IO uint32_t*) (appAddress + 4);
pFunction Jump_To_Application = (pFunction) JumpAddress;
Jump_To_Application();
代码中的appAddress表示检测到的当前程序空间的Flash基地址,所以appAddress指向_INITIAL_SP, (appAddress + 4)指向OTA_APP_TAG元素。
4. 用户程序存储位置
用户程序准备好以后,需要先烧录引导程序,再烧录用户程序。用户程序可能放在APP_A空间,也可能放在APP_B空间,而且不能覆盖引导程序。
需要利用链接文件(*.icf)控制程序在Flash上的存放位置。
打开程序的链接文件(BlueNRG1.icf),发现里面的内容十分复杂,一眼望不到头。下面挑出重要的代码,挖掘程序保存在Flash指定位置的思路。以APP_A程序为例:
define symbol _MEMORY_FLASH_BEGIN_ = 0x10040000;
define symbol RESET_MANAGER_SIZE = 0x800; /* 2KB */
define symbol MEMORY_FLASH_APP_SIZE = 0x13000; /* 76KB */
define symbol _MEMORY_FLASH_OFFSET_ = RESET_MANAGER_SIZE;
define region REGION_FLASH = mem:[from _MEMORY_FLASH_BEGIN_ + _MEMORY_FLASH_OFFSET_
to _MEMORY_FLASH_BEGIN_ + _MEMORY_FLASH_OFFSET_ + MEMORY_FLASH_APP_SIZE - 1];
place at start of REGION_FLASH { readonly section .intvec };
第一行,定义了当前内存的开始地址,这个地址是芯片规定的Flash起始地址。
第二行,定义了引导程序的大小,代码中引导程序用“Reset Manager”表示。
第三行,定义了用户程序的大小,为76KB。
第四行,定义了用户程序相对于Flash起始地址的偏移量。对于APP_A而言,该偏移量为引导程序的大小(RESET_MANAGER_SIZE),对于APP_B而言,该偏移量为引导程序的大小加上APP_A的大小(RESET_MANAGER_SIZE + MEMORY_FLASH_APP_SIZE)。
第五行,定义了REGION_FLASH区域,这块区域就是当前用户程序的Flash区域。
最后一行,表示所有的readonly数据、.intvec段都放在REGION_FLASH区域的开头,翻译过来就是中断向量表放在REGION_FLASH的起始位置。这一行就决定了烧录工程二进制文件时,从REGION_FLASH的开头处开始烧写。
对于APP_B程序,只需要将第四行做如下更改即可:
define symbol _MEMORY_FLASH_OFFSET_ = RESET_MANAGER_SIZE + MEMORY_FLASH_APP_SIZE
5. 实现协议
系统提供了OTA_btl.c/OTA_btl.h两个文件,将所有的操作都打包成了API,这里分析其实现思路。
5.1 添加GATT服务
OTA Service的UUID、特征项、特性都已经定义好,所以可以封装成无参函数,在初始化BLE的GATT时候多添加这个服务项即可。
5.2 特征项
Current Image Char特征项需要准备当前设备空闲的程序空间供主机读取,由于这些数据是静态数据,所以在构建GATT服务时即可完成。
有三个特征项需要接收主机的Write数据,在回调函数中需要分别处理。
对于New Image Info Char特征项,接收的数据中包括新程序文件的大小和基地址。
对于New Image Data Char特征项,接收的数据位新程序文件的数据块,还附带校验信息和块序号。如果校验和块序号均有效,则立即写入Flash。同时统计总的数据长度,如果等于前面接收的程序文件的大小,说明传输完毕,则设置两个程序空间的标志位。
对于Expected Data Block Sequence Number Char特征项,写入一个数据块后会发送一个Notification给主机,告知下一个期望的块序号。
5.3 设置标志位
设置标志位时候只需要利用用户程序空间基地址,加上合适的偏移量,用标准库函数FLASH_ProgramWord写入即可。
6. APP_A与APP_B区别
Flash层面区别,二者是独立的。在链接文件中,需要用代码将应用程序的基地址指向APP_A或APP_B的基地址。
软件层面,主机需要知道从机的空闲Flash的地址和边界,在Current Image Char中需要将APP_A或APP_B的地址信息以硬代码形式写入程序。设置标志位时候,也需要知道当前程序是APP_A还是APP_B。
实际使用时,主机端需要准备APP_A和APP_B两套bin文件,先与从机沟通确定旧程序所在位置,然后选出合适的新程序传给从机。
疑问——能不能实现用户编程时候不管APP_A或APP_B,在设备端或主机端自动判断位置并将二进制文件写入到合适的Flash地址?
7. 单程OTA
前面介绍的OTA方案,新旧程序独立存放,因此在OTA升级过程中如果断电,重启后仍然可以运行旧程序。
但是该方案用户程序只能使用不足一半的Flash空间,浪费较多。
单程OTA方案不分割应用程序空间,将OTA Service 放在引导程序,更新时候在引导程序中接收新程序数据,并直接覆盖在程序空间。
这样好处是能够有效利用Flash空间,但如果OTA中途失败,将破坏旧程序,重启后会(且只能)进入等待升级状态。
单程OTA方案架构图如下:
实现思路与需要考虑的问题,与双程OTA方案大同小异。
(完)
c语言空中升级协议,BLE的空中升级(OTA)相关推荐
- c语言空中升级协议,esp32 http空中升级
1. 先搭建一个HTTP服务器 先将hello_wordl例子拷贝到~/esp中,在hello_wordl/build中创建get文件夹,且将hello-world.bin 放进去. cp -r $I ...
- aptos中文版白皮书-前Facebook团队打造明星公链,三个优势:Move语言、Move虚拟机、合约可升级
摘要 区块链作为一种新的互联网基础设施的崛起,导致开发者以快速增长的速度部署了数万个去中心化的应用程序.不幸的是,由于频繁的中断.高成本.低吞吐量限制和许多安全问题,区块链的使用还不普遍.为了在web ...
- OC语言Block和协议
OC语言Block和协议 分类: OC基础2014-10-07 09:24 162人阅读 评论(0) 收藏 举报 OC Block OC协议 OC语言BLOCK和协议 一.BOLCK (一)简介 B ...
- c语言编写modbus程序,C语言编写modbus协议
<C语言编写modbus协议>由会员分享,可在线阅读,更多相关<C语言编写modbus协议(23页珍藏版)>请在人人文库网上搜索. 1.include / 字地址 0 - 25 ...
- 从入门到入土:基于C语言采用UDP协议实现远程控制|详细说明|利用流套接字实现一个简单的远程控制系统|代码展示
此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 本人博客所有文章纯属学习之用,不涉及商业利益.不合适引用,自当删除! 若 ...
- 从入门到入土:基于C语言采用TCP协议实现远程控制|详细说明|利用流套接字实现一个简单的远程控制系统
此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 本人博客所有文章纯属学习之用,不涉及商业利益.不合适引用,自当删除! 若 ...
- 从入门到入土:基于C语言采用TCP协议实现通信功能的程序(仅有代码)
此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 本人博客所有文章纯属学习之用,不涉及商业利益.不合适引用,自当删除! 若 ...
- 从入门到入土:基于C语言采用UDP协议实现通信功能的程序
此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 本人博客所有文章纯属学习之用,不涉及商业利益.不合适引用,自当删除! 若 ...
- STM32 CUbeIDE 使用Ymodem协议进行串口IAP升级
STM32 CUbeIDE 使用Ymodem协议进行串口IAP升级 1.Ymodem协议简介 2.Boodload程序 2.1 传输32K限制解决 3.APP程序 4.升级测试 5.工程文件下载 ...
最新文章
- 分布式缓存的选择及问题
- datanode 不能连接master
- GLSL实现滤镜效果
- $_SERVER[HTTP_HOST]
- 机器学习之路:python 集成分类器 随机森林分类RandomForestClassifier 梯度提升决策树分类GradientBoostingClassifier 预测泰坦尼克号幸存者...
- C语言实现--背包问题 算法(Knapsack Problem)
- 【Swing】了解Swing,Swing是什么?
- bryntum gantt 5.0.6
- SD卡无法识别怎么办?
- 解析BMP GIF JPEG TGA PNG图像格式
- 基于java的商城后台管理系统计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署
- OpenCV:minMaxLoc vs minMaxIdx
- java 字符串转时间,时间转字符串
- oracle索引 oracle索引结构 oracle索引使用 B*Tree索引
- 一些英文词的标准缩写
- 第十四章 SQL命令 CREATE TABLE(一)
- 训练时评估指标无变化,且预测值都一样
- windows平台 VS2017 live555 rtsp推流服务器编译
- bulk es 删除_ES 批量操作 bulk
- linux php环境搭建教程,linux php环境搭建教程
热门文章
- Android Adapte中getItemViewType越界问题
- python制作字符画视频来啦~
- Java WebSocket实现简易聊天室
- 网易游戏研发工程师笔试题----赛马
- 在Unity中,PlayableBehaviour如何获取片段的开始和结束时间?
- C++ TGP 模板基础知识--01函数模板
- 【珍爱生命,抵制淘宝,淘宝售后!!!只售不后】
- node.js学习笔记Day8:关于回调地狱和其解决方案Promise的几个应用和理解。
- C语言的运行环境及运行方法(例子)
- DELPHI常用函数集及简要范例(转载大富翁)