首页 / 用AI开发

自定义 logic 开发流程与下载方法 (PIO 标准 7 步)

2026年11月4日

适用场景: AG32 工程要在芯片内部 CPLD 写自己的 Verilog(SPI 主机、APB 外设、AHB mux、FSM 等)。CPLD 部分 = logic/user_ip.v,烧到 flash 0x80034000 起的 48KB 区域(256K 压缩模式)。MCU 部分 = src/main.c,烧到 0x80000000。

前置条件(都已经在工程里):
– board.ve 配好引脚 + 内部信号
– platformio.ini 配好 logic_ve, ip_name = user_ip, logic_dir = ./logic, logic_device = AGRV2KL100, logic_compress = true, board_upload.logic_address = 0x80034000
– logic/user_ip.v 写好用户 RTL(顶层 module 名 = ip_name)
– src/main.c 写好 MCU 固件


完整流程(7 步,PIO + 工具链)

Step 1: pio run --target prelogic              # gen_vlog + pre_logic.tcl 准备 Quartus 工程
Step 2: quartus_sh -t af_quartus.tcl           # Quartus 综合 (生成 board.vo)
Step 3: af --batch -F my_run.tcl               # Supra P&R + bitgen (生成 board.bin)
Step 4: pio run -t logic                       # 烧 CPLD bitstream + 写 option bytes
Step 5: pio run -t buildprog                   # 编译 MCU code (生成 target_demo.bin)
Step 6: pio run -t upload                      # 烧 MCU code 到 0x80000000
Step 7: ocd_resume reset+resume                # 让 CPU 跑 main

合并下载替代 Step 4+6:

Step 1-3 同上
Step 4': pio run --target batch               # 合并 option+logic+code → target_demo_debug_batch.bin
Step 5': pio run --target batch_upload        # 一条 agrv download 烧全量
Step 6': ocd_resume reset+resume

Step 1: pio run --target prelogic

# 在 VSCode terminal,工程根目录
pio run --target prelogic --environment debug

做了什么: PIO 调 gen_vlog + pre_logic.tcl
– gen_vlog 读 board.ve → 生成 logic/board.vx / logic/board.h (顶层 wrapper)
– gen_vlog 同时生成 logic/user_ip_tmpl.v (顶层 module 接口模板,只读,别手改)
– pre_logic.tcl 准备 Quartus 项目骨架 → logic/board.qpf board.qsf board.proj board.asf board.sdc 等

如果已经改过 VE / 加新顶层 port:
1. 打开 logic/user_ip_tmpl.v,把 module user_ip ( ... ) 这段 port 列表原样复制到 logic/user_ip.v 顶部
2. 不要复制 tmpl 里的 assign stub 和 endmodule —— user_ip.v 里写自己逻辑
3. 不要直接复制 tmpl 整个文件覆盖 user_ip.v —— tmpl 是接口骨架,user_ip.v 是你的代码,会丢失

预期输出:

Preparing LOGIC compilation project board
Info: Using device QSF template file .../AGRV2K_templ.qsf.
Total 0 fatals, 0 errors, 1 warnings, 1 infos.
========== [SUCCESS] Took 6.x seconds ==========

如果文件已存在,会跳过 (warning),这是 PIO 增量行为,正常。


Step 2: quartus_sh -t af_quartus.tcl

# 在 logic 目录下执行
cd logic
quartus_sh -t af_quartus.tcl

或者在 Quartus GUI 里:Tools → Tcl Scripts… → 选 af_quartus.tcl → Run。

做了什么 (看 logic/af_quartus.tcl):
1. qexec quartus_sh -t af_ip.tcl — 设置 IP 分区
2. project_open board — 打开 Quartus 项目
3. execute_flow -compile — 完整 Quartus 流程

完整 Quartus 子步骤:
– Analysis & Synthesis
– Fitter (placement + routing)
– TimeQuest Timing Analyzer
– EDA Netlist Writer

预期输出:

Info: Quartus II Full Compilation was successful. 0 errors, 280 warnings
Info (204019): Generated file board.vo in .../logic/simulation/modelsim/

280 warnings 大多是 “未完全约束” 类的,可忽略。看 0 errors 就过。

生成的产物: logic/simulation/modelsim/board.vo (Quartus 综合后网表,给 Supra 用)


Step 3: af --batch -F my_run.tcl

# 仍在 logic 目录下
af --batch -F my_run.tcl

