这一篇在干嘛?

系列收尾篇,素材最短但值得展开:EF2、EF3 器件的 Flash 不仅用来存位流,还允许用户逻辑直接读写——这是实现”非 JTAG 在线升级”和”掉电不丢数据存储”的钥匙。本篇讲清楚:为什么它值得讲、怎么打开这个能力、读写流程、以及”一个地址写错就变砖”的风险控制。前置知识见:硬件接口(三):加载模式全解(Dual Boot 机制)、硬件接口(一):IO 上下拉与 PCI Clamp

为什么内部 Flash 值得单独讲

打开大门的两个前提条件

读写流程:先擦后写

典型应用:非 JTAG 在线升级与数据存储

注意事项与风险控制

为什么内部 Flash 值得单独讲

先理清一个背景:FPGA 是 SRAM 工艺,配置数据(位流)必须存在非易失存储器里,上电加载进来。EF2、EF3 系列把这颗 SPI Flash 直接合封在芯片内部(合封结构见硬件接口(三)的 MSPI 一节),而 EG4 系列的 Flash 在片外

这颗 Flash 里通常装着什么?

  1. 位流数据:加载参数区 + Primary/Golden 两份位流(EF2/EF3 的合封 Flash 容量设计得能装两份位流);
  2. 大片剩余空间:位流一般只占 Flash 的一小部分(EF2 也就几百 Kbit 量级),剩下的空间白白闲置。

用户逻辑直接读写它的价值就在这两点上:

  • 非 JTAG 在线升级:没有 JTAG 线、没有外部 CPU 摸得到 Flash 的场合(EF2/EF3 的 Flash 在片内,外部总线根本接不到),只能让 FPGA 自己的逻辑当”编程器”,通过 UART/SPI/I2C 等任意接口接收新位流写进 Flash——产品部署到现场后照样能升级。
  • 用户数据存储:用剩余空间保存校准系数、序列号、运行日志、掉电记忆配置等需要掉电不丢的数据,省掉一颗外部 EEPROM/Flash。

注意区分:本篇机制针对 EF2、EF3(内置 Flash);EG4 的 Flash 在片外,CPU 或 FPGA 逻辑可通过外部 SPI 总线访问,思路类似但不存在”内部 Flash 原语”一说。参赛者若用 EG4S20,可把本篇的流程与风险控制思想迁移到外挂 Flash 上。

打开大门的两个前提条件

默认情况下,加载完成后 Flash 是”加载系统专用”的,用户逻辑碰不到它。要让用户代码访问内置 Flash,EF2、EF3 各需满足两个条件:

条件一:调用 PHY 原语,把 Flash 的 SPI 接口引出到用户逻辑

  • EF2 调用 EF2_PHY_INTFLASH 原语,EF3 调用 EF3_PHY_INTFLASH 原语;
  • 原语(Primitive)是芯片里真实存在的硬件单元,在 Verilog 里像用模块一样例化它。EF2 的原语定义:
module EF2_PHY_INTFLASH (
    mosi_io0,     // SPI 数据线 0(PT6D)
    miso_io1,     // SPI 数据线 1(PT23B)
    wp_n_io2,     // 写保护,低有效(PT20D)
    hold_n_io3,   // 保持,低有效(PT9D)
    cclk,         // SPI 时钟(PT9B)
    cs_n          // 片选,低有效(PT11D)
);
endmodule

本质:这颗合封 Flash 就是一个标准 SPI Flash 芯片,这六根信号就是它的 SPI 总线。原语把这条总线”桥接”进你的逻辑——例化后,你用 SPI 时序协议就能和它对话。引脚注释里的 PT6D、PT23B 等是这些信号对应的物理管脚位置,说明配置端口的走线在芯片内是固定的。

条件二:TD 软件里把 persist_bit 设为 0

在 TD 软件的 Properties -> Control Option 里将 persist_bit(配置端口保持位)设置为 0

persist_bit 是什么?它决定加载完成后,配置专用端口(本来归加载硬件管的 SPI 接口)交不交给用户逻辑。设为 0 = 加载完成后端口释放给用户;默认(1)= 端口继续保持配置功能。不设这一项,原语引出来了也连不到 Flash 上。

代价:persist_bit = 0 之后,通过 JTAG 编程时不能再选择 bg_mode(后台模式)——因为配置端口的所有权换人了。这是硬件配置上的取舍,做方案时要想清楚你的产品是否还需要 JTAG 后台升级(JTAG 常规编程仍可用,只是后台模式受限)。

读写流程:先擦后写

