专为32位单片机开发的轻量级OTA组件(开源)

  目录

今天为大家分享一款专为 32 位 MCU 开发的 OTA 组件。组件包含了 bootloader 、固件打包器 (Firmware_Packager) 、固件发送器 三部分,并提供了基于多款 MCU (STM32F1 / STM32F407 / STM32F411 / STM32L4) 和 YModem-1K 协议的案例。

该项目的开源地址:https://gitee.com/DinoHaw/mOTA.git

简介

项目名称为 mOTA,m 可意为 mini 、 micro 、 MCU ( Microcontroller Unit ),而 OTA ( Over-the-Air Technology ),即空中下载技术,OTA 是一种为设备分发新软件、配置,乃至更新加密密钥(为例如移动电话、数字视频转换盒或安全语音通信设备——加密的双向无线电)的方法。
参考文章:嵌入式设备实现OTA升级的原理
OTA 的一项重要特征是,一个中心位置可以向所有用户发送更新,其不能拒绝、破坏或改变该更新,并且该更新为立即应用到频道上的每个人。用户有可能“拒绝” OTA 更新,但频道管理者也可以将其踢出频道。由此可得出 OTA 技术几个主要的特性:

  • 一个中心可向多个设备分发更新资料(固件);
  • 更新资料一旦发送便不可被更改;
  • 设备可以拒绝更新;
  • 中心可以排除指定的设备,使其不会接收到更新资料。

本工程仅实现 OTA 更新资料的部分技术,即上文列出的 OTA 技术几个主要的特性,而不关心中心分发资料中间采用何种传输技术。(本工程的 example 使用 UART 作为 MCU 和外部的传输媒介)

功能介绍

MCU 设备上的 OTA 升级可理解为 IAP (In Application Programming) 技术, MCU 通过外设接口(如 UART 、 IIC 、 SPI 、 CAN 、 USB 等接口),连接具备联网能力的模块、器件、设备(以下统称上位机)。上位机从服务器上拉取固件包,再将固件包以约定的通讯协议,经由通讯接口发送至 MCU ,由 MCU 负责固件的解析、解密、存储、更新等操作,以完成设备固件更新的功能。
本组件实现了以下功能:

  • 固件包完整性检查: 自动检测固件 CRC 值,保证固件数据的可靠性。
  • 固件加密: 支持 AES256 加密算法,提高固件的安全性。
  • APP 完整性检查: 支持 APP 运行前进行完整性检查,以确认运行的固件无数据缺陷。
  • 断电保护: 当固件更新过程中(含下载、解密、更新等过程),任何一个环节断电,设备再次上电时,依然能确保有可用的固件。(需配置为至少双分区)
  • 固件水印检查: 可检测固件包是否携带了特殊的水印,确认非第三方或非匹配的固件包。
  • 固件自动更新: 当 download 或 factory 分区有可用的固件,且 APP 分区为空或 APP 分区不是最新版本的固件时,可配置为自动开始更新。
  • 恢复出厂设置: factory 分区存放稳定版的固件,当设备需要恢复出厂设置时,该固件会被更新至 APP 分区。
  • 无须 deinit : 我们知道,固件更新完毕后从 bootloader 跳转至 APP 前需要对所用的外设进行 deinit ,恢复至上电时的初始状态。本组件的 bootloader 包含了下载器的功能,当使用复杂的外设收取固件包时, deinit 也将变得复杂,甚至很难排除对 APP 的影响。为此,本组件采用了再入 bootloader 的方式,给 APP 提供一个相当于刚上电的外设环境,免去了 deinit 的代码。
  • 功能可裁剪: 本组件通过功能裁剪可实现单分区、双分区、三分区的方案切换、是否配置解密组件、是否自动更新 APP 、是否检查 APP 完整性、 是否使用 SPI Flash (待实现) 。
  • 固件存放至 SPI flash : 本组件可通过 user_config.h 配置 download 分区和 factory 分区的所在位置为片内 flash 或 SPI flash ,使用了 SFUD (Serial Flash Universal Driver) 作为 SPI flash 的底层驱动库。若使用的 SPI flash 支持 SFDP (Serial Flash Discovable Parameters) ,则可在不修改任何源代码的情况下更换其它品牌型号的 SPI flash 。若不支持 SFDP ,SFUD 中已有对应 SPI flash 参数表的话,也可做到在不修改任何源代码的情况下更换其它品牌型号的 SPI flash 。

