雲栈小驿 · 2022年04月17日

从IAP升级到涂鸦OTA升级介绍(上)

仅作为个人学习笔记使用

序言

虽然说是重复造轮子,但是我觉得学习阶段还是很有必要的,主要目的验证数据接收(环形缓冲队列+空闲中断)以及重新复习IAP。本篇内容分为上下两部分 第一部分介绍传统IAP升级的方案到实现,第二部分介绍Tuya平台OTA升级使用及SDK代码部分介绍,本篇为上篇。

一、什么是IAP升级

IAP--In Application Programming. 即在线应用编程,也就是说用户可以使用自己的程序对单片机的user flash区域进行烧写。可以很方便的对已经发布的产品进行功能升级或者程序上的修复,只要保留预先的通信接口即可(USART, 网口等),避免了要进行拆机使用下载器进行烧录。

而进行IAP升级最核心的两点是实现:
1.BootLoader程序的编写 存储在FLASH中,主要负责引导APP程序的升级
2.APP程序的编写 实现产品功能升级的程序或者对程序的修复

二、解析STM32如何启动方式

2.1 STM32 FLASH空间划分

以STM32F103RC为例,可知 其FLASH大小每页2K字节,内部FLASH的首地址从0x08000000开始 程序在此地址开始写入。由于后续要涉及到将bin文件写入FLASH,这里简单说下对FLASH写操作过程,首先要清楚一下几点:

  • 字=32位=4个字节;半字=16位=2个字节
  • 每次写入必须是两个字节
  • 写入之前是必须先擦除的
  • FLASH地址为空的时候0xffff
  • 擦除: 页擦除

FLASH写入过程
1.解锁
2.擦除扇区
3.写数据到指定位置
4.上锁
1.png
IAP时FLASH地址空间具体划分如下
2.png

2.2 STM32的启动过程

无论是Keil MDK还是IAR EWARM开发环境 ST公司都已经帮你写好了cortex内核的启动程序,你只需要进行引用就好 大大降低了开发难度。传统的ARM架构总是从地址为0处开始执行第一条指令,而Cortex-M3内核却不相同,有三种启动方式:

1.通过boot引脚设置可以将中断向量表定位于SRAM区,即起始位置0x2000000 复位后PC指针0x2000000
2.通过boot引脚设置可以将中断向量表定位于FLASH区,即起始位置0x8000000 复位后PC指针0x800000(最常用的方式)
3.本文暂时不对这种情况论述

1)没有IAP只有APP程序的正常流程

STM32的FLASH地址起始于0x08000000, 程序从此地址开始写入
3.png
根据上图分析启动和执行流程
1.STM32在复位后,从0x08000004地址处取得复位中断向量起始地址,并跳转到复位中断程序入口
2.在执行完复位中断程序后,会跳转到main函数
3.由于main函数一般数一个while(1)的循环体,在程序执行过程中发生中断时,PC指针会被强制指回中断向量表
4.根据中断源进入相应中断服务程序
5.执行完中断服务程序后 返回main函数

2) 加入IAP后流程

4.png
同理对流程进行分析。

1.STM32复位后,从0x08000004地址处取得复位中断向量地址,随后跳转到复位中断程序入口,并执行完复位中断程序 最后跳转到IAP的main函数入口(这里将原先的步骤1和2进行合并)
2.在执行完IAP后(固件升级后),会跳转到APP的复位中断向量起始位置 即复位向量表处
3.取复位中断向量地址后,跳转到新的复位中断程序入口 并执行新的复位中断程序 最后进入APP的main函数
4.APP的main函数是一个while(1)循环体,在程序执行过程中发生中断后 (此时有两个中断向量表)先将PC指向0x08000004,再根据相应中断源进入中断函数
5.执行完中断函数后再回到APP的main函数

三、IAP升级方案介绍

主要实现两个事情,1)BootLoader程序 2)APP程序。

升级APP无非是将旧程序换成新程序,就是一包一包的接收然后再一包一包的写入FLASH中,而在实际开发中为了确保数据接收的完整性 一般会设定传输协议 帧头 数据 校验位等,根据协议进行一包一包的校验。这里主要是为了验证IAP升级的demo测试数据接收的写法,所以就不设置相关协议类似于直接将接收的bin文件存到FLASH的指定地点中。

IAP升级流程

5.png

1.接收APP (bin文件)

这里采用环形队列+空闲中断的的方式
实际上数组就是一个大的队列,但是随着接收数据的增加 增加到数组最大容量后就会出现假溢出现象,数组就无法使用了,所以环形队列出现了。
1.png
一个字节一个字节的数据接收后进入中断,在环形队列(大小256)中先判断写指针和读指针是否重合,是则返回0xff, 否则写入USART_RECV_BUF,每次写入一个数据,后写指针(入队指针)加进行加一

2.png
3.png
next_pos = (p_queue->tail_pos + 1) % USART_BUFF_LEN; 主要是防止写指针越界,读出环形队列数据并直接写入FLASH指定位置中。

这里说明几点:
1.FLASH在擦除、写入时候会花费较长时间 所以为了避免队列读出的数据直接写入FLASH过程中接收的其他接收的数据会丢失 在初始化时先将要写入的页及可能用到的页全部擦除,方便直接写入
2.在测试过程中,串口助手发送大约几十个字节 FLASH写入正常,但是将bin文件发送出去时候 会出现FLASH数据写入一半后会出现程序跑飞 可能还是串口发送的速度太快而在FLASH写入中很慢 所以后面将串口波特率改为9600 经过测试是完全没有问题的
3.STM32属于小端模式对写入FLASH的数据要进行处理
4.FLASH写入/读出半字也就是一次写入2个字节,写完/读出一次地址会加2
4.png
5.png
6.png
同样这里是为了防止越界,并且每次读取一个字节数据后长度都进行减减操作。
6.png

2)跳转APP

判断程序是否已经完成拷贝到FLASH中 后开始执行FLASH中代码
7.png
程序运行时是在SRAM中,SRAM的栈顶地址0x20000000 也就是判断程序是否已经拷贝完成。
8.png

四、怎么生成bin文件

首先要保证FLASH地址和BootLoadert中设定的相同
1.png
其次在这里输入
2.png
编译后就会生成如下所示 表示bin文件已经生成好了
3.png
最后在串口调试助手中点击发送文件即可
5.png

五、测试结果

4.png

推荐阅读
关注数
1
内容数
2
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息