基于FPGA的APS6404L-3SQR QSPI PSRAM驱动设计(2)

1.摘要

上一篇文章 基于FPGA的APS6404L-3SQR QSPI PSRAM驱动设计(1)主要记录了数据手册和设计中框架,这里记录一下具体的spi协议相关的设计。

在PSRAM的众多命令中有一些命令用spi协议控制更方便(我感觉)。比如两个复位命令66和99,在没配置QPI命令模式之前只能用SPI协议,所以类似复位命令这些指令如(良品检测、配置QPI和边界选择)都使用SPI来控制即可。

这些协议中除了良品检测命令其他都只是需要简单发送8bit命令,利用spi协议发送简单的一批。对于良品检测命令就需要用到状态机控制了,分别写命令+写地址+读数据了,稍微复杂一点。

2.FPGA设计

2.1、时序图设计

当spi模块的状态机跳转到写命令状态时,即可开始向PSRAM芯片写入命令,具体工作过程如时序图所示:

具体设计思路为:

状态机检测到命令输入立刻从IDLE跳转到SPI_CMD,同时spi工作有效信号r_run拉高。因为是8bit命令,所以计数器r_cnt计数0-7,r_spi_cnt作为计数器标志信号,通过在spi有效期内翻转实现,也就是二分频,同时也作为o_spi_clk。

当输入的命令为良品检测时,r_run信号将延迟拉低,具体时间为24bit的地址周期,加上56bit的读数据周期,最终当 r_cnt计数到88时在拉低,其余信号逻辑不变。

代码中的i_spi_8bit_cmd信号是上层模块输入的判断是否是良品检测命令,不是为1是为0。