软件架构

  • 硬件层描述的是运算器件和逻辑器件,如CPU、ADC、TIMER、各类IC等,是所有软件组件的硬件基础,是软件逻辑的最终底层实现。
  • 硬件抽象层是位于驱动与硬件电路之间的接口层,将硬件抽象化。它隐藏了特定平台的硬件接口细节,为驱动层提供抽象化的硬件接口,使其具有硬件无关性。
  • 驱动层通过调用硬件抽象层的开放接口,实现一定的逻辑功能后封装,提供给上层软件调用。
  • 数据传输层负责收发数据,对外开放的是数据发送与接收相关的接口,屏蔽了通讯接口的逻辑代码,使其易于修改为其他类型的通讯接口。
  • 协议析构层将调用数据传输层的数据收发接口进行封包发送与收包解析,通过实现用户的自定义协议,完成对数据的构造和解析。
  • 应用层负责业务逻辑代码的实现,通过调用其他层封装的接口,完成顶层逻辑功能。

固件更新流程

根据配置的分区方案不同,固件的更新流程会有些不同,此处仅展示简要的更新流程,便于快速理解固件更新的流程,因此屏蔽了很多细节,更详细的内容,请阅读《bootloader程序设计思路》文档和源代码。
本组件的目的是最大程度的减少 APP 的改动量以实现 OTA 的功能,从下图可知, bootloader 便完成了固件的下载、存放、校验、解密、更新等所有操作, APP 部分所需要做的有以下三件事。

  • 根据 bootloader 占用的大小和 flash 的最小擦除单位,重新设置 APP 的起始位置和中断向量表。
  • 增加触发进入 bootloader 以开始固件更新的方式。(如:接收来自上位机的更新指令)
  • 设置一个更新标志位,且这个标志位在 APP 软复位进入 bootloader 时仍能被读取到。(当固件更新的方式为上位机指令控制时,可以不执行此步骤)

一般来说,通知 bootloader 需要进行固件更新的方式有以下两种:

  • 采用上位机指令控制的方式,优点是 APP 无须设置更新标志位,即便设备在收到更新指令后断电,也可以照常更新。缺点是设备在上电后, bootloader 需要等待几秒的时间(时间长短由通讯协议和上位机决定),以确认是否有来自上位机的更新指令,从而决定进入固件更新模式亦或跳转至 APP 。
  • APP 在软复位进入 bootloader 之前设置一个特殊的标志位,可以放置在 RAM 、备份寄存器或者外部的非易失性存储介质中(如:EEPROM)。此方式的优点是设备上电时 bootloader 无须等待和验证是否有固件更新的指令,通过标志位便可决定是否进入固件更新模式亦或跳转至 APP ,且利用再入 bootloader 的机制,可以给 APP 提供一个干净的外设环境。缺点则是 APP 和 bootloader 都要记录标志位所在的地址空间,且该地址空间不能被挪作他用,不能被意外修改,更不能被编译器初始化。相较于上个方案多了要专门指定该变量的地址并且不被初始化的步骤。若使用的是 RAM 作为记录标志位的介质,则还有断电后更新标志信息丢失的问题。

综上所述,没有完美的方案。本组件支持上述方案二选一,根据实际需求进行选择和取舍即可。

获取方式

可以自己从 gitee 仓库拉取下载。
附件下载 mOTA-master.zip
附件下载 mOTA-tools.zip

版权声明

文章来源于网络,版权归原作者所有,如有侵权,请联系删除。
原文:https://mp.weixin.qq.com/s/iK7gW0HHjiYsTV_5-wPY2g


评论