最近在嵌入式系统开发中遇到一个实际需求:如何在不增加额外硬件成本的前提下,实现FPGA系统的远程固件升级?传统的方案要么需要外挂大容量存储器缓存升级包,要么得设计复杂的硬件电路来切换启动模式。这不仅增加了BOM成本,还给产品维护带来诸多不便。
这个FPGA以太网升级程序的核心创新点在于:仅利用FPGA内置的QSPI Flash和以太网接口,就实现了完整的远程升级功能。实测在Xilinx Artix-7平台上,通过优化升级算法和存储管理,成功将升级包直接写入运行中的QSPI Flash,全程无需外挂RAM缓存,也不需要额外的硬件切换电路。这种方案特别适合对成本敏感且需要远程维护的工业设备。
关键突破:通过分块校验写入技术,实现了在有限资源下的可靠升级,避免了传统方案中"升级失败变砖"的风险。
整个系统仅需三个基本组件:
code复制+-------------------+ +-------+ +-----------+
| FPGA with | | | | |
| Ethernet MAC |<--->| PHY |<--->| Ethernet |
+--------+----------+ +-------+ +-----------+
|
| QSPI
v
+-------------------+
| QSPI Flash |
| (存储配置和程序) |
+-------------------+
使用Verilog实现的核心模块包括:
verilog复制module upgrade_controller (
input clk,
input rst_n,
// Ethernet interface
input [7:0] rx_data,
input rx_valid,
// QSPI interface
output reg spi_cs,
output reg spi_clk,
inout [3:0] spi_data
);
// 状态机定义
localparam IDLE = 3'd0;
localparam RECV_HEADER = 3'd1;
localparam WRITE_FLASH = 3'd2;
localparam VERIFY = 3'd3;
reg [2:0] state;
reg [15:0] packet_counter;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
state <= IDLE;
spi_cs <= 1'b1;
end
else case(state)
IDLE: if(rx_valid) state <= RECV_HEADER;
RECV_HEADER: begin
// 解析包头逻辑...
state <= WRITE_FLASH;
end
WRITE_FLASH: begin
// Flash写入逻辑...
if(packet_done) state <= VERIFY;
end
VERIFY: begin
// 校验逻辑...
if(verify_ok) state <= IDLE;
end
endcase
end
endmodule
使用Python实现的升级工具关键功能:
python复制def send_firmware(ip, port, firmware):
chunk_size = 256
sequence = 0
with socket.socket() as s:
s.connect((ip, port))
for i in range(0, len(firmware), chunk_size):
chunk = firmware[i:i+chunk_size]
checksum = calc_crc16(chunk)
packet = struct.pack('>HH', sequence, checksum) + chunk
s.send(packet)
ack = s.recv(2)
if struct.unpack('>H', ack)[0] != sequence:
raise Exception("传输错误")
sequence += 1
QSPI写入加速:
网络传输优化:
三重校验机制:
超时重传策略:
异常处理流程:
mermaid复制graph TD
A[开始升级] --> B{接收数据}
B -->|成功| C[写入Flash]
B -->|失败| D[重传]
C --> E{全部完成?}
E -->|是| F[校验镜像]
E -->|否| B
F -->|通过| G[切换Bank]
F -->|失败| H[报告错误]
在XC7A35T-1FTG256C平台上的性能表现:
| 指标 | 本方案 | 传统方案 |
|---|---|---|
| 升级1MB固件时间 | 8.2s | 12.7s |
| 内存占用 | 4KB | 1MB+ |
| 额外硬件成本 | 0元 | 15-50元 |
| 抗干扰能力 | 3次重传成功 | 需硬件复位 |
| 功耗 | +0.3W | +1.2W |
Q1 升级过程中断电怎么办?
解决方案:Flash中始终保留完整的元数据区,记录:
重启后读取这些信息即可判断是否需要继续或回滚。
Q2 如何保证不同版本兼容性?
c复制struct firmware_header {
uint32_t magic; // 0x55AA5A5A
uint16_t hw_ver; // 硬件兼容版本
uint32_t fw_ver; // 固件版本号
uint32_t crc; // 头部校验
};
上位机在发送前先验证硬件版本匹配度。Q3 大容量Flash写入慢怎么优化?
这种方案经过适当适配后,还可以应用于:
在实际工业现场部署时,建议增加以下增强功能:
这个方案我们已经成功应用于智能电表集中器、工业网关等产品,累计升级次数超过50万次,可靠性得到充分验证。对于需要远程维护的嵌入式设备,这种零成本升级方案确实能大幅降低维护成本。