• 正文
  • 相关推荐
申请入驻 产业图谱

基于I2C Bootloader的固件升级完整实施方案

09/29 10:09
125
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

1. 方案设计目标与约束条件

本方案的核心设计目标是在硬件受限条件下,实现STM32H563的完整固件升级与用户程序运行。具体而言,方案需要满足以下功能目标:通过I2C接口下载用户固件到目标Flash;在不切换BOOT0引脚的前提下实现启动路径切换;完成OBKEY安全配置;最终使目标芯片从用户Flash正常启动运行。

方案的设计受到以下硬约束的限制:在硬件层面,BOOT0引脚被固定接至高电平且无法通过软件或外部手段改变状态;调试接口(SWD/JTAG)不可用,无法通过调试器进行烧录或选项字节配置;I2C通信接口可用,作为唯一的固件更新通道。在软件层面,目标芯片的TrustZone未使能(TZEN=0xC3),这决定了OBKEY必须使用带密码版本,且Product State的行为遵循非安全世界的规则。

在非功能目标方面,方案要求具备高可靠性:每一步操作都应有明确的状态反馈与错误处理机制,避免因通信异常导致芯片变砖。方案应具备可重复性:相同的输入条件应产生一致的输出结果,适用于量产环境。方案还应具备可测试性:提供完整的测试用例与验证方法,确保每个功能模块都能被独立验证。

资料获取:实战经验 | LAT1726 如何通过STM32H5 Bootloader进行固件升级与运行

2. 硬件平台搭建:双NUCLEO-H563架构

方案的验证与开发基于两块NUCLEO-H563开发板构建。NUCLEO-H563是ST官方推出的STM32H563开发板,集成了ST-LINK调试器、Arduino Uno接口扩展以及丰富的外设资源,非常适合用于原型验证与功能开发。

两块开发板的角色分工如下:Host端NUCLEO-H563运行参考工程中的Host程序,负责初始化I2C外设、发送Bootloader命令、处理应答与状态码,并通过串口终端提供人机交互界面。Target端NUCLEO-H563作为目标设备,其BOOT0引脚接3.3V高电平,上电后自动进入系统Bootloader模式,等待Host端的I2C命令。

硬件连接的具体方案如下表所示:

信号名称 Host端引脚 Target端引脚 说明
I2C_SCL PD12 PD12 I2C时钟线,需外接上拉电阻
I2C_SDA PD13 PD13 I2C数据线,需外接上拉电阻
GND GND GND 共地连接,确保通信电平参考一致
BOOT0 — 接3.3V 目标端BOOT0固定高电平,进入Bootloader

I2C上拉电阻的实现是硬件搭建的关键。SCL和SDA线必须通过上拉电阻连接至VDD(3.3V),典型阻值为4.7kΩ。在NUCLEO开发板上,可通过外接电阻或利用开发板上的预留焊盘实现。若使用面包板搭建验证环境,需在SCL和SDA线上分别插入上拉电阻,切勿遗漏。

在量产场景下,硬件平台需要从双板验证架构迁移到单板量产架构。Host端的功能可由专用烧录器、PC端USB-I2C适配器或产线上的主控MCU实现。Target端则是实际产品中的STM32H563芯片,其I2C引脚需在产品设计时预留测试点或接口,以便产线烧录与现场维护使用。电源设计方面,需确保Host与Target共地,且I2C电平兼容(均为3.3V)。

3. 七步升级流程详细实施

以下对七步升级流程的每一步进行详细实施说明,包括前置条件、执行动作、验证方法与异常处理。

步骤一:进入Bootloader模式

前置条件:Target端BOOT0引脚已接3.3V高电平,Product State处于Open状态(出厂默认)。执行动作:对Target端上电或按下复位键,芯片上电复位后检测到BOOT0为高且Product State为Open,自动进入系统Bootloader模式,I2C接口被激活,等待Host端命令。验证方法:Host端通过I2C发送同步字节(0x7F),若收到Target端的ACK(0x79),则确认Bootloader已就绪。异常处理:若未收到ACK,检查I2C接线、上拉电阻、BOOT0电平以及Product State是否为Open。

步骤二:下载用户固件