做了什么 (看 logic/my_run.tcl):
1. 设置 DEVICE DESIGN LOGIC_DEVICE LOGIC_BIN 等变量
2. source af_run.tcl — 调官方 Supra P&R + bitgen 脚本
3. Supra 读 board.proj 的 P&R 参数 (fitting=1, fitter=5, effort=2, skew=2, seed=…)
4. 跑 P&R (placement → routing → timing → bitgen)

预期输出关键行:

Total 0 fatals, 0 errors, 0 warnings, X infos.
*** Post Routing Timing Report ***
Fmax report
  User constraint: 100.000MHz, Fmax: 200+MHz
  Slack: > 0       (setup slack 越大越好)

生成的产物:
– logic/board.bin ← CPLD bitstream,主产物
– logic/board_batch.bin ← CPLD-only batch,临时,稍后 PIO batch 会再合一次
– logic/board_routed.v ← routing 后的网表

如果 Fmax 不达标或 routing 失败:
– 改 my_run.tcl 里的 SEED(默认 666),重跑
– 或跑 pio run -t batch_upload 让 PIO 自动换 6 个 seed 试


Step 4: pio run -t logic 烧 CPLD + 写 option bytes

# 回工程根目录
cd ..
pio run -t logic --environment debug

做了什么 (openocd 内部):
1. check_device_id 0x40200001:256KB — 验证设备
2. agrv write_fpga_config {logic\board.bin} 0x80034000 — 同时:
– 写 option bytes (FPGA config address = 0x80034000, compression = true)
– 写 CPLD bitstream 到 0x80034000(0x100 头部是 decompressor 算法,0x80035100 是 bitstream 主体)
3. reset halt — 烧完 CPU halt

预期输出关键行:

Info : FPGA configuration address is updated to 0x80034000
Info : FPGA configuration compression is updated to true
Info : Option bytes are written
wrote 4893 bytes from file logic\board.bin
verified 4893 bytes
agrv wrote fpga decompression algorithm at 0x80034000
agrv wrote fpga configuration at 0x80035100

这就是修 option bytes 错位的关键 —— pio run -t logic 用 agrv write_fpga_config,会正确写 option bytes(包括正确的 logic address 和 compression flag)。如果直接用 flash write_image 写 raw bin 到 0x81000000,DAP openocd 不支持 (No flash at address 0x81000000)。


Step 5: pio run -t buildprog 编译 MCU code

pio run -t buildprog --environment debug

做了什么: 编译 src/main.c + 链接 SDK + 生成 MCU bin

预期输出关键行:

Compiling .pio\build\debug\agrv_sdk\src\uart.o
...
Linking .pio\build\debug\target_demo.elf
Building .pio\build\debug\target_demo.bin
RAM:   [          ]   1.5% (used 2012 bytes from 131072 bytes)
Flash: [          ]   4.2% (used 11136 bytes from 262144 bytes)
========== [SUCCESS] Took 4.x seconds ==========

生成的产物: .pio/build/debug/target_demo.bin (MCU code, 烧到 0x80000000)


Step 6: pio run -t upload 烧 MCU code

pio run -t upload --environment debug

做了什么 (openocd 内部):
1. check_device_id — 验证设备
2. check_logic 0x00000000 — 验证 option bytes 里 logic pointer 有效(所以 Step 4 必须先跑)
3. flash erase_address pad 0x80000000 11136 — 擦除 MCU code 区域
4. flash write_image {.pio\build\debug\target_demo.bin} 0x80000000 bin — 写 MCU code
5. verify_image — 校验
6. reset halt — 烧完 CPU halt

预期输出关键行:

Info : Checking logic configuration at 0x80034000
erased address 0x80000000 (length 11136)
wrote 11136 bytes from file .pio\build\debug\target_demo.bin
verified 11136 bytes
========== [SUCCESS] Took 7.x seconds ==========

如果报 No valid logic configuration address is found:
– 说明 Step 4 (pio run -t logic) 没跑,option bytes 是空的
– 先跑 pio run -t logic,再跑 pio run -t upload


Step 7: reset + resume 让 CPU 跑 main

烧完 code 后,CPU 在 halt 状态。ocd_resume.cfg:

# logic/../ocd_resume.cfg
source [find agrv2k.cfg]
reset
sleep 200
resume
sleep 200
shutdown
# 工程根目录
& "$env:USERPROFILE\.platformio\packages\tool-agrv_openocd\bin\openocd.exe" `
  -s "$env:USERPROFILE\.platformio\platforms\AgRV\etc" `
  -c "set ADAPTER cmsis-dap" `
  -c "set ADAPTER_SPEED 10000" `
  -f ocd_resume.cfg

