当前位置: 首页 > news >正文

AXI DMA

一、AXI DMA介绍

        DMA是现代计算机的重要特色之一,是硬件实现存储器与存储器之间或存储器与I/O设备之间直接进行 高速数据传输的内存技术,它允许不同速度的硬件设备进行沟通,而不需要依靠中央处理器的中断负载。 如果不用DMA搬运数据,那么中央处理器就需要从来源把每一片段的数据复制到寄存器中,这一过程一直 占用CPU的资源。当使用DMA时,CPUDMA控制器发出一个存储传输请求,当DMA控制器接收到请求就会将数据从源地址搬运到目的地址。在数据搬运过程中不占用CPU资源,CPU可以执行其它操作,当传输成时DMA以中断的方式通知CPU。为了发起传输事务,DMA 控制器必须得到以下数据:
• 源地址 — 数据被读出的地址;
• 目的地址 — 数据被写入的地址;
• 传输长度 — 应被传输的字节数。
DMA 存储传输的过程如下:
1. 处理器向 DMA 控制器发送一条 DMA 命令;
2. DMA 控制器把数据从外设传输到存储器或从存储器搬运到存储器,而让 CPU 腾出手来做其它操作;
3. 数据传输完成后,DMA 控制器向 CPU 发出一个中断,来通知处理器 DMA 传输完成。 ZYNQ 提供了两种 DMA,一种是集成在 PS 中的硬核 DMA,另一种是 PL 中使用的软核 AXI DMA IP
ARM CPU设计的过程中,已经考虑到了大量数据搬移的情况,因此在CPU中自带了一个DMA控制器 DMAC,这个DMAC驻留在PS内,而且必须通过驻留在内存中的DMA指令编程,这些程序往往由CPU运行, 因此需要部分的CPU参与。DMAC支持高达8个通道的数据传输,所以多个DMA结构的核可以挂在单个 DMAC上。DMACPL的连接是通过AXI_GP接口,这个接口最高只支持到32位数据位宽,这也限制了这种 模式下的传输速率,理论最高速率为600MB/s。这种模式不占用PL资源,但需要对DMA指令编程,会增加代码的复杂性。
        可以看到 DMA 的数据传输经 S_AXI_HP 接口(以下简称 HP 接口)。ZYNQ 拥有 4 HP 接口,提供了 ZYNQ 内最大的总带宽。每一个 HP 接口都包含控制和数据 FIFO。这些 FIFO 为大数据量突发传输提供缓冲,让 HP 接口成为理想的高速数据传输接口。对 DMA 的控制或配置通过 M_AXI_GP 接口,传输状态通过中断传达到 PS 的中断控制器。下面我们简单的介绍下 PL DMA,即 AXI DMA IP 核。

二、实验任务

        本章的实验任务是使用启明星 ZYNQ 开发板上 PL 端的 AXI DMA IP 核实现对 DDR3 中数据的读取与写入,实现环回的效果,具体流程为:PS 端产生测试数据并写入到 DDR3 中,然后 PL 端的 AXI DMA IP核从 DDR3 中读取数据,将读取到的数据存储到 AXI Stream Data FIFO 中,然后再将 AXI Stream Data FIFO中的数据写回到 DDR3 中。判断从 DDR3 中读取的数据和写入的数据是否一致。

三、整体设计框图

        由上图可知,PS 通过 M_AXI_GP0 接口将配置信息发送给 AXI DMAAXI DMA 在配置完成后即可开始工作。AXI DMA 先通过 S_AXI_HP0 接口从 DDR3 中读出数据,将读出的数据通过 MM2S 接口写入 AXIStream Data FIFO 中;在写入完成后,AXI DMA 再通过 S2MM 接口Stream Data FIFO 中读出数据,通过S_AXI_HP0 接口写入 DDR3 中。在读写结束后,PS 只需要对比 DDR3 中读出的数据和写入的数据是否一致来判断 AXI DMA 搬运数据是否成功。

四、实验过程

