DMA IP PS

实现DMA传输的三要素:

  1. TX_BUFFE&RX_BUFFER
  2. TX&RX channel
  3. TX&RX interrupts

一: Vivado SDK 上的c语言
对DMA ip核的调用其main()主要可以分为如下结构

main()DMA_Intr_Init()        //初始化DMAXAXIDma_Lookup Config()     //查找DMA设备XAXIDma_CfgIntialize()     //初始化DMA设备Init_Intr_System()        //初始化中断XScuGic_Lookup Config()XScuGic_CfgConfig()Setup_Intr_Exception()Xil_ExceptionInit()      //使能硬件中断Xil_ExceptionRegister Handler()     //中断注册函数DMA_setup_IntrSystem()      //设置DMA中断XScuGic_SetPriority Trigger Type()XScuGic_Connect()        //连接中断源XScuGic_Enable()DMA_Intr_Enable()        //axi_dma使能中断XAxiDma_IntrDisable()XAxiDma_IntrEnable()      //根据Xilinx的sample给出的先禁用再使能

Xilinx dma_test_bsp_xaxidma_example_simple_intr:
xilinx给出的官方用例(simple Intr模式)主要包含以下部分:

  1. main()函数
  2. CheckData()函数
  3. TxIntrHandler & RxIntrHandler 函数
  4. SetupIntrSystem及DisableIntrSystem函数

具体如下:
1.Include files及变量定义(分完全代码)

#ifndef
DDR_BASE_ADDR#warning CHECK
FOR THE VALID DDR ADDRESS IN XPARAMETERS.H, \DEFAULT SET TO 0x01000000#define
MEM_BASE_ADDR       0x01000000#else#define MEM_BASE_ADDR       (DDR_BASE_ADDR + 0x1000000)#endif#ifdef XPAR_INTC_0_DEVICE_ID#define RX_INTR_ID      XPAR_INTC_0_AXIDMA_0_S2MM_INTROUT_VEC_ID#define TX_INTR_ID      XPAR_INTC_0_AXIDMA_0_MM2S_INTROUT_VEC_ID#else#define
RX_INTR_ID      XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID#define
TX_INTR_ID      XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID#endif#define
TX_BUFFER_BASE      (MEM_BASE_ADDR + 0x00100000)#define
RX_BUFFER_BASE      (MEM_BASE_ADDR + 0x00300000)/*TX buffer与RX buffer的基地址分别定义为MEM_BASE_ADDR加上0x00100000和0x00300000的偏移量*/#define RX_BUFFER_HIGH      (MEM_BASE_ADDR + 0x004FFFFF)

在这里我们通过查看xparameters.h文件可以得到DDR的内存地址范围,我们定义的MEM_BASE_ADDR必须处在这一范围之内,笔者查看到的范围如下:

/*
Definitions for peripheral PS7_DDR_0 */#define
XPAR_PS7_DDR_0_S_AXI_BASEADDR 0x00100000#define
XPAR_PS7_DDR_0_S_AXI_HIGHADDR 0x3FFFFFFF

2.main()

