接上一篇博文,使用了在线升级的STM32程序的方法。此篇博文将利用4G模块Air720H,使用AT指令集,通过HTTP协议从云端服务器下载新版固件,从而实现对STM32的远程无线程序升级。
前面关于前期准备工作,在此不再累述 具体可以参考上一篇博文https://blog.csdn.net/ylzmm/article/details/104234099,关于简易的HTTP服务器的搭建参考这篇博文https://blog.csdn.net/ylzmm/article/details/104311190。
本文在 RT_thread给出的HTTP升级的案例(具体参考https://www.rt-thread.org/document/site/application-note/system/rtboot/an0028-rtboot/中的源码实现部分),进行了部分修改。修改了为AT指令的方式获取固件。以下是整体的升级思路和在使用AT指令获取固件时需要注意的事项。
1.AT指令获取固件 (未提供完整AT指令步骤,重点步骤提出)
发送:AT+HTTPACTION=0
应答:
OK
+HTTPACTION: 0,200,92240 /*200为正常的服务器返回状态 92240为固件大小*/
发送:AT+HTTPREAD=0,100 /*0表示获取固件从固件头开始,100表示获取前100个字节*/
应答: /*100,100 表示获取从固件的100字节开始,后面100个字节*/
+HTTPREAD: 100 /*本次获取的固件大小100*/
RBLk??^app2.0.000010203040506070809`?荱{qa苎餲噗?%2? /*实际固件数据*/
OK
通过AT指令依次循环获取固件数据,获取一批固件数据,写入FLASH,以此循环。
2.固件数据的接收与写入处理
但是我在调试的过程中遇到了一个很奇特的问题。在升级固件时偶尔会出现升级失败的现象,提示固件的CRC校验错误,明显是固件数据出现了遗漏。开始的时候我一直觉得是HTTP通信的问题,通信上下载固件数据偶尔出现了掉数据,后面实际中测试发现某次固件升级不成功,他会一直不成功,无论你重复下载多少次。由此排除了通信遗漏数据问题。之前我遇到的问题可以参考论坛中这一篇https://www.rt-thread.org/qa/thread-423550-1-1.html。
采用论坛中网友的答复的方法,从而解决了这个问题。
确实。我进行AT指令的应答处理中,我遗漏了一个很严重的问题。固件数据是一堆16进制的数据,如果我以读取到OK,或者\r\n
这样的判断方式来进行判断本次接收固件数据完毕,很容易出现误判,固件数据可能存在干扰。
最后采用了以下方式成功做到了100%升级:
/*仅仅发送 应答数据在URC函数中处理*/
if (at_exec_cmd(NULL,"AT+HTTPREAD=%d,4096",len_fir) != RT_EOK)
{
LOG_E("AT+HTTPACTION=%d,4096, send commands failed , response error or timeout
!",len_fir);
goto __exit;
}
/*发送邮件 下载的字节数*/
rt_mb_send(&http_mb, (rt_uint32_t)4096);
/* 等待http数据传回 信号量 */
result = rt_sem_take(http_dysem, HTTP_OTA_OUTTIME);
AT指令只是发生下载的固件的指令,不进行返回值的判断处理。一直等待一个信号量。
/*HTTP固件信息数据处理*/
static void urc_http_func(struct at_client *client ,const char *data, rt_size_t size)
{
char *recv_buf = RT_NULL;
int number = 0;
recv_buf = (char *)rt_calloc(1, 4096);
if (rt_mb_recv(&http_mb, (rt_ubase_t *)&number, RT_WAITING_FOREVER) == RT_EOK)
{
at_client_obj_recv(client,recv_buf,number,number);
// /*打印接收部分数据*/
// ulog_hexdump(LOG_TAG, 16, (rt_uint8_t *)recv_buf, number);
rt_memset(firmware_http,0,sizeof(firmware_http));
rt_memcpy(firmware_http,recv_buf,number);
rt_sem_release(http_dysem);
}
rt_free(recv_buf);
}
static struct at_urc urc_firmware[]= {
{"+HTTPREAD:", "\r\n", urc_http_func},
};
通过注册URC回调函数,当接收到“+HTTPREAD:”数据时,表明了正在进入了固件下载时。于是在URC回调函数中进行接收指定的固件数的大小的数据字节即可。
更加具体的代码实现,可以去参考RT的底层上关于TCP接收服务器下发的数据的处理方法。
2020.2.23 补充几个可能遇到的问题:
1. 注意修改宏定义大小 RT_SERIAL_RB_BUFSZ 。每次重新使用ENV工具生成工程后,会被重置为64。这里应该设置为大于4096。
2. 在AT组件的ENV配置过程中,不要开启图中这一项。不知道为什么开启后,在极少的情况下,AT指令的在发送上可能会失败。
3. 注意在配置串口的引脚的电气属性时,一定记得配置上拉,不要处于浮空状态。不然在一定的情况下引脚会受到干扰。