一、按照上述要求添加IP 

1、zynq ip,打开HP 接口

2、dma ip

3、data 缓存ip,保持默认

4、concat ip将单个信号整合成总线信号。

5、点击自动连接,全选默认

6、手动连接如下,点击验证即可

7、生成顶层文件

8、生成bit流后导出设计打开SDK

9、新建空项目并且添加源文件main.c

10、添加以下代码

 #include "xaxidma.h"#include "xparameters.h"#include "xil_exception.h"#include "xscugic.h"/************************** Constant Definitions *****************************/#define DMA_DEV_ID          XPAR_AXIDMA_0_DEVICE_ID#define RX_INTR_ID          XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID#define TX_INTR_ID          XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID#define INTC_DEVICE_ID      XPAR_SCUGIC_SINGLE_DEVICE_ID#define DDR_BASE_ADDR       XPAR_PS7_DDR_0_S_AXI_BASEADDR   //0x00100000#define MEM_BASE_ADDR       (DDR_BASE_ADDR + 0x1000000)     //0x01100000#define TX_BUFFER_BASE      (MEM_BASE_ADDR + 0x00100000)    //0x01200000#define RX_BUFFER_BASE      (MEM_BASE_ADDR + 0x00300000)    //0x01400000#define RESET_TIMEOUT_COUNTER   10000    //复位时间#define TEST_START_VALUE        0x0      //测试起始值#define MAX_PKT_LEN             0x100    //发送包长度/************************** Function Prototypes ******************************/static int check_data(int length, u8 start_value);static void tx_intr_handler(void *callback);static void rx_intr_handler(void *callback);static int setup_intr_system(XScuGic * int_ins_ptr, XAxiDma * axidma_ptr,u16 tx_intr_id, u16 rx_intr_id);static void disable_intr_system(XScuGic * int_ins_ptr, u16 tx_intr_id,u16 rx_intr_id);/************************** Variable Definitions *****************************/static XAxiDma axidma;     //XAxiDma实例static XScuGic intc;       //中断控制器的实例volatile int tx_done;      //发送完成标志volatile int rx_done;      //接收完成标志volatile int error;        //传输出错标志/************************** Function Definitions *****************************/int main(void){int i;int status;u8 value;u8 *tx_buffer_ptr;u8 *rx_buffer_ptr;XAxiDma_Config *config;tx_buffer_ptr = (u8 *) TX_BUFFER_BASE;rx_buffer_ptr = (u8 *) RX_BUFFER_BASE;xil_printf("\r\n--- Entering main() --- \r\n");config = XAxiDma_LookupConfig(DMA_DEV_ID);if (!config) {xil_printf("No config found for %d\r\n", DMA_DEV_ID);return XST_FAILURE;}//初始化DMA引擎status = XAxiDma_CfgInitialize(&axidma, config);if (status != XST_SUCCESS) {xil_printf("Initialization failed %d\r\n", status);return XST_FAILURE;}if (XAxiDma_HasSg(&axidma)) {xil_printf("Device configured as SG mode \r\n");return XST_FAILURE;}//建立中断系统status = setup_intr_system(&intc, &axidma, TX_INTR_ID, RX_INTR_ID);if (status != XST_SUCCESS) {xil_printf("Failed intr setup\r\n");return XST_FAILURE;}//初始化标志信号tx_done = 0;rx_done = 0;error   = 0;value = TEST_START_VALUE;for (i = 0; i < MAX_PKT_LEN; i++) {tx_buffer_ptr[i] = value;value = (value + 1) & 0xFF;}Xil_DCacheFlushRange((UINTPTR) tx_buffer_ptr, MAX_PKT_LEN);   //刷新Data Cache//传送数据status = XAxiDma_SimpleTransfer(&axidma, (UINTPTR) tx_buffer_ptr,MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE);if (status != XST_SUCCESS) {return XST_FAILURE;}while (!tx_done && !error) //等待AXI DMA搬运完从DDR3到AXI Stream Data FIFO的数据;//如果PS向FIFO传输出错if (error) {xil_printf("Failed test transmit%s done\r\n", tx_done ? "" : " not");goto Done;}status = XAxiDma_SimpleTransfer(&axidma, (UINTPTR) rx_buffer_ptr,MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);if (status != XST_SUCCESS) {return XST_FAILURE;}while (!rx_done && !error) //等待AXI DMA搬运完从AXI Stream Data FIFO到DDR3的数据;// 如果PS接收FIFO传过来的数据出错if (error) {xil_printf("Failed test receive%s done\r\n",rx_done ? "" : " not");goto Done;}Xil_DCacheFlushRange((UINTPTR) rx_buffer_ptr, MAX_PKT_LEN);   //刷新Data Cache//传输完成,检查数据是否正确status = check_data(MAX_PKT_LEN, TEST_START_VALUE);if (status != XST_SUCCESS) {xil_printf("Data check failed\r\n");goto Done;}xil_printf("Successfully ran AXI DMA Loop\r\n");disable_intr_system(&intc, TX_INTR_ID, RX_INTR_ID);Done: xil_printf("--- Exiting main() --- \r\n");return XST_SUCCESS;}//检查数据缓冲区
