1. i.MX RT系列OTA升级方案设计解析
在嵌入式设备开发中,固件空中升级(OTA)功能已成为现代IoT设备的标配需求。针对恩智浦i.MX RT系列MCU,Tiny OTA提供了一套轻量级参考实现,其核心设计思路是通过双Slot机制实现可靠升级。这套方案特别适合资源受限但需要OTA功能的场景,比如工业控制、智能家居等嵌入式应用。
整个系统由三部分组成:运行在MCU上的bootloader程序(tota_sbl)、用户应用程序(tota_app)以及PC端的上位机工具(MCU-TinyOtaUtility)。bootloader负责固件版本管理和跳转逻辑,应用程序则是用户实际业务代码的载体,上位机工具则提供固件打包、烧录和通信功能。
关键设计要点:采用双Slot存储设计,bootloader通过CRC32校验确保固件完整性,版本号比较决定升级策略,5秒超时机制保证设备可用性。
2. 固件架构与核心组件实现
2.1 Bootloader(tota_sbl)设计细节
tota_sbl基于i.MX RT1180的flashloader工程改造而来,主要实现了以下核心功能:
-
启动引导:通过ROM加载后,首先检查Flash中的FCB(Flash配置块)和IVT(中断向量表),确认硬件环境正常。这里特别要注意RT1180的TRDC权限管理,当前方案通过扩大container的image_entry.size来规避权限问题。
-
双Slot管理:在0x28080000(Slot0)和用户定义的Slot1地址存放应用程序。bootloader头部信息复用了ARM向量表中的保留字段,包含以下关键参数:
c复制typedef struct { uint32_t magic; // 幻数校验值 uint32_t slot0_addr; // Slot0起始地址 uint32_t slot1_addr; // Slot1起始地址 uint32_t app_load_addr;// 应用程序加载地址(预留) } ota_header_t; -
可靠升级流程:采用Kinetis Bootloader的成熟方案,通过四步判断确保系统可靠性:
- 双Slot CRC32校验(使用MPEG-2多项式)
- 版本号比对(最大支持255.255版本格式)
- 固件拷贝(需要先擦除目标区域)
- 跳转执行(配置好栈指针和PC指针)
2.2 应用程序(tota_app)设计要点
tota_app基于SDK的hello_world_xip示例工程改造,开发者需要注意以下关键配置:
-
链接脚本配置:必须正确定义Flash布局,以下是典型配置:
javascript复制define symbol m_flash_start = 0x28000000; // FlexSPI1起始地址 define symbol app_image_offset = 0x00080000; // 应用程序偏移量 define symbol m_text_start = m_flash_start + app_image_offset; -
OTA头部信息:同样复用ARM向量表保留字段,包含:
c复制typedef struct { uint32_t magic; // 幻数校验 uint32_t length; // 固件长度 uint32_t crc32; // 固件CRC校验值 uint16_t version_major; // 主版本号 uint16_t version_minor; // 次版本号 } app_header_t; -
调试技巧:在开发阶段,可以直接修改startup文件中的以下参数,避免每次都要通过上位机烧录:
c复制#define APP_SLOT0_ADDR 0x28080000 #define APP_SLOT1_ADDR 0x28100000 #define APP_SLOT0_VER 0x0100 #define APP_SLOT1_VER 0x0101
3. PC端工具链使用指南
3.1 开发环境准备
-
硬件连接:
- 使用USB转串口工具连接MCU的调试UART
- 对于RT1180-EVK开发板,需将启动模式设置为ISP模式
- 确保Flash供电正常(特别是外部NOR Flash)
-
软件安装:
bash复制# 安装Python依赖(工具基于PyQT5) pip install pyqt5 pyserial # 下载预编译工具 wget https://github.com/JayHeng/MCU-TinyOtaUtility/archive/refs/tags/v1.0.zip
3.2 固件打包与烧录流程
-
单步操作模式:
- 先添加bootloader头并烧录:
code复制选择文件 → 设置偏移0x400 → 设置Magic值 → 点击"Stage1 BL File" - 再分别处理两个Slot的应用固件:
code复制选择文件 → 设置Slot0偏移(如0x80000) → 设置版本号 → 点击"Slot0 App File"
- 先添加bootloader头并烧录:
-
一键操作模式:
- 配置好所有参数后,点击"All In One"按钮自动完成:
- 为bootloader添加头部信息
- 为应用程序添加头部信息
- 擦除目标Flash区域
- 烧录所有固件
- 校验写入内容
- 配置好所有参数后,点击"All In One"按钮自动完成:
烧录技巧:对于量产环境,可以预先用工具生成带头的固件,然后直接使用"Flash Write"功能批量烧录,提高生产效率。
3.3 常见问题排查
-
连接失败:
- 检查串口线是否正常(尝试用终端工具连接)
- 确认开发板处于ISP模式(Boot引脚配置正确)
- 检查波特率设置(默认115200)
-
固件无法运行:
- 确认链接脚本中的地址与烧录位置一致
- 检查向量表是否正确(特别是Stack Pointer和Reset Handler)
- 用读回功能验证Flash内容是否正确写入
-
升级异常:
- 确认两个Slot的版本号设置正确
- 检查CRC计算是否一致(可用工具重新计算)
- 验证Flash擦除是否成功(全FF检查)
4. 高级开发与定制技巧
4.1 多核处理器支持
对于i.MX RT1170/1180等双核MCU,需要特别注意:
-
核间同步:在CM7和CM4的应用程序中都需要实现:
c复制void Sync_Cores(void) { // 通过共享内存或IPC机制协调升级过程 while(*upgrade_flag != IDLE) { __WFI(); // 等待另一核准备就绪 } } -
内存划分:在链接脚本中合理分配各核资源:
code复制/* CM7专用内存 */ define symbol m_text_start = 0x28080000; /* CM4专用内存 */ define symbol m_text2_start = 0x28180000; /* 共享内存区 */ define symbol shared_mem_start = 0x20200000;
4.2 安全增强方案
-
签名校验:在现有CRC校验基础上增加ECDSA签名:
python复制# 上位机签名工具示例 from ecdsa import SigningKey sk = SigningKey.generate() # 生成私钥 vk = sk.verifying_key # 导出公钥 signature = sk.sign(firmware_data) # 生成签名 -
加密传输:在blhost协议层增加AES加密:
c复制// MCU端解密示例 void AES_Decrypt(uint8_t *data, uint32_t len) { AES128_ECB_decrypt(data, aes_key, data, len); } -
防回滚:在Flash中存储最高版本号:
c复制uint32_t Get_Max_Version(void) { return *((uint32_t*)0x280FF000); // 存储在Flash末尾 }
4.3 性能优化建议
-
差分升级:实现bsdiff算法减少传输数据量:
python复制# 上位机生成差分包 import bsdiff4 patch = bsdiff4.diff(old_fw, new_fw) -
压缩传输:集成LZMA压缩库:
c复制// MCU端解压实现 int Lzma_Decode(uint8_t *input, uint8_t *output) { CLzmaDec state; LzmaDec_Construct(&state); // ...初始化并解压数据 } -
后台更新:实现双Bank切换机制:
c复制void Switch_Bank(void) { FLASH_Erase(BANK2_START); FLASH_Program(BANK2_START, new_fw); NVIC_SystemReset(); // 复位后从新Bank启动 }
在实际项目中,我们还需要考虑异常处理、日志记录、断电保护等工程细节。Tiny OTA作为一个参考设计,开发者可以根据具体需求进行功能扩展和优化。比如增加远程HTTP/FTP下载支持、完善状态报告机制等,这些都可以在现有框架基础上逐步实现。
