N25Q128是美光推出的128Mb串行Flash存储器,采用SPI接口协议,广泛应用于FPGA配置、嵌入式存储等场景。第一次接触这个芯片时,我被它灵活的Quad SPI模式吸引,但实际开发中发现标准SPI模式已经能满足大部分需求。下面分享从数据手册解读到Verilog实现的全过程。
核心参数速览:
在Verilog控制器设计中,最关键的是理解SPI的四种工作模式:
实际项目中建议先从标准SPI入手,稳定后再扩展Quad模式。我在Xilinx Artix-7平台上测试时,标准SPI模式下读写速度已经能达到5MB/s。
拿到芯片手册后,建议按这个顺序重点阅读:
verilog复制// 状态寄存器读取示例
always @(posedge clk) begin
if(cmd_state == READ_STATUS) begin
status_reg <= spi_rx_data;
busy_flag <= spi_rx_data[0];
end
end
常见命令码:
| 指令名称 | 操作码 | 说明 |
|---|---|---|
| WRITE_ENABLE | 0x06 | 写使能 |
| PAGE_PROGRAM | 0x02 | 页编程 |
| QUAD_PAGE_PROGRAM | 0x32 | 四线页编程 |
| READ_DATA | 0x03 | 读数据 |
| FAST_READ | 0x0B | 快速读 |
建议采用三段式状态机设计:
verilog复制// 状态定义
parameter IDLE = 4'd0;
parameter CMD_SEND = 4'd1;
parameter ADDR_SEND = 4'd2;
parameter DATA_READ = 4'd3;
// 状态转移
always @(posedge clk) begin
case(current_state)
IDLE: if(cmd_valid) next_state <= CMD_SEND;
CMD_SEND: if(cmd_done) next_state <= ADDR_SEND;
...
endcase
end
// 输出逻辑
always @(*) begin
case(current_state)
CMD_SEND: spi_tx_data = cmd_byte;
ADDR_SEND: spi_tx_data = addr_byte[addr_cnt];
...
endcase
end
verilog复制// Quad模式使能序列
task quad_enable;
begin
// 标准SPI模式发送写使能
spi_tx(8'h06);
// 写状态寄存器
spi_tx(8'h01);
spi_tx(8'h40); // 设置QE位
// 等待写入完成
wait_busy();
end
endtask
Xilinx FPGA的CCLK引脚需要通过STARTUPE2原语访问:
verilog复制STARTUPE2 #(
.PROG_USR("FALSE"),
.SIM_CCLK_FREQ(0.0)
) STARTUPE2_inst (
.USRCCLKO(spi_clk), // 用户时钟输出
.USRCCLKTS(1'b0) // 0表示驱动时钟
);
Vivado无法直接调试inout端口,需要IOBUF隔离:
verilog复制IOBUF #(
.DRIVE(12),
.IBUF_LOW_PWR("TRUE"),
.IOSTANDARD("LVCMOS33")
) io_buf [3:0] (
.O(rx_data), // 输入数据
.IO(flash_io), // 双向端口
.I(tx_data), // 输出数据
.T(~oe) // 方向控制
);
有一次调试Quad模式读取异常,最终发现是IOBUF的驱动强度设置不当。将DRIVE参数从12改为4后问题解决,这个坑足足浪费了我两天时间。
建议采用双时钟设计:
verilog复制// 异步FIFO实例化
fifo_generator_0 data_fifo (
.wr_clk(sys_clk),
.rd_clk(spi_clk),
.din(wr_data),
.dout(rd_data),
.full(),
.empty()
);
通过AXI Stream接口实现高速传输:
性能对比:
| 传输方式 | 速度(MB/s) | CPU占用 |
|---|---|---|
| 轮询模式 | 2.1 | 100% |
| 中断模式 | 3.8 | 30% |
| DMA模式 | 5.2 | <5% |
工业级应用建议实现:
verilog复制// ECC校验模块示例
ecc_encoder encoder (
.data_in(page_data),
.ecc_out(ecc_code)
);
ecc_decoder decoder (
.data_in(read_data),
.ecc_in(stored_ecc),
.error_flag(ecc_error)
);
在最近的一个气象站项目中,我们通过Quad SPI+DMA方案将数据采集速率提升了4倍,同时采用动态坏块映射确保了五年连续运行的可靠性。FPGA的灵活性让这些优化成为可能,这也是硬件加速的魅力所在。