复制代码
always@(*)
begin
	if(i_rst)
		r_spi_fsm_next	<=	'd0	;
	else begin
		case (r_spi_fsm_current)
			IDLE		:	
				if (w_user_active)	begin
					r_spi_fsm_next	<=	SPI_CMD	;
				end else 
					r_spi_fsm_next	<=	IDLE	;
			SPI_CMD		:
				if (r_cnt == 'd7 && r_spi_cnt)
					if (i_spi_8bit_cmd)
						r_spi_fsm_next	<=	SPI_END	;
					else 
						r_spi_fsm_next	<=	SPI_ADDR	;
				else 
					r_spi_fsm_next	<=	SPI_CMD		;
			SPI_ADDR	:
				if (r_cnt == 'd23 && r_spi_cnt)
					r_spi_fsm_next	<=	SPI_DATA	;
				else 
					r_spi_fsm_next	<=	SPI_ADDR	;
			SPI_DATA	:
				if (r_cnt == 'd55 && r_spi_cnt)
					r_spi_fsm_next	<=	SPI_END	;
				else 
					r_spi_fsm_next	<=	SPI_DATA	;
			SPI_END		:
				r_spi_fsm_next	<=	IDLE	;
			default		:
				r_spi_fsm_next	<=	IDLE	;
		endcase 
	end 
end 

always@(posedge i_clk,posedge i_rst)
begin
	if(i_rst)	
		r_run <= 'd0;
	else if (r_spi_fsm_current == SPI_CMD && i_spi_8bit_cmd)	begin
		if (r_spi_cnt && r_cnt == 'd7)
			r_run 	<=	1'b0;
		else 
			r_run	<=	1'b1;
	end else if (r_spi_fsm_current == SPI_DATA && r_run)	begin
		if (r_spi_cnt && r_cnt == 'd55)
			r_run	<=	1'b0	;
		else 
			r_run	<=	1'b1	;
	end else if(w_user_active)
		r_run <= 'd1;
	else 
		r_run <= r_run;
end

always@(posedge i_clk,posedge i_rst)
begin
	if(i_rst)
		r_cnt	<=	'd0	;
	else if (r_spi_fsm_current != r_spi_fsm_next)
		r_cnt <= 'd0;
	else if (r_run && r_spi_cnt)	
		r_cnt	<=	r_cnt + 'd1	;
end 

always@(posedge i_clk,posedge i_rst)
begin
	if(i_rst)
		r_spi_cnt <= 'd0;
	else if(r_run)
		r_spi_cnt <= r_spi_cnt + 1;
	else 
		r_spi_cnt <= 'd0;
end

对于6线spi芯片来说,它的数据线是inout接口,所以需要添加控制信号来判断是输入还是输出。如下代码,输出一下信号用于上层模块判断。

复制代码
(* PAP_MARK_DEBUG="1" *)wire    cmd_flag		=	(r_spi_fsm_current == SPI_CMD);
(* PAP_MARK_DEBUG="1" *)wire    addr_flag	=	(r_spi_fsm_current == SPI_ADDR);
(* PAP_MARK_DEBUG="1" *)wire    data_flag	=	(r_spi_fsm_current == SPI_DATA);

spi驱动模块的所有端口信号如下:

复制代码
spi_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               ,
	input	wire					i_rst               ,

	output	wire					o_spi_clk           ,
	output	wire					o_spi_cs            ,
	
	input	wire					i_spi_mosi		,
	output 	wire					o_spi_miso		,
	output 	wire					o_spi_cmd_flag	,
	output 	wire					o_spi_addr_flag	,
	output 	wire					o_spi_data_flag	,

	input	wire					i_spi_8bit_cmd	,

	input	wire	[23:0]			i_user_addr			,
	input	wire	[7 :0]   		i_user_cmd        ,
	input	wire					i_user_valid        ,
	output	wire					o_user_ready        ,

    output	wire	[7:0]   		o_user_read_data    ,
    output	wire                    o_user_read_valid   
);

对于读取PSRAM读取良品检测输出信号,按照时序图我们需要在读数据阶段读到的第二个字节数据作为良品与否的判断。所以当r_cnt计数到15切r_qpi_cnt为1的时候获取读到的值。具体代码如下:

复制代码
always@(posedge ro_spi_clk,posedge i_rst)
begin
	if(i_rst)
		ro_user_read_data <= 'd0;
	else	if (data_flag)
		ro_user_read_data <= {ro_user_read_data[P_DATA_WIDTH - 2 : 0],i_spi_mosi};
	else 
		ro_user_read_data <= 'd0;
end

always@(posedge i_clk,posedge i_rst) 
begin
	if(i_rst)
		ro_user_read_valid <= 'd0;
	else if (r_spi_fsm_current == SPI_DATA && ((r_cnt == 'd7 || r_cnt == 'd15) && r_spi_cnt))
		ro_user_read_valid <= 'd1;
	else 
		ro_user_read_valid <= 'd0;
end

3.上板验证

按照时序图,关于spi驱动部分正确输出良品检测通过指令8'H5D。

相关推荐
Dr.kangder1 小时前
嵌入式处理器架构解析(十)——DSP+FPGA
fpga开发·架构·嵌入式
szxinmai主板定制专家8 小时前
Zynq MPSoC实现半导体真空腔体状态监测|FPGA多传感器时序同步采集方案
fpga开发·zynq·控制器·mpsoc·半导体设备·fpga同步
学习FPGA的电气小兴兴10 小时前
基于FPGA的DDS信号发生器设计,生成频率可调的正弦波、三角波、锯齿波和方波
fpga开发·数字信号处理·fpga·vivado·dsp·dds·diy
szxinmai主板定制专家1 天前
Zynq MPSoC半导体高精度运动控制方案|FPGA硬件插补实现亚微米级伺服实时控制
人工智能·嵌入式硬件·fpga开发·zynq·运动控制·ethercat
星夜离尘562 天前
ILA 在线调试:Vivado 抓取片内信号与定位下板问题(附完整实操)
fpga开发
jz_ddk2 天前
[学习] 深入理解 USB 通信与 FPGA 实现:从协议到逻辑设计
学习·fpga开发·xilinx·usb2.0
星夜离尘562 天前
PWM 信号生成与呼吸灯:占空比控制、按键调光与舵机扩展(附完整 Verilog 实操)
fpga开发
zlinear数据采集卡3 天前
ZLinear DABM-D223 通信协议与软件开发全解析:从 USB CDC 到 DDS 波形输出
arm开发·嵌入式硬件·fpga开发·开源
LCMICRO-133108477463 天前
国产长芯微LD3092完全pin-pin替代LT3092,是一款可编程两端电流源
arm开发·单片机·嵌入式硬件·fpga开发·硬件工程·恒流源·lt3092