二、实战篇-NVME SSD控制之ZYNQ实现(三)

本章节讲述如何使用ZYNQ(纯C语言)实现NVME SSD硬盘的读写控制。

参考:

FPGA控制NVME开发流程-CSDN博客

一、理论篇-NVME协议学习笔记-CSDN博客

二、实战篇-NVME SSD控制之ZYNQ实现(一)-CSDN博客

二、实战篇-NVME SSD控制之ZYNQ实现(二)-CSDN博客

前面完成了PCIE的建链和枚举,以及FPGA和NVME SSD的PCIE CFG空间的配置。

下面进行NVME SSD的寄存器配置,NVME SSD内部寄存器位于BAR空间中,完成地址映射后就可以进行访问了。

寄存器表如下:

先定义寄存器偏移地址

cpp 复制代码
#define RegOffset_CAP_L 	0x00
#define RegOffset_CAP_H 	0x04
#define RegOffset_VS 		0x08
#define RegOffset_INTMS		0x0C
#define RegOffset_INTMC		0x10
#define RegOffset_CC 		0x14
#define RegOffset_CSTS 		0x1C
#define RegOffset_AQA 		0x24
#define RegOffset_ASQ_L 	0x28
#define RegOffset_ASQ_H 	0x2C
#define RegOffset_ACQ_L 	0x30
#define RegOffset_ACQ_H 	0x34
#define RegOffset_Admin_SQTDBL 	0x1000
#define RegOffset_Admin_CQHDBL 	0x1004
#define RegOffset_IO_SQ0TDBL 	0x1008
#define RegOffset_IO_CQ0HDBL 	0x100c
#define RegOffset_IO_SQ1TDBL 	0x1010
#define RegOffset_IO_CQ1HDBL 	0x1014

1 、读取寄存器

先进行寄存器读取,验证链路以及寄存器映射是否正确

获取CAP,VS,CC寄存器数据,对应地址分别为0x80000000(CAP低32位),0x80000004(CAP高32位)0x80000008,0x80000014。

cpp 复制代码
	u32	acpl,acph,VS,CC,CSTS;

	acpl = XAxiPcie_ReadReg((XPAR_AXI_PCIE_0_AXIBAR_0),RegOffset_CAP_L);
	xil_printf("acpl is %08X \r\n",	acpl);
	acph = XAxiPcie_ReadReg((XPAR_AXI_PCIE_0_AXIBAR_0),RegOffset_CAP_H);
	xil_printf("acph is %08X \r\n",	acph);
	VS = XAxiPcie_ReadReg((XPAR_AXI_PCIE_0_AXIBAR_0),RegOffset_VS);
	xil_printf("VS is %08X \r\n",	VS);
	CC = XAxiPcie_ReadReg((XPAR_AXI_PCIE_0_AXIBAR_0),RegOffset_CC);
	xil_printf("CC is %08X \r\n",	CC);

2 、配置寄存器(初始化)

①等待CSTS寄存器(0x8000001C)ready位为0

cpp 复制代码
	// 循环查询,直到最低位CSTS.RDY(Bit0)为 0
	while(1)
	{
	    CSTS = XAxiPcie_ReadReg(XPAR_AXI_PCIE_0_AXIBAR_0, RegOffset_CSTS);
	    xil_printf("CSTS: 0x%08X\r\n", CSTS);

	    // 判断 Bit0 是否为 0
	    if( (CSTS & 0x00000001) == 0 )
	    {
	        break;
	    }
	    usleep(1000);  // 延时1ms,避免频繁读寄存器占用总线
	}
	xil_printf("Controller Ready!\r\n");

②配置CC寄存器(0x80000014)为0x00460000 :配置Admin提交队列单条大小为64byte, Admin完成队列单条大小为16byte。

cpp 复制代码
//配置CC寄存器(不设置EN位)
	XAxiPcie_WriteReg(XPAR_AXI_PCIE_0_AXIBAR_0, RegOffset_CC, 0x00460000) ;
	usleep(1000);

	CC = XAxiPcie_ReadReg((XPAR_AXI_PCIE_0_AXIBAR_0),RegOffset_CC);
	xil_printf("CC is %08X \r\n",	CC);

③配置AQA寄存器(0x80000024)为0x00100010:配置Admin提交、完成队列深度为16。

cpp 复制代码
	 u32 aqa_val, asq_val, acq_val;

	    // AQA寄存器:Admin队列属性
	    // [15:0] ASQS (Admin Submission Queue Size)
	    // [31:16] ACQS (Admin Completion Queue Size)
	    aqa_val = ((NVME_ADMIN_QSIZE - 1) << 16) | (NVME_ADMIN_QSIZE - 1);
	    XAxiPcie_WriteReg(XPAR_AXI_PCIE_0_AXIBAR_0, RegOffset_AQA, aqa_val) ;
	    xil_printf("AQA set to 0x%08X\r\n", aqa_val);

④配置ASQ寄存器(0x80000028、0x8000002C)分别为0x10100000,0x00000000:配置Admin提交队列基地址高32位为0,低32位为0x10100000。

cpp 复制代码
	    // ASQ寄存器:Admin Submission Queue Base Address(低64位)
	    asq_val = ADMIN_SQ_BASE & 0xFFFFFFFF;
	    XAxiPcie_WriteReg(XPAR_AXI_PCIE_0_AXIBAR_0, RegOffset_ASQ_L, asq_val) ;
	    XAxiPcie_WriteReg(XPAR_AXI_PCIE_0_AXIBAR_0, RegOffset_ASQ_H, (ADMIN_SQ_BASE >> 32) & 0xFFFFFFFF) ;
	    xil_printf("ASQ set to 0x%08X\r\n", asq_val);

⑤配置ACQ寄存器(0x80000030、0x80000034)分别为0x10101000,0x00000000:配置Admin完成队列基地址高32位为0,低32位为0x10101000。

cpp 复制代码
	    // ACQ寄存器:Admin Completion Queue Base Address(低64位)
	    acq_val = ADMIN_CQ_BASE & 0xFFFFFFFF;
	    XAxiPcie_WriteReg(XPAR_AXI_PCIE_0_AXIBAR_0, RegOffset_ACQ_L, acq_val) ;
	    XAxiPcie_WriteReg(XPAR_AXI_PCIE_0_AXIBAR_0, RegOffset_ACQ_H, (ADMIN_CQ_BASE >> 32) & 0xFFFFFFFF) ;
	    xil_printf("ACQ set to 0x%08X\r\n", acq_val);

⑥配置CC寄存器(设置EN)地址0x80000014写0x00460001

cpp 复制代码
//配置CC寄存器(设置EN)
	    XAxiPcie_WriteReg(XPAR_AXI_PCIE_0_AXIBAR_0, RegOffset_CC, 0x00460001) ;
	    usleep(1000);
	    CC = XAxiPcie_ReadReg((XPAR_AXI_PCIE_0_AXIBAR_0),RegOffset_CC);
		xil_printf("CC is %08X \r\n",	CC);

⑦等待CSTS寄存器(0x8000001C)ready位为1

cpp 复制代码
// 循环查询,直到最低位CSTS.RDY(Bit0)为 1
		while(1)
		{
		    CSTS = XAxiPcie_ReadReg(XPAR_AXI_PCIE_0_AXIBAR_0, RegOffset_CSTS);
		    xil_printf("CSTS: 0x%08X\r\n", CSTS);

		    // 判断 Bit0 是否为 1
		    if( (CSTS & 0x00000001) == 1 )
		    {
		        break;
		    }
		    usleep(1000);  // 延时1ms,避免频繁读寄存器占用总线
		}
		xil_printf("Controller Ready!\r\n");

至此寄存器就配置完成

相关推荐
FPGA小迷弟1 小时前
FPGA 应用技术能力的完整闭环(5-8)
fpga开发·dsp开发·fpga·sdr·无线电
狂奔蜗牛(bradley)2 小时前
搞定100ns抖动:ARM+FPGA混合EtherCAT主站实战方案
嵌入式硬件·fpga开发
free-elcmacom7 小时前
FPGA学习笔记<2>Verilog输入
fpga开发·硬件工程
学习FPGA的电气小兴兴9 小时前
基于FPGA的CORDIC向量模式实现arctan运算,Verilog HDL实现
嵌入式硬件·fpga开发·数字信号处理·verilog·fpga·cordic·arctan
FPGA小迷弟1 天前
FPGA 应用技术能力的完整闭环(1-4)
fpga开发·dsp开发·fpga·sdr·无线电
Eloudy1 天前
FPGA 开发与 IC 数字前端设计
fpga开发
tju新生代魔迷1 天前
Verilog HDL 学习笔记(十八)| 附录C:关键字、系统任务和编译指令
fpga开发
free-elcmacom1 天前
FPGA学习笔记<1>FPGA的开发流程
fpga开发·硬件工程·hdl
明德扬2 天前
AD9653单通道波形怎么看?幅度、频率与基础测量入门
学习·fpga开发·fpga
ERROR:992 天前
GPT Images 2.5将手稿转时序图效果不佳
fpga开发