前置条件:Bootloader通信已建立。执行动作:Host端首先根据固件大小计算需要擦除的Flash页数,发送Flash擦除命令(0x44)擦除目标区域;然后将固件分割为不超过256字节的数据块,通过写Memory命令(0x31)依次写入目标Flash地址(通常为0x08000000)。验证方法:写入完成后,可通过读Memory命令(0x11)回读部分数据进行校验,或在后续步骤中通过程序运行间接验证。异常处理:若擦除或写入失败,检查Flash地址是否正确、固件大小是否超出Flash容量、I2C通信是否稳定。

步骤三:切换至Provisioning状态

前置条件:固件下载完成且校验通过。执行动作:Host端发送Special命令(0x50)配合更改Product State子命令(0x01),参数为Provisioning状态代码0x2F7。Target端接收到命令后,修改选项字节中的PRODUCT_STATE字段。验证方法:命令返回状态码0x00表示成功;可通过读取选项字节命令确认Product State已变为Provisioning。异常处理:若状态切换失败,检查当前状态是否允许转换(仅Open状态可直接进入Provisioning),以及命令参数是否正确。

步骤四:下载OBKEY数据到SRAM3

前置条件:Product State已处于Provisioning状态。执行动作:Host端首先在本地对OBKEY文件进行Header重计算(更新CRC-32),然后通过写Memory命令(0x31)将处理后的OBKEY数据写入Target端的SRAM3地址区域。验证方法:写入完成后可回读SRAM3数据确认完整性。异常处理:若写入失败,检查目标地址是否在SRAM3范围内、数据长度是否为16的倍数、I2C通信是否正常。

步骤五:切换至Closed状态

前置条件:OBKEY数据已成功写入SRAM3。执行动作:Host端发送Special命令(0x50)配合更改Product State子命令(0x01),参数为Closed状态代码0x2F2。此操作将产品锁定为Closed安全状态。验证方法:命令返回状态码0x00表示成功。异常处理:若切换失败,确认OBKEY Provisioning是否已成功执行(步骤四与Provisioning命令的配合),以及当前状态是否允许转换到Closed。

步骤六:复位目标MCU

前置条件:Product State已成功切换为Closed。执行动作:Host端发送Special命令(0x50)配合复位子命令(0x02),Target端接收到命令后执行系统复位。验证方法:Target端复位后I2C通信将中断,Host端可检测到通信超时,间接确认复位已执行。异常处理:若复位命令无响应,检查命令格式是否正确,或通过硬件复位按钮手动复位。

步骤七:从用户Flash启动运行

前置条件:目标MCU已复位。执行动作:复位后,由于Product State为Closed,芯片忽略BOOT0引脚,根据选项字节NSBOOTADD0指定的地址(默认0x08000000)从用户Flash启动,运行用户程序。验证方法:若用户程序包含LED翻转等可见行为,可观察Target端板载LED状态;也可通过用户程序中的串口输出确认程序已运行。异常处理:若程序未运行,检查固件下载是否正确、启动地址配置是否正确、Product State是否确实为Closed。

4. 参考工程架构解析

ST官方提供的参考工程H563-bootloader基于MDK-KEIL V6编译器开发,完整实现了Host端的全部功能。工程结构清晰,核心代码集中在少数几个源文件中,便于理解与移植。

bootloader.c是工程的核心源文件,包含了与STM32H5 Bootloader通信的全部命令实现。以下是关键函数的功能说明:

函数名 功能描述 对应命令
BOOT_Erase Flash擦除命令实现,计算并擦除指定范围的Flash页 0x44
BOOT_WriteMem 写Memory命令实现,将数据写入目标Flash或RAM指定地址 0x31
BOOT_SP_ProductState 更改Product State命令实现,切换目标芯片的产品状态 0x50 + 0x01
BOOT_SP_ResetCmd 复位MCU命令实现,通过I2C远程复位目标芯片 0x50 + 0x02
Run_ProvisionCmd OBKEY Provisioning完整流程实现,包含Header重计算、下载到SRAM3、发送Provisioning命令 0x31 + 0x50 + 0x83

OBKey.s是一个汇编文件,用于将原始的OBK二进制文件嵌入到Host端固件中。该文件包含了STM32Cube FW_H5 V1.5.1包中的DA_ConfigWithPassword.obk文件的二进制数据,通过汇编伪指令将其作为只读数据段链接到Host程序中。用户可以根据需要将其替换为自己的合法OBK文件。这种嵌入方式确保了OBKEY数据在Host端的完整性与不可篡改性。

