您的位置:首页 > 其它

10. ESP8266通过OTA更新固件的实践

2017-07-26 14:02 393 查看
1. OTA是什么

OTA(Over The Air),通常也称为FOTA(Firmware Over The Air),意思是硬件中的固件通过无线升级版本。众所周知,硬件固件的部署,以及固件版本升级颇为繁琐,很多时候得通过人工完成,成本很高。所以OTA是一个颇为实用、也是很实惠的功能。

手环等设备,其实也有这类问题,一般都是通过APP升级-> ->蓝牙固件升级的方式。

2. 乐鑫对OTA的支持

ESP8266的厂商乐鑫提供了FOTA的功能,AT固件和NONSDK的都支持。

根据官方资料,乐鑫的FOTA是通过HTTP协议实现,且支持自建FOTA下载服务(WEB服务器)。

但乐鑫对常用功能和传感器的支持力度较少,需要不停造轮子、找轮子,效率相对较低。

在乐鑫以外,esp-open-rtos等也可以支持OTA功能,该有的功能都已经具备。

加之对mqtt、传感器的驱动支持更好,因此esp-open-rtos是个不错的选择,

本文基于esp-open-rtos的OTA实现了在线升级的简单例子,并对原理进行说明。

关于esp-open-rtos详细,可参照前文http://blog.csdn.net/ydogg/article/details/75194902

3. Esp-open-rtos的OTA简介

Esp-open-rtos的OTA实现也很简洁:

通过tftp协议在线下载固件,利用rboot进行新旧固件的切换和硬件重启。

其中固件下载支持client和server两种模式,可根据具体情况选择一种,也可同时使用。

Client模式下,是从tftp服务器中下载固件;

Server模式下,是esp8266作为tftp服务,接收tftp客户端发送的新固件。

总的来说,Client模式更加灵活些,可以通过各种事件进行触发(如mqtt通知),且硬件侧的负载更轻。

本文基于Client模式进行说明。

4. OTA环境准备

主要是tftp的安装,下面命令以CentOS为例:

yum install tftp-server tftp


默认情况下tftp是托管给xinit,其配置文件位于/etc/xinit.d/tftp,内容如下:

service tftp
{
socket_type     = dgram
protocol        = udp
wait            = yes
user            = root
server          = /usr/sbin/in.tftpd
server_args     = -s /var/lib/tftpboot -c
disable         = yes
per_source      = 11
cps         = 100 2
flags           = IPv4
}


server_args中 –s指明了tftp服务所使用的磁盘路径;如果需要上传,需要增加-c选项。

在OTA只需要下载,因此可以不开启-c。(直接复制新固件到/var/lib/tftpboot下即可)

测试:

# cp mybin/xxx.bin /var/lib/tftpboot


# tftp -m binary <yourip> -c get xxx.bin


如果能成功取得xxx.bin,说明tftp服务正常。

另外, tftp的端口为69,如有防火墙,注意相关设置需要放开。

5. OTA代码准备

在esp-open-rtos/examples/ota_basic下,有OTA的示例代码,

但因为有固件验证等功能,略复杂,理解方便起见,精简为如下代码:

#include <string.h>
#include "espressif/esp_common.h"
#include "esp/uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "esp8266.h"
#include "ssid_config.h"

#include "ota-tftp.h"
#include "rboot-api.h"

/* TFTP client will request this image filenames from this server */
#define TFTP_IMAGE_SERVER "192.168.31.192"
#define TFTP_IMAGE_FILENAME1 "fm1.bin"
#define TFTP_IMAGE_FILENAME2 "fm2.bin"

void download_and_restart(char* filename)
{
if( !filename ) {
return;
}

// 获取当前固件的slot序号
rboot_config conf = rboot_get_config();
int slot = (conf.current_rom + 1) % conf.count;

// 只有1个slot时不能进行OTA
// 2个的情况下(一般有2个),新固件会被放到非当前(空闲)的那个slot下
if(slot == conf.current_rom) {
printf("FATAL ERROR: Only one OTA slot is configured!¥n");
return;
}

// 下载指定的固件文件到非当前(空闲)slot
printf("Downloading %s to slot %d...¥n", filename, slot);
int res = ota_tftp_download(TFTP_IMAGE_SERVER, TFTP_PORT, filename, 1000, slot, NULL);
printf("ota_tftp_download %s result %d¥n", filename, res);

if( res != 0 ) {
return;
}

// vertify固件,检查基本参数,不做也可以
uint32_t length = 0;
bool valid = rboot_verify_image(conf.roms[slot], &length, NULL);
if( !valid ) {
printf("Not valid after all :(¥n");
return;
}

printf("Rebooting into slot %d...¥n", slot);
// 设置新的当前slot
rboot_set_current_rom(slot);
// 重启
sdk_system_restart();
}

void update_fm_task(void *pvParameters)
{
printf("update task starting...¥n");
while(1) {
// 模拟触发,task在delay 20秒后开始更新固件(默认网络正常)
// 根据业务,可以通过mqtt通知或者http调用等方式进行触发
vTaskDelay(20000 / portTICK_PERIOD_MS);
download_and_restart(TFTP_IMAGE_FILENAME2);
}
}

