一,DMA相关定义和注意事项
DMA是Direct Memory Access 的缩写,也就是内存到内存,不通过 CPU。DMA 的可以支持内存到外设、外设到内存、内存到内存的数据交互,必要时节省径多 CPU 资源。虽然 DMA 几乎不占用 CPU,但还是会占用系统总线。
1,PS通过DMA向PL写数据
 (1)调用:Xil_DCacheFlushRange(INTPTR adr, u32 len);
 (2)DMA写PL:XAXIDMA_DMA_TO_DEVICE
2,PS通过DMA从PL读数据
 (1)DMA读PL:XAXIDMA_DEVICE_TO_DMA
 (2)调用:Xil_DCacheInvalidateRange(INTPTR adr, u32 len)

3,注意事项:

DMA IP 中,需要关注的就是M_AXIS_MM2S、S_AXIS_S2MM、mm2s_introut、s2mm_introut四个IOs 其它系统自动连线。M_AXIS_MM2S、S_AXIS_S2MM为数据流总线,mm2s_introut、s2mm_introut为中断信号,可连接到PS端,在PS端编程控制处理。其中MM2S为DDR3 到 PL, S2MM为PL到DDR3。transfer size,transfer wide,burst size,transfer wide 可以理解为单次传输数据的大小,串口来比较的话,串口一次只能传一个字节,而DMA则可以选择一次能传输的数据大小。在这基础上的transfer size则是传输的次数,而不是单纯总大小,也就是DMA传输总长度实际上是transfer size 乘上 transfer wide。burst size 是乘以DMA内部缓存大小。DMA传输目的是内存memory时,DMA会先读取数据到缓存,再传入或传出。
4,scatter-gather
DMA操作必须是连续的物理内存,在实际应用中难免会遇到处理物理内存,不连续的数据的情况,scatter-gather 指的就是把不连续的数据拷贝到连续的 buffer 中的操作。返个操作过程可以用软件实现,也有直接的硬件支持,这里主要是强调 DMA 操作必项是连续的物理内存这件事。

5,参数对齐

(1)地址addr对齐的示例代码举例

    const u32 CACHE_LINE = 64U;u32 adr = (u32)malloc(DMA_LENGTH + 2*CACHE_LINE);//对齐CACHE_LINEadr += CACHE_LINE;adr &= ~(CACHE_LINE - 1U);g_txDma_mgr.orig_ptr =(u8*) adr;

(2)数据长度len对齐的示例代码举例