static int check_data(int length, u8 start_value)
{u8 value;u8 *rx_packet;int i = 0;value = start_value;rx_packet = (u8 *) RX_BUFFER_BASE;for (i = 0; i < length; i++) {if (rx_packet[i] != value) {xil_printf("Data error %d: %x/%x\r\n", i, rx_packet[i], value);return XST_FAILURE;}value = (value + 1) & 0xFF;}return XST_SUCCESS;
}//DMA TX中断处理函数
static void tx_intr_handler(void *callback)
{int timeout;u32 irq_status;XAxiDma *axidma_inst = (XAxiDma *) callback;//读取待处理的中断irq_status = XAxiDma_IntrGetIrq(axidma_inst, XAXIDMA_DMA_TO_DEVICE);//确认待处理的中断XAxiDma_IntrAckIrq(axidma_inst, irq_status, XAXIDMA_DMA_TO_DEVICE);//Tx出错if ((irq_status & XAXIDMA_IRQ_ERROR_MASK)) {error = 1;XAxiDma_Reset(axidma_inst);timeout = RESET_TIMEOUT_COUNTER;while (timeout) {if (XAxiDma_ResetIsDone(axidma_inst))break;timeout -= 1;}return;}//Tx完成if ((irq_status & XAXIDMA_IRQ_IOC_MASK))tx_done = 1;
}//DMA RX中断处理函数
static void rx_intr_handler(void *callback)
{u32 irq_status;int timeout;XAxiDma *axidma_inst = (XAxiDma *) callback;irq_status = XAxiDma_IntrGetIrq(axidma_inst, XAXIDMA_DEVICE_TO_DMA);XAxiDma_IntrAckIrq(axidma_inst, irq_status, XAXIDMA_DEVICE_TO_DMA);//Rx出错if ((irq_status & XAXIDMA_IRQ_ERROR_MASK)) {error = 1;XAxiDma_Reset(axidma_inst);timeout = RESET_TIMEOUT_COUNTER;while (timeout) {if (XAxiDma_ResetIsDone(axidma_inst))break;timeout -= 1;}return;}//Rx完成if ((irq_status & XAXIDMA_IRQ_IOC_MASK))rx_done = 1;
}//建立DMA中断系统
//  @param   int_ins_ptr是指向XScuGic实例的指针
//  @param   AxiDmaPtr是指向DMA引擎实例的指针
//  @param   tx_intr_id是TX通道中断ID
//  @param   rx_intr_id是RX通道中断ID
//  @return:成功返回XST_SUCCESS,否则返回XST_FAILURE
static int setup_intr_system(XScuGic * int_ins_ptr, XAxiDma * axidma_ptr,u16 tx_intr_id, u16 rx_intr_id)
{int status;XScuGic_Config *intc_config;//初始化中断控制器驱动intc_config = XScuGic_LookupConfig(INTC_DEVICE_ID);if (NULL == intc_config) {return XST_FAILURE;}status = XScuGic_CfgInitialize(int_ins_ptr, intc_config,intc_config->CpuBaseAddress);if (status != XST_SUCCESS) {return XST_FAILURE;}//设置优先级和触发类型XScuGic_SetPriorityTriggerType(int_ins_ptr, tx_intr_id, 0xA0, 0x3);XScuGic_SetPriorityTriggerType(int_ins_ptr, rx_intr_id, 0xA0, 0x3);//为中断设置中断处理函数status = XScuGic_Connect(int_ins_ptr, tx_intr_id,(Xil_InterruptHandler) tx_intr_handler, axidma_ptr);if (status != XST_SUCCESS) {return status;}status = XScuGic_Connect(int_ins_ptr, rx_intr_id,(Xil_InterruptHandler) rx_intr_handler, axidma_ptr);if (status != XST_SUCCESS) {return status;}XScuGic_Enable(int_ins_ptr, tx_intr_id);XScuGic_Enable(int_ins_ptr, rx_intr_id);//启用来自硬件的中断Xil_ExceptionInit();Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler) XScuGic_InterruptHandler,(void *) int_ins_ptr);Xil_ExceptionEnable();//使能DMA中断XAxiDma_IntrEnable(&axidma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);XAxiDma_IntrEnable(&axidma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);return XST_SUCCESS;
}//此函数禁用DMA引擎的中断
static void disable_intr_system(XScuGic * int_ins_ptr, u16 tx_intr_id,u16 rx_intr_id)
{XScuGic_Disconnect(int_ins_ptr, tx_intr_id);XScuGic_Disconnect(int_ins_ptr, rx_intr_id);
}