或更简单,按一下板子 RST 按钮。

然后监听 COM5 看 MCU code 输出(如果 main 有 printf):

python monitor.py   # 项目里的 monitor.py,监听 COM5 10 秒

合并下载替代(Step 4′ + 5′ + 6′)

pio run --target batch 把 option+logic+code 三个独立产物合并成一个 target_demo_debug_batch.bin:

pio run --target batch --environment debug

预期输出:

Generating BATCH bin target_demo_debug_batch.bin
Logic: .../logic/board.bin, 4893 bytes
Input: .../.pio/build/debug/target_demo.bin, 11136 bytes
Output: .../target_demo_debug_batch.bin, 21277 bytes

target_demo_debug_batch.bin 内部含 3 段(每个带 header):
| 段 | 大小 | 目标地址 |
|—|—|—|
| 1 | 128 B | 0x81000000 (option bytes) |
| 2 | 9,245 B | 0x80034000 (logic 含 decompressor 头部) |
| 3 | 11,136 B | 0x80000000 (MCU code) |

然后 pio run --target batch_upload 一条命令烧全量:

pio run --target batch_upload --environment debug

预期输出:

Info : Downloading 128 bytes at address 0x81000000
Info : Oscillator calibrated with value 84
Info : Downloading 9245 bytes at address 0x80034000
Info : Downloading 11136 bytes at address 0x80000000
erased, wrote and verified 128 bytes
wrote and verified 9245 bytes
wrote and verified 11136 bytes
========== [SUCCESS] Took 7.x seconds ==========

对比分步 vs 合并:

分步 (logic + upload)合并 (batch_upload)
命令数2 (Step 4 + 6)2 (Step 4′ + 5′)
总耗时~10.8 秒~7.4 秒
DAP 协议flash write_image + agrv write_fpga_configagrv download (统一)
写 option bytes✅ via Step 4✅ via batch 第一段
用哪个已分阶段调试,只改 MCU 时改任何东西后全量重烧

建议:
– 调 CPLD 逻辑时,跑 Step 1-4(不烧 MCU,省时间)
– 调 MCU code 时,跑 Step 5-6(Step 4 已写过 option bytes,Step 6 会 check_logic 通过)
– 改完所有东西,跑 Step 1-3 (build) + Step 4′-5′(batch + upload) 一次性重烧


常见错误

Can't analyze file -- file board.v is missing (Quartus)

  • 原因: pio run --target prelogic 没跑,board.v 不存在
  • 修复: 先跑 Step 1

Error (12007): Top-level design entity "board" is undefined (Quartus)

  • 同上,缺 board.v

0 fatals, 0 errors 但 Supra 没生成 board.bin

  • 检查 my_run.tcl 里 LOGIC_BIN = board.bin 路径对不对
  • 检查 LOGIC_DIR = .(必须是相对当前工作目录的)

pio run -t logic 报 No valid logic configuration address is found

  • 原因: option bytes 被擦除,找不到 logic pointer
  • 修复: pio run --target batch_upload 重烧一次,或单独跑 Step 4 让它写 option bytes

pio run -t upload 报 No valid logic configuration address is found

  • 原因: 同上,option bytes 没写过
  • 修复: 先跑 Step 4 (pio run -t logic),再跑 Step 6

烧完后 CPU 卡在 SYS_IsPllReady 死循环

  • 原因: option bytes 里 OSC_CAL 校准值被擦,PLL 锁不住
  • 修复: 不要 Wipe Flash!直接跑 pio run --target batch_upload 重烧,agrv download 会自动 calibrate OSC (Info : Oscillator calibrated with value 84)

COM5 收到乱码

  • 见 UART乱码时排查清单.md

Exit 1 但 PIO 报 SUCCESS

  • PowerShell 把 PIO 的 stderr (Warn / Info) 当成 RemoteException,exit code 非 0
  • 忽略,看 PIO 自己的输出 ([SUCCESS] = 真成功)

修改后重跑的最小命令

改了跑
board.veStep 1 → Step 2 → Step 3 → Step 4′ → Step 5′
logic/user_ip.vStep 1 → Step 2 → Step 3 → Step 4′ → Step 5′
src/main.cStep 5 → Step 6
什么都没改,只想重烧Step 4′ → Step 5′(batch_upload)

.

返回用AI开发