int main(void){int Status;XAxiDma_Config *Config;int Tries = NUMBER_OF_TRANSFERS;int Index;u8 *TxBufferPtr;u8 *RxBufferPtr;u8 Value;TxBufferPtr = (u8 *)TX_BUFFER_BASE ;RxBufferPtr = (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;}/* Initialize DMA engine */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;}/* Set up Interrupt system  */Status = SetupIntrSystem(&Intc,&AxiDma, TX_INTR_ID, RX_INTR_ID);if (Status != XST_SUCCESS) {xil_printf("Failed intr setup\r\n");return XST_FAILURE;}/* Disable all interrupts before setup */XAxiDma_IntrDisable(&AxiDma,XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);XAxiDma_IntrDisable(&AxiDma,XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);/* Enable all interrupts */XAxiDma_IntrEnable(&AxiDma,XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);XAxiDma_IntrEnable(&AxiDma,XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);/* Initialize flags before start transfer test  */TxDone = 0;RxDone = 0;Error = 0;Value = TEST_START_VALUE;for(Index = 0; Index < MAX_PKT_LEN; Index ++) {TxBufferPtr[Index] = Value;Value = (Value + 1) & 0xFF;}/* Flush the SrcBuffer before the DMA transfer, in case
the Data Cache is enabled*/Xil_DCacheFlushRange((UINTPTR)TxBufferPtr, MAX_PKT_LEN);#ifdef __aarch64__Xil_DCacheFlushRange((UINTPTR)RxBufferPtr,MAX_PKT_LEN);#endif/* Send a packet */for(Index = 0; Index < Tries; Index ++) {Status = XAxiDma_SimpleTransfer(&AxiDma,(UINTPTR)RxBufferPtr,MAX_PKT_LEN,XAXIDMA_DEVICE_TO_DMA);if (Status != XST_SUCCESS) {return XST_FAILURE;}Status = XAxiDma_SimpleTransfer(&AxiDma,(UINTPTR) TxBufferPtr,MAX_PKT_LEN,XAXIDMA_DMA_TO_DEVICE);if (Status != XST_SUCCESS) {return XST_FAILURE;}/*Wait TX done and RX done*/while (!TxDone && !RxDone &&!Error) {/* NOP */}if (Error) {xil_printf("Failed test transmit%s done, ""receive%s done\r\n", TxDone? "":" not",RxDone? "":" not");goto Done;}/*Test finished, check data*/Status = CheckData(MAX_PKT_LEN, 0xC);if (Status != XST_SUCCESS) {xil_printf("Data check failed\r\n");goto Done;}}xil_printf("Successfully ran AXI DMA interrupt Example\r\n");/* Disable TX and RX Ring interrupts and return success */DisableIntrSystem(&Intc, TX_INTR_ID,RX_INTR_ID);Done:xil_printf("--- Exiting main() --- \r\n");return XST_SUCCESS;}

3.TxIntrHandler & RxIntrHandler 函数(二者结构功能类似,这里以TX为例)

static void TxIntrHandler(void *Callback){u32 IrqStatus;int TimeOut;XAxiDma *AxiDmaInst = (XAxiDma *)Callback;/* Read pending interrupts */IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst,XAXIDMA_DMA_TO_DEVICE);       //取出当前中断/* Acknowledge pending interrupts */XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus,XAXIDMA_DMA_TO_DEVICE);        //确认当前中断被接收/* If no interrupt is asserted, we do not do anything*/if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {return;}/** If error interrupt is asserted, raise error flag, reset the hardware to recover from the error, and return with no further processing.*/if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {Error = 1;      //设置错误标记/*Reset should never fail for transmit channel*/XAxiDma_Reset(AxiDmaInst);      //复位DMATimeOut = RESET_TIMEOUT_COUNTER;//看门狗控制复位完成等待//while (TimeOut) {if (XAxiDma_ResetIsDone(AxiDmaInst)) {break;}TimeOut -= 1;}return;}/*If Completion interrupt is asserted, then set the TxDone flag*/if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {TxDone = 1;      //中断类型为传输完成,表示tx传输结束}}

二:PYNQ里的python.lib.dma