targetApp.s同样是一个汇编文件,包含了目标板上运行的测试程序的二进制制文件。该测试程序实现了简单的LED翻转功能,用于验证固件下载与启动运行是否成功。用户也可以自行替换为自己的目标固件代码。在实际量产中,targetApp.s将被实际的产品固件所替代。

工程还包含一个基于串口的测试菜单交互界面。Host端通过串口终端向用户提供测试选项,其中x选项用于测试固件下载、Product State切换、OBKEY Provisioning以及Target MCU复位等完整功能。用户可通过串口终端选择测试项,观察执行过程与结果输出,便于调试与验证。

5. OBKEY文件处理与Header重计算

OBKEY文件的正确处理是Provisioning成功的关键。以下对OBKEY文件的来源、结构与处理流程进行详细说明。

OBKEY文件来源于STM32Cube FW_H5 V1.5.1固件包,该包可从ST官方网站免费下载。在固件包的Utilities/PC_Software/STM32CubeProgrammer/bin目录或相关安全工具目录中,可找到DA_ConfigWithPassword.obk文件。该文件是带密码版本的OBKEY配置文件,适用于TrustZone未使能的场景。文件中包含了64位密码信息以及OB密钥数据。

OBKEY文件的结构分为Header和Payload两部分。Header包含了文件标识、版本号、数据长度、加密算法标识以及CRC校验值等元数据。Payload包含了实际的OB密钥数据以及64位密码。ST工具生成的Header格式是为工具自身的Provisioning流程设计的,与Bootloader通过I2C接口执行Provisioning时所需的格式存在差异。

Header重计算的核心任务是更新CRC-32校验值。根据RM0481的要求,Provisioning数据结构中的Crc字段应覆盖pConfig->pData指向的Provisioning数据缓冲区,计算使用CRC-32算法,多项式为0x4C11DB7(Ethernet标准),初始值为0xFFFFFFFF。参考工程中的Run_ProvisionCmd函数在下载OBKEY之前,会先读取原始OBK文件,提取Payload数据,构建符合Bootloader要求的Provisioning数据结构,然后计算CRC并填入Header,最后将处理后的数据通过I2C写入目标SRAM3。

对于需要使用自定义OBKEY的用户,ST提供了STM32CubeProgrammer工具或专用的OBKEY生成工具,可根据用户指定的密码与配置生成新的OBK文件。生成后,用户需将新的OBK文件替换参考工程中OBKey.s文件里的二进制数据,重新编译Host端程序即可。需要注意的是,自定义OBKEY的密码必须与Provisioning命令中使用的密码一致,否则打开/关闭Provisioning状态将失败。

6. 测试验证方案与结果分析

完整的测试验证需要两块NUCLEO-H563开发板、一台运行串口终端软件的PC以及必要的连接线材。测试环境搭建完成后,按照以下步骤执行验证:

第一步,编译参考工程并将其烧录到Host开发板。使用MDK-KEIL V6打开工程,编译无误后通过ST-LINK将Host程序下载到Host端NUCLEO-H563。第二步,连接硬件:按照硬件连接示意图将Host端与Target端的I2C引脚、GND连接,确保Target端BOOT0接3.3V,I2C上拉电阻已接好。第三步,打开串口终端,连接Host端的虚拟串口(ST-LINK提供的USB转串口),波特率通常为115200。

上电后,串口终端将显示测试菜单。菜单中提供了多个测试选项,其中x选项用于执行完整的固件升级流程,包括固件下载、Product State切换、OBKEY Provisioning以及Target MCU复位。用户输入x并回车后,Host端将自动执行七步流程,并在串口终端输出每一步的执行状态与结果。

测试成功的标志包括:Target端成功运行测试程序后,板载LED(通常为PD13对应的用户LED)开始翻转;通过STM32CubeProgrammer连接Target端(此时调试接口已被Closed状态限制,需通过OBKEY认证)读取Product State,确认其已变为Closed状态。

若需要将Target端恢复为Open状态以便重新测试,可使用STM32CubeProgrammer通过DA(Debug Authentication,调试认证)操作恢复。具体方法是在STM32CubeProgrammer中选择OBKEY认证,输入正确的密码后执行Regression操作,将Product State从Closed回退到Open。恢复后,Target端可重新进入Bootloader模式,再次执行升级流程。

测试过程中,串口终端输出的日志是分析问题的重要依据。每一步命令的发送与接收、ACK/NACK状态、错误码等信息都会被打印出来。若某一步失败,可根据日志中的错误码与状态信息定位问题原因,结合2.7节的技术陷阱分析进行排查。

