尝试用IPcore调用DDR3及相关知识

背景:之前通过PS通过MIG实现了对DDR的调用:

ARM用MIG调用DDR3的c程序解析

实践教程(一)用HLS生成IPcore

实践教程(三)系统搭建与烧录

实践教程(四)片上ARM运行程序

实践教程(五)PS用MIG调用DDR

 

目的:由易到难实现IPcore对DDR3的调用

目录

一、简单IPcore

二、用vivado搭建系统

三、直接试图调用DDR3


预想步骤:

1.编写简单IPcore,能够与PS进行通信。

2.搭建系统,SDK编译环境下实现IPcore与PS的通信,验证成功

3.搭建系统,PS连接IPcore,IPcore通过MIG连接DDR3

4.用之前的IPcore,验证成功

5.更改IPcore,能与DDR3通信

6.系统不变,进行验证

但是实际过程中,此步骤总是遇到问题,在发现其他人用IPcore调用DDR的帖子之后,我们参照他们的方法实现。

 

一、简单IPcore

步骤实践教程(一)用HLS生成IPcore目录四

用cnnIP,记得进行接口综合,将streamIn与streamOut综合成axis数据流。然后不进行优化,直接进行c synthesis与RTL export输出IPcore

二、用vivado搭建系统

参考实践教程(三)系统搭建与烧录中的系统搭建,其目的是调用DMA,与实践教程(五)PS用MIG调用DDR中的目录三,定制7035的zynq的PS,系统

先按照(三)中搭建系统,然后,按照(五)配置PS。

结果发现linux下面编写的系统,在用单片机时打开DMA时打开就failed,我们只能查找单片机的测试例程。运用测试程序。

尝试用IPcore调用DDR3及相关知识_第1张图片

虽然程序卡了,没有运行完,但是万幸看到DMA已经通了,我们大致看一下测试程序中关于DMA调用的程序代码。

SDK环境下调用DMA始终无法成功,方案失败。

三、直接试图调用DDR3

听取骆工建议直接学习网上调用DDR3的范例,查找范例。

能否用IPcore直接调用DDR?

Using the DDR memory independently of the Processor:

http://zedboard.org/content/using-ddr-memory-independently-processor

UG873 Chaptet 6中,AXI CDMA core有可能调用DDR3,但实际查看后依然是PS对DDR的调用。

尝试用IPcore调用DDR3及相关知识_第2张图片

我们可以在vivado中搭建相应的系统,然后用Address Editor运用Offset Address实现相应的地址访问。但必须注意,IP block中的函数必须作为总线的master。

四、在查找相关资料失败之后,我们在骆工帮助下运用axi-lite的例程

D:\xilinx\SDx\2016.4\Vivado_HLS\examples\design\axi_lite

与其他人调用DDR3的流程:

https://forums.xilinx.com/t5/Vivado-High-Level-Synthesis-HLS/Axi-Master-DDR-MIG-tester/td-p/641990

作者运用MicroBlaze搭建的系统

我们用7z035搭建的系统:(不要出现多余的连接的external,不然生成比特流总是不成功)

第一次:

第二次:

第一次通过一个interconnect连接,PS与IPcore均与interconnect相连,所以两者有共同的地址,第二次通过两个interconnect相连,IPcore只与mig相连,所以PS只能有testerIPcore的指针,IPcore只有DDR3的指针。

 

 

 

注意!在axi-lite接口的时候,HLS会生成一个.h和.c的源文件,路径为\ddrHLS\solution1\impl\ip\drivers\memDDR3Tester_v1_0\src    意思是相关IP的单片机的驱动。

以供后续的SDK的单片机使用。我们之前不知道这个东西。以后必须记得这个东西并且及时添加。

SDK的单片机参考程序D:\xilinx\SDx\2016.4\SDK\data\embeddedsw\XilinxProcessorIPLib\drivers

 

// HLS IP Core
#include 
#include 
#include 