//从DDR更新DCache
if(g_tcp_mgr.total_byte_num % CACHE_LINE>0)
{ dcacheInvalidLen = (g_tcp_mgr.total_byte_num / CACHE_LINE + 1)*CACHE_LINE;
}
else
{ dcacheInvalidLen = (g_tcp_mgr.total_byte_num ;
}Xil_DCacheInvalidateRange((INTPTR)g_rxDma_mgr.orig_ptr, dcacheInvalidLen);

4,DMA与Dcache一致性问题解决

CPU <——>  Dcache  <——>  DDR3  <——>  XDMA <——>  Stream FIFO(PL)

在无操作系统ZYNQ应用中,Dcache技术的应用的优点是提高CPU访问DDR3内存的速率;但会带来一个潜在的问题:cache数据发生更新时,不能马上同步更新到DDR中。用DMA进行数据传输时,需要解决DCache(Data Cache)和DDR Memory之间的数据一致性问题。调用Xil_DCacheInvalidateRange(INTPTR adr, u32 len)时,地址adr和长度len必须和CacheLine的长度对齐(A9的CacheLine=32字节,A53的是64字节)。

如果首地址/尾地址没有和CacheLine对齐,数据会出错,原因是:

Xil_DCacheInvalidateRange函数内部会先把未对齐的首地址/尾地址对应的CacheLine先Flush到DDR里,导致DDR里的数据被覆盖出错。

例如:CPU拟通过Dcache间接读取DDR3内存起始地址为0x0010_0000,长度为0x100,共计256个数据;该起始地址处开始的256个数据已被PL端刚更新过,但是Dcache尚未通过PS程序进行同步更新,则CPU从当前Dcache拿到的数据就是未更新过的数据,从而造成数据交互错误。

解决办法:关闭cache或更新cache

(1):直接关闭Dcache功能;即CPU直接与DDR内存数据交互,不需要Cache的介入;该方法坏处在于降低CPU处理数据的性能,所以不建议这个方法。

(2):程序中调用函数进行更新cache

Xil_DcacheFlushRange(Address, Length) 该函数功能:将Cache关联地址的数据写入到DDR中,并把Cache里的数据清空;

Xil_DcacheInvalidRange(Address, Length)该函数功能:将当前Cache制定地址和长度的缓存的数据无效,则CPU就直接从DDR3中对应地址处获取数据。

二,vivado搭建

单个DMA每次只能发送一定量的数据,但对于数据源来说数据时源源不断产生的,所以在单个DMA单次发送完成至下一次传输期间,这段时间的数据流失了,所以采用两个DMA实现循环发送数据,防止数据丢失。自定义一个IP核用于一直产生的测试数据模拟数据源,再自定义一个IP用于切换DMA发送数据。

三,在SDK裸机进行验证

1,dma_intr.h

2,dma_intr.c

#include "dma_intr.h"
volatile int TxDone;
volatile int RxDone;
volatile int Error;int DMA_CheckData(int Length, u8 StartValue)
{u8 *RxPacket;int Index = 0;u8 Value;RxPacket = (u8 *) RX_BUFFER_BASE;Value = StartValue;
#ifndef __aarch64__Xil_DCacheInvalidateRange((u32)RxPacket, Length);
#endiffor(Index = 0; Index < Length; Index++){if (RxPacket[Index] != Value){xil_printf("Data error %d: %x/%x\r\n",Index, RxPacket[Index], Value);return XST_FAILURE;}Value = (Value + 1) & 0xFF;}return XST_SUCCESS;
}void DMA_DisableIntrSystem(XScuGic * IntcInstancePtr,u16 TxIntrId, u16 RxIntrId)
{
#ifdef XPAR_INTC_0_DEVICE_IDXIntc_Disconnect(IntcInstancePtr, TxIntrId);XIntc_Disconnect(IntcInstancePtr, RxIntrId);
#elseXScuGic_Disconnect(IntcInstancePtr, TxIntrId);XScuGic_Disconnect(IntcInstancePtr, RxIntrId);
#endif
}
static void DMA_TxIntrHandler(void *Callback)
{u32 IrqStatus;int TimeOut;XAxiDma *AxiDmaInst = (XAxiDma *)Callback;IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DMA_TO_DEVICE);XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DMA_TO_DEVICE);if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { return; }if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)){Error = 1;XAxiDma_Reset(AxiDmaInst);TimeOut = RESET_TIMEOUT_COUNTER;while (TimeOut){if (XAxiDma_ResetIsDone(AxiDmaInst)) { break; }TimeOut -= 1;}return;}if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {TxDone = 1;}
}
static void DMA_RxIntrHandler(void *Callback)
{u32 IrqStatus;int TimeOut;XAxiDma *AxiDmaInst = (XAxiDma *)Callback;IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA);XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DEVICE_TO_DMA);if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {return;}if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)){Error = 1;XAxiDma_Reset(AxiDmaInst);TimeOut = RESET_TIMEOUT_COUNTER;while (TimeOut){if(XAxiDma_ResetIsDone(AxiDmaInst)){break;}TimeOut -= 1;}return;}if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {RxDone = 1;}
}
int DMA_Setup_Intr_System(XScuGic * IntcInstancePtr,XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId)
{int Status;XScuGic_SetPriorityTriggerType(IntcInstancePtr, TxIntrId, 0xA0, 0x3);XScuGic_SetPriorityTriggerType(IntcInstancePtr, RxIntrId, 0xA0, 0x3);Status = XScuGic_Connect(IntcInstancePtr, TxIntrId,(Xil_InterruptHandler)DMA_TxIntrHandler,AxiDmaPtr);if (Status != XST_SUCCESS) {return Status;}Status = XScuGic_Connect(IntcInstancePtr, RxIntrId,(Xil_InterruptHandler)DMA_RxIntrHandler,AxiDmaPtr);if (Status != XST_SUCCESS) {return Status;}XScuGic_Enable(IntcInstancePtr, TxIntrId);XScuGic_Enable(IntcInstancePtr, RxIntrId);return XST_SUCCESS;
}
int DMA_Intr_Enable(XScuGic * IntcInstancePtr,XAxiDma *DMAPtr)
{XAxiDma_IntrDisable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);XAxiDma_IntrDisable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);XAxiDma_IntrEnable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);XAxiDma_IntrEnable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);return XST_SUCCESS;
}
int DMA_Intr_Init(XAxiDma *DMAPtr,u32 DeviceId)
{int Status;XAxiDma_Config *Config=NULL;Config = XAxiDma_LookupConfig(DeviceId);if (!Config){xil_printf("No config found for %d\r\n", DeviceId);return XST_FAILURE;}Status = XAxiDma_CfgInitialize(DMAPtr, Config);if (Status != XST_SUCCESS){xil_printf("Initialization failed %d\r\n", Status);return XST_FAILURE;}if(XAxiDma_HasSg(DMAPtr)){xil_printf("Device configured as SG mode \r\n");return XST_FAILURE;}return XST_SUCCESS;
}