from pynq import DefaultIP
import warningsMAX_C_SG_LENGTH_WIDTH = 26      #应大于vivado pl侧定义的width of buffer length registerclass _DMAChannel:"""Drives a single channel of the Xilinx AXI DMAThis driver is designed to be used in conjunction with the`pynq.allocate()` method of memory allocation. The channel hasmain functions `transfer` and `wait` which start and wait forthe transfer to finish respectively. If interrupts are enabledthere is also a `wait_async` coroutine.This class should not be constructed directly, instead usedthrough the AxiDMA class."""def __init__(self, mmio, offset, size, flush_before, interrupt=None):self._mmio = mmioself._offset = offsetself._interrupt = interruptself._flush_before = flush_beforeself._size = sizeself._active_buffer = Noneself._first_transfer = Trueself.start()@propertydef running(self):"""True if the DMA engine is currently running"""return self._mmio.read(self._offset + 4) & 0x01 == 0x00
#通过查阅pg021 IP AXI DMA v7.0手册得知,self._offset+4对应寄存器为MM2S_DMASR,其bit0在为0时,DMA cahnnel 处于running状态@propertydef idle(self):"""True if the DMA engine is idle`transfer` can only be called when the DMA is idle"""return self._mmio.read(self._offset + 4) & 0x02 == 0x02
#通过查阅pg021 IP AXI DMA v7.0手册得知,self._offset+4对应寄存器为MM2S_DMASR,其bit1在为1时,DMA cahnnel 处于Idle状态def start(self):"""Start the DMA engine if stopped"""if self._interrupt:self._mmio.write(self._offset, 0x1001) #向寄存器MM2S_DMACR赋值,0x1001,bit0为1时DMA = RUN,bits31-24赋值为1使能Interrupt Delay Time Outelse:self._mmio.write(self._offset, 0x0001) #为启用interrupt则正常开启DMAwhile not self.running:passself._first_transfer = Truedef stop(self):"""Stops the DMA channel and aborts the current transfer"""self._mmio.write(self._offset, 0x0000)  #DMA Stopwhile self.running:passdef _clear_interrupt(self):self._mmio.write(self._offset + 4, 0x1000)def transfer(self, array):"""Transfer memory with the DMATransfer must only be called when the channel is idle.Parameters----------array : ContiguousArrayAn xlnk allocated array to be transferred"""if array.nbytes > self._size:raise ValueError('Transferred array is {} bytes, which exceeds ''the maximum DMA buffer size {}.'.format(array.nbytes, self._size))if not self.running:raise RuntimeError('DMA channel not started')if not self.idle and not self._first_transfer:raise RuntimeError('DMA channel not idle')if self._flush_before:array.flush()self._mmio.write(self._offset + 0x18,array.physical_address)  #Direct Register Mode MM2S_SA,Source Addressself._mmio.write(self._offset + 0x28, array.nbytes)    #MM2S transfer length(Bytes)self._active_buffer = arrayself._first_transfer = Falsedef wait(self):"""Wait for the transfer to complete"""if not self.running:raise RuntimeError('DMA channel not started')while not self.idle:passif not self._flush_before:self._active_buffer.invalidate()async def wait_async(self):"""Wait for the transfer to complete"""if not self.running:raise RuntimeError('DMA channel not started')while not self.idle:await self._interrupt.wait()self._clear_interrupt()if not self._flush_before:self._active_buffer.invalidate()class DMA(DefaultIP):
def __init__(self, description, *args, **kwargs):"""Create an instance of the DMA DriverParameters----------description : dictThe entry in the IP dict describing the DMA engine"""if type(description) is not dict or args or kwargs:raise RuntimeError('You appear to want the old DMA driver which ''has been deprecated and moved to ''pynq.lib.deprecated')super().__init__(description=description)if 'parameters' in description and \'c_sg_length_width' in description['parameters']:self.buffer_max_size = \1 << int(description['parameters']['c_sg_length_width'])else:self.buffer_max_size = 1 << MAX_C_SG_LENGTH_WIDTHmessage = 'Failed to find parameter c_sg_length_width; ' \'users should really use *.hwh files for overlays.'warnings.warn(message, UserWarning)if 'mm2s_introut' in description['interrupts']:self.sendchannel = _DMAChannel(self.mmio, 0x0,self.buffer_max_size,True, self.mm2s_introut)   #基地址00h配置MM2Selse:self.sendchannel = _DMAChannel(self.mmio, 0x0,self.buffer_max_size,True)if 's2mm_introut' in description['interrupts']:self.recvchannel = _DMAChannel(self.mmio, 0x30,self.buffer_max_size,False, self.s2mm_introut)    #基地址30h配置S2MMelse:self.recvchannel = _DMAChannel(self.mmio, 0x30,self.buffer_max_size,False)bindto = ['xilinx.com:ip:axi_dma:7.1']

Fin

