二、实战篇-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");

至此寄存器就配置完成

相关推荐
HUSTCH20211 天前
FPGA中的LUT和DSP
fpga开发
Riwuarua1 天前
从近似0基础开始FPGA开发 -- part.4 FPGA-PS(MicroBlaze)
fpga开发
zlinear数据采集卡1 天前
FRAM铁电存储器原理深度解析:D223校准参数的“永久保险箱“
arm开发·人工智能·stm32·单片机·fpga开发·开源
明德扬2 天前
Quartus Prime Pro 26.1 更新了什么?Arria 10 FPGA 工程升级与迁移注意事项
fpga开发
9527华安2 天前
Xilinx Zynq7000系列FPGA纯verilog图像缩放,串口上位机动态调整缩放分辨率,提供4套工程源码和技术支持
fpga开发·图像缩放·zynq7000
Riwuarua2 天前
从近似0基础开始FPGA开发 -- part.3 ila与debug
fpga开发
松小白song3 天前
FPGA架构解密:为何要用750kHz低频时钟驱动二级缓存?
fpga开发
Riwuarua3 天前
从近似0基础开始FPGA开发 -- part.2 仿真
fpga开发
unicrom_深圳市由你创科技3 天前
国产FPGA的芯片选型应该考虑哪些因素?
fpga开发
明德扬3 天前
高速采集选 Direct RF 还是外置 ADC/FMC?从采样率、JESD204B 和开发周期对比
fpga开发·fpga