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

至此寄存器就配置完成

相关推荐
xiaojiaohuazi20 分钟前
基于Zynq UltraScale+ MPSoC的PL DDR4直写多NVMe条带阵列(RAID 0)与exFAT高速采集存储系统
fpga开发
ALINX技术博客26 分钟前
【黑金云课堂】FPGA技术教程Vitis开发:AXI总线
fpga开发·vitis
星夜离尘5614 小时前
UART 串口通信:从帧格式到收发回显(附完整 Verilog 实操)
fpga开发
仲南音19 小时前
Xilinx FPGA—— DDR4读写
fpga开发
思尔芯S2C1 天前
思尔芯RCF RTL自动分割工具,助力大规模AI/HPC芯片原型验证
人工智能·fpga开发·内存模型·自动编译·ddr5·prototyping·原型验证
Terasic友晶科技2 天前
答疑解惑|Agilex 3 FPGA QSPI时钟设置注意事项
fpga开发·de23-lite·terasic·qspi flash
国科安芯2 天前
卫星星务计算机数据管理中SEU容错机制的技术实现研究——以AS32S601存储器ECC架构为例
网络·单片机·算法·fpga开发·架构·云计算·risc-v
国科安芯2 天前
卫星电推进系统阀门驱动控制中的宽温域高可靠MCU应用研究——基于AS32S601电气特性与辐照试验数据的工程分析
单片机·嵌入式硬件·fpga开发·云计算·信息与通信·卫星·抗辐射芯片
郝旭帅电子设计团队3 天前
图像处理是什么
图像处理·fpga开发·郝旭帅电子设计团队·郝旭帅
ARM|X86+FPGA工业主板厂家3 天前
基于ARM+FPGA平台在精密测控领域的应用:8路同步IEPE振动采集系统
arm开发·fpga开发