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

至此寄存器就配置完成

相关推荐
忆锦紫4 小时前
vivado报错及解决【十】
fpga开发·fpga·vivado
喵喵苗4 小时前
FPGA 核心资源解析:FF 触发器(Flip-Flop)—— 时序逻辑的“记忆心脏”
fpga开发
忆锦紫8 小时前
vivado报错及解决【十一】
fpga开发·fpga·vivado·xilinx
Saniffer_SH1 天前
NAND技术(二):从 Channel、Die/LUN、P/E Cycle 到 LDPC,一次讲透 NAND 里那些最容易误解的概念
人工智能·驱动开发·嵌入式硬件·测试工具·fpga开发·计算机外设·压力测试
千寻xun1 天前
二、实战篇-NVME SSD控制之ZYNQ实现(四)
fpga开发·nvme·nvme ssd
ALINX技术博客1 天前
【黑金云课堂】FPGA技术教程Linux开发:系统进阶-PS DMA
linux·fpga开发
喵喵苗1 天前
FPGA Verilog 入门避坑:寄存器与锁存器的本质区别 & 为什么时序逻辑缺 else 不会生成锁存器
fpga开发
Thinker3611 天前
笔记本外接创新5.1声卡实战:M.2转PCIe软排线方案 vs 雷电扩展卡方案对比
fpga开发·声卡·笔记本外接pcie·显卡坞
传感器与混合集成电路1 天前
136通道采集模块SPI接口设计:协议结构、时序要求与多模块级联扩展方案
fpga开发