在嵌入式系统和FPGA开发中,高速数据存储和访问一直是关键挑战。APS6404L-3SQR是一款采用QSPI接口的PSRAM芯片,相比传统SPI接口的存储设备,它通过四线并行传输显著提升了数据吞吐率。本文将深入解析基于FPGA的QSPI PSRAM驱动设计,重点聚焦QPI模式下的状态机实现与优化技巧。
对于需要高速数据缓冲的应用场景(如视频帧缓存、高速数据采集等),QSPI PSRAM提供了理想的解决方案。其QPI模式通过四线并行传输,理论上可以达到标准SPI接口四倍的带宽。但在实际FPGA实现中,时序控制、状态机设计和信号完整性等问题都需要特别关注。
QPI(Quad Peripheral Interface)模式是QSPI接口的高性能工作模式,与标准SPI模式相比主要差异在于:
在APS6404L-3SQR芯片中,QPI模式通过特定的命令序列激活。一旦进入QPI模式,所有后续通信(命令、地址、数据)都通过四线并行传输,直到收到退出QPI模式的指令。
设计QPI驱动状态机时需要考虑以下关键因素:
驱动核心采用经典的三段式状态机设计(当前状态寄存器、次态逻辑、输出逻辑),共定义8个主要状态:
verilog复制parameter IDLE = 5'd0, // 空闲状态
QPI_WRCMD = 5'd1, // 写命令状态
QPI_WRADDR= 5'd2, // 写地址状态
QPI_WRDATA= 5'd3, // 写数据状态
QPI_WREND = 5'd4, // 写结束状态
QPI_RDWAIT= 5'd5, // 读等待状态
QPI_RDDATA= 5'd6, // 读数据状态
QPI_RDEND = 5'd7; // 读结束状态
状态转移逻辑采用组合逻辑实现,确保每个时钟周期都能及时响应外部事件:
verilog复制always@(*) begin
case (r_qspi_fsm_current)
IDLE: if (w_user_active) r_qspi_fsm_next <= QPI_WRCMD;
QPI_WRCMD:
if (r_cnt == 'd1 && r_qpi_cnt)
r_qspi_fsm_next <= i_exit_qpi_mode ? QPI_WREND : QPI_WRADDR;
// 其他状态转移逻辑...
endcase
end
在QPI模式下,8位命令需要分两个时钟周期传输(每个周期4位)。代码实现采用动态位选择:
verilog复制if (cmd_flag & r_qpi_cnt) begin
rio_qspi_mosi0 <= i_user_cmd[(2-r_cnt)*4 - 4]; // 位选择逻辑
rio_qspi_mosi1 <= i_user_cmd[(2-r_cnt)*4 - 3];
rio_qspi_mosi2 <= i_user_cmd[(2-r_cnt)*4 - 2];
rio_qspi_mosi3 <= i_user_cmd[(2-r_cnt)*4 - 1];
end
注意:命令传输完成后需要根据是否退出QPI模式决定下一状态。如果是退出命令,则直接跳转到结束状态;否则进入地址传输状态。
24位地址需要6个时钟周期传输(QPI模式下每个周期传输4位)。地址传输完成后根据操作类型跳转:
verilog复制if (i_qspi_wren && r_cnt == 'd5 && r_qpi_cnt)
r_qspi_fsm_next <= QPI_WRDATA; // 写操作进入写数据状态
else if (i_qspi_rden && r_cnt == 'd5 && r_qpi_cnt)
r_qspi_fsm_next <= QPI_RDWAIT; // 读操作进入读等待状态
地址位的并行输出实现与命令类似,但需要处理更多位数:
verilog复制if (addr_flag & r_qpi_cnt) begin
rio_qspi_mosi0 <= i_user_wr_addr[(6-r_cnt)*4 - 4];
rio_qspi_mosi1 <= i_user_wr_addr[(6-r_cnt)*4 - 3];
rio_qspi_mosi2 <= i_user_wr_addr[(6-r_cnt)*4 - 2];
rio_qspi_mosi3 <= i_user_wr_addr[(6-r_cnt)*4 - 1];
end
数据传输状态是性能关键路径,需要特别注意:
verilog复制// 写字节计数器
always@(posedge i_clk) begin
if(i_rst) r_wrbyte_cnt <= 'd0;
else if (i_user_data_val && r_qpi_cnt) begin
if (r_wrbyte_cnt == i_write_length) r_wrbyte_cnt <= 'd0;
else r_wrbyte_cnt <= r_wrbyte_cnt + 'd1;
end
end
// 数据位分配
if (wr_data_flag & r_qpi_cnt) begin
if (!r_wrfifo_flag) begin // 第一个半字节
rio_qspi_mosi0 <= i_user_data[P_DATA_WIDTH - 4];
rio_qspi_mosi1 <= i_user_data[P_DATA_WIDTH - 3];
rio_qspi_mosi2 <= i_user_data[P_DATA_WIDTH - 2];
rio_qspi_mosi3 <= i_user_data[P_DATA_WIDTH - 1];
end else begin // 第二个半字节
rio_qspi_mosi0 <= i_user_data[P_DATA_WIDTH - 8];
rio_qspi_mosi1 <= i_user_data[P_DATA_WIDTH - 7];
rio_qspi_mosi2 <= i_user_data[P_DATA_WIDTH - 6];
rio_qspi_mosi3 <= i_user_data[P_DATA_WIDTH - 5];
end
end
verilog复制always@(negedge o_spi_clk) begin
if (r_rd_data_flag[1] & r_qpi_cnt) begin
if (r_wrfifo_flag) begin // 第一个半字节
ro_user_read_data[P_DATA_WIDTH - 1] <= i_qspi_sio3;
ro_user_read_data[P_DATA_WIDTH - 2] <= i_qspi_sio2;
ro_user_read_data[P_DATA_WIDTH - 3] <= i_qspi_sio1;
ro_user_read_data[P_DATA_WIDTH - 4] <= i_qspi_sio0;
end else begin // 第二个半字节
ro_user_read_data[P_DATA_WIDTH - 5] <= i_qspi_sio3;
ro_user_read_data[P_DATA_WIDTH - 6] <= i_qspi_sio2;
ro_user_read_data[P_DATA_WIDTH - 7] <= i_qspi_sio1;
ro_user_read_data[P_DATA_WIDTH - 8] <= i_qspi_sio0;
end
end
end
驱动模块的顶层接口包含以下关键信号:
verilog复制module qspi_drive #(
parameter P_DATA_WIDTH = 8,
P_ADDR_WIDTH = 24,
P_READ_DATA_WIDTH = 8,
P_CPOL = 0,
P_CPHL = 0
)(
input wire i_clk, i_rst,
output wire o_spi_clk, o_spi_cs,
// 四线QSPI接口
input wire i_qspi_sio0, i_qspi_sio1, i_qspi_sio2, i_qspi_sio3,
output wire o_qspi_sio0, o_qspi_sio1, o_qspi_sio2, o_qspi_sio3,
// 调试标志
output wire o_qspi_cmd_flag, o_qspi_addr_flag,
output wire o_qspi_wrdata_flag, o_qspi_rddata_flag,
// 控制接口
input wire i_fifo_full, i_qspi_wren, i_qspi_rden,
input wire [7:0] i_write_length, i_read_length,
input wire i_exit_qpi_mode,
output wire o_wr_requset,
// 用户接口
input wire [23:0] i_user_wr_addr,
input wire [7:0] i_user_data,
input wire i_user_data_val,
input wire [7:0] i_user_cmd,
input wire i_user_cmd_valid,
output wire o_user_ready,
// 数据输出
output wire [7:0] o_user_read_data,
output wire o_user_read_valid
);
在实际调试中,以下几个技巧非常实用:
信号捕获策略:
常见问题排查:
性能优化建议:
通过SignalTap逻辑分析仪捕获的实际波形显示,驱动能够稳定工作在104MHz时钟频率下,实现52MB/s的有效数据传输率(考虑协议开销)。下图展示了连续读写操作的波形:

关键观察点:
在长期稳定性测试中,该驱动实现了: