XDMA ip core的使用
Posted luxinshuo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XDMA ip core的使用相关的知识,希望对你有一定的参考价值。
XDMA核的使用
一、 XDMA相关知识
绝对地址就是物理地址=段地址*16+偏移地址,也就是段地址<<4+偏移地址
主机host通过PCIe接口访问DMA,DMA即外部设备不通过CPU而直接与系统内存(DDR)交换数据。
PIO模式下硬盘和内存之间的数据传输是通过CPU来控制的,而在DMA模式下,CPU只需向DMA控制下达命令,让DMA来控制数据的发送,数据传送完毕后再把数据反馈给CPU,这样很大程度上减轻了 CPU的资源占有率。
DMA和PIO模式的区别就在于,DMA模式不过分依赖CPU,可以大大的节省系统资源,二者在传输速度上的差异并不明显。
PIO模式:CPU通过执行端口IO指令来进行数据读写的交换方式。CPU占有率高。
在例程中数据传输使用XDMA方式,与DMA相同,CPU通过向DMA发送指令完成数据的读写。
读写部分分为两种,一种是数据的读写,另一种数配置数据的读写,在数据读写部分,DMA通过MIG控制DDR完成数据读写。配置数据读写通过与BRAM通过AXI-lite总线连接完成,XDMA将PCIe配置信息存在BRAM,在进行配置信息读写时,将传入主机映射到用户逻辑的地址,然后与偏移地址处理(物理地址=段地址<<4+偏移地址),所以在bram设置时需要将其偏移地址设置的与主机地址映射的偏移地址相同。
对于DDR则不必,设置的话还减少了可使用的内存空间,只是一个袋子,写在哪里就从哪里读取即可,必须设置为0。
XDMA ip core的配置:
1、 Basic
Functional mode:功能模式,即DMA模式。
Mode:模式,选择basic即可,basic与advanced的区别在于advanced模式开放更多的可选选项与功能,basic的话为默认。
Device/Port Type:选择设备与端口类型,为端点设备。
PCIe Block Location:从可用的集成块中选择,以启用生成特定位置的约束文件和输出,产品能够pg054datasheet截取的位置说明P249。
Lane width:通道宽度,根据接口进行选择。
AXI Address width:AXI地址宽度选择,只支持64bit(用户手册73页)。
AXI Data Width:AXI总线上传输的数据宽度,可以是64bit、128bit、256bit、512bit(这个只有ultrascale+可以满足,一分钱一分货),根据datasheet进行配置即可P249,见下图。
DMA Interface option:DMA的接口类型用于数据传输,有两种AXI MM(memory mapped)与AXI ST(stream),二选一。
PCIe ID:
见之前推送。
PCIe BARs:
PCIe to AXI Lite Master Interface:使能,这样可以在主机一侧通过PCIe来访问用户逻辑侧寄存器或者其他AXI-Lite总线设备。
此处将配置信息存储到BRAM,通过AXI-lite总线读写Bram。
(1)、BAR为32bit,不使能64bit,prefetchable表示预读取,不使能。
(2)、映射空间选择1M,大小随意。
(3)、PCIe to AXI Translation:主机侧BAR地址与用户逻辑侧地址不同,通过设置转换地址实现BAR地址到AXI地址的转换。比如主机一侧BAR地址为0,则主机访问BAR地址0转换到AXI-Lite总线就是0x8000_0000.
PCIe to DMA Interface:数据传输宽度64bit,DMA控制器一般只支持数据8字节对齐的情况。
当数据从上位机通过PCIe接口发送到端点设备,XDMA内部自行解包对将数据与指令进行分析,得到读写操作的指令地址,并对DDR进行读写操作。操作的结果通过AXI接口返回XDMA,XDMA对数据进行组包,之后通过物理层发出,实现数据的DMA控制。
二、上位机设计
2.1 h2c_transfer函数
该函数的作用是向DDR中写入数据,写入大小固定的数据,根据写入时间计算传输的速度(MB/s)。
1、变量定义
Double型变量bd,用于寄存传输速度。
Double型变量time_sec,用于保存传输定量数据所需时间。
LARGE_INTEGER型变量变量start和stop用于保存频率计数值。还有freq,用于保存机器内部计时器的时钟频率。
2、函数操作
2.1 获取传输所需时间
获取传输所需时间,则需要三个量:机器时钟频率,传输开始前后计数器的计数值。
获取机器内部计时器的时钟
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&start);
…… //数据传输
QueryPerformanceCounter(&stop);
头文件为<Windows.h>,函数原型为:
BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
BOOL QueryPerformanceCounter (LARGE_INTEGER *lpCount);
在定时前先调用QueryPerformanceFrequency函数获得机器内部计时器的时钟频率,然后在严格计时的时间发生前后调用QueryPerformanceCounter函数,获得两次计数的差值经过转换得到事件耗费的精准时间。
LARGE_INTEGER为一个typedef定义的变量,其原型为:
typeef union _ LARGE_INTEGER
{
struct
{
DWORD LowPart;
LONG HighPart;
};
LONGLONG QuadPart;
} LARGE_INTEGER;
2.2 数据写入操作
使用的是自定义的write_device()函数,操作语句为:write_device(h2c0_device,FPGA_DDR_START_ADDR+0x20000000,size,h2c_align_mem_tmp);四个参数分别为:设备句柄,传输目的地址,传输的数据大小(单位为字节),写入数据的缓存区地址。
在write_device函数中,重点是变量与函数语句:
变量:
DWORD wr_size:用于保存写入的字节数
unsigned int transfers;传输次数,每次传输的最大字节数为0x800000,也就是8MB,根据要传输的字节数计算所需传输的次数。
函数语句:
数据的写入通过WriteFile()函数完成,操作语句为WriteFile(device, (void *)(buffer+i*MAX_BYTES_PER_TRANSFER), MAX_BYTES_PER_TRANSFER, &wr_size, NULL),传入参数分别为:系统文件句柄,写入数据的存储地址,每次传输的字节数,成功写入的字节数。
WriteFile()函数的返回值为bool类型,操作成功为true,操作失败返回-1,实际写入的字节数与设定的写入字节数不同时返回-2。
在数据写入之前,需要先设置一个文件在设备的对应地址中的操作位置,FILE_BEGIN表示在文件的起始位置接收传输的数据。
unsigned int h2c_transfer(unsigned int size) { double bd=0; double time_sec; LARGE_INTEGER start; LARGE_INTEGER stop; LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&start); write_device(h2c0_device,FPGA_DDR_START_ADDR+0x20000000,size,h2c_align_mem_tmp); QueryPerformanceCounter(&stop); time_sec = (unsigned long long)(stop.QuadPart - start.QuadPart) / (double)freq.QuadPart; bd = ((double)size)/(double)(time_sec)/1024.0/1024.0; return (unsigned int)bd; }
2.3 数据读取操作
与数据写入类似,读取的起始地址为写入时的起始地址。
unsigned int c2h_transfer(unsigned int size) { double bd=0; double time_sec; LARGE_INTEGER start; LARGE_INTEGER stop; LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&start); read_device(c2h0_device,FPGA_DDR_START_ADDR+0x10000000,size,c2h_align_mem_tmp); QueryPerformanceCounter(&stop); time_sec = (unsigned long long)(stop.QuadPart - start.QuadPart) / (double)freq.QuadPart; bd = ((double)size)/(double)(time_sec)/1024.0/1024.0; return (unsigned int)bd; }
以上是关于XDMA ip core的使用的主要内容,如果未能解决你的问题,请参考以下文章
如何使用模块化代码片段中的LeakCanary检测内存泄漏?
markdown [Apereo CAS 3.5 CORE] Apereo CAS 3.5 #CAS的核心代码片段
django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)(代码片段
django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)(代码片段