# STM32-OTA
**Repository Path**: JeanHay/stm32-ota
## Basic Information
- **Project Name**: STM32-OTA
- **Description**: 基于STM32的BootLoader实现OTA程序升级
- **Primary Language**: C
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 50
- **Forks**: 12
- **Created**: 2023-07-12
- **Last Updated**: 2025-08-27
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# STM32-OTA
### 1、介绍
本工程是专为 **STM32** 单片机 **MCU** 开发的 **OTA** 组件,组件包含了 **bootloader** 、固件发送器 部分,其中固件发送器采用的是 **YModem-1K** 协议。
在STM32单片机方面来说,也可以称为单片机实现 **IAP** 程序升级, **IAP** 是 **In Application Programming** 的缩写,即在应用编程, **IAP** 是用户自己的程序在运行过程中对User Flash的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。单片机通过外设接口(如 UART 、 IIC 、 SPI 、 CAN 、 USB 等接口),连接具备联网能力的模块、器件、设备(以下统称上位机)。上位机从服务器上拉取固件包,再将固件包以约定的通讯协议,经由通讯接口发送至 **MCU** ,由 **MCU** 负责固件的解析、解密、存储、更新等操作,以完成设备固件更新的功能.
### 2、实现的功能
**本工程实现以下功能:**
1、**固件自动更新:** 当 download 或 factory 分区有可用的固件,且 APP 分区为空或 APP 分区不是最新版本的固件时,可配置为自动开始更新。
2、**固件更新完成性检查:** 自动检测固件 CRC 值,保证固件数据的可靠性。
3、**掉电保护:** 当固件更新过程中(含下载、解密、更新等过程),任何一个环节断电,设备再次上电时,依然能确保有可用的固件。(需配置为至少双分区)
4、**出厂设置:** factory 分区存放稳定版的固件,当设备需要恢复出厂设置时,该固件会被更新至 APP 分区。
5、**固件备份:** MCU接收到要更新的固件,接收之后将接收到的固件存储在W25Q64或者EEPROM存储芯片中。
### 3、BootLoader
BootLoader的意思就是启动引导,跟电脑启动先加载主板BIOS一样,引导程序从哪一部分映射地址启动。
#### 3.1、硬件架构
**STM32单片机的启动方式有三种:**
单片机根据Boot0和Boot1的引脚来确定启动方式。主Flash即为用户程序空间,IAP启动将会从这里开始,系统存储器是ISP启动,内置SRAM不讨论。
1.BOOT1=x BOOT0=0:从用户闪存启动,这是正常的工作模式,主闪存存储器(Flash)被映射到启动空间(0x0000 0000),但仍然能够在它原有的地址(0x0800 0000)访问它,即闪存存储器的内容可以在两个地址区域访问,0x0000 0000或0x0800 0000。在keil5中点击魔术棒,再点击Target即可验证上述。
2.BOOT1=0 BOOT0=1:从系统存储器启动,这种模式启动的程序功能由厂家设置。
3.BOOT1=1 BOOT0=1:从内置SRAM启动,这种模式可以用于调试。

#### 3.2、软件架构
**3.2.1、正常程序启动流程**
**(1)程序结构**
1.正常程序从起始地址(0x08000000)开始写入;
2.中断向量表(地址:0x08000004)用于存储中断处理程序向量;
3.中断处理函数(0x08000004+n)用于各种中断服务函数;
4.main函数(0x08000004+N),一个死循环,存放用户处理程序;
**(2)程序启动流程**
1.系统复位启动,从中断向量表中取出复位中断向量;
2.跳转到复位中断处理函数,执行复位中断函数完成启动,跳转到main函数入口;
3.执行main函数循环;
4.中断产生,STM32硬件强制将PC指针指向中断向量表;
5.根据中断源选择相应中断处理函数向量;
6.跳转到对应中断处理函数,处理中断;
7.中断函数结束,PC指针跳回main函数执行;

**3.2.2、含BootLoader程序运行流程**
**(1)程序结构**
1.正常程序从起始地址(0x08000000)开始写入;
2.中断向量表(地址:0x08000004)用于存储中断处理程序向量;
3.中断处理函数(0x08000004+n)用于各种中断服务函数;
4.main函数(0x08000004+N),一个死循环,存放用户处理程序;
5.APP 中断向量表(地址:0x08000004+N+M)用于存储中断处理程序向量;
6.APP main函数(0x08000004+N+M+n),一个死循环,存放用户处理程序;
**(2)含BootLoader程序启动流程**
1.系统复位启动,从中断向量表中取出复位中断向量;
2.跳转到复位中断处理函数,执行复位中断函数完成启动,跳转到main函数入口;
3.执行bootloader main函数,此时bootloader main函数内部有APP下载程序和跳转程序,执行跳转程序后会跳转到新程序的中断向量表,得到app程序的复位中断向量;
4.跳转到APP复位中断处理函数,执行复位中断函数完成启动,跳转到APP main函数入口;
5.中断产生,STM32硬件强制将PC指针指向Bootloader中断向量表;
6.程序再根据我们设置的中断向量表偏移量,得到对应中断源新的中断服务程序向量;
7.跳转到对应中断处理函数,处理中断;
8.中断函数结束,PC指针跳回main函数执行;

#### 3.3、FLASH详解
MCU闪存模块存储器主要由主存储器、信息块、闪存存储器接口寄存器组成,其中MCU的固件代码存储在主存储器中。
**本工程采用的MUC型号为STM32F103C8T6,MCU主存储器的容量(FLASH)为64KB,SRAM的大小为20KB。**
- **主存储块容量由以下说明:**
**1.小容量产品:** 主存储器大小为32KB(小于等于32KB),主存储器每页的大小为1K;
**2.中容量产品:** 主存储器大小为128KB(大于32KB小于等于128KB),主存储器每页的大小为1K;
**3.大容量产品:** 主存储器大小为128KB(大于128KB),主存储器每页的大小为2K;

#### 3.3、FLASH分区
**本工程对MCU的FLASH进行了BootLoader分区、Application分区、Factory分区;**
**1.BootLoader分区:** 其实就是存放的一段启动程序,它在芯片启动的时候最先被执行,可以用来做一些硬件的初始化和用作固件更新,当初始化完成和固件更新完之后跳转到对应的应用程序中去,BootLoader分区的地址范围为0x0800 0000 ~ 0x0800 2800;
**2.Application分区:** 存储正在运行的应用程序,Application分区的地址范围为0x0800 2800 ~ 0x0800 7800;
**3.Factory分区:** 存储出厂程序,也就是稳定的固件版本,Factory分区的地址范围为0x0800 7800 ~ 0x0800 c800;

### 4、YMODEM协议
#### 4.1、YMODEM帧格式
Ymodem 有两种帧格式,主要区别是信息块长度不一样。
| 帧头 | 包序号 | 包序号取反 | 信息快 | 校验 |
|---------|-------|-------|--------------|-------|
| SOH/STX | PN | XPN | DATA | CRC |
| 1byte | 1byte | 1byte | 128/1024byte | 2byte |
#### 4.1.1、帧头
帧头表示两种数据帧长度,主要是信息块长度不同。
(1)当帧头为SOH(0x01)时,信息块为128字节;
(2)当帧头为STX(0x02)时,信息块为1024字节;
#### 4.1.2、包序号
数据包序号只有1字节,因此计算范围是0~255;对于数据包大于255的,序号归零重复计算。
#### 4.1.3、帧长度
(1)以SOH(0x01)开始的数据包,信息块是128字节,该类型帧总长度为133字节;
(2)以STX(0x02)开始的数据包,信息块是1024字节,该类型帧总长度为1029字节。
#### 4.1.4、校验
Ymodem采用的是CRC16校验算法,校验值为2字节,传输时CRC高八位在前,低八位在后;CRC计算数据为信息块数据,不包含帧头、包号、包号反码。
#### 4.2、YMODEM起始帧
Ymodem起始帧并不直接传输文件内容,而是先将文件名和文件大小置于数据帧中传输;起始帧是以SOH 133字节长度帧传输,格式如下。
| 帧头 | 包序号 | 包序号取反 | 文件名称 | 文件大小 | 填充区 | 校验 |
|-----|------|-------|---------------|---------------|---------|-------|
| SOH | 0x00 | 0xFF | filename+0x00 | filesize+0x00 | n字节0x00 | CRC16 |
1.其中包号为固定为0;
2.filename为文件名称,文件名称后必须加0x00作为结束;
3.filesize为文件大小值,文件大小值后必须加0x00作为结束;
4.余下未满128字节数据区域,则以0x00填充;
5.可以看出起始帧也是遵守4.1中Ymodem包格式的;
#### 4.3、YMODEM数据帧
Ymodem数据帧传输,在信息块填充有效数据,传输有效数据时主要考虑的是最后一包数据的是处理,SOH帧和STR帧有不同的处理。
(1)对于SOH帧,若余下数据小于128字节,则以0x1A填充,该帧长度仍为133字节。
(2)对于STX帧需考虑几种情况:
1.余下数据等于1024字节,以1029长度帧发送;
2.余下数据小于1024字节,但大于128字节,以1029字节帧长度发送,无效数据以0x1A填充;
3.余下数据等于128字节,以133字节帧长度发送;
4.余下数据小于128字节,以133字节帧长度发送,无效数据以0x1A填充;
#### 4.4、YMODEM结束帧
Ymodem的结束帧采用SOH 133字节长度帧传输,该帧不携带数据(空包),即数据区、校验都以0x00填充。
| 帧头 | 包序号 | 包序号取反 | 信息块 | 校验 |
|------|------|-------|----------|-----------|
| 0x01 | 0x00 | 0xff | 128个0x00 | 0x00 0x00 |
#### 4.5、YMODEM握手信号
握手信号由接收方发起,在发送方开始传输文件前,接收方需发送YMODEM_C (字符C,ASII码为0x43)命令,发送方收到后,开始传输起始帧。
#### 4.5、YMODEM命令
| 命令 | 命令码 | 说明 |
|-----|------|---------------|
| SOH | 0x01 | 128字节数据包 |
| STX | 0x02 | 1024字节的数据包 |
| EOT | 0x04 | 结束传输 |
| ACK | 0x06 | 回应 |
| NAK | 0x15 | 没回应,需要重传当前数据包 |
| CA | 0x18 | 取消传输 |
| C | 0x43 | 握手 |
#### 4.6、YMODEM工具
有些工具是支持YMODEM传输的,比如SecureCRT等。
### 5、固件更新流程
根据配置的分区方案不同,固件的更新流程会有些不同,本工程采用的是MCU的FLASH分成三个分区,分别是BootLoader分区、Application分区、Factory分区;
**三个分区分别实现以下三个任务流程:**
**1.BootLoader分区:** 在BootLoader分区完成固件的下载、存放、校验、更新等操作;
**2.Application分区:** 根据 bootloader 占用的大小和 flash 的最小擦除单位,重新设置 APP 的起始位置和中断向量表,增加触发进入 bootloader 以开始固件更新的方式,设置一个更新标志位,且这个标志位在 APP 软复位进入 bootloader 时仍能被读取到;
**3.Factory分区:** 存储出厂程序,也就是稳定的固件版本,当MCU固件更新阶段出现故障,MCU可直接运行存储在本分区的固件;
**BootLoader分区实现固件更新的方式是通过:** APP 在软复位进入 bootloader 之前设置一个特殊的标志位,可以放置在 RAM 、备份寄存器或者外部的非易失性存储介质中(如:EEPROM)。此方式的优点是设备上电时 bootloader 无须等待和验证是否有固件更新的指令,通过标志位便可决定是否进入固件更新模式亦或跳转至 APP ,且利用再入 bootloader 的机制,可以给 APP 提供一个干净的外设环境。缺点则是 APP 和 bootloader 都要记录标志位所在的地址空间,且该地址空间不能被挪作他用,不能被意外修改,更不能被编译器初始化。相较于上个方案多了要专门指定该变量的地址并且不被初始化的步骤。
**固件更新流程图如下所示:**

### 6、BootLoader主程序和APP主程序讲解
#### 6.1、BootLoader主程序
BootLoader在0x8000000的位置启动,引导程序文件一般情况是必须烧录进去的,可以根据自己定义的标志去获取状态,来跑入自己的boot流程,或者直接跳转到自己定义的APP程序。这个标志可以是flash上的一个值、一个电平、按键、网络数据等等,只要是系统可以识别到的,都是可以的;下面是通过一个按键实现的。
#### 6.2、APP主程序
APP工程是用户使用的主功能程序,一般方法都是可以通过在运行中的APP中启动OTA行为。APP工程可以通过AT指令、电平、按键、网络数据控制等方法启动OTA 功能也可以通过跳转实现多个自定义系统的切换,需要注意的是代码存储空间是否够用。