DMA IP PS侧c / python代码笔记相关推荐

  1. xilinx DMA IP核(一) —— loop测试 代码注释

    本篇笔记中的代码来自:米联科技的教程"第三季第一篇的DMA_LOOP环路测试" 硬件的连接如下图所示: 图:DMA Loop Block Design 橘色的线就是DMA加FIFO ...

  2. linux zynq ps dma,Zynq PS侧DMA驱动

    Linux中,驱动必然会有驱动对应的设备类型.在linux4.4版本中,其设备是以设备树的形式展现的. PS端设备树的devicetree表示如下 324 dmac_s: dmac@f8003000 ...

  3. python 通信系统仿真_深入浅出通信原理连载22-40(Python代码版)

    深入浅出通信原理Python代码版 深入浅出通信原理是陈爱军的心血之作,于通信人家园连载,此处仅作python代码笔记训练所用 陈老师的连载从多项式乘法讲起,一步一步引出卷积.傅立叶级数展开.旋转向量 ...

  4. 深入浅出通信原理连载1-21(Python代码版)

    目录 深入浅出通信原理Python代码版 连载1:从多项式乘法说起 连载2:卷积的表达式 连载3: Python计算卷积 连载4:将信号表示成多项式的形式 连载5:欧拉公式证明 理解复数 连载6:利用 ...

  5. 深入浅出通信原理连载41-70(Python代码版)

    目录 深入浅出通信原理Python代码版 码元(Symbol)详解 BPSK旋转向量理解 PSK=映射+调制 调制解调与傅里叶级数展开 矩形波的复傅立叶级数 离散谱推广到连续谱 各种有用的频谱指标 深 ...

  6. python频域三维图_深入浅出通信原理连载1-21(Python代码版)

    深入浅出通信原理Python代码版 深入浅出通信原理是陈爱军的心血之作,于通信人家园连载,此处仅作python代码笔记训练所用 陈老师的连载从多项式乘法讲起,一步一步引出卷积.傅立叶级数展开.旋转向量 ...

  7. 深入浅出通信原理(Python代码版)

    深入浅出通信原理Python代码版 深入浅出通信原理是陈爱军的心血之作,于通信人家园连载,此处仅作python代码笔记训练所用 陈老师的连载从多项式乘法讲起,一步一步引出卷积.傅立叶级数展开.旋转向量 ...

  8. 关于创建zeromq消息队列,设置和更改IP地址,远程可以访问,不只是本地链接。python代码。

    关于zeromq的创建,绑定本地,和绑定其他客户端的方法. 网上一大堆关于zmq的通信模式的介绍,包括三种类型,具体我就不在描述. 但是他们给的demo,都是创建本地作为server服务端,也作为cl ...

  9. UN Comtrade(联合国商品贸易统计数据库)数据爬取Python代码——使用动态IP

    目录 Virtual Private Network 代理服务器 测试代理IP是否生效 上一篇博文UN Comtrade(联合国商品贸易统计数据库)数据爬取Python代码讲了如何使用Python爬取 ...

最新文章

  1. [Nuxt.js]Nuxt项目启动如何跳过“Are you interested in participation?”
  2. 目前最好用的大规模强化学习算法训练库是什么?
  3. C++知识点41——运算符的重载概念与分数类实现(下)
  4. 快速解码base64和utf-8的ASCII编码和URL解码
  5. 分布式ID-数据库自增ID
  6. 汇编语言 段前缀的使用 复制内存单元数据到指定位置
  7. java 连接 oracle 10_java-连接到oracle 10g数据库时,获得IOException“...
  8. 基于JAVA+Servlet+JSP+MYSQL的学生信息管理系统
  9. 稀疏矩阵转置 java代码_三元组稀疏矩阵的快速转置
  10. MySQL数据库迁移
  11. 免费的网站地图生成器,sitemap支持xml、html、txt生成绝对站长工具必备使用教程
  12. Gradle教程--基础篇
  13. 使用Zxing及豆瓣API
  14. html动画人物走路,CSS3动画中的steps(),制作人物行走动画
  15. 缓存在日常生活中的体现
  16. VLOG的文字遮罩(利用文字显示内部)
  17. 一文搞懂 STL 中 deque 与 hashtab 的底层实现
  18. 云计算基础技术及解决方案介绍 - ZCCT考试
  19. 精品软件推荐 CCleaner中文版 好用的系统垃圾清理工具
  20. Linux journal日志文件维护

热门文章

  1. Logstash【从无到有从有到无】【L24】贡献了Java插件
  2. 傻傻分不清楚:裸纤、专线、SDH、MSTP、MSTP+、OTN、PTN、IP-RAN
  3. Linux游戏开发工具收集
  4. 谁是三国演义里最奸诈的人
  5. 护理个人简历模板范文--带具体内容
  6. [C++] 类的静态成员 (静态数据成员 和 静态成员函数)
  7. 使用CLion开发openCV——环境搭建全记录
  8. Unable to find a version of the runtime to run this application解决方法
  9. M - C语言实验——整除
  10. elementui中el-table表格根据不同的值设置单元格背景色