3,main.c

#include "dma_intr.h"
#include "sys_intr.h"
static XScuGic Intc;
static  XAxiDma AxiDma;
volatile u32 success;
char oled_str[16]="";
int Tries = NUMBER_OF_TRANSFERS;
int i,Index;
u8 *TxBufferPtr= (u8 *)TX_BUFFER_BASE;
u8 *RxBufferPtr=(u8 *)RX_BUFFER_BASE;
u8 Value;
int axi_dma_test()
{int Status;TxDone = 0;RxDone = 0;Error = 0;xil_printf("\r\n----DMA Test----\r\n");for(i = 0; i < Tries; i ++){Value = TEST_START_VALUE + (i & 0xFF);for(Index = 0; Index < MAX_PKT_LEN; Index ++){TxBufferPtr[Index] = Value;Value = (Value + 1) & 0xFF;}Xil_DCacheFlushRange((u32)TxBufferPtr, MAX_PKT_LEN);Status = XAxiDma_SimpleTransfer(&AxiDma,(u32) RxBufferPtr,MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);if (Status != XST_SUCCESS){return XST_FAILURE;}Status = XAxiDma_SimpleTransfer(&AxiDma,(u32) TxBufferPtr,MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE);if (Status != XST_SUCCESS){return XST_FAILURE;}success++;TxDone = 0;RxDone = 0;if (Error){xil_printf("Failed test transmit%s done, ""receive%s done\r\n", TxDone? "":" not",RxDone? "":" not");goto Done;}Status = DMA_CheckData(MAX_PKT_LEN, (TEST_START_VALUE + (i & 0xFF)));if (Status != XST_SUCCESS){xil_printf("Data check failed\r\n");goto Done;}}xil_printf("AXI DMA interrupt example test passed\r\n");xil_printf("success=%d\r\n",success);DMA_DisableIntrSystem(&Intc, TX_INTR_ID, RX_INTR_ID);
Done:xil_printf("--- Exiting Test --- \r\n");return XST_SUCCESS;
}
int init_intr_sys(void)
{DMA_Intr_Init(&AxiDma,0);//initial interrupt systemInit_Intr_System(&Intc); // initial DMA interrupt systemSetup_Intr_Exception(&Intc);DMA_Setup_Intr_System(&Intc,&AxiDma,TX_INTR_ID,RX_INTR_ID);//setup dma interrpt systemDMA_Intr_Enable(&Intc,&AxiDma);
}
int main(void)
{init_intr_sys();axi_dma_test();
}

四,DMA linux驱动:详细内容参考下面这篇博客

ZYNQ DMA linux设备驱动详解_wangjie36的博客-CSDN博客

1,DMA框架示意图:

DMA controller 框架抽象出channel对应DMA的物理通道,也定义了虚拟的channel,软件可以实现多个虚拟 channel 对应一个物理通道。

2,DMA controller 框架中主要涉及到的数据结构:

channels:链表头。cap_mask:表示 controller 的传输能力,需要后面 device_prep_dma_xxx 形式的回调函数对应。

