这一篇在干嘛?
假如你手上有一块 EG4S20 开发板,想让同一个芯片既能跑流水灯、又能跑按键消抖,切换时还不用重新接下载器烧录——这就是 MULTI BOOT(多启动)要解决的事。这篇笔记带你从原理到实操,完整走一遍多镜像启动的全流程。
先搞懂几个词
| 术语 | 全称 | 意思 |
|---|---|---|
| EG4 | Eagle4 | 安路的一个 FPGA 系列,EG4S20 属于这一族 |
| FPGA | Field Programmable Gate Array | 现场可编程门阵列,可以反复改写电路的芯片 |
| TD | Tang Dynasty | 安路官方的 FPGA 开发软件,综合、布局布线、下载都靠它 |
| SPI | Serial Peripheral Interface | 串行外设接口,FPGA 和配置 Flash 之间就用它通信 |
MULTI BOOT 是什么?和 DUAL BOOT 有啥区别?
MULTI BOOT(multi boot)的意思是:你可以在 SPI Flash 里存放两套或者更多套 FPGA 位流(bitstream,就是编译出来的”程序”)。上电后 FPGA 先加载 Primary 位流(第一套),而这第一套代码里可以发出跳转信号,让 FPGA 跳到 Flash 的指定地址,重新加载另一套位流。
它和常见的 DUAL BOOT(双启动)长得很像,但思路完全不同:
| 对比点 | DUAL BOOT(双启动) | MULTI BOOT(多启动) |
|---|---|---|
| 什么时候跳 | 第一套位流加载失败后,自动跳到第二套 | 由用户给的跳转信号触发,跳到指定地址 |
| 两套位流的关系 | 功能相同,第二套只是备份,用于容错 | 功能不同,用来在多种功能之间切换 |
| 典型场景 | 程序损坏后的”保命”兜底 | 运行中切换功能,比如今天跑流水灯、明天跑通信实验 |
一句话总结:DUAL BOOT 是”坏了自动换备份”,MULTI BOOT 是”我想切就切”,而且可以不止两套。
最佳实践
如果只是担心固件写坏、芯片变砖,用 DUAL BOOT 放一份相同功能的备份就够了;需要在多个功能之间动态切换,才上 MULTI BOOT。
Flash 里长什么样:多配置镜像布局
先了解硬件约束:
- EAGLE 系列的配置位流长度大约 4.8M~6M bits(具体大小还和 BRAM 初始化数据的长度有关),所以配置芯片容量必须 ≥ 6M bit。
- 配置芯片用工业标准串行 SPI 接口 Flash,比如 M25Pxx、SST25LFxxx、S25FLxxx 等型号都可以,但要求读命令为 0x03。
- 在 MSPI 模式下,当 SPI Flash 容量 大于 12M bit 时,EAGLE FPGA 才支持 MSPI MULTI BOOT,也就是能放两套以上的位流。
把两套以上的位流放进 Flash 后,空间大致是这样分的(图 1 的示例布局):
| Flash 地址 | 内容 |
|---|---|
| 0x000000 …… | Primary bitstream(第一套位流) |
| 0x0A0000 …… | Second bitstream(第二套位流) |
| 0x140000 …… | Third bitstream(第三套位流) |
注意
Primary 位流的起始地址必须固定放在 0x000000,这是上电默认加载的位置;而第二套、第三套位流的起始地址,可以根据 bit 文件大小和 Flash 容量自定义,上面的地址只是示例,不是硬性规定。
核心模块:EG_LOGIC_MBOOT
想让 FPGA 会”跳转”,必须在 FPGA 代码里添加多启动控制模块 EG_LOGIC_MBOOT。它的工作逻辑很直白:
- 地址模式为 STATIC(静态)时,使用参数里设好的静态启动地址
static_addr; - 地址模式为 DYNAMIC(动态)时,使用
dynamic_addr端口实时传入的地址; - 这个地址是跳转地址的高 8 位;
- 当
rebootn收到低电平信号时,FPGA 就跳到对应地址,重新加载从那里开始存放的另一套位流。
端口和参数
| 端口 | 方向 | 位宽 | 功能 |
|---|---|---|---|
| rebootn | 输入 | 1 | 重启控制信号,低电平有效 |
| dynamic_addr | 输入 | 8 | 动态重启地址,即 SPI Flash 的高 8 位地址 |
| 参数 | 可选值 | 默认值 | 说明 |
|---|---|---|---|
| ADDR_SOURCE_SEL | ”STATIC” / “DYNAMIC" | "STATIC” | 启动模式,动态或者静态 |
| STATIC_ADDR | 8 位地址 | 8’b00000000 | 静态启动地址,为 Flash 地址的高 8 位 |
怎么用?
这个模块只支持原语例化(直接在 Verilog 里手写例化),不支持通过 IP Generator 图形界面生成。
Verilog 例化模板长这样:
EG_LOGIC_MBOOT #(
.ADDR_SOURCE_SEL ("STATIC"),
.STATIC_ADDR (8'b00000000))
MBOOT_inst (
.rebootn (reboot_n),
.dynamic_addr (addr)
);最佳实践
如果你只想固定跳到一个地址,用默认的 “STATIC” 模式、把 STATIC_ADDR 设好就行;如果想让运行中的逻辑(比如按键、通信命令)决定跳哪儿,就用 “DYNAMIC” 模式,从端口喂地址。
用 TD 软件烧写:download 工具操作步骤
在每套代码里都添加好 EG_LOGIC_MBOOT 模块后,就可以生成两套或多套 bit 位流,然后按下面的步骤用 TD 的 download 工具烧写:
- 把目标板通过下载器连接电脑,打开 TD 的 Download 界面,找到器件后,在 mode 栏选择 multi boot 模式。
- 单击 add,把两套或多套位流添加进来。每套位流都要单独烧写,并为其填写 Start address(该位流在 Flash 中存放的起始地址),例如第一套位流填 0x000000,第二套位流填 0x0A0000。
- 设置好后,选中当前要烧写的 bit 位流,点 Run,即可把它下载到 FLASH 中。
下面两张图就是 download 工具里配置第一套和第二套位流的实际界面:


实战例程:三套位流按灯切换
手册给出了一个完整例程:在 EG4X20BGA256 开发板上,TD 软件工程生成三套 bit 位流,通过按键发出跳转信号 reboot_n,让 FPGA 重新加载新的位流,实现不同 LED 闪烁效果的切换。我们把三套位流分别叫 bitstream0、bitstream1、bitstream2,上电先跑 bitstream0,按一次键切到下一套,循环往复。
第一步:规划位流存储空间
外置 Flash 型号是 M25P16,容量 16Mb(2MB)。算一笔账:
2MB = 2^21 = 2^5 × 2^16 = 32 × 64KB
也就是 32 个 64KB 的 block(每次写入的最小长度)。而 EG4 示例工程生成的 bit 位流为 614KB,即占用 10 个扇区。算下来这块 Flash 最多可以存入 3 套位流,规划如下:
| 位流 | 占用扇区 | 起始地址 | 跳转地址(下一套) |
|---|---|---|---|
| bitstream0 | sector00~sector09 | 0x000000 | 0x0a0000 |
| bitstream1 | sector10~sector19 | 0x0a0000 | 0x140000 |
| bitstream2 | sector20~sector29 | 0x140000 | 0x000000 |
注意看跳转地址一列:三套位流首尾相接、循环跳转,bitstream2 跳回 bitstream0,形成闭环。
第二步:代码里添加控制模块
在每套代码中都添加 EG_LOGIC_MBOOT,这次把 ADDR_SOURCE_SEL 设为 “DYNAMIC”,由各套代码分别给 dynamic_addr 赋不同的值(别忘了,这是跳转地址的高 8 位):
- 第一套 bit 的 dynamic_addr 赋 0x0a(对应跳到 0x0a0000)
- 第二套 bit 的 dynamic_addr 赋 0x14(对应跳到 0x140000)
- 第三套 bit 的 dynamic_addr 赋 0x00(对应跳回 0x000000)
例化代码:
EG_LOGIC_MBOOT #(
.ADDR_SOURCE_SEL ("DYNAMIC"),
.STATIC_ADDR (8'b00000000))
MBOOT_inst (
.rebootn (reboot_n),
.dynamic_addr (addr)
);第三步:download 工具烧写三套位流
参考上一节的步骤,用 download 工具把 3 套 bit 位流分别添加、分别烧写:第一套 Start address 填 0x000000,第二套填 0x0A0000,第三套填 0x140000。三套都烧完后,按一下开发板上的按键就能切换位流重新加载,看到不同 LED 闪烁效果的切换。
踩坑提醒
这两个坑一定要避开
- 烧写方式:代码里加了 EG_LOGIC_MBOOT 后,只能用 download 工具的 MULTI BOOT 模式烧写 bit 文件。如果直接用 JTAG 模式烧写,因为没有填写 bit 文件的起始地址,可能会导致烧写后功能无效。
- 空间规划:一定要根据 bit 文件大小和 Flash 容量,提前规划好位流的存放位置,避免出现位流存放位置冲突或者存储空间不足的情况(比如例程里 614KB 的位流要留足 10 个扇区)。
自测一下
自测:MULTI BOOT 和 DUAL BOOT 最本质的区别是什么?
DUAL BOOT 是在第一套位流加载失败后自动跳到第二套(功能相同的备份),属于容错机制;MULTI BOOT 是由用户给出的跳转信号触发,跳到指定地址重新加载功能不同的位流,用来实现多种功能的切换。
自测:为什么第三套位流的 dynamic_addr 要赋 0x00?
因为 dynamic_addr 是跳转地址的高 8 位,0x00 对应地址 0x000000——那正是 Primary 位流(第一套)的起始地址,这样 bitstream2 按键后就跳回 bitstream0,三套位流形成循环切换。