Files
skills-win/fpga_update/references/quickboot.md
T
2026-07-14 18:18:17 +08:00

4.4 KiB
Raw Blame History

Flash 布局与 QuickBoot 兜底

板上 flash:Winbond w25q128bv,128 Mbit = 16 MB,SPIx1,24-bit 地址,64 KB sector / 4 KB subsector。

三个地址,一个都不能记错

来自 my_exciter.srcs/sources_1/quickboot/SpiFlashProgrammer.vhd(RU_golden 和 my_exciter 引用的是同一份文件, 见 RU_golden.xpr 里的 $PPRDIR/../my_exciter/.../SpiFlashProgrammer.vhd,所以两个工程的常数天然一致):

cAddrUpdateStart     = X"00400000"   -- update 镜像起点
cAddrUpdateEnd       = X"00C00000"   -- update 镜像终点+1  →  槽宽 8 MB
cAddrSwitchWordN25Q  = X"00000FFC"   -- 切换字
cAddrWidth           = 24            -- 和 w25q128bv 匹配

flash 实际布局(从 golden_design_initial.mcs 解码得到,不是推测):

0x000000..0x000FFB  FF FF ...                  空
0x000FFC            00 99 55 66                切换字(AA 被写成 00 = 无效)
0x001000            20000000                   NOOP
                    30020001 00400000          写 WBSTAR = 0x400000
                    30008001 0000000F          写 CMD = IPROG   → 跳到 update 镜像
0x001050            AA995566                   golden bitstream 自己的同步字
        ..0x3FFFFF  golden bitstream(RU_golden_top.bit,3.4 MB)
0x400000..0xBFFFFF  update 镜像(8 MB,日常远程升级写这里)
0xC00000..0xFFFFFF  未用

兜底机制:上电时 FPGA 从地址 0 扫描同步字。

  • 切换字 = AA995566 → 在 0xFFC 同步 → 执行 0x1000 处的 IPROG → 加载 update 镜像。
  • 切换字 ≠ AA995566(擦除后是 FFFFFFFF)→ 0xFFC 不同步 → 继续扫 → 在 0x1050 撞上 golden 的同步字 → 加载 golden。

远程升级一开始就把切换字所在的 subsector 擦掉(sProgrammerEraseSwitchWord,SSE 命令, 擦 0x000000..0x000FFF),写完校验通过后再把切换字写回去。所以升级中途断电只会退回 golden,不会变砖。

subsector 是 4 KB,擦 0xFFC 只波及 0x000000..0x000FFF。IPROG 头在 0x001000,属于下一个 subsector,不会被擦到。golden 是安全的 —— 如果怀疑"升级把 golden 弄坏了",可以排除这条。

为什么 -imagesize 64

perl 脚本的模型是"golden 和 update 一样大、update 紧跟 golden": imageSizeBytes = imagesize(Mbit) × 131072,updateStartAddr = imageSizeBytes。

  • golden(MakeSpiFlashProgrammerOnlyInitMcs.pl -imagesize 32)→ 4 MB → IPROG 里的 WBSTAR = 0x400000,和 cAddrUpdateStart 对上。日志见 RU_golden/bitstream/gen_initial.log。
  • update(MakeSpiFlashProgrammerMcsFiles_backup.pl -imagesize 64)→ 8 MB → 负载 pad(bitstream, 0x7FFFFC) + crc32 正好 8 MB,和槽宽 0xC00000-0x400000 对上。

两个 imagesize 不一样是故意的(VHDL 注释里的 "Plan B: golden enlarged to 4MB"),别去"统一"它们。

_update.mcs 里的 Intel-HEX 地址写的是 0x800000,看起来和 cAddrUpdateStart=0x400000 矛盾 —— 它不矛盾,因为地址被忽略。imx6 的 recv_upgrade_data_parse() 只从 :10xxxx00<32 hex> 记录里抠出 16 个数据字节,扩展线性地址记录 :02000004 直接当"中间控制字段"丢掉。FPGA 从 cAddrUpdateStart 顺序写。所以对远程升级而言,_update.mcs 只有负载长度和CRC是有意义的。

校验 _update.mcs 的起始地址是 0x800000,本质上是在校验"这个文件是用 -imagesize 64 生成的"。

两条烧写路径,别搞混

JTAG 直烧 网络远程升级
文件 RU_golden/bitstream/golden_design_initial.mcs bitstream/<tag>_update.mcs
工具 /fpga_flash skill(flash 型号 w25q128bv) scripts/fpga_ru.py
写到 0x000000..0x3FFFFF 0x400000..0xBFFFFF
何时用 首次装机、板子变砖、换打底镜像 日常迭代

_update.mcs 不能拿去 JTAG 烧写:它只是 8 MB 裸数据 + CRC,没有 bitstream 头。 反过来 _initial.mcs 也不能拿去远程升级。

严守上电时序:断电 → 断 USB-Blast → 上电 → 连 USB-Blast → 烧写 → 断电 → 断 USB-Blast → 上电 → 连 USB-Blast。

调试期的第三条路

program_device 直接把 .bit 下到 FPGA,掉电即失,不碰 flash,配 .ltx 还能抓 ILA。 迭代验证用它最快,功能确认后再走远程升级固化。固化用的 bit 要去掉 ILA 重新实现。