unsigned int memDDR3Tester(unsigned int start, unsigned int size,
 unsigned int mode, unsigned int data, 
volatile unsigned int *memPtr, unsigned int *expectedVal, 
unsigned int *failedAddr, unsigned int *numErrors)
{
#pragma HLS INTERFACE s_axilite port=numErrors bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=failedAddr bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=expectedVal bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=start bundle=CRTL_BUS
#pragma HLS INTERFACE m_axi depth=512 port=memPtr
#pragma HLS INTERFACE s_axilite port=data bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=mode bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=size bundle=CRTL_BUS
#pragma HLS INTERFACE s_axilite port=return bundle=CRTL_BUS

	unsigned int result = 0;
	unsigned int idxMemAddr = 0;
	unsigned int errorCounter = 0;
	*numErrors = 0;
	*expectedVal = 0;
	*failedAddr = 0;

	switch (mode)
	{
	/*
	 * Send 0xAA55 (16b1010101001010101) or 0x55AA if the address is odd/even
	 * write then read and stop on the first error
	 */

	case 0:
	{
		// Write
		for (idxMemAddr = 0; idxMemAddr < size; idxMemAddr++)
		{
			unsigned char isOdd = (idxMemAddr % 2);
			unsigned int value = (isOdd)?0x55AA:0xAA55;
			memPtr[idxMemAddr] = value;
		}

		// Read
		for (idxMemAddr = 0; idxMemAddr < size; idxMemAddr++)
		{
			unsigned char isOdd = (idxMemAddr % 2);
			unsigned int value = (isOdd)?0x55AA:0xAA55;
			if (memPtr[idxMemAddr] != value)
			{
				result = 1;
				*expectedVal = value;
				*failedAddr = idxMemAddr;
				// Bail out on the first error
				*numErrors = 1;
				break;
			}
		}
		break;
	}

	/*
	 * Send an incremental value but don't stop if some error occured and return the number of errors
	 * */
	case 1:
	{
		// Write
		for (idxMemAddr = 0; idxMemAddr < size; idxMemAddr++)
		{
			unsigned int value = idxMemAddr;
			memPtr[idxMemAddr] = value;
		}
		// Read
		for (idxMemAddr = 0; idxMemAddr < size; idxMemAddr++)
		{
			unsigned int value = idxMemAddr;
			if (memPtr[idxMemAddr] != value)
			{
				result = 1;
				errorCounter++;
			}
		}
		*numErrors = errorCounter;
		break;
	}

	/*
	 * Send just a value and read it back
	 * */
	case 2:
	{
		memPtr[start] = data;
		if (memPtr[start] != data)
		{
			result = 1;
			*expectedVal = data;
			*failedAddr = start;
		}

		break;
	}

	/*
	 * Send on mode burst (memset) the value 0xAA55 (16b1010101001010101)
	 * */
	case 3:
	{
		//memset((unsigned int*)memPtr,(int)0xAA55,(size_t)(sizeof(unsigned int)*size));
		// Write
		for (idxMemAddr = 0; idxMemAddr < size; idxMemAddr++)
		{
			memPtr[idxMemAddr] = 0xAA55;
		}
		// Read
		for (idxMemAddr = 0; idxMemAddr < size; idxMemAddr++)
		{
			if (memPtr[idxMemAddr] != 0xAA55)
			{
				result = 1;
				errorCounter++;
			}
		}
		*numErrors = errorCounter;
		break;
	}
	}
	return result;
}

运用memptr传入指针,然后对指针所指的内容进行读写。所以后续在FPGA中传入DDR的指针,就能对DDR进行相应的读写。

 

 

// HLS test Bench
#include 

unsigned int memDDR3Tester(unsigned start, unsigned int size, 
unsigned int mode, unsigned int data, 
volatile unsigned int memPtr[512000000], unsigned int *expectedVal, 
unsigned int *failedAddr, unsigned int *numErrors);

int main()
{
	unsigned int memPtr[10];
	unsigned int expectedVal;
	unsigned int failedAddr;
	unsigned int numErrors;
	unsigned int result;
	unsigned int size=10;
	unsigned int mode=0;

	printf("	Test Size:%d, Test mode %d\n",size,mode);
	result = memDDR3Tester(0,size,mode,0,memPtr,&expectedVal,&failedAddr,&numErrors);
	printf("Result mode 0: %d Expected: %d failedAddr:%d numErrors:%d\n",result,expectedVal,failedAddr,numErrors);

	printf("Results:\n");
	for (int idx = 0; idx < size; idx++)
	{
		printf("address:%x DDR3[%d]=%x\n",&memPtr[idx],idx,memPtr[idx]);
	}

	return 0;
}

mode=0为根据idx的奇偶性决定写入指针所指的地址的值。我们写了十个。testBench运行结果为:

 

 

 

未完

 

 

 

 

 

 

你可能感兴趣的:(FPGA)