背景:之前通过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的帖子之后,我们参照他们的方法实现。
步骤实践教程(一)用HLS生成IPcore目录四
用cnnIP,记得进行接口综合,将streamIn与streamOut综合成axis数据流。然后不进行优化,直接进行c synthesis与RTL export输出IPcore
参考实践教程(三)系统搭建与烧录中的系统搭建,其目的是调用DMA,与实践教程(五)PS用MIG调用DDR中的目录三,定制7035的zynq的PS,系统
先按照(三)中搭建系统,然后,按照(五)配置PS。
结果发现linux下面编写的系统,在用单片机时打开DMA时打开就failed,我们只能查找单片机的测试例程。运用测试程序。
虽然程序卡了,没有运行完,但是万幸看到DMA已经通了,我们大致看一下测试程序中关于DMA调用的程序代码。
SDK环境下调用DMA始终无法成功,方案失败。
听取骆工建议直接学习网上调用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的调用。
我们可以在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运行结果为:
未完