常见形式函数如下:
DMA_MEMCPY:可运行memory copy。
DMA_MEMSET:可运行 memory set。
DMA_SG:可进行scatter list 传输。
DMA_CYCLIC:可进行 cyclic 类的传输。
DMA_INTERLEAVE:可进行交叉传输。
src_addr_widths:表示 controller 支持哪些宽度的 src类型。
dst_addr_widths:表示 controller 支持哪些宽度的 dst 类型。
directions:表示 controller 支持的传输方向取值参考构枚举 dma_transfer_direction。
max_burst:最大的 burst 传输的 size。
descriptor_reuse:表示 controller 的传输描述能不能复用。
device_alloc_chan_resources:client 申请 channel 时会调用。
device_free_chan_resources:client 释放 channel 时会调用。
device_prep_dma_xxx:client 通过 dmaengine_prep_xxx 获取传输描述符时会调用。
device_config:client 调用 dmaengine_slave_configchannel 时会调用。
device_pause:client 调用 dmaengine_pause 时会调用。
device_resume:client 调用 dmaengine_resume 时会调用。
device_terminate_all:client 调用 dmaengine_terminate_xxx 时会调用。
device_issue_pending:client 调用 dma_async_issue_pending 启动传输时会调用。
DMA controller 驱动需要实现返些函数的具体处理内容,相当于字符设备框架中的 ops操作函数。

struct dma_chan定义:

struct dma_chan
{
struct dma_device *device;
dma_cookie_t cookie;
dma_cookie_t completed_cookie;int chan_id;
struct dma_chan_dev *dev;struct list_head device_node;
struct dma_chan_percpu __percpu *local;
int client_count;
int table_count;/* DMA router */
struct dma_router *router;
void *route_data;
void *private;
};

3,DMA驱动流程总结

(1)申请DMA中断。

(2)申请内存空间作为src和dts的空间。

(3)注册设备注册节点

(4)将申请到的src和dst内存空间地址的指针,映射到dma设备:ioremap。

五,添加驱动