7. 异常处理与故障排查

在实际实施过程中,可能遇到各类异常情况。以下提供系统化的故障排查流程:

I2C通信失败是最常见的异常。排查顺序为:首先检查物理连接,确认SCL、SDA、GND接线正确且接触良好;其次检查上拉电阻,确认SCL和SDA均有上拉电阻且阻值合适;然后检查I2C地址参数,确认HAL函数中使用的是左移后的地址(0xCA);最后检查I2C时钟频率,确保不超过Bootloader支持的最大速率。若使用示波器,可观察I2C波形是否符合标准。

固件写入失败的排查重点:确认Flash擦除是否成功执行,未擦除的Flash无法写入;确认写入地址是否在用户Flash范围内(0x08000000起始);确认固件大小是否超出目标Flash容量;确认每次写入的数据块不超过256字节;检查I2C通信是否在长数据传输过程中出现丢包。

Product State切换失败的排查:确认当前状态是否允许目标转换(状态转换规则限制);确认Special命令格式与参数是否正确;确认选项字节写入是否成功(某些状态切换可能需要复位后才生效);若从Closed状态回退,必须通过调试认证(OBKEY)执行Regression操作。

OBKEY Provisioning失败的排查:确认OBKEY数据是否已正确下载到SRAM3区域(地址范围检查);确认OBKEY Header是否已重新计算CRC-32;确认使用的是带密码版本的OBKEY(TrustZone未使能条件);确认Provisioning命令(0x50+0x83)的格式与参数正确;确认数据长度为16的倍数。

启动失败(程序未运行)的排查:确认固件是否正确下载到用户Flash(可通过读Memory命令回读校验);确认Product State是否确实为Closed(复位后状态是否保持);确认启动地址NSBOOTADD0是否指向正确的固件入口地址;确认用户固件的中断向量表是否已正确重定位;检查用户程序本身是否存在运行时错误。

对于变砖风险的应对:若因Product State配置错误导致芯片无法启动且无法进入Bootloader,可尝试通过STM32CubeProgrammer在复位窗口期连接,或使用OBKEY调试认证恢复。在量产前务必充分验证状态切换的可靠性,避免批量变砖。

8. 方案扩展与定制化路径

本方案提供了基础的I2C Bootloader固件升级实现,开发者可根据实际需求进行多维度的扩展与定制。

从双板验证到单板量产的迁移是最常见的扩展方向。在量产环境中,Host端功能可集成到专用烧录治具中,通过I2C接口对产品板上的STM32H563进行批量烧录与配置。烧录治具可采用PC加USB-I2C适配器的方案,也可采用独立MCU作为主控的嵌入式方案。量产流程需要增加固件版本管理、序列号写入、Product State校验等步骤,确保每台产品的一致性与可追溯性。

自定义Host端实现是另一个重要方向。参考工程基于STM32 HAL库实现,开发者可将其移植到其他平台,如基于Python的PC端工具(使用python-smbus2或FTDI I2C适配器)、基于LabVIEW的测试系统、或基于其他MCU平台的嵌入式Host。移植时需重点关注I2C时序、命令协议格式以及状态码处理,确保与STM32 Bootloader的兼容性。

固件加密与签名验证的扩展可显著提升升级安全性。在本方案基础上,可在Host端对固件进行AES加密,目标端Bootloader虽不直接支持解密,但可配合用户自定义的二级Bootloader实现加密固件的解密与验签。此外,可引入非对称签名(如ECDSA)确保固件来源的真实性,防止恶意固件注入。

与OTA(Over-The-Air)远程升级的结合是产品智能化的必然趋势。本方案中的I2C Bootloader可作为OTA升级的最后一环:设备通过WiFi/Bluetooth/蜂窝网络接收新固件,暂存到外部Flash或空闲Flash区域,然后通过I2C(或直接调用内部Flash写入接口)执行固件更新。Product State机制可用于保障OTA过程的安全性与回退能力。

TrustZone使能场景下的方案调整需要特别关注。若产品需要启用TrustZone以获得更高的安全性,OBKEY版本、Product State行为、启动路径配置均会发生变化。此时需参考ST关于TrustZone Provisioning的专门文档(如AN5822等),调整Provisioning流程与安全配置。本方案中关于TrustZone未使能的假设不再适用,需要重新设计状态流转与安全配置。

相关推荐