前言
- 之前使用了XILINX 提供的 DMA IP做了一个小实验,完成了PL和PS端通过DDR的方式进行数据交互,但是只能在XILINX的器件上使用,如果在一些国产FPGA板卡使用的话还需要使用的自己的IP, 幸运的是,MLK团队他们的FDMA造福无数人,代码质量比较优秀,于是在网上找到一个FDMA3.2版本的进行一个测试,完成LOOP的功能
- 既然要实现LOOP的功能就需要有一个临时存储空间来存储数据
基本图示
-
- DMA先从PS端DDR中读数据,到内部的FIFO
- DMA从PL端的FIFO读数据,到PS端DDR
- 但是这个流程不是将TX_ADDR中的数据完全存入到FIFO内,再从FIFO中将数据搬到RX_ADDR中,而是根据FIFO已有数据量来决定什么时候从PL端的FIFO读数据到PS端DDR
结果
-
PS 串口打印接口
-
检查10次
-
内存查看
-
-
波形查看
-
BD设计
-
地址分配
-
- 1:是控制UI-FDMA-DBUF-LOOP IP内部寄存器的起始地址,这个地址比较重要,因为要在SDK设计中使用,即使导出硬件描述文件后会有对应的参数的宏定义
- 2:DDR其实地址,但不代表从地址0就可以给PL端使用,因为DDR中从地址0开始有一部分是存放启动应用程序的,一般从0x100000地址开始就可以使用了
-
UI-FDMA-DBUF-LOOP IP参数
-
-
这些参数都很重要!!
-
-
uiFDMA IP参数
-
-
这里的数据位宽最大支持128bit,是因为SOC的AXI接口只支持128bit, 手册上也有说明,但没说原因,我猜测是为了使用最大突发长度增加传输效率,而且又要保证4K边界对齐
- 4K边界对齐:(AXI_DATA_width / 8) x AXI_BURST_LEN <= 4096
-
IP封装
- 自定义IP的打包和封装参考[[5-1 创建和打包AXI Interface IP]]
- M_UFDMA和S_UFDMA接口总线的封装参考[[5-3 自定义Interface BUS]]
- 自定义接口总线正确自动连线参考[[5-2 User Inteface BUS MAP]]
IP逻辑介绍
- uiFDMA IP 使用的MLK的RTL 封装单独讲
uiFDMA_DBUF_LOOP IP
- 读DDR状态机
-
-
R0_FS:为读开始信号,由PS端应用程序通过写UI-FDMA-DBUF-LOOP IP内部寄存器进行控制
-
fdma_rbusy:读忙碌信号,表示正在进行一次突发读,突发长度为IP设置参数
-
如果没有传输指定个数,继续传输,否则进入空闲态
-
这里有个点,什么时候fdma_rbusy信号拉高?
- if(fdma_wbusy == 1’b0 && W0_REQ)的时候
- W0_REQ <= (W0_rcnt > X_BURST_LEN - 2)&&(~W0_rbusy)
- W0_rcnt:是FIFO中已有的数据量,这是一个异步的过程
- X_BURST_LEN:指定的一次突发长度
- 当FIFO中的数据量大于一次突发写长度的时候就从DDR中写数据
- if(fdma_wbusy == 1’b0 && W0_REQ)的时候
-
- 写DDR状态机
-
-
W0_FS:为写开始信号,由PS端应用程序通过写UI-FDMA-DBUF-LOOP IP内部寄存器进行控制
-
fdma_wbusy:写忙碌信号,表示正在进行一次突发写,突发长度为IP设置参数
-
如果没有传输指定个数,继续传输,否则进入空闲态
-
同理,什么时候fdma_rbusy信号拉高?
- if(fdma_rbusy == 1’b0 && R0_REQ)的时候
- R0_REQ <= (R0_wcnt < X_BURST_LEN - 2)&&(~R0_wbusy)
- R0_wcnt:是FIFO中已有的数据量,这是一个异步的过程
- X_BURST_LEN:指定的一次突发长度
- 当FIFO中的数据量小于一次突发写长度的时候就从DDR中读数据
- if(fdma_rbusy == 1’b0 && R0_REQ)的时候
-
- 中断信号
- 读完成中断
- 在S_DATA2转换到S_IDLE状态的时候触发中断,表示一次完成的读结束
- 写完成中断
- 在S_DATA2转换到S_IDLE状态的时候触发中断,表示一次完成的写结束
- 读完成中断
控制寄存器
SDK开发
开发流程
主要技术栈
- 中断的使用 , 参考1-2 SDK Interrupt 测试
- 用户IP寄存器读写, 参考[4 AXI USER IP]
相关IP 参数
程序设计
#include "xparameters.h"
#include "xil_printf.h"
#include "xscugic.h"
#include "xil_exception.h"
#include <sleep.h>
/* define GIC parameters */
#define INTR_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define FDMAW_INT_ID 121U
#define FDMAR_INT_ID 122U
/* define UI_FDMA_DBUF_LOOP control interface parameters */
#define FDMA_BASE_ADDR XPAR_UIFDMA_DBUF_LOOP_0_BASEADDR // 分配给 UI_FDMA_DBUF_LOOP IP核控制接口的基地址,其实就是BD分配的地址0x00_A000_0000
#define FDMA_DBUF_REG0 FDMA_BASE_ADDR