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

6.3 KiB
Raw Blame History

name, description
name description
fpga_update 通过网络远程升级 SMOD 板(192.168.1.143)上 ATSC 激励器工程的 FPGA 镜像——先用 Vivado + perl 生成 quickboot 的 _update.mcs,再用 TCP 1234 的私有协议把它流式烧进 SPI flash 的 update 槽。只要用户提到"远程升级"、"升级 mcs"、"把新 bit 升上去"、"update mcs"、"远程更新 FPGA"、"Xfpga_ru"、"生成 quickboot mcs"、"quickboot"、"RU_golden 之后怎么升级"、"192.168.1.143 升级",或者在 my_exciter 工程里跑完综合实现后想把结果固化到板子上,就必须用这个 skill——哪怕他们没说"skill"、没提 mcs,只说了"升上去"、"更新一下 FPGA"、"重新出个 mcs"。注意:这条路和网页上的 Remote Update 完全无关(那个只认 imx6 的 tar.gz 固件包)。JTAG 直烧打底镜像请改用 fpga_flash skill。

SMOD FPGA 远程升级

把 my_exciter 工程实现出的 .bit 变成 quickboot 更新镜像,再通过网络烧进板子的 SPI flash。

板子必须事先用 JTAG 烧过 RU_golden 才支持远程升级 —— golden 提供上电时的兜底镜像和 IPROG 跳转头。没烧过 golden 就先走 /fpga_flash。

先搞清楚你在走哪条路

这是最容易出错的地方,两条路互不相干:

这个 skill 网页 Remote Update
升什么 FPGA 镜像(.mcs) imx6 固件包(.tar.gz)
走哪 TCP 1234,私有帧协议 HTTP upload.cgi → check_package.sh

把 .mcs 传到网页上不会报错,但 check_package.sh 找不到 *.tar.gz 就会 rm -rf /aw/upgrade/* 把它删掉,什么都不会发生。原厂的 GUI 工具是 tools/Xfpga_ru.exe, 没有命令行接口;scripts/fpga_ru.py 是它的等价替代,而且会告诉你失败在第几帧。

流程

1. 生成 _update.mcs

python scripts/gen_update_mcs.py                 # → bitstream/atsc_exciter_update.mcs
python scripts/gen_update_mcs.py --tag smod_dpd  # → bitstream/smod_dpd_update.mcs

脚本按顺序跑项目里一直在用的那三个脚本(post_bitstream.tcl → runScript_GenRu.tcl → MakeSpiFlashProgrammerMcsFiles_backup.pl -imagesize 64),然后校验产物的起始地址是 0x800000(这等价于"确实是用 -imagesize 64 生成的")。

它还替你挡了一个坑:runScript_GenRu.tcl 里是 glob *.bit,而 bitstream/ 目录里躺着二十几个 历史 .bit。脚本会把旧的临时挪走、跑完再放回去。别绕过它去手动跑 tcl,除非你已经清空了目录。

-imagesize 64 不要改。它和 SpiFlashProgrammer.vhd 里的 cAddrUpdateStart/End 是一对, 理由见 references/quickboot.md。

2. 确认 ADPC 为 OFF(保险起见)

DPD 的 sample&load 和升级数据流共用同一条 SPI1,而 FPGA 在升级期间会把 SPI1 上任何字都当成镜像数据。 这条路径没被验证过(三次连续升级成功那次 adpc=0),所以稳妥起见先关掉:

# 登录后读 sys_cfg,第 3 个字段就是 adpc(0=OFF)
curl -s -b "session=$SESS" "http://192.168.1.143/atsc_status_cfg.cgi?sys_cfg=&"

网页账号是 anywavecom / anywavecom(不是 root;root/anywavecom 是 SSH 的)。

3. 烧进去

python scripts/fpga_ru.py --mcs bitstream/atsc_exciter_update.mcs
python scripts/fpga_ru.py --mcs ... --dry-run     # 只校验文件,不碰硬件

先跑 --dry-run。它会检查行长、整行切分、EOF 记录、起始地址 —— 这些错误在真机上要等几分钟 才会以一个没有上下文的 ABORT_ERROR 暴露出来。

烧写要几分钟(8 MB,约 47600 帧)。中途不要断电、不要重试。 真断了也不会变砖:升级一开始就把 切换字擦掉了,冷启动会退回 golden。

成功后 app 会自动重启 imx6、复位 FPGA。然后冷启动板子(遵守 SMOD 上电时序)让 FPGA 从 flash 重新加载新镜像。

4. 验证

抓 ILA、看 app 日志(/var/module_log/imx_atsc_app.log)、或者看频谱。 闭环调试交给 fpga-imx6-flow skill。

排错

fpga_ru.py 会打印失败在哪一步、哪一帧、收到什么 ack。对着这张表看:

  • 擦除永不结束(最容易误判的一个)→ 十有八九 programmer 已经报错退出了。 imx6 的 POLL_ERASER 不看 ERROR 位,把"已失败"当成"还在擦",所以客户端只会一直等。 别信进度条,直接读设备日志:

    ssh -o HostKeyAlgorithms=+ssh-rsa root@192.168.1.143 \
      "grep 'ing|end' /var/module_log/imx_atsc_app.log | tail -3"
    

    rstate=0x7(ERROR=1, DONE=1, EraseOK=0)= programmer 中止;rstate=0x0 才是真的在擦, 擦完会看到 rstate=0xc + UPSTATE_EARSE_END。 历史上这里的元凶是 smod_top.v 没把 flash 的 SPI 引脚接出去,见 references/protocol.md。

  • ABORT_ERROR 出现在第一帧 → mcs 格式不对,先跑 --dry-run。

  • ABORT_ERROR 出现在数据流中后段 → 怀疑 SPI1 上有别人(DPD)在写,把 ADPC 关掉重试。

  • 没有应答 / 超时 → app 的 sys_ready 还是 0,或者 app 没在跑。 ssh root@192.168.1.143 'ps | grep atsc'(SSH 密码 anywavecom,dropbear 老得很, 命令行 ssh 要加 -o HostKeyAlgorithms=+ssh-rsa)。

别用 python ssh.py "tail -f ..." 之类一次性读到 EOF 的封装去跟日志 —— 它永远不返回, 什么也抓不到。升级完再 grep 日志文件即可,log_printf 已经落盘。

不碰硬件地改协议客户端

scripts/mock_device.py 是照着 tcp_task.c 的状态机实现的假设备,包括那三个硬限制和 ':' 重切分行为。改完 fpga_ru.py 先拿它跑一遍:

python scripts/mock_device.py --port 12340 &
python scripts/fpga_ru.py --mcs <某个>_update.mcs --host 127.0.0.1 --port 12340 --yes

正确的一次会让 mock 收到恰好 8388608 字节(8.000 MiB)—— 正是 cAddrUpdateEnd - cAddrUpdateStart。 对不上就是客户端的分帧错了。--not-ready-every N / --abort-at-frame N 可以逼出重传和中止路径。

参考

  • references/protocol.md —— TCP 1234 帧格式、时序、三个硬限制、DPD 污染缺陷的完整证据链
  • references/quickboot.md —— flash 布局、切换字兜底、为什么是 -imagesize 64、两条烧写路径的区别