dma驱动代码dma_driver.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <asm/irq.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>/***DMA驱动程序* **///DMA 基地址
#define DMA_S2MM_ADDR       0X40400000
#define DMA_MM2S_ADDR       0X40410000//DMA MM2S控制寄存器
volatile unsigned int  * mm2s_cr;
#define MM2S_DMACR      0X00000000//DMA MM2S状态控制寄存器volatile unsigned int * mm2s_sr;#define MM2S_DMASR       0X00000004//DMA MM2S源地址低32位
volatile unsigned int * mm2s_sa;
#define MM2S_SA         0X00000018//DMA MM2S传输长度(字节)
volatile unsigned int * mm2s_len;
#define MM2S_LENGTH     0X00000028//DMA S2MM控制寄存器
volatile unsigned int  * s2mm_cr;
#define S2MM_DMACR      0X00000030//DMA S2MM状态控制寄存器
volatile unsigned int  * s2mm_sr;
#define S2MM_DMASR      0X00000034//DMA S2MM目标地址低32位
volatile unsigned int  * s2mm_da;
#define S2MM_DA         0X00000048//DMA S2MM传输长度(字节)
volatile unsigned int  * s2mm_len;
#define S2MM_LENGTH     0X00000058#define DMA_LENGTH        524288
dma_addr_t axidma_handle;void* axidma_addr = NULL;static irqreturn_t dma_mm2s_irq(int irq,void *dev_id)
{printk("\nPs write data to fifo is over! irq=%d\n",irq);iowrite32(0x00001000,mm2s_sr);return IRQ_HANDLED;
}static irqreturn_t dma_s2mm_irq(int irq,void *dev_id)
{iowrite32(0x00001000,s2mm_sr);printk("\nps read data from fifo is over! irq=%d\n",irq);//读出了FIFO里数据触发中断return IRQ_HANDLED;
}int major;static struct class *dma_class   = NULL;
static int dma_init(void);
static void dma_exit(void);
static int dma_open(struct inode *inode,struct file *file);
static int dma_release(struct inode *inode,struct file *file);
static int dma_write(struct file *file,const char __user *buf, size_t count,loff_t *ppos);
static int dma_read(struct file *file,char __user *buf,size_t size,loff_t *ppos);/*file_operations 结构数据,沟通内核与操作系统桥梁*/static struct file_operations dma_lops={
.owner = THIS_MODULE,
.read  = dma_read,
.open  = dma_open,
.write = dma_write,
.release = dma_release,
};/** 初始化,用于module init* */static int dma_init(void)
{int err;major=register_chrdev(0,"dma_dev",&dma_lops);dma_class= class_create(THIS_MODULE,"dma_dev");device_create(dma_class,NULL,MKDEV(major,0),NULL,"dma_dev");printk("major dev number= %d\n",major);err = request_irq(61,dma_mm2s_irq,IRQF_TRIGGER_RISING,"dma_dev",NULL);printk("err=%d\n",err);err = request_irq(62,dma_s2mm_irq,IRQF_TRIGGER_RISING,"dma_dev",NULL);printk("err=%d\n",err);mm2s_cr  =  ioremap(DMA_MM2S_ADDR+MM2S_DMACR, 4);mm2s_sr  =  ioremap(DMA_MM2S_ADDR+MM2S_DMASR, 4);mm2s_sa  =  ioremap(DMA_MM2S_ADDR+MM2S_SA,    4);mm2s_len =  ioremap(DMA_MM2S_ADDR+MM2S_LENGTH,4);s2mm_cr  =  ioremap(DMA_S2MM_ADDR+S2MM_DMACR, 4);s2mm_sr  =  ioremap(DMA_S2MM_ADDR+S2MM_DMASR, 4);s2mm_da  =  ioremap(DMA_S2MM_ADDR+S2MM_DA,    4);s2mm_len =  ioremap(DMA_S2MM_ADDR+S2MM_LENGTH,4);printk("dma_init OK\n");return 0;
}/*退出 用于 module exit */static void dma_exit(void)
{unregister_chrdev(major,"dma_dev");device_destroy(dma_class,MKDEV(major,0));class_destroy(dma_class);free_irq(dma_mm2s_irq,NULL);free_irq(dma_s2mm_irq,NULL);iounmap(mm2s_cr);iounmap(mm2s_sr);iounmap(mm2s_sa);iounmap(mm2s_len);iounmap(s2mm_cr);iounmap(s2mm_sr);iounmap(s2mm_da);iounmap(s2mm_len);return ;
}//open 接口函数static int dma_open(struct inode *inode,struct file *file)
{   int err;printk("DMA open\n");axidma_addr = dma_alloc_coherent(NULL,DMA_LENGTH,&axidma_handle,GFP_KERNEL);if(axidma_addr == NULL){printk("dma_alloc_coherent error\n");return -1;}return 0;}//release 接口函数static int dma_release(struct inode *inode,struct file *file)
{printk("DMA release\n");if(axidma_addr != NULL){dma_free_coherent(NULL,DMA_LENGTH,axidma_addr,axidma_handle);}return 0;
}// write 接口函数
static int dma_write(struct file *file,const char __user *buf, size_t count,loff_t *ppos)
{unsigned int mm2s_status = 0;printk("dma write start !\n");if(count>DMA_LENGTH){printk("the number of data is too large!\n");return 0;}if(copy_from_user(axidma_addr,buf,count))return -EFAULT;iowrite32(0x00001001,mm2s_cr);iowrite32(axidma_handle,mm2s_sa);iowrite32(count,mm2s_len);mm2s_status = ioread32(mm2s_sr);while((mm2s_status&(1<<1))==0){msleep(100);mm2s_status = ioread32(mm2s_sr);}printk("write mm2s_status =0x%x\n",mm2s_status);printk("dma write is over!\n");return count;
}/** read 接口函数*DMA读取数据是按照32bit读取的* */static int dma_read(struct file *file,char __user *buf,size_t size,loff_t *ppos)
{static int flag = 0;unsigned int s2mm_status=0;printk("dma read start!\n");if(size>DMA_LENGTH){printk("the number of data is not enough!\n");return 0;}if(flag==0){iowrite32(0x00001001,s2mm_cr);iowrite32(axidma_handle,s2mm_da);iowrite32(size,s2mm_len);}s2mm_status=ioread32(s2mm_sr);while(((s2mm_status&(1<<1))==0)){msleep(100);if(signal_pending(current)){flag = 1;return 0;}printk("~~~~~~~~~~~~~~\n");s2mm_status=ioread32(s2mm_sr);}printk("s2mm_sr=0x%x\n",s2mm_status);flag = 0;printk("+++++++++++++++++++\n");if(copy_to_user(buf,axidma_addr,size))return -EFAULT;printk("\ndma read is over!\n");return size;
}module_init(dma_init);module_exit(dma_exit);MODULE_AUTHOR("TEST@dma");MODULE_DESCRIPTION("dma driver");MODULE_ALIAS("dma linux driver");MODULE_LICENSE("GPL");