void user_init(void)
{
// 设置波特率为
uart_set_baud(0, 115200);

// 打印当前固件的slot号
rboot_config conf = rboot_get_config();
printf("¥r¥n¥r¥nOTA Basic demo.¥r¥nCurrently running on flash slot %d / %d.¥r¥n¥r¥n",
conf.current_rom, conf.count);

// 打印当前固件的地址信息
printf("Image addresses in flash:¥r¥n");
for(int i = 0; i <conf.count; i++) {
printf("%c%d: offset 0x%08x¥r¥n", i == conf.current_rom ? '*':' ', i, conf.roms[i]);
}

// 当前fm信息(现在是fm1的代码)
printf("fm1 is runnning!¥n");

// wifi设定,
struct sdk_station_config config = {
.ssid = "your_wifi_ssid",
.password = "your_pass",
};
sdk_wifi_set_opmode(STATION_MODE);
sdk_wifi_station_set_config(&config);

// 启动下载task
xTaskCreate(&update_fm_task, "update_fm _task", 2048, NULL, 2, NULL);
}


Makefile内容如下:

PROGRAM=otatest
EXTRA_COMPONENTS=extras/rboot-ota
include ../../common.mk


执行:

make


cp ./firmware/otatest.bin /var/lib/tftpboot/fm1.bin


另外需要做成固件2,变更上面的第37行和第84行:

download_and_restart(TFTP_IMAGE_FILENAME2);


printf("fm1 is runnning!¥n");


->

download_and_restart(TFTP_IMAGE_FILENAME1);


printf("fm2 is runnning!¥n");


执行:

make


cp ./firmware/otatest.bin /var/lib/tftpboot/fm2.bin


6 固件下载

将fm1.bin下载到esp8266(具体硬件是nodemcu dev1.0),

注意nodemcu的SPI Mode是DIO。

写入成功后,首先是fm1运行,20s后,如果网络正常,会被更新为fm2。

Fm2运行后20s再次更新成fm1,如此循环往复。fm1->fm2->fm1…

如果首先下载的是fm2,则上述过程则会反过来。fm2->fm1->fm2…

写入参数如下图:



通过串口,可看到如下日志如下

SP-Open-SDK ver: 0.0.1 compiled @ Jul 26 2017 12:56:25
phy ver: 273, pp ver: 8.3

OTA Basic demo.
Currently running on flash slot 0 / 2. >>>>>>>2个slot,当前是0(写入地址是0x2000)

Image addresses in flash:
*0: offset 0x00002000
1: offset 0x00202000
fm1 is runnning!                      >>>>>>>第一次是fm1运行
…
mode : sta(5c:cf:7f:a3:13:83)
add if0
TFTP client task starting...         >>>>>>>下载线程
…

connected with iotwifi, channel 7
dhcp client start...
ip:192.168.31.170,mask:255.255.255.0,gw:192.168.31.1 >>>下载线程
Downloading fm2.bin to slot 1...       >>>>>>>fm2被下载到slot1
ota_tftp_download fm2.bin result 0

Rebooting into slot 1... >>>>>>>从slot1重启,切换为fm2
…

rBoot v1.4.0 - richardaburton@gmail.com
Flash Size:   32 Mbit
Flash Mode:   DIO
Flash Speed:  40 MHz
rBoot Option: Big flash
rBoot Option: RTC data

Booting rom 1.
system param error

ESP-Open-SDK ver: 0.0.1 compiled @ Jul 26 2017 12:56:25
phy ver: 273, pp ver: 8.3

OTA Basic demo.
Currently running on flash slot 1 / 2. >>>>>>>2个slot,当前是1

Image addresses in flash:
0: offset 0x00002000
*1: offset 0x00202000
fm2 is runnning!                     >>>>>>>fm2运行!固件更新成功。
mode : sta(5c:cf:7f:a3:13:83)
add if0
TFTP client task starting...
scandone
add 0
aid 2
cnt

connected with iotwifi, channel 7
dhcp client start...
ip:192.168.31.170,mask:255.255.255.0,gw:192.168.31.1
Downloading fm1.bin to slot 0...       >>>>>>>fm1被下载到slot0
ota_tftp_download fm1.bin result 0
----
Rebooting into slot 0...               >>>>>>>从slot0重启,重新切换为fm1


7. 其他问题

目前切换slot时,启动会提示system param error,并dump信息。

经过确认esp-open-rtos的代码后,原因是启动时checksum,导致打印警告信息,

具体原因还没有查清,但固件本身的功能没有受到影响。

如要使用Server模式更新固件,在wifi连接成功并取得IP后,调用如下代码即可:

ota_tftp_init_server(YOUR_TFTP_PORT);


参考url:

乐鑫:http://espressif.com/zh-hans/support/download/documents

esp-open-rtos:https://github.com/SuperHouse/esp-open-rtos/wiki/OTA-Update-Configuration
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: