参考教程:https://www.bilibili.com/video/BV1SatHeBEVG/?spm_id_from=333.1387.favlist.content.click
一、OTA与BootLoader的功能
1、OTA的功能
(1)为单片机升级程序的办法可分为两种------本地下载与OTA升级。
(2)本地下载要求找到需要刷写程序的单片机实体才能进行,比如通过串口下载程序。

(3)OTA升级不需要找到需要刷写程序的单片机实体,当发生版本迭代时,开发者把新版本的程序上传到服务器,用户端从服务器把最新版本的程序下载后,由BootLoader负责把新版本的程序更新到Flash中,从而实现远程升级(前提是设备能够联网)。

2、BootLoader的功能
(1)BootLoader也是单片机中的一段程序,它也需要由程序员进行开发。
(2)BootLoader必须具备的功能:
①当发生OTA事件时,先通过能联网的模块与服务器建立连接,下载最新版本的软件,下载完毕后,BootLoader将A分区(Flash中存放应用功能程序的区域)中的老版本程序擦除,再将新版本的应用功能程序写入A分区,完成写入后,重启单片机,再次执行BootLoader,BootLoader直接将指令指针指向A分区。
②没有OTA事件时,BootLoader直接将指令指针指向A分区,使得单片机运行A分区中的应用功能程序。
(3)BootLoader可选择实现的功能(包括但不限于):
①通过串口更新A分区的应用功能程序。
②设置物联网平台要求的OTA初始版本号。
③利用外部大容量Flash存放多个应用功能程序文件,当有需求时,直接从外部Flash中读取应用功能程序文件数据并写入A分区。
二、设计BootLoader程序的注意事项
1、OTA标志(OTA Flag)
(1)需要设置OTA Flag用于标记是否有OTA事件,该标志需要存储在EPPROM中,一旦有更新,EPPROM中的OTA Flag也要同步更新,以保证该标志位不会被异常重置。
(2)OTA Flag的置位逻辑:
①当OTA事件发生时,单片机控制通信模块连接服务器,将新版本程序下载至外部Flash中,当下载完成后,置位OTA Flag(置位通常由应用功能程序负责),并重启单片机(单片机重启后先运行BootLoader,从而执行更新程序的操作)。
②当BootLoader程序完成A分区程序更新后,将OTA Flag清除,再重启单片机(单片机重启后先运行BootLoader,BootLoader直接将指令指针指向A分区)。
(3)OTA Flag的使用逻辑:
①运行BootLoader程序时,如果判断OTA Flag没有被置位,则BootLoader将指令指针指向A分区,以运行应用功能程序。
②运行BootLoader程序时,如果判断OTA Flag有被置位,则BootLoader执行更新A分区应用功能程序的操作。
(4)OTA Flag工作流示意:

2、Flash分区
(1)前面提及过分区的概念,可人为地将Flash划分为B区和A区,B区的地址在A区前面,B区存放BootLoader程序,A区存放应用功能程序。

(2)对于单片机本身来说,只要复位,都会从Flash的起始位置开始运行,如果使用了BootLoader程序,那么单片机就会从B区首条指令开始运行,也就是Flash的第一条指令。

(3)当使用了BootLoader程序时,单片机不可能每次上电都把BootLoader完完整整地跑一遍,才将指令指针指向A区,因此BootLoader中应该有跳转指令,满足某些条件后,直接将指令指针指向A区。
(4)B区地址在A区之前的原因:
①假设A区地址在B区之前,当发生OTA事件时,指令指针跳转到B区运行BootLoader程序,将A区中的内容擦除,再往A去写入新版本的应用功能程序,如果在刷写进度为50%时发生异常事件(如单片机掉电)导致刷写被中断,那么设备恢复正常后,指令指针仍默认指向Flash的首地址,也就是A区的第一条指令,但此时A区中的应用功能程序不完整,运行不完整的程序是很危险的,而因为指令指针无法跳转至B区,BootLoader也就无法重新更新A区的程序。

②假设B区地址在A区之前,当发生OTA事件时,指令指针跳转到B区运行BootLoader程序,将A区中的内容擦除,再往A去写入新版本的应用功能程序,如果在刷写进度为50%时发生异常事件(如单片机掉电)导致刷写被中断,那么设备恢复正常后,指令指针仍默认指向Flash的首地址,也就是B区的第一条指令,从而运行完整的BootLoader程序,由于刷写未完成,OTA Flag未置位,BootLoader将继续进行应用功能程序刷写流程,直到刷写完成。

3、程序下载方式
(1)前面提到过,从服务器下载的新版本程序会存放在外设大容量Flash(如W25Q64,SPI接口的串行NOR Flash存储器芯片)中,即便单片机掉电,下载的程序也不会丢失。
(2)从服务器下载新版本程序采用的是"分片"的方式,每下载"一片"就将其存放在外设大容量Flash中。
三、BootLoader程序功能规划
1、处理OTA事件
这是必须具备的功能,当OTA Flag置位时,BootLoader更新A区程序,否则将指令指针跳转至A区第一条指令,运行A区程序
2、通过串口刷写程序
(1)上位机通过串口发送程序文件,BootLoader应能将其接收并写入A分区中。
(2)对于STM32,其自带串口下载功能,刷写前,需要置BOOT0引脚为高电平,进入软件刷写模式,通过串口完成刷写后,再将BOOT0引脚复位为低电平,进入正常运转模式。
(3)下图所示的是STM32的程序自动下载电路原理图。

①该电路由1个S8550三极管、1个S8050三极管、1个阻值为10kΩ的电阻、3个阻值为1kΩ的电阻和一个1N4007W_C7528871二极管(作用是提供一个钳位)组成。
②如下表所示,该表反映了复位时BOOT0和BOOT1电平组合对应的单片机启动方式,单片机在复位时会对这两个引脚进行采样,根据采样结果选择对应的启动方式。
1\] 从Flash启动:单片机启动后进入正常工作状态。 \[2\] 下载启动:单片机启动后从串口下载程序。 \[3\] 从SARM启动:用于一些调试场合,不太常见,此处不进行详细介绍。  ③该电路通过BOOT0、DTR和RTS控制RST的电平,其中DTR和RTS由CH340C芯片输出,而CH340C芯片又通过USB通信与上位机交互,所以在上位机中可以直接配置DTR和RTS,同时在开发板上通过跳线帽可选择BOOT0和BOOT1的电平,由此控制单片机启动方式。需要说明的是,CH340C芯片中DTR和RTS使用的是负电平逻辑(可通过标识"#"识别),上位机中将它们配置为低电平,实际上引脚出输出的是高电平。   ④电路工作原理分析(以上图刷写程序过程为例): \[1\] 当上位机配置DTR为低电平、RTS为高电平,则DTR实际为高电平、RTS实际为低电平,此时S8050导通,RTS的电平与1N4007W阴极侧电平近似相等,则RST为低电平,同时S8550也导通,BOOT0的电平与网络VCC+3.3V的电平近似相等,则BOOT0为高电平,此时BOOT1通过跳线帽连接地,则其为低电平,单片机进入BootLoader。(如上图所示,会延时100ms,主要是为了给单片机的RST引脚留出响应时间) \[2\] 单片机复位后,上位机置DTR为高电平(RTS不变),则DTR实际为低电平,此时S8050关断,RST为高电平,同时S8550导通,BOOT0的电平与网络VCC+3.3V的电平近似相等,则BOOT0为高电平,此时BOOT1通过跳线帽连接地,则其为低电平,由此可知,此刻单片机结束复位状态,进入下载启动模式,开始从串口下载程序。 \[3\] 程序刷写完毕后,上位机置RTS为低电平(DTR不变),则RTS实际为高电平,此时S8050关断,RST为高电平,同时S8550关断,BOOT0和BOOT1都通过跳线帽连接地,则它们均为低电平,由此可知,此刻单片机完成程序下载,进入正常工作模式。 ### 3、设置初始软件版本号 (1)使用平台的OTA功能时,单片机需要维护当前软件的版本号,与服务器连接后,将软件版本号上报,若服务器判断单片机程序版本老旧,就可以主动发送询问,确认用户是否需要升级程序。  (2)版本号需时刻保存在EEPROM中,可以在BootLoader中设计命令行,输入命令,再输入初始版本号,让BootLoader将其保存到EEPROM中,这个初始版本号相当于一个默认值,只要刷写其它版本的应用功能程序,那么这个默认值就会被覆盖。 ### 4、多程序切换 (1)设计不同的程序,让单片机能够实现不同的功能,当需要哪个程序时,就执行哪个程序的代码,但单片机的Flash空间并不是无限大,当可选程序过多时,显然不能把所有可选程序放在Flash中(Flash可以分区存放多个程序),对此可以将暂不使用的程序存储在外部大容量Flash中(如W25Q64),当需要运行哪个程序,就输入相应的命令,BootLoader接收命令后将对应的程序从外设Flash中读出,并更新至A区。 (2)当然,程序不一定存储在外部大容量Flash中,也可以存放在服务器中,这样,输入响应的命令后,BootLoader就从服务器下载相应的程序,并更新至A区。 (3)如果不同程序之间存在数据交互,可以通过EEPROM实现。 