基于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。

相关推荐
仲南音10 小时前
Xilinx FPGA——时钟IP核MMCM、PLL
fpga开发
I'm a winner1 天前
基于Xilinx FPGA的LVDS高速串行通信系统(三)--数据训练及握手机制【文末源码】
fpga开发
upper20201 天前
coremark移植坑之-nostartfiles -nostdlib参数
学习·fpga开发·coremark移植·riscv设计
Eloudy1 天前
Vivado 纯命令行构建 FPGA 项目教程
fpga开发
Rambo.xia1 天前
AXI跨时钟域与数据一致性——CDC FIFO深度不够、写后读冒险、多Master仲裁、乱序返回,出了Bug根本查不出来
fpga开发·bug
upper20201 天前
FPGA部署卷积神经网络识别MINST图片
fpga开发·卷积神经网络·minst·minst识别·部署神经网络·神经网络识别图片
你是我的解忧王子2 天前
嵌入式 ADC采样 原始数据分析上层(平均值 波动率 正态分布 线性补偿 系统误差)
fpga开发·数据挖掘·数据分析
9527华安2 天前
FPGA纯verilog代码ISP图像处理培训教程,基于IMX214,提供工程源码+视频教程+FPGA开发板
图像处理·fpga开发·isp·imx214·mipi
千寻xun3 天前
二、实战篇-NVME SSD控制之ZYNQ实现(六)-读写NVME SSD硬盘数据
fpga开发·nvme·nvme ssd
千寻xun3 天前
二、实战篇-NVME SSD控制之ZYNQ实现(三)
fpga开发·nvme ssd·nvme协议