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

至此寄存器就配置完成

相关推荐
幻智星科技19 小时前
蒙哥马利模乘FPGA优化实战
fpga开发·密码学
星夜离尘5619 小时前
FPGA 多通道 DAC 目标码影子寄存器:成组提交、同拍写入与快照边界
fpga开发
t_niu_niu21 小时前
基于多帧累加平均的图像传感器暗电流抑制方法与 FPGA 实现
fpga开发·ram·fpn·固定模式噪声·image sensor
幻智星科技21 小时前
FPGA纯硬件UDP桥接:微秒级响应新范式
c++·fpga开发·硬件架构
小蘇的FPGA21 小时前
基于FPGA实现PCIe H2C过程中TAG的一种管理方法
fpga开发
威嵌神州21 小时前
一台加固平板,能替掉几台现场设备?
嵌入式硬件·fpga开发·电脑·平板
幻智星科技1 天前
树形架构破解FPGA扇出瓶颈
fpga开发·硬件架构
FPGA小迷弟2 天前
FPGA开发Vivado Block Design/Vitis/SDK/xlinx/开发教程,保姆级别,一看就会!
网络协议·tcp/ip·fpga开发·verilog·fpga
FPGA小迷弟2 天前
基于FPGA实现智能网卡的概念,什么是智能网卡
网络协议·tcp/ip·fpga开发·verilog·fpga
好焊孙辉2 天前
螺柱焊机哪家质量好
python·fpga开发