11、后面的可以自己添加数据流debug信号验证,这里就不演示了。

http://www.dtcms.com/a/393301.html

相关文章:

  • 1:1复刻真实场景,机器人训练不再“纸上谈兵”
  • CMake快速上手:编译、构建与变量管理(包含示例)
  • vscode配置C/C++教程(含常见问题)
  • F021 五种推荐算法之美食外卖推荐可视化系统vue+flask
  • C++学习记录(10)模板进阶
  • cesium案例:三维钢铁厂园区开发平台(附源码下载)
  • 电商开放平台API接口对比爬虫的优势有哪些?
  • SpringDoc-OpenApi 现代化 API 文档生成工具介绍+使用
  • 打造现象级H5答题游戏:《终极主题答题冒险》开源项目详解
  • 实验1.2呼吸灯实验指导书
  • 实验1.3通过for循环精确定时呼吸灯
  • 【c++】多态(一)
  • 01、Python从入门到癫狂:基础
  • uniapp 弹窗
  • 17.2 《16小时→2.3小时!多模态AI颠覆PPT制作:跨国企业实战验证》
  • MyBatis 从入门到实战:环境搭建与核心原理详解
  • 深入剖析陌讯AIGC检测算法:Transformer架构在AIGC识别中的技术创新
  • 【Ai智能客服上篇】
  • 《C++程序设计》笔记p3
  • 华为数字化转型战略框架:从“1套方法+4类场景+3个平台”的全景设计
  • Redis:主从复制与哨兵模式解析
  • 【中压选型篇】中压电源进线与变压器选型全指南:从拓扑设计到并联运行
  • 【精品资料鉴赏】数据治理咨询项目实施方案
  • 基于陌讯AIGC检测算法的局限性探讨:最大512Token输入下的长文本处理方案
  • 应用随机过程(三)
  • A/B测试:随机化与观察单位不一致,如何处理更科学
  • 树拍易购商业模式解析:创新与合规并行的数实融合样本
  • 使用递归求阶乘的和
  • HTML 结构与常用标签
  • AI 智能体开发工作流从哪些方面入手?