ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FPGA Multiboot远程升级实战:Golden/Update双镜像设计要点

FPGA Multiboot远程升级实战:Golden/Update双镜像设计要点 做FPGA固件升级这些年Multiboot一直是我认为最值得花时间啃透的功能之一。手里一批板卡已经部署到现场升级固件不可能每次都拆机箱、焊下载器远程通过SPI Flash引导多镜像的方案就成了刚需。Vivado的Multiboot功能正好解决这个问题它允许把两个甚至多个配置镜像放在同一条SPI Flash里系统启动时先加载一个最稳妥的Golden镜像正常运行后再加载功能完整的Update镜像万一Update镜像有问题还能自动回退到Golden镜像板子不至于变砖。这篇文章就围绕一套我实际跑通的流程来写从Flash分区设计、Vivado工程配置、镜像生成到MCU/软核触发Multiboot跳转最后到常见故障的排查思路。适合正在做FPGA远程升级、或者准备在SPI Flash上做多镜像启动的工程师参考一些细节是我踩过坑之后整理出来的应该能帮你少走弯路。1. 为什么需要Multiboot远程更新方案的整体设计思路FPGA远程更新本质上是“把新比特流写入配置存储介质然后让FPGA重新加载新配置”。但这个过程有个核心矛盾配置存储介质比如SPI Flash本身只有一个如果直接把新镜像覆盖掉旧镜像而新镜像写坏了、下电时序不对、或者本身就有Bug那FPGA重新上电后就可能加载失败整块板变砖。这就是Multiboot存在的意义。1.1 双镜像架构Golden镜像与Update镜像的分工Multiboot方案在SPI Flash里放两个镜像。第一个是Golden镜像也就是“工厂镜像”存放在Flash最开始的地址通常包含最基础的固件逻辑功能上不必太完整但必须保证能正常加载、能执行最基本的操作比如活下去、能响应简单的升级命令。第二个是Update镜像存放在Golden镜像之后的地址存放真正完整的功能逻辑。这两者的关系我习惯用一个比喻Golden镜像类似于电脑的BIOS恢复分区Update镜像类似于主系统。正常情况下系统从主分区启动大部分时间在跑主系统但主系统坏了Reset之后还能从恢复分区重新起来机器不会彻底瘫掉。Multiboot的Fallback机制就是这个道理——上电默认从Flash地址0x0加载Golden加载成功后在软件里通过IPROG命令跳到Update镜像的地址重新配置如果Update镜像加载失败FPGA会自动回退到Golden镜像继续运行。这里有一个值得注意的点Golden镜像不一定要和Update镜像完全独立它可以是Update镜像的一个子集。比如Update镜像里做了DDR读写测试、网络通信、算法加速等全部功能而Golden镜像里只保留最简的串口打印和GPIO控制用来确认“板子还活着、还能进升级模式”。这样做的好处是Golden镜像体积小编译时间短出错的概率也低更稳妥。1.2 Multiboot的工作机制WBSTAR寄存器与IPROG命令要把“跳到哪个地址启动”这件事落实关键在两个东西WBSTAR寄存器Warm Boot Start Address Register和IPROG命令Internal PROGRAM_B。WBSTAR寄存器在7系列和UltraScale系列里都存在它保存的是“下一次内部重配置时要从Flash的哪个地址开始加载”这一信息。注意它是一个16位的寄存器保存的是地址的高16位也就是说地址必须按64KB对齐。比如Update镜像放在0x0080_0000那WBSTAR里写入的就是0x0080。如果地址不按64KB对齐FPGA在回跳的时候会直接按对齐后的地址去找镜像容易落空。IPROG命令则是一个触发信号软件里向ICAPInternal Configuration Access Port或者通过MCU控制FPGA的PROGRAM_B引脚拉低再拉高让FPGA重新进入配置流程。但Multiboot选的是IPROG因为它可以在不需要外部引脚动作的情况下直接从内部触发重配置而且会读取WBSTAR里预设的地址把新地址作为本次重配置的首选加载位置。流程笼统说就是这样板卡上电配置逻辑先从Flash地址0x0加载Golden镜像构建起最小系统。软件MCU或者软核决定进入升级模式向WBSTAR写入Update镜像的起始地址。软件向ICAP发送IPROG命令FPGA内部触发重配置。FPGA配置逻辑转向WBSTAR指定的地址加载Update镜像。Update镜像加载中如果CRC校验失败、IDCODE不匹配、或者同步字收不到配置逻辑自动清空WBSTAR回退到Flash地址0x0重新加载Golden镜像。这个回退机制是Xilinx在硅片层面做了硬件支持的不需要额外的外部逻辑参与。前提是Update镜像必须在同一片SPI Flash里且Golden镜像所在区域不能被擦除。如果设计上把Flash分成两个独立分区那就必须从设计规范上保证任何升级命令都不能触碰Golden分区这是预防变砖的第一道闸门。1.3 为什么用SPI Flash而不是其他介质FPGA配置介质的选择其实很宽泛有BPIParallel NOR Flash、SPI Flash、SD卡、QSPI Flash等。我最终选SPI/QSPI Flash理由很直接引脚占用极少通常只需要4根或6根信号线CS、CLK、MOSI、MISOQSPI再加IO2、IO3。单芯片容量可以做到64MB甚至更大一个镜像几十MB完全放得下还可以放多个镜像、文件系统、日志区。SPI Flash几乎每家FPGA板卡都标配量产和采购都很成熟。但要注意SPI Flash的读速度天然比BPI NOR Flash慢。不过对于配置这种“一次性加载、之后不再访问”的场景慢一点完全没关系。真正需要在意的是SPI Flash的型号规格容量、电压、是否支持Quad/Dual Read要和Vivado里设置匹配不然生成MCS文件时地址映射会出错。2. 硬件准备与Vivado工程设置动手前的关键配置Multiboot不只是一个软件配置功能它和硬件设计强相关。如果板卡上FPGA的配置引脚没有预留正确或者SPI Flash的位置摆放不对后续做远程升级基本就无从谈起。这块我在多个项目里吃过亏拿出来讲一讲。2.1 SPI Flash容量规划与分区设计先算容量。一个普通的7系列FPGA比如Artix-7 200T的比特流文件大小通常在10MB到40MB之间——取决于资源利用率、压缩设置、配置位流等。如果开启比特流压缩set_property BITSTREAM.GENERAL.COMPRESS TRUE文件能缩小到原来的1/2甚至1/3这对远程升级的传输时间很有价值。UltraScale系列的比特流体积会更大部分器件接近70MB此时Flash容量选64MB甚至128MB更稳妥。分区建议这样规划分区起始地址大小建议存放内容Golden0x0000008MB~32MB工厂镜像、最小引导逻辑Update0x00800000起按需功能完整镜像标志区/升级包缓存区末尾4MB~8MB软件标志位、升级包暂存、日志地址的颜色块怎么分很考验经验。我建议Golden分区留足余量不差这1-2MB。考虑极端情况一个增强版Golden镜像可能需要升级到更大的资源和更多的IPFlash太小就变成硬约束改Flash封装是板级灾难。另外要考虑Flash擦除块大小的对齐。W25Q256Winbond 256Mbit这类Flash的扇区一般是4KB块是64KB。分区的起始地址最好按64KB对齐这既和WBSTAR的对齐要求一致也方便擦写。不然软件擦写的时候一个升级包可能横跨两个块擦除或写入稍有不慎就可能破坏相邻分区的数据。2.2 Vivado里配置SPI Flash相关的关键参数在Vivado里生成比特流之前有几个属性必须设好。在综合、布局布线完成后打开Edit Device Properties或者在约束里添加set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design] set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design] set_property BITSTREAM.CONFIG.SPI_FALLBACK Yes [current_design] set_property BITSTREAM.CONFIG.OVERTEMPPOWERUP_DISABLE TRUE [current_design]第一行是配置时钟速率默认可能只有20MHz或者更慢为了可靠可以配到50MHz左右。如果SPI Flash支持更高读时钟也可以适当提高但不建议一上来就冲极限先稳定跑通再提速度。第二行是SPI数据位宽。Master SPI模式下通常支持1-bit、2-bit、4-bit。QSPI Flash肯定走4-bit加载速度能快很多。这里要注意如果Flash不支持Quad Read命令却配了4-bit加载会失败。所以要么确认Flash型号支持要么直接配1-bit先跑通后面再优化。第三行是Fallback使能。Multiboot的自动回退机制必须在比特流里显式打开如果不设置Update镜像加载失败后就静止在失败状态不会自动跳回Golden。这个属性极重要我见过好几个项目就是漏了这个现场设备升级失败后需要人为重新上电才能恢复非常被动。第四行是温度相关不是Multiboot必需但我习惯加上确保因为过温导致的配置失败不让系统误判为Multiboot问题。此外还有一个需要注意的属性set_property BITSTREAM.CONFIG.NEXT_CONFIG_ADDR 0x00800000 [current_design]这一条是为了生成支持“双镜像启动流程”的比特流而配置的。但对于Update镜像本身这个属性配不配都没有关系因为在运行时是由MCU/软核显式写WBSTAR的。如果你用的是Vivado自带的“Program Flash”向导在生成MCS时它会让你选“Golden Image”和“Next Image”本质上也等价于替你把NEXT_CONFIG_ADDR这种属性加进去。2.3 管脚分配与硬件电气注意点SPI Flash在板上和FPGA的连接建议尽量靠近走线短。这与信号完整性有关但更高频的场景是板子在现场环境恶劣SPI Flash虚焊或者连接器松动就会导致配置加载间歇性失败。远程升级设计里要额外考虑这些因为现场人员不可能去动烙铁。FPGA的配置模式引脚M[1:0]需要设置为Master SPI模式通常M[1:0]0b10具体见器件手册这个在硬件设计时就要固定拉好。不要在软件里指望能改——配置模式是硬件决定的。如果这几个引脚悬空或者被拉成从模式FPGA上电就等外部主机来配置不会主动去读SPI FlashMultiboot自然无从谈起。另外SPI Flash的WP#写保护引脚和HOLD#引脚千万不要悬空要么接上拉电阻要么由FPGA控制。HOLD#悬空时可能因为噪声导致Flash误进入Hold状态读数据卡死。WP#悬空时如果Flash内部寄存器被意外写保护远程写Flash就会失败并且排错起来极其痛苦。这两根引脚我在PCB Layout检查里必查。3. 镜像生成与SPI Flash烧写从BIT到MCS的完整链路Vivado本身提供了一条龙工具链从综合、实现、生成比特流到直接烧写SPI Flash。但Multiboot场景需要两个镜像合并成一条MCS或者分两次写入Flash流程上有些细节需要掰开说清楚。3.1 生成Golden与Update两张镜像开发环境中我们需要各自独立综合、实现两个工程。这很关键一张BIT对应一个FPGA设计Golden和Update的硬件配置可能不同但必须都在同一个FPGA型号下编译。一个常见做法是使用同一份RTL但通过宏定义区分ifdef GOLDEN_IMAGE // 极简逻辑串口打印、GPIO控制、升级命令响应 else // 完整功能逻辑 endif综合时给不同的Vivado工程设置不同的宏即可。这样做的好处是降低了双工程维护成本也便于确保Golden镜像的硬件约束比如引脚分配和Update完全一致——尤其是SPI Flash、时钟、复位这些引脚如果两张镜像用的引脚不一致Multiboot跳转后外设会复位到不确定状态后患无穷。在生成比特流前务必再检查一次参数重点确认配置模式已经是Master SPI。SPI_BUSWIDTH设置与Flash能力匹配。SPI_FALLBACK已打开。时钟约束正确比特流生成不报错。两张镜像生成后可以分别在本地先用JTAG下载到FPGA验证功能确认无误后再做MCS合并。3.2 合并镜像生成包含Golden和Update的单一MCS文件合并镜像的方式有很多我推荐直接用Vivado硬件管理器里的“Add Configuration Memory Device”流程。具体步骤如下进入Vivado Hardware Manager连接开发板。右键FPGA设备选择“Add Configuration Memory Device”。在弹出的窗口里选择对应的SPI Flash型号比如W25Q256。在“Configuration Memory Part”窗口下面有一个“Address”设置默认是0x0我们先烧Golden镜像所以这里填0x0加载Golden的BIT文件。烧写成功后不要断开再次执行“Add Configuration Memory Device”这次在Address里填Update分区的起始地址比如0x00800000加载Update的BIT文件。下载完成后Flash里就有了两个镜像重新上电会先加载Golden之后如果想验证Multiboot跳转再在软件里执行跳转命令。如果不想每次都进硬件管理器手动烧也可以先把Golden和Update的BIT转换成一个MCS文件一次性烧写。在Tcl Console里可以这样操作write_cfgmem -format mcs -size 64 -interface spix4 \ -loadbit up 0x0 golden.bit \ -loadbit up 0x00800000 update.bit \ -file combined.mcs这个命令把两个bit文件打包成一个MCS。参数里-up表示该bit作为image文件烧写-size要选择实际Flash容量单位MB-interface要和SPI_BUSWIDTH一致spix4对应4-bit。生成的MCS可以直接用Vivado Hardware Manager烧录。也可以让产线使用第三方的Flash烧录器如DediProg、BPMicro等先把MCS文件烧录到Flash芯片里再贴片。两种方式都行但第三方烧录器对MCS格式的支持各有不同建议产线用的烧录器提前试一下确认它能识别这个文件。3.3 用Vivado直接固化从BIT到Flash的另一种方式有的工程师习惯在连接硬件的情况下直接生成固化文件。这其实就是在Hardware Manager里操作但要注意一个细节如果你打开Hardware Manager后选择的不是对应的FPGA型号而是用“Open Target”自动探测程序返回的JTAG ID可能和开发板上的标准ID不同可能导致无法识别到Flash。这时需要手动指定FPGA型号或者在Vivado工程里先做“Add Configuration Memory Device”再连接。另外一个坑如果开发板上FPGA的模式引脚M[1:0]没有正确设置成Master SPIHardware Manager虽然能识别到FPGA但烧写Flash后重新上电FPGA不会自动去读Flash看起来像是“烧写没有生效”。排错时先查配置模式引脚再查Flash的CS/CLK信号是否有正常活动。4. 远程更新的核心引擎触发Multiboot跳转的软件实现镜像和Flash都准备好了现在要解决的是“如何让FPGA从Golden跳到Update”的问题。这个环节一般由板载MCU、软核处理器MicroBlaze、或者一段状态机逻辑来完成。4.1 方式一外部MCU/ARM通过GPIO控制PROGRAM_B和SPI Flash如果你的板子上有一颗MCU比如STM32、Zynq的PS侧最直接的控制方式是MCU通过GPIO拉低FPGA的PROGRAM_B引脚保持至少几百纳秒。MCU再拉高PROGRAM_BFPGA进入重新配置流程。在FPGA重新配置前MCU需要先把WBSTAR的值写入FPGA。但这里有个难点WBSTAR寄存器不在外部总线空间里用GPIO控制PROGRAM_B无法直接写WBSTAR。如果完全靠外部引脚触发重配置FPGA会按黄金启动流程回0x0。所以外部MCU控制方式真正要做的是MCU向FPGA发送一段特殊的配置序列这段配置序列里包含“设置WBSTAR 触发IPROG”的指令。其实更常见的工程方案是MCU预先通过SPI接口把Update镜像写入Flash然后在特定寄存器比如用户自定义的软寄存器里写一个“upgrade”标志再触发FPGA复位。FPGA复位加载的是Golden镜像Golden镜像启动后第一件事就是检查升级标志如果存在就主动执行Multiboot跳转。这种方式的好处是职责分离MCU管“写Flash”FPGA管“重配置”。但要特别注意MCU写Flash的时候必须关掉FPGA对Flash的访问——因为FPGA配置完成后一般不会再读Flash但这不代表时序上不会冲突。稳妥做法是MCU在写Flash前把FPGA复位住保持PROGRAM_B拉低写完Flash后再释放。4.2 方式二FPGA内部软核/逻辑通过ICAP触发Multiboot如果FPGA设计里本身就有MicroBlaze或者一段状态机那就不需要外部MCU参与了直接使用ICAP原语。ICAP原语在7系列里叫ICAPE2在UltraScale里叫ICAPE3。通过它软核可以向FPGA内部配置逻辑发送IPROG命令。下面这段代码演示如何用AXI接口封装一个简单的ICAP控制器实现WBSTAR写入和IPROG触发module icap_warm_boot #( parameter NEXT_IMAGE_ADDR 32h00800000 )( input wire clk, input wire rst, input wire trigger, output reg done ); localparam CMD_WBSTAR 32h30020001; // Write WBSTAR localparam CMD_IPROG 32h30008001; // IPROG command localparam CMD_NOP 32h20000000; // NOP localparam WBSTAR_VALUE {16h0000, NEXT_IMAGE_ADDR[23:8]}; // 地址高16位 reg [63:0] shifter; reg [3:0] state; reg [1:0] cmd_index; always (posedge clk or posedge rst) begin if (rst) begin state 0; done 0; end else begin case (state) 0: begin done 0; if (trigger) begin state 1; cmd_index 0; end end 1: begin if (cmd_index 0) shifter {CMD_WBSTAR, WBSTAR_VALUE}; else if (cmd_index 1) shifter {CMD_IPROG, CMD_NOP}; state 2; end 2: begin // 实际ICAP接口是32bit宽需要按字节/半字发送此处简化为状态推进 if (cmd_index 2) begin cmd_index cmd_index 1; state 1; end else begin state 3; end end 3: begin done 1; state 0; end endcase end end endmodule这段代码把关键命令简化成了状态机的推进核心意图是让你理解命令序列的构成先写WBSTAR再发IPROG中间用NOP填充32位对齐。这里有个细节WBSTAR_VALUE提取的是地址的高16位也就是NEXT_IMAGE_ADDR[23:8]。比如Update镜像放在0x00800000高16位就是0x0080写进WBSTAR后FPGA重新配置时就会从这个地址开始找镜像数据。如果觉得手写状态机麻烦也可以直接用Xilinx提供的AXI Hard IPAXI QSPI或者AXI Configuration。MicroBlaze中使用AXI CDMACentral DMA把Update镜像从网络或SD卡搬到Flash再写出WBSTAR和IPROG命令整个过程就完整了。4.3 远程更新的业务逻辑闭环抛开底层时序设计和“业务”相关的状态机时我建议想清楚下面几条版本管理Flash里要记录当前镜像的版本号Update镜像自身也要带一个版本标识。软件在触发跳转前要检查更新包版本是否高于当前版本避免旧包覆盖新包。升级包完整性校验在写Flash之前MCU/软核先对整个升级包做CRC32或者SHA256校验确认完整再写。不要为了省时间跳过这一步远程升级最怕“传一半断掉”。超时回退设置一个看门狗如果在指定时间内比如10秒没有成功跳转到Update镜像强制触发Fallback回到Golden。这一步在Xilinx的硬件机制里是自动的但如果升级流程是你自己控制的仍然建议在MCU侧做一层超时保护。实际项目中我见过一个有效的做法是Update镜像在启动后不久会主动向MCU发送一个“i am alive”的统一报文。MCU收到这个报文后才认为升级成功并把当前工作版本号更新到Flash的另一个区域。如果没收到MCU就认为Update镜像有问题主动复位FPGA触发Fallback。这套机制写起来不复杂但对现场运维的帮助非常大。5. 实战踩坑与排查最容易翻车的几个环节Multiboot本身在Xilinx文档里写得挺清楚但实操起来问题层出不穷而且很多问题不直接报错需要结合波形、时序、日志去定位。我梳理了几个高频问题几乎每个项目都会踩到一两个。5.1 当配置逻辑卡死无法Fallback到Golden镜像有一个搜索热度挺高的说法叫“when configuration logic is stuck and unable to fallback when multiboot image”。我在现场真的遇到过这种状态Update镜像加载失败后FPGA既没有回退到Golden也没有任何输出看起来像死机了。排查这类问题第一步是确认Fallback在比特流里真的打开了。有些工程师在Golden镜像里开了Fallback但Update镜像里没有开——这会导致模板误导。因为Fallback行为本质上是由“正在尝试加载的那个镜像”的配置头决定的如果Update镜像的头里没有做允许Fallback的设置配置引擎可能就停在错误状态不再动作了。第二步是检查Update镜像的地址是否对齐。WBSTAR只认高16位地址如果你的Update镜像起始地址是0x00800001这显然不现实但可能是转换脚本里粗心设置了偏移FPGA会试图在0x00800000读取结果出来的全是垃圾数据配置必然失败。第三步是检查ICAP命令时序。IPROG命令必须严格按照Xilinx文档中的32位对齐方式来发否则FPGA会忽略这条命令。这里特别提醒很多以“用MCU模拟ICAP时序”实现的项目把命令拼装和位宽搞错了。ICAPE2的接口是32bit位宽但一次配置操作中IPROG命令需要连续写两个32bit字命令字参数不能中间插入别的操作。5.2 MCS烧录成功但上电不启动的排查思路这种情况我遇到得最多。排查顺序是这样的确认模式引脚M[1:0]是否已经固定为Master SPI模式可以用万用表直接量引脚电平。确认CS信号上电瞬间用示波器抓FPGA连接SPI Flash的CS引脚应该能看到一个低脉冲。如果CS完全没动作说明FPGA没去访问Flash大概率是模式引脚或配置时钟的问题。确认Flash信号用示波器抓CLK和MOSI如果CS有活动但CLK没波形大概率是配置时钟没起来或者配置模式不对。确认Flash内容用SPI Flash编程器读出Flash内容检查0x0地址的镜像头是否正常或者用Vivado的Verify功能对比Flash内容和BIT是否一致。这里有一个笔者踩过的坑某个项目里SPI Flash的HOLD#引脚在PCB Layout时被接到了一个FPGA的普通IO而且默认状态是低。结果就是Flash一直处于Hold状态FPGA读不到任何数据。排查了好几个小时才发现是HOLD#引脚的问题。所以原理图阶段就一定要把HOLD#、WP#引脚的连接方式定好这俩引脚绝不能简单悬空。5.3 常见问题速查表现象可能原因解决措施上电后FPGA无任何加载动作配置模式引脚M[1:0]不对调整为Master SPI模式CS有信号但CLK没波形配置时钟没有起来检查CCLK引脚连接确认晶振/时钟源正常加载到一半失败SPI_BUSWIDTH设置与Flash能力不符将SPI_BUSWIDTH改为1或2先跑通再优化能加载Golden但跳转后死机WBSTAR地址不对或Update镜像损坏检查WBSTAR写入值重新烧写Update跳转后不作任何动作过一段时间自动回退Update镜像的头配置没有允许Fallback在Update镜像里也打开SPI_FALLBACK远程写Flash成功但校验失败写Flash时WP#没拉高或Flash被保护检查WP#控制关闭Flash写保护跳转时同步字错误Flash读时序不满足降低CONFIGRATE或调整Flash读命令5.4 一些实操上的经验和建议我在多个项目上跑完Multiboot之后有几点体会很强烈。第一Flash的分区规划一定要在项目一开始就确定不要等到快量产了才回头改。分区地址一旦定下来Golden镜像、Update镜像、软件升级脚本、产线烧录文件全都要跟着改牵一发动全身。第二在本地调试时不要每次都用整片擦除的方式重烧Flash。开发阶段建议只擦除Update分区保留Golden不动。这样每次验证远程升级只需要覆盖Update区域能快速迭代。但要注意如果你的MCS文件是双镜像合并的烧写时小心不要把Golden分区也覆盖了。第三远程升级一定要有“断点续传”和“失败重传”的考虑。网络环境再好现场也可能出现几百K的文件传输到一半断掉的情况。如果Update镜像比较大建议在Flash里开辟一个“下载暂存区”先把升级包完整下载并校验再一次性写入Update分区。虽然占用了一部分Flash空间但安全系数大幅提升。第四尽可能在Update镜像里加一个看门狗功能。FPGA内部逻辑如果跑飞了至少能触发内部复位不至于整个系统完全失控。看门狗超时时间不宜太短一些复杂的初始化流程可能超过几百毫秒需要预留足够余量。最后再补一个我个人的习惯拿到一块新板子第一件事就是验证Multiboot的回退功能。方法很简单Golden镜像里写一个LED闪烁程序Update镜像里故意写一个坏BIT比如从别的型号复制一个BIT过来然后运行跳转看它是否能在几秒内自动回退到Golden。能回退说明硬件链路和配置架构是健康的之后再做真实升级包才有底气。这套流程跑通之后远程固件升级就不再是让人提心吊胆的操作了。整个体系的关键就是“硬件上把引脚和Flash电路设计稳、Vivado里把配置属性设对、软件上把WBSTAR/IPROG时序搞清楚、流程上把回退机制验证到位”。做到这四点不管板卡部署在什么地方升级固件只需要在办公室里点一下按钮就行这才是Multiboot带来的最大价值。
返回列表