拿到 SPI 总线后,剩下的就是标准 SPI Flash 的操作学。如果你读过 W25Q 之类的 SPI Flash 芯片手册,会发现流程一模一样:

  1. 读(Read):拉低 CS_N → 发读命令 + 地址 → 按时钟移出数据 → 拉高 CS_N。读是无破坏性的,可以随便读。
  2. 擦除(Erase):Flash 的物理特性决定了写只能是”把 1 改成 0”,想重新写必须先整块擦回全 1。擦除按块/扇区进行,不能擦单个字节。
  3. 写/编程(Program):擦完后按页(Page)写入数据。所以顺序永远是:先擦除,再写入

这些命令时序、扇区大小、页大小、擦写时间,都可以参考合封 Flash 的数据手册(安路提供 Flash 型号信息),FAE 也明确说了:用户可参考 Flash 数据手册,自行编写 SPI 接口逻辑完成读写——不一定非要等安路的参考设计。自己写的好处是接口、缓存策略完全可控;缺点是要自己处理好命令时序与等待时间(擦除可能要几十到几百毫秒,期间不能操作该块)。

还有一个方向性的问题:怎么知道该读/写哪个地址? Flash 开头是加载参数区和位流区(Dual Boot 的地图见硬件接口(三)),用户数据必须放到位流占用范围之外——这个边界要按你的位流实际大小和 Flash 地图划定,并且最好在软件里做地址保护(写入前检查地址范围)。

典型应用:非 JTAG 在线升级与数据存储

应用一:非 JTAG 在线升级。 安路提供了三种现成的”接口桥”参考设计,把常见通信口桥接到 Flash 编程逻辑:

参考设计桥接接口典型场景
Uart_2_FlashUART 串口最简单:上位机串口发升级包,无需额外硬件
SPI_2_FlashSPI主控 MCU 通过 SPI 更新 FPGA 的 Flash
IIC_2_FlashI2C挂在系统 I2C 总线上,多设备共享总线升级

工作流程串起来看:外部(上位机/MCU)通过桥接接口把新位流发给 FPGA → FPGA 逻辑按 SPI 时序擦除 Flash 的 Primary 区域 → 写入新位流 → 校验 → 复位重新加载。升级过程中 FPGA 自身还在跑旧逻辑(写 Flash 不影响 SRAM 里的运行状态),所以配合上一篇讲的 Dual Boot:Golden 区域永不擦写,Primary 写坏了也能从 Golden 启动、保持通信能力再次升级——这套组合拳就是量产产品在线升级的标准姿势。

应用二:用户数据存储。 用 Flash 剩余空间做”EEPROM”:上电后用户逻辑从约定地址读出校准系数/配置参数;需要保存时按”先擦后写”更新。相比外部 EEPROM 省一颗芯片、省走线;缺点是擦写粒度大(扇区级)、擦写寿命有限(通常 10 万次量级),高频写入的数据不适合直接落 Flash,可先攒在 RAM 里、低频批量写入。

注意事项与风险控制

把手册的注意事项展开成一张风险清单:

  • 头号红线:不能破坏已有的 bit 位流数据。 用户代码访问 Flash 时地址算错、越界,擦掉的就是位流本身——下次上电直接变砖。对策:固化 Flash 地图文档(参数区/Primary/Golden/用户数据区各自的起止地址);代码里做地址范围保护;升级逻辑严格遵守 Dual Boot 分工(只动 Primary,Golden 神圣不可侵犯)。
  • persist_bit = 0 的副作用要记牢:JTAG 编程不能选 bg_mode(后台模式)。如果产品既要做用户逻辑访问 Flash、又依赖 JTAG 后台模式做产线烧录,两者冲突,需要重新规划升级路径。
  • 擦写等待时间必须做足:擦除/编程期间状态寄存器会指示 busy,逻辑要轮询等待,不能掐表硬等——超时不足就是写入失败。
  • 擦写寿命与掉电保护:Flash 擦写次数有限,升级、存参数都不应频繁全量擦写;写入过程中突然掉电会导致数据不完整——升级场景靠 Golden 兜底,参数存储场景可设计”双页备份 + CRC 校验”。
  • 不用原语自写 SPI 逻辑时,注意 Flash 的四线信号(含 WP_N 写保护、HOLD_N)都要正确驱动,写保护功能可以利用起来保护位流区。

本篇通关标准:

  • 能说出用户逻辑访问内置 Flash 的两个前提条件(例化 EF2_PHY_INTFLASH/EF3_PHY_INTFLASH 原语 + TD 里 persist_bit=0),以及 persist_bit=0 牺牲了什么(JTAG 不能选 bg_mode)。
  • 能完整叙述 Flash “先擦除再写入”的流程及原因(物理上只能把 1 写成 0),并说出 Uart_2_Flash / SPI_2_Flash / IIC_2_Flash 三种参考设计的用途。
  • 能画出”在线升级 + Dual Boot”的组合安全方案:Golden 永不擦写、只动 Primary、写坏也能启动并再次升级。