Makefile文件:

KDIR=/home/alinx/Downloads/dma_7010/dma_linux/build/tmp/work/plnx_arm-xilinx-linux-gnueabi/linux-xlnx/4.9-xilinx-v2017.4+git999-r0/linux-xlnx-4.9-xilinx-v2017.4+git999PWD := $(shell pwd)CC     = $(CROSS_COMPILE)gccARCH =armMAKE =makeobj-m:=dma_driver.omodules:$(MAKE) -C $(KDIR) ARCH=$(ARCH) CROSS_COMPLE=$(CROSS_COMPILE) M=$(PWD) modulesclean:make -C $(KDIR) ARCH=$(ARCH) CROSS_COMPLE=$(CROSS_COMPILE) M=$(PWD) clean

六,设备树文件pl.dtsi:注意驱动要与这里的设备树终端号保持一致

/** CAUTION: This file is automatically generated by Xilinx.* Version:  * Today is: Thu Aug 26 20:49:09 2021*// {amba_pl: amba_pl {#address-cells = <1>;#size-cells = <1>;compatible = "simple-bus";ranges ;axi_dma_0: dma@40400000 {#dma-cells = <1>;clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_s2mm_aclk";clocks = <&clkc 15>, <&clkc 15>, <&clkc 15>;compatible = "xlnx,axi-dma-1.00.a";interrupt-parent = <&intc>;interrupts = <0 62 4>;reg = <0x40400000 0x10000>;xlnx,addrwidth = <0x20>;dma-channel@40400030 {compatible = "xlnx,axi-dma-s2mm-channel";dma-channels = <0x1>;interrupts = <0 62 4>;xlnx,datawidth = <0x20>;xlnx,device-id = <0x0>;};};axi_dma_1: dma@40410000 {#dma-cells = <1>;clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk";clocks = <&clkc 15>, <&clkc 15>, <&clkc 15>;compatible = "xlnx,axi-dma-1.00.a";interrupt-parent = <&intc>;interrupts = <0 61 4>;reg = <0x40410000 0x10000>;xlnx,addrwidth = <0x20>;dma-channel@40410000 {compatible = "xlnx,axi-dma-mm2s-channel";dma-channels = <0x1>;interrupts = <0 61 4>;xlnx,datawidth = <0x20>;xlnx,device-id = <0x1>;};};};
};

六,测试文件 my_dma.c

#include <fcntl.h>#include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <string.h>#include <signal.h>#include <stdlib.h>int fd;void delay(void){int i,j;for(i=0;i<20000;i++)for(j=0;j<10000;j++);}void bibi(int n){printf("---------------n=%d\n",n);close(fd);exit(-1);}int main(int argc , char ** argv){int ret;int i=0;fd_set     rfds;struct timeval  tv;unsigned char buf[1024]={0x1,0x2,0x3,0x4,5,6,7,8,9,10,11,12,13,14};for(int k=0;k<1024;k++){buf[k]=k;} signal(SIGINT, bibi); fd = open("/dev/dma_dev",O_RDWR);if(fd<0) {printf("can not open file\n");while(1);}else {printf("open file sucuss\n");}   //ret = write(fd,buf,strlen(buf));ret = write(fd,buf,1024);printf("write ret -%d\n",ret);for(i=0;i<ret;i++){printf("%04x   ",buf[i]);}printf("\n");memset(buf,0,sizeof(buf));printf("regin to read:\n");ret = read(fd,buf,1024);printf(" xxxxxxxxxx read ret -%d\n",ret);printf("%04x   ",buf);close(fd);return 0;
}

七,测试

(1)petalinux启动打印:

(2)查看中断号

(3)加载驱动

root@dma_0827:/mnt# insmod dma_driver.ko
dma_driver: loading out-of-tree module taints kernel.
major dev number= 244
genirq: Flags mismatch irq 45. 00000001 (dma_dev) vs. 00000084 (xilinx-dma-controller)
genirq: Flags mismatch irq 46. 00000001 (dma_dev) vs. 00000084 (xilinx-dma-controller)
dma_init OK

(4)运行程序:

