尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

FPGA远程更新实战:Multiboot双镜像与Flash分区策略

发布时间:2026/9/18 12:26:28

资讯中心
01
ARTICLE

FPGA远程更新实战:Multiboot双镜像与Flash分区策略

FPGA远程更新实战:Multiboot双镜像与Flash分区策略
1. 从一次现场升级翻车说起为什么FPGA需要远程更新前两年做一个工业相机的项目设备已经装在客户产线的机柜里离地三米多拆一次得停机半天。结果固件里有个图像预处理的状态机在特定光照下会死锁需要改逻辑重新烧录。当时第一反应是让现场工程师拿下载器接JTAG但设备封在防爆壳里JTAG排针根本没引出来。那次折腾了整整两天最后是拆机柜解决的。回来之后我就下定决心下一版硬件必须把远程更新通道做进去而且要做双镜像兜底——万一新固件本身有问题设备还能自己退回去。这就是FPGA Multiboot要解决的核心问题让FPGA在上电时能从多个镜像里选一个加载并且支持在运行中触发重新配置切换到备用镜像。它依赖两个东西一个是Flash分区策略把配置文件按地址切好另一个是ICAPE2原语7系列或对应的内部配置访问端口让逻辑内部能主动发起重配置请求。关键词里的Multiboot、Flash分区、XDC、ICAPE2基本就是这条链路上的四个关键节点。这篇文章适合谁看如果你正在做带FPGA的嵌入式产品尤其是设备部署后不方便物理接触的场景比如工业现场、车载、基站、医疗设备那这套方案你迟早要用。如果你只是做实验室验证可能觉得JTAG就够了但产品化阶段远程更新是绕不过去的。下面我按实际项目落地的顺序把分区规划、镜像生成、原语调用、约束写法、以及几个我踩过的坑完整讲一遍。2. Multiboot的工作机制与镜像切换的底层逻辑2.1 上电配置流程里FPGA到底在做什么7系列FPGA上电后的配置流程大致是这样POR上电复位释放后FPGA根据M[2:0]模式引脚决定配置模式SPI Flash模式下会从地址0开始读配置数据。它先读一段配置头里面包含同步字、器件ID、配置数据长度等信息。如果这段数据校验通过就继续加载如果失败FPGA会去看WBSTAR寄存器里存的地址从那个地址重新开始读。这就是Multiboot的硬件基础——Golden镜像 Update镜像的结构。Golden镜像是出厂就烧好的、经过充分验证的稳定版本地址固定在0。Update镜像是后续通过远程通道写入的放在Flash的另一个区域。正常上电时FPGA先加载GoldenGolden逻辑里判断是否需要跳转到Update。如果需要就通过ICAPE2写WBSTAR寄存器指定Update的起始地址然后触发IPROG命令FPGA就会从WBSTAR指向的地址重新配置。这里有个关键点很多人会忽略IPROG触发后FPGA内部会做一次相当于热复位的操作所有逻辑状态清零包括你用来做判断的那些寄存器。所以Golden镜像里负责跳转的逻辑必须足够简单、足够可靠不能依赖复杂的状态机。我一般就在Golden里放一个极简的SPI控制器加一个跳转判断模块其他功能全部放在Update里。2.2 WBSTAR和IPROG两个寄存器撑起整个切换WBSTARWarm Boot Start Address是一个32位寄存器但实际只用低28位左右表示地址高位有保留位。写的时候要注意地址是按字节还是按字取决于配置模式SPI模式下一般按字节地址。ICAPE2的输入数据是32位WBSTAR的地址需要放在正确的位段上。我见过有人直接把字节地址塞进低28位结果跳转到了错误位置FPGA加载失败后回落到Golden但Golden又判断需要跳转形成死循环。IPROG命令是ICAPE2的一个特定指令码写入后FPGA立即执行内部重配置。它的行为等价于把PROGRAM_B拉低再释放但不需要外部引脚。写IPROG之前必须先写WBSTAR顺序不能反。另外IPROG执行后FPGA会重新走一遍配置流程包括重新读取模式引脚、重新初始化配置逻辑。所以如果你的板子上有多个配置源要确保模式引脚状态和你的预期一致。2.3 Golden和Update的职责划分Golden镜像的职责只有三个第一保证FPGA一定能起来哪怕Update是空的或者损坏的第二提供最基本的通信通道比如SPI或UART用来接收新的Update数据第三判断是否需要跳转到Update。除此之外Golden里不要放任何复杂逻辑LUT占用越低越好因为Golden的可靠性直接决定了设备的可恢复性。Update镜像才是真正干活的里面放完整的应用逻辑。Update镜像的配置数据里必须包含一个有效的配置头否则FPGA加载到一半发现头不对会直接回落到WBSTAR指向的地址。这里有个细节Update镜像的配置头里的地址字段通常要写成它自己的起始地址这样即使FPGA从Update启动后再次触发IPROG也能正确回到Update自己。3. Flash分区策略地址怎么切才不出事3.1 分区规划的基本原则Flash分区不是随便切一刀就行的。首先要确认Flash的总容量和扇区大小。比如常用的W25Q12816MB容量扇区4KB块64KB。FPGA的配置文件大小取决于器件型号和设计规模Artix-7 35T的配置文件大概2MB左右Kintex-7 325T可能到10MB以上。分区的时候要留足余量因为后续逻辑增加会导致配置文件变大。我一般按这样的结构切地址0x000000到0x400000给Golden4MB0x400000到0x800000给Update4MB0x800000往后给用户数据比如参数、日志、固件备份。Golden和Update之间留一段保留区用来存跳转标志、版本号、校验值等元数据。保留区不要放在Golden内部因为Golden更新时可能会被擦除元数据要独立于两个镜像。区域起始地址大小用途Golden0x0000004MB出厂稳定镜像元数据区0x40000064KB跳转标志、版本、CRCUpdate0x4100004MB应用镜像用户数据0x810000剩余参数、日志、备份3.2 地址对齐与扇区边界Flash擦除是按扇区或块进行的所以分区起始地址必须对齐到扇区边界。4KB扇区的话地址低12位必须是0。我见过有人把Update起始地址设成0x400100结果擦除时把前面的元数据区也擦了一部分跳转标志丢了设备每次上电都回落到Golden。这种问题在实验室不容易发现因为实验室可能只擦一次就烧录但现场远程更新时会反复擦写问题就暴露了。另外配置文件的起始地址必须是配置模式支持的地址。SPI模式下FPGA从地址0开始读但WBSTAR可以指向任意字节地址。不过为了保险我建议所有镜像起始地址都按64KB对齐这样兼容块擦除也方便计算。3.3 元数据区的设计元数据区我一般放这几个字段magic number固定值用来判断元数据是否有效、update_validUpdate镜像是否有效、update_addrUpdate起始地址、update_sizeUpdate大小、update_crcUpdate配置数据的CRC、boot_count启动尝试次数。boot_count很关键用来防止Update镜像本身有问题导致无限重启。Golden启动后先读元数据区。如果magic不对说明元数据没初始化直接留在Golden。如果update_valid为1且boot_count小于阈值比如3次就写WBSTAR并触发IPROG。如果boot_count达到阈值说明Update连续启动失败Golden把update_valid清零留在Golden等待新的更新。这个机制能有效防止“Update镜像一启动就死但Golden每次都跳过去”的死循环。4. ICAPE2原语逻辑内部发起重配置的正确姿势4.1 ICAPE2的端口和时序ICAPE2是7系列FPGA的内部配置访问端口例化后可以直接在逻辑里读写配置寄存器。它的端口不多CLK、CSIB、RDWRB、I[31:0]、O[31:0]。CSIB是片选低有效RDWRB是读写选择0写1读。操作时先拉低CSIB然后在CLK上升沿给出数据最后拉高CSIB。注意ICAPE2的时钟频率不能太高一般建议不超过50MHz我通常用20MHz左右稳一点。写WBSTAR的流程是先发WBSTAR的寄存器地址0x00000000再发地址数据。ICAPE2的寄存器地址是16位的但通过I[31:0]传输时高16位是命令低16位是数据。具体格式要查UG470不同命令的位段不一样。我一般封装成一个状态机把常用命令做成常量避免每次手算位段。4.2 写WBSTAR和IPROG的代码结构下面是我常用的一个简化状态机用Verilog写的实际项目中会加更多错误处理localparam CMD_WBSTAR 16h0000; localparam CMD_IPROG 16h0001; // 状态机片段 always (posedge clk) begin case (state) IDLE: if (trigger) state SEND_WBSTAR_CMD; SEND_WBSTAR_CMD: begin icape2_i {CMD_WBSTAR, 16h0000}; icape2_csib 1b0; state SEND_WBSTAR_DATA; end SEND_WBSTAR_DATA: begin icape2_i update_addr; state SEND_IPROG_CMD; end SEND_IPROG_CMD: begin icape2_i {CMD_IPROG, 16h0000}; state WAIT_DONE; end WAIT_DONE: begin icape2_csib 1b1; // IPROG执行后FPGA会复位这里不会真正到达 end endcase end注意IPROG命令发出后FPGA会立即开始重配置逻辑会停止运行所以状态机后面的状态实际上不会执行。但代码里还是要写完整因为综合器需要看到完整的状态转移。4.3 常见错误CSIB和RDWRB的时序配合ICAPE2的CSIB和RDWRB必须在CLK上升沿之前稳定。我见过有人在CLK上升沿同时改变CSIB结果ICAPE2采样到错误的片选状态命令没写进去。正确的做法是在CLK下降沿改变CSIB和RDWRB在上升沿保持稳定。另外两次操作之间要留足够的间隔至少几个时钟周期让ICAPE2内部完成处理。还有一个坑ICAPE2的O端口在读操作时才有意义写操作时可以忽略。但有些综合器会警告O端口未使用可以在例化时把O接到一个dummy寄存器或者用(* keep true *)保留。5. XDC约束让工具链正确识别Multiboot配置5.1 配置文件属性约束Vivado里生成配置文件时需要告诉工具这个bitstream是用于Multiboot的。在XDC里加这样的约束set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design] set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design] set_property BITSTREAM.CONFIG.SPI_FALL_EDGE YES [current_design] set_property BITSTREAM.CONFIG.NEXT_CONFIG_ADDR 0x00410000 [current_design]NEXT_CONFIG_ADDR就是WBSTAR的初始值告诉FPGA如果当前镜像加载失败下一个尝试的地址。这个值要和你的Flash分区一致。SPI_BUSWIDTH设成4表示Quad SPI速度更快但要注意Flash支持。CONFIGRATE是配置时钟频率50MHz是常用值太高可能导致配置失败。5.2 Golden和Update的约束差异Golden和Update的XDC约束要分开写。Golden的约束里NEXT_CONFIG_ADDR指向Update的起始地址Update的约束里NEXT_CONFIG_ADDR指向Golden的起始地址0x000000这样Update启动失败后能回落到Golden。另外Golden的BITSTREAM.CONFIG.TIMER_CFG可以设短一点比如5秒让它快速判断是否跳转Update的可以设长一点比如30秒给应用逻辑足够的初始化时间。5.3 约束不生效的排查方法如果发现Multiboot不工作先检查生成的bit文件里有没有正确写入配置属性。可以用write_bitstream -force生成后用report_property查看。另外Vivado的updatemem工具可以用来合并bit文件和ELF文件但Multiboot场景下一般不需要除非你用MicroBlaze做Golden的控制器。还有一个容易忽略的点SPI Flash的地址映射。有些Flash的地址是3字节模式有些是4字节模式。16MB以上的Flash需要4字节地址但FPGA的配置控制器默认可能是3字节。这时候要在XDC里加BITSTREAM.CONFIG.SPI_32BIT_ADDR YES否则WBSTAR的高位地址会被截断。6. 实测中的坑从死循环到Flash损坏6.1 Update镜像启动失败导致的无限重启第一次做Multiboot的时候我犯了个典型错误Golden里判断跳转的条件太宽松只要元数据区有update_valid就跳没有检查boot_count。结果Update镜像里有个时钟约束没写对实际跑起来时序违例逻辑行为异常看门狗不断复位。每次复位后Golden又跳转到Update形成无限重启。设备在现场跑了半小时Flash的擦写次数就涨了几百次。修复方案是在元数据区加boot_count每次Golden跳转前先加1Update启动成功后由应用逻辑清零。如果boot_count超过3Golden就清除update_valid留在Golden。这个机制后来救了好几次现场有一次Update的SPI通信初始化有问题设备自动回落到Golden客户甚至没察觉到异常。6.2 Flash擦除时的地址越界另一个坑是Flash擦除。远程更新时新固件先写到Flash的临时区校验通过后再拷贝到Update区。拷贝过程中要擦除Update区如果擦除范围计算错误可能把元数据区也擦了。我当时的代码里擦除长度用的是Update镜像大小但起始地址没对齐到扇区边界结果擦掉了元数据区的前几个字节magic number丢了Golden认为元数据无效直接留在Golden。修复方法是擦除前先计算对齐后的起始地址和结束地址擦除范围要覆盖整个Update区但不能碰到元数据区。我一般会在元数据区和Update区之间留一个扇区的保护间隔即使计算有误也不会立刻破坏元数据。6.3 配置文件CRC校验的必要性远程更新最大的风险是传输过程中数据损坏。SPI Flash写入时如果电源波动或者通信误码可能导致配置文件部分字节错误。FPGA加载时会做配置数据的CRC校验如果校验失败会回落到WBSTAR指向的地址。但如果WBSTAR指向的地址也是损坏的就会一直回落最终可能停在某个未知状态。所以我在元数据区里存了Update配置数据的CRC32Golden在跳转前先算一遍CRC和元数据区的值比对。如果不一致直接不跳转留在Golden等待重新更新。这个校验增加了跳转前的处理时间但换来了可靠性。实测下来CRC计算2MB数据大概几十毫秒完全可以接受。7. 几个让方案更稳的工程习惯7.1 Golden镜像的LUT占用要压到最低Golden镜像里我只放三样东西SPI控制器、ICAPE2状态机、一个极简的看门狗。其他全部不放。综合时用-flatten_hierarchy和-retiming尽量减小面积。Golden的配置文件越小加载越快可靠性越高。我一般把Golden的LUT占用控制在5%以内这样即使FPGA其他部分有问题Golden也能起来。7.2 远程更新通道要独立于应用逻辑更新通道比如以太网、UART、SPI从机最好放在Golden里而不是Update里。这样即使Update镜像完全跑不起来Golden仍然能接收新固件。如果更新通道放在Update里Update挂了就彻底没法远程恢复了。当然Golden里的更新通道功能可以简单一点只支持基本的固件写入和校验不需要完整的协议栈。7.3 版本号和回滚策略元数据区里一定要存版本号。Golden启动后如果发现Update版本号比当前低可以选择不跳转防止误刷旧版本。回滚策略也很重要如果新固件启动后应用逻辑检测到自身异常比如关键外设初始化失败可以主动写元数据区把update_valid清零然后触发IPROG回到Golden。这样设备能自己恢复到可用状态不需要人工干预。7.4 上电时的Flash访问时序SPI Flash上电后需要一段时间才能进入可读状态具体时间看Flash手册一般几百微秒到几毫秒。FPGA的配置控制器会等Flash就绪后再读但Golden里的SPI控制器如果自己访问Flash要加足够的延时。我一般在上电后等10ms再访问Flash避免读到无效数据。8. 从Multiboot延伸出去还能怎么用这套机制不只用于远程更新。比如你做多功能设备可以用Multiboot在启动时根据外部引脚或配置区选择不同的功能镜像相当于一个Flash存多个产品型号的固件。再比如安全启动Golden里做签名校验只有校验通过的Update才允许跳转防止未授权固件运行。还有一个场景是现场调试。设备部署后如果发现某个功能有问题可以临时切到一个带调试接口的Update镜像抓完日志再切回正式镜像。这比重新烧录快得多也不需要拆机。我在实际项目里还试过用Multiboot做双备份两个Update区轮流写每次更新写备用区校验通过后切换跳转地址。这样即使更新过程中断电原来的Update区仍然完好设备不会变砖。代价是Flash空间翻倍但对于可靠性要求高的场景这个代价值得。最后分享一个小技巧ICAPE2的时钟最好用独立的BUFG不要和逻辑时钟共用。因为IPROG触发后逻辑时钟会停止但ICAPE2需要时钟来完成命令写入。如果共用时钟可能在命令写完之前时钟就停了导致IPROG没生效。独立BUFG能保证ICAPE2在重配置前完成所有操作。这个细节在UG470里没有明确写是我调试时用示波器抓出来的。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。