更新时间:2024-04-11 06:52:37下载pdf
OTA(Over-the-Air)即空中下载技术,通过网络远程为设备更新和升级软件程序。
Wi-Fi 标准协议接入支持 MCU OTA 功能。通过 涂鸦 IoT 开发平台,先将需要更新的固件文件上传至涂鸦服务器,然后 Wi-Fi 模组通过涂鸦协议对文件进行分包传输,最后 MCU 接收升级包并写入本地闪存,最终实现固件的升级。详细的平台操作,参考 固件升级 和 选择和管理固件版本。
MCU OTA 功能需要设备 MCU 资源支持,设备配网成功后,通过平台配置或升级检测,可以启动 OTA 流程。升级流程如下:
Wi-Fi 模组发送完所有的升级包,重新发送查询产品指令 0x01
,MCU 需要在一分钟回复产品信息中的 MCU 软件版本号(升级后的版本号),版本号需要和在涂鸦后台配置升级的版本号保持一致。
MCU OTA 升级成功条件是固件包传输完成,设备重启上报新的版本号,两者同时完成才会提示成功。
设备不论是在调试阶段还是出厂阶段,都可以使用 MCU OTA 功能进行 MCU 固件的更新迭代,实现设备功能的优化升级。在 MCU 硬件资源支持的情况下,建议增加 OTA 功能。
固件管理:使用 MCU OTA 功能需要先将验证正确的 MCU 固件上传到涂鸦服务器,固件上传及管理操作参考 固件管理。
应用说明:根据是否移植涂鸦协议 SDK 分为移植 SDK 和自行对接。这两种方式都需要自行完成 BootLoader 开发。
移植 SDK:使用 MCU SDK 提供的函数,回复固件分包传输大小启动升级过程,并接收模组发送的固件包,接收到的固件包需要 MCU 自行处理。可参考下面 SDK 示例介绍。
自行对接:需要自行实现 OTA 功能相关协议指令,完成固件传输配置及固件包接收处理。
设备需要先完成协议基础功能对接,MCU RAM 需大于 260B。
何时升级由客户在涂鸦 IoT 开发平台自己的产品页面配置相关升级选项触发。模组仅作为支持 MCU 升级的数据传输通道,也不对数据内容做任何解析。
目前,涂鸦平台的 MCU 升级支持以下三种升级方式的配置:
OTA 流程涉及以下协议指令:
命令字 | 命令说明 |
---|---|
0x0a | MCU 升级启动(升级包大小通知) |
0x0b | MCU 升级包传输 |
启动 OTA 升级后,模组首先会使用0x0a
指令告诉 MCU 升级固件包大小,此时 MCU 需回复模组固件分包传输大小。
升级包分包传输大小
回复升级包分包传输值 | 升级包分包大小 |
---|---|
0x00 | 默认 256 字节(兼容旧固件) |
0x01 | 512 字节 |
0x02 | 1024 字节 |
模组发送
字段 | 字节数 | 说明 |
---|---|---|
帧头 | 2 | 0x55aa |
版本 | 1 | 0x00 |
命令字 | 1 | 0x0a |
数据长度 | 2 | 0x0004/0x0008 |
数据 | 4 | 固件包字节数,unsigned int,大端 |
数据 | 1 | MCU Type: 10~19 |
数据 | 3 | 预留扩展 |
校验和 | 1 | 从帧头开始,按字节求和,得出的结果对 256 求余 |
示例:55 aa 00 0a 00 04 00 00 68 00 75
表示固件包长度 26624,即 26KB。
MCU 返回
字段 | 字节数 | 说明 |
---|---|---|
帧头 | 2 | 0x55aa |
版本 | 1 | 0x03 |
命令字 | 1 | 0x0a |
数据长度 | 2 | 0x0001 |
数据 | 1 | 升级包分包传输大小:
|
校验和 | 1 | 从帧头开始,按字节求和,得出的结果对 256 求余 |
示例:55 aa 03 0a 00 01 00 0d
模组通过该指令按包传输固件包给到 MCU,MCU 接收到传输分包进行接收处理。若 MCU 5s 内未回复模组,模组将进行重发,若 3 次重发后仍未收到 MCU 回复,则认为升级失败。
模组发送
字段 | 字节数 | 说明 |
---|---|---|
帧头 | 2 | 0x55aa |
版本 | 1 | 0x00 |
命令字 | 1 | 0x0b |
数据长度 | 2 | 0x0004+N |
数据 | 4+N |
|
校验和 | 1 | 从帧头开始,按字节求和,得出的结果对 256 求余 |
示例:
若要升级的文件大小 530 字节,(最后一包数据可不回复)
0x00000000
,数据包长度为 256 字节55 aa 00 0b 01 04 00000000 xx…xx XX
0x00000100
,数据包长度为 256 字节55 aa 00 0b 01 04 00000100 xx…xx XX
0x00000200
,数据包长度为 18 字节55 aa 00 0b 00 16 00000200 xx…xx XX
0x00000212
,数据包长度为 0 字节55 aa 00 0b 00 04 00000212 xx...xx XX
MCU 返回
字段 | 字节数 | 说明 |
---|---|---|
帧头 | 2 | 0x55aa |
版本 | 1 | 0x03 |
命令字 | 1 | 0x0b |
数据长度 | 2 | 0x0000 |
数据 | 0 | 无 |
校验和 | 1 | 从帧头开始,按字节求和,得出的结果对 256 求余 |
示例:55 aa 03 0b 00 00 0d
打开 SUPPORT_MCU_FIRM_UPDATE
宏定义,开启 MCU 固件 OTA 功能。
#define SUPPORT_MCU_FIRM_UPDATE //开启 MCU 固件升级功能,默认关闭
/* Firmware package size selection */
#ifdef SUPPORT_MCU_FIRM_UPDATE
#define PACKAGE_SIZE 0 //包大小为 256 字节
//#define PACKAGE_SIZE 1 //包大小为 512 字节
//#define PACKAGE_SIZE 2 //包大小为 1024 字节
#endif
在串口接收数据处理函数 data_handle()
中,收到模组发来的 MCU 升级启动命令。
/**
* @brief 数据帧处理
* @param[in] {offset} 数据起始位
* @return Null
*/
void data_handle(unsigned short offset)
{
......
case UPDATE_START_CMD: //升级开始
//获取升级包大小全局变量
firm_flag = PACKAGE_SIZE;
if(firm_flag == 0) {
firm_size = 256;
}else if(firm_flag == 1) {
firm_size = 512;
}else if(firm_flag == 2) {
firm_size = 1024;
}
firm_length = wifi_data_process_buf[offset + DATA_START];
firm_length <<= 8;
firm_length |= wifi_data_process_buf[offset + DATA_START + 1];
firm_length <<= 8;
firm_length |= wifi_data_process_buf[offset + DATA_START + 2];
firm_length <<= 8;
firm_length |= wifi_data_process_buf[offset + DATA_START + 3];
upgrade_package_choose(PACKAGE_SIZE);
firm_update_flag = UPDATE_START_CMD;
break;
......
}
MCU SDK 调用 upgrade_package_choose()
回复分包大小,该函数定义在 protocol.c
文件中。开发者需通过以上宏,实现升级包分包传输大小配置。
/**
* @brief 升级包大小选择
* @param[in] {package_sz} 升级包大小
* @ref 0x00:256 字节 (默认)
* @ref 0x01:512 字节
* @ref 0x02:1024 字节
* @return Null
* @note MCU 需要自行实现该功能
*/
void upgrade_package_choose(unsigned char package_sz)
{
#error "请自行实现升级包大小选择代码,完成后请删除该行"
unsigned short send_len = 0;
send_len = set_wifi_uart_byte(send_len, package_sz);
wifi_uart_write_frame(UPDATE_START_CMD, MCU_TX_VER, send_len);
}
调试助手示意图
启动 OTA 过程后,模组按照约定的分包大小给 MCU 发送数据包,在串口接收数据处理函数 data_handle()
中,收到模组发来的数据包。
/**
* @brief 数据帧处理
* @param[in] {offset} 数据起始位
* @return Null
*/
void data_handle(unsigned short offset)
{
......
case UPDATE_TRANS_CMD: //升级传输
if(firm_update_flag == UPDATE_START_CMD) {
//停止一切数据上报
stop_update_flag = ENABLE;
total_len = (wifi_data_process_buf[offset + LENGTH_HIGH] << 8) | wifi_data_process_buf[offset + LENGTH_LOW];
dp_len = wifi_data_process_buf[offset + DATA_START];
dp_len <<= 8;
dp_len |= wifi_data_process_buf[offset + DATA_START + 1];
dp_len <<= 8;
dp_len |= wifi_data_process_buf[offset + DATA_START + 2];
dp_len <<= 8;
dp_len |= wifi_data_process_buf[offset + DATA_START + 3];
firmware_addr = (unsigned char *)wifi_data_process_buf;
firmware_addr += (offset + DATA_START + 4);
if((total_len == 4) && (dp_len == firm_length)) {
//最后一包
ret = mcu_firm_update_handle(firmware_addr,dp_len,0);
firm_update_flag = 0;
}else if((total_len - 4) <= firm_size) {
ret = mcu_firm_update_handle(firmware_addr,dp_len,total_len - 4);
}else {
firm_update_flag = 0;
ret = ERROR;
}
if(ret == SUCCESS) {
wifi_uart_write_frame(UPDATE_TRANS_CMD, MCU_TX_VER, 0);
}
//恢复一切数据上报
stop_update_flag = DISABLE;
}
break;
......
}
MCU SDK 调用 mcu_firm_update_handle()
将数据、数据包位置数据和数据包长度传递给 MCU,MCU 根据相关参数做固件数据处理。开发者需实现该函数。
/**
* @brief MCU 进入固件升级模式
* @param[in] {value} 固件缓冲区
* @param[in] {position} 当前数据包在于固件位置
* @param[in] {length} 当前固件包长度,固件包长度为 0 时表示固件包发送完成
* @return Null
* @note MCU 需要自行实现该功能
*/
unsigned char mcu_firm_update_handle(const unsigned char value[],unsigned long position,unsigned short length)
{
#error "请自行完成 MCU 固件升级代码,完成后请删除该行"
if(length == 0) {
//固件数据发送完成
}else {
//固件数据处理
}
return SUCCESS;
}
调试助手示意图
当 mcu_firm_update_handle()
函数接收到固件包长度为 0
时,表示固件包发送完成,MCU 在此时可以做 MCU 固件升级处理。开发者需实现该函数。
/**
* @brief MCU 进入固件升级模式
* @param[in] {value} 固件缓冲区
* @param[in] {position} 当前数据包在于固件位置
* @param[in] {length} 当前固件包长度(固件包长度为 0 时,表示固件包发送完成)
* @return Null
* @note MCU 需要自行实现该功能
*/
unsigned char mcu_firm_update_handle(const unsigned char value[],unsigned long position,unsigned short length)
{
#error "请自行完成 MCU 固件升级代码,完成后请删除该行"
if(length == 0) {
//固件数据发送完成
}else {
//固件数据处理
}
return SUCCESS;
}
该内容对您有帮助吗?
是意见反馈该内容对您有帮助吗?
是意见反馈