ZYNQ linux dma驱动及其单向读写相关推荐

  1. Linux DMA 驱动学习总结

    Linux DMA驱动构架分析 以linux2.6.32中的S3C2440驱动为例进行分析,DMA驱动所对应的源码为linux-2.6.32.2\arch \arm\mach-s3c2440\dma. ...

  2. Linux DMA驱动构架分析

    转载于: http://www.voidcn.com/blog/bcbobo21cn/article/p-5777739.html 以linux2.6.32中的S3C2440驱动为例进行分析,DMA驱 ...

  3. linux dma驱动,linux下DMA驱动测试代码

    DMA传输可以是内存到内存.内存到外设和外设到内存.这里的代码通过dma驱动实现了内存到内存的数据传输. /* Function description:When we call dmatest_re ...

  4. zynq linux内核驱动编写,【原创】Linux下驱动Zynq GPIO (Switch、button、led)

    版权声明: 本文由电子技术应用博主"cuter"发布.欢迎转载,但不得擅自更改博文内容,也不得用于任何盈利目的.转载时不得删除作者简介和作者单位简介.如有盗用而不说明出处引起的版权 ...

  5. zynq linux千兆网卡驱动,zynq linux ar8031驱动 使得支持千兆网

    使用相同的环境,目前稍好点,mii info能看到东西了: U-Boot 2018.01 (Jun 04 2020 - 02:02:40 +0000) Xilinx ZynqMP ZCU102 rev ...

  6. linux_dma驱动构架分析,s3c6410 linux DMA驱动分析

    1.static void dbg_showchan(struct s3c2410_dma_chan *chan) 通过读寄存器查看channel信息 2. static void show_lli( ...

  7. s3c 6410 DMA驱动分析

    s3c6410 linux DMA驱动分析 2010-11-08 19:23 最近准备开发DMA驱动,先对s3c6410驱动做了一些分析. 代码路径:arch\arm\plat-s3c64xx\Dma ...

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

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

  9. 米尔科技ZYNQ -Linux下的DMA驱动

    一.目标 在米尔科技的z-turn板上实现linux下的DMA驱动,同时对DMA中断进行测试. 二.分析 ZYNQ的AXIDMA有Direct Register Mode和Scatter/Gather ...

最新文章

  1. Fabric--启动网络自动
  2. (java)短时间批量访问数据库(oracle)小结
  3. android存到手机内存,android保存文件到手机内存
  4. pod中mysql配置文件修改_通过configmap更新k8s里的mysql配置文件
  5. 业务逻辑全写在sql_12306的业务逻辑很复杂么?一条SQL语句搞不定?
  6. 推荐一个看ELF文件的软件 010Editor
  7. Filter Session and Async 第三周博客
  8. JSTL的一些使用规范,坑
  9. 机械硬盘换固态硬盘重装系统
  10. android逆向笔记 -- 记一次解决飞天助手未知模拟器方法
  11. java 购物网站毕业设计_基于JavaWeb的购物网站(商城)的设计与实现(SSH,MySQL)(含录像)...
  12. 谈一下wxid转扫一扫的核心
  13. 多实践、少扯淡,生死看淡,不服就干
  14. 斯坦福的《机器学习》课程上线了
  15. 夺命雷公狗---DEDECMS----32dedecms电影网评价星星功能的实现
  16. 人工智能实验-动物识别系统
  17. 软件评测和测试国家现行标准
  18. 数值计算笔记之数值积分(一)
  19. 键盘按d就计算机,电脑为什么一按D就返回桌面?一按M也回桌面、按L直接待机了?:excle按d就返回桌面...
  20. linux 下的 wchar_t

热门文章

  1. html页面居中怎么设置,实现div标签在html页面中居中的几种方式
  2. html li span 居中,如何实现HTML span标签的居中和右对齐
  3. 叶酸偶联壳聚糖载多西他赛纳米粒(FA-CTS/DTX)纳米粒
  4. java输出和opensl,OpenSL ES范例,无java代码,纯C
  5. oracle合计去掉重复,关于oracle 去掉重复数据问题
  6. Visio 转为高质量PDF
  7. Java网络编程框架
  8. python爬朋友圈数据_利用Python爬取朋友圈数据,爬到你开始怀疑人生
  9. 人工智能发展弊端的解决方案_目前人工智能存在的问题
  10. 计算机科目三教学设计,科目三详细教案.doc