基于串口的FPGA远程升级程序设计与实现

张开发
2026/4/10 20:18:18 15 分钟阅读

分享文章

基于串口的FPGA远程升级程序设计与实现
【基于串口的FPGA远程升级程序】 verilog源代码vivado开发支持xilinx等各类厂家FPGA。 串口升级支持RS422RS232RS485最大速率可达921600bps波特率可设置奇偶校验可设置。具备升级过程中异常掉电防变砖的功能具备golden镜像、multiboot镜像、支持镜像损坏回退看门狗超时回退等功能。串口预留FIFO接口后续可移植其它接口升级搞硬件调试最怕啥不是代码写不对是板子突然变砖。尤其是那种部署在偏远地方的设备你没法随身带个 JTAG 下载器爬上去救场。这时候一个靠谱的串口 Bootloader 就是最后的救命稻草。最近把之前攒的一个基于串口的 FPGA 远程升级方案整理了一下核心思路其实很直接把复杂的烧录逻辑下沉到 FPGA 内部利用 UART 这种最底层的通信通道做传输配合一些防呆机制尽量保证“怎么折腾都不死机”。这玩意儿是用 Vivado 写的 Verilog虽然主要是在 Xilinx 板上跑的但原理层面对 Altera 或者其他厂家的 FPGA 基本通用只要你有 SPI Flash 或者 QSPI Flash 接口就行。物理层上我做了兼容RS232、RS422、RS485 都支持毕竟工业现场有时候环境恶劣差分信号更稳些。波特率最高给到了 921600bps速度不算快但对于固件升级来说稳定性比速度重要得多。先看看核心的状态机部分。很多简单的升级程序只关心数据收发忽略了握手和校验结果网络稍微有点抖动就废了。我这里把接收过程拆得很细特别是针对异常掉电的保护不能简单地把数据往 Flash 里灌。// 简化版的状态定义 typedef enum logic [2:0] { ST_IDLE, // 空闲等待命令 ST_WAIT_SYNC, // 等待同步头 ST_RECV_LEN, // 接收长度信息 ST_RECV_DATA, // 接收有效载荷 ST_VERIFY_CRC, // 校验 CRC ST_WRITE_FLASH, // 写入 Flash ST_UPDATE_DONE, // 更新完成 ST_ERROR_ROLLBACK // 错误回滚 } t_upgrade_state; always_ff (posedge clk) begin case (curr_state) ST_RECV_DATA: // 这里有个小细节接收过程中如果看门狗超时直接跳去回滚 if (watchdog_timeout || uart_rx_error) next_state ST_ERROR_ROLLBACK; else if (data_cnt expected_len) next_state ST_VERIFY_CRC; ST_WRITE_FLASH: // 双 Bank 切换逻辑确保旧镜像还在 if (current_bank 0) target_bank 1; else target_bank 0; endcase end这段代码里埋了两个关键点的影子。一个是看门狗超时检测 (watchdog_timeout)另一个是双 Bank 切换。以前遇到过几次升级写到一半电源闪了一下Flash 里的分区表乱了下次启动找不到入口。现在的方案里引入了 Golden 镜像的概念。你可以理解为系统里始终保留一份绝对可靠的“出厂设置”一旦新刷入的镜像损坏或者启动失败超过阈值比如启动失败 3 次Bootloader 会自动切回 Golden 分区引导。为了防止校验出错我在数据链路层加了奇偶校验配置并且每个数据包都有 CRC 校验。一旦校验失败不会尝试修复而是直接丢弃并重传实在重传多次失败就触发那个STERRORROLLBACK状态。这个状态下程序会检查主备用分区的标志位强制从已知良好的分区启动。// 镜像健康度检查与回退逻辑 always_comb begin boot_partition 0; // 默认从 Partition A 启动 if (partition_a_valid partition_a_crc_pass) begin boot_partition 0; end else if (partition_b_valid partition_b_crc_pass) begin // 如果 A 坏了尝试 B boot_partition 1; end else begin // 全挂了强制进入 Golden 模式或复位 golden_mode_enable 1b1; reset_system 1b1; end end这里还有个挺有意思的设计就是预留了 FIFO 接口。你可能觉得串口升级慢以后想换以太网或者 USB 升级怎么办如果整个协议栈都绑死在 UART IP 核上改起来得推倒重来。所以我把数据接收模块抽象成了一个标准的 FIFO 输入接口。【基于串口的FPGA远程升级程序】 verilog源代码vivado开发支持xilinx等各类厂家FPGA。 串口升级支持RS422RS232RS485最大速率可达921600bps波特率可设置奇偶校验可设置。具备升级过程中异常掉电防变砖的功能具备golden镜像、multiboot镜像、支持镜像损坏回退看门狗超时回退等功能。串口预留FIFO接口后续可移植其它接口升级现在的架构是外部物理接口UART/Ethernet/USB - FIFO - 升级控制器。这样以后如果要移植成网口升级只需要替换最外层的收发模块中间的校验、Flash 写入、多版本管理逻辑完全不用动。这在项目后期维护时能省不少事特别是那种系列化产品不同型号可能通讯介质不一样但固件升级流程必须统一的时候。关于波特率设置虽然标称 921600bps但在实际工程里如果线缆比较长或者干扰大建议降到 115200 甚至更低。代码里留了一个寄存器配置位可以在编译前通过参数宏定义固定波特率也可以通过上位机下发指令动态调整。不过为了安全起见动态调整最好在升级流程开始前完成不要在数据传输中间改否则时序对不上容易丢包。最后说下 Multiboot 的支持。有些场景需要测试新功能但不想覆盖掉生产环境的稳定代码。这个方案允许同时存在多个镜像副本启动时根据特定的按键组合或者 GPIO 电平来选择加载哪个版本的固件。这就像手机的双系统一样万一新版本有问题重启选个旧的就完事了不用重新烧录。总之这套东西的核心不在于功能有多炫酷而在于“兜底”。硬件这东西一次意外就能让之前的努力白费所以能在 FPGA 内部把这些容错逻辑写扎实比什么都强。代码已经开源了一部分有需要的可以拿去改改希望能帮大家少踩几个坑。

更多文章