精华内容
下载资源
问答
  • zynq-linux-dma Petalinux 下 Zynq 平台 (ZC706) 上的用户空间 DMA 示例。 环境要求 EDK 版本 带有相应 Petalinux SDK 的 Vivado 2014.4。 硬件平台 ZC706 评估板。 硬件架构 该项目实现了一个与 PL 和 PS DDR ...
  • ZedBorad 嵌入式Linux下的DMA测试(PS+PL), 包含VIVADO工程代码,LinuxDMA测试APP源代码,Makefile文件,亲测可用。
  • zynq dma linux 配置

    2017-04-02 18:56:52
    该资源是博客中附带的资源下载链接
  • Zynq DMA Linux 驱动程序 该 Linux 驱动程序已开发为可在 Xilinx Zynq FPGA 上运行。 它是一个包装驱动程序,用于与低级 Xilinx 驱动程序 (xilinx_axidma.c) 对话,该驱动程序连接到在 Zynq FPGA 的 PL 部分中实现的...
  • Zynq中使用AXI_DMADMA向FIFO1中写入数据,PL从FIFO1中读出数据;PL向FIFO2中写入数据,当写入完成后,触发GPIO中断,控制DMA开启接收,从FIFO2中读出数据。写入数据、读出数据的开启均由VIO控制。开发环境:Vivado...
  • ZYNQ系列(十二)linuxDMA使用 文章目录ZYNQ系列(十二)linuxDMA使用前言 前言

    ZYNQ系列(十二)linux的DMA使用




    前言

    linux的DMA对于新手而言一直是一个噩梦,先不谈如何实现用户空间的零拷贝DMA传输,光是Linux环境下的DMA传输就已经感觉比较棘手,一方面是对Linux了解不够深入,另一方面则是Linux在相关的使用说明方面的确没有比较好的官方支持。

    Xilinx提供了一个AXI-DMA的IP核,其可以通过AXI-Lite进行配置,命令其从AXI高性能总线(HP)上直接的对内存数据进行读取存储,这一切在PS使用裸机时感觉是那么的简单,就如同之前在MCU上一般,调用库函数对DMA配置好起始、结束地址、传输大小及相关的即可。但是这一切到linux上则变得狰狞起来。复杂的基于DMA engine 的操作机制使得刚开始上手在zynq上使用linux系统操作AXI-DMA变得不那么简洁明了。

    而到了实际应用中,用户往往是在用户空间申请一块内存区域,想要从PL端读一些数据到这个内存区域,或者是从这块内存区域写到PL端,如果直接的使用cpu进行搬运,则会耗费大量的时间,DMA是不可或缺的。

    为了“避免”繁杂的linux下dma engine的操作,有的用户想到了是否可以只把AXI-DMA这个IP核的寄存器(挂载在AXI-Lite总线上)通过mmap的方式映射到内存中,然后像之前裸机上一样,对这块内存读写就直接配置AXI-DMA寄存器,完成了对AXI-DMA的配置操作,但是,其也不可避免的从内核空间通过copy_to_usr来拷贝数据到用户空间,在大批量的数据时,这是很缓慢的一个过程。

    幸好,有一个开源项目xilinx_axidma,实现了从用户空间使用AXI-DMA的零拷贝,并且将其封装为了库,这篇文章主要就是记录如何使用这个库的。

    开发环境

    开发板:黑金的zynq7010。
    petalinux版本:2017.4。
    vivado版本:2017.4。

    准备工作

    1. 下载dma的源码:https://github.com/bperez77/xilinx_axidma/tree/master
    2. 黑金的dma回环例程的*.HDF文件或者自己根据其他博客搭建dma硬件环境。

    petalinux工程建立

    建立工程

    根据第一章的内容,建立petalinux工程,hdf文件需要选择准备工作中第二条产生的hdf(有需要的直接评论留言给我)。

    配置内核

    1. 配置DMA

    我使用的是黑金自带的内核,我检查DMA的项都已开启,就没有动。

    如果使用自己编译的内核,可能需要查看几个CONFIG是否开启。(别的博客都这么说)

    CONFIG_CMA=y
    CONFIG_DMA_CMA=y
    CONFIG_XILINX_DMAENGINES=y
    CONFIG_XILINX_AXIDMA=y
    CONFIG_XILINX_AXIVDMA=y
    CONFIG_DMA_SHARED_BUFFER=y
    

    根据petalinux的版本不同,好像有几个配置也不需要了,自己网上看吧,我用的黑金的内核,直接Petalinux-config -c kernel,查看DMA的项都开启了,就没搭理。

    2. 配置CMA

    CMA是什么我也不知道,具体为什么配置CMA我也不知道,我只看到网上有人说没有配CMA,运行的时候会出错。
    根据其他博主的文章现在知道了。

    1. 报错如下为CMA空间不够导致的,重新设置CMA大小可解决。
      在这里插入图片描述

    2. 原因:因为transfer_file函数中对发送和接收都分配了cma空间,所以发送和接收的文件大小不能超过设置的cma空间的一半。

    3. 后面根据别人的博客出一个错误的说明。

    4. 配置方式
      在这里插入图片描述

    修改设备树

    打开设备树文件

    $  vi project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi 
    

    增加dma相关内容,这里使用的设备树的引用覆盖的方法来修改device-id。也有直接去pl.dtsi中更改的。

    &amba_pl {
    	axidma_chrdev: axidma_chrdev@0 {
    		compatible = "xlnx,axidma-chrdev";
    		dmas = <&axi_dma_0 0 &axi_dma_0 1>;
    		dma-names = "tx_channel", "rx_channel";
    	};
    };
    
    &axi_dma_0{
    	dma-channel@40400000 {
    		xlnx,device-id = <0x0>;
    	};
    	dma-channel@40400030 {
    		xlnx,device-id = <0x1>;
    	};
    };
    
    

    生成BOOT.BIN烧录

    不做过多解释。

    编译Github的DMA代码

    1. 代码路径截图如下
      在这里插入图片描述

    2. 修改config_template.mk
      将config_template.mk 名字改为confi.mk,里面内容修改如下

       第21行改为    CROSS_COMPILE = arm-linux-gnueabihf-
       第25行改为    ARCH = arm
       第35行改为    KBUILD_DIR = /home/workzc/alinx/50-dma_test/dma_test/build/tmp/work/plnx_arm-xilinx-linux-gnueabi/linux-xlnx/4.9-xilinx-v2017.4+git999-r0/linux-xlnx-4.9-xilinx-v2017.4+git999
       第41行改为    OUTPUT_DIR = outputs
      

      第35行 是petalinux-build -c kernel以后才产生的,路径可能和这个不一样,自己查找。

    3. 将include中的两个.h文件移动到driver目录中

    4. 编译驱动程序

       $ make driver
      
    5. 编译应用程序

       $ make examples
      
    6. 查看outputs文件夹,有以下文件说明安装成功。
      在这里插入图片描述

    7. 该步骤可以使用petalinux module那种方式将ko文件弄到文件系统,或者直接编译进内核,方法网上看吧。

    运行

    接下来就是挂载,运行了。

    1. 使用insmod加载模块,出现以下信息说明加载成功。
      在这里插入图片描述

    2. 运行axidma_benchmark,查看dma速率。
      在这里插入图片描述

    3. 运行axidma_transfer,回环测试。

       创建两个txt文件,1.txt和2.txt。
       在1.txt文件中胡乱输入点内容。
       运行axidma_transfer,2.txt中会出现和1.txt一样的内容。
      

    在这里插入图片描述
    在这里插入图片描述

    收工

    笔者也是小白一枚,都是按照网上别人博客来的,下面将我看到几个不错的博客贴出来,供大家欣赏。

    这几篇博客都是根据 github上的那个dma代码来做解释的。

    1. ZYNQ Linux应用层 利用 AXI DMA 进行数据传输
    该文章有错误说明,第二个错误我就碰上了,我是用自己创建的vivado工程产生的hdf,结果不中用,出了第二个问题,还没仔细分析原因。改为黑金的DMA回环的hdf好用了。

    我关于config.mk的修改来源此文章,就是他没说KBUILD_DIR = /home/osrc/Projects/zynq-mz7100fa/osrc-lab-linux-4.19/sources/kernel/ 这东西的来源是哪让我费了点功夫。

    2. ZYNQ #3 - Linux环境下在用户空间使用AXI-DMA进行传输
    该文章还有个后续#4 讲的是PS使用直接采集PL外接的ADC数据,相当不错。

    3. ZYNQ跑系统 系列(三) AXI-DMA的linux下运行
    他们都可以改了设备树,直接弄到sd卡里启动就行,我不会啊。我都是改了设备树在重新编译,重新烧录,相当麻烦,会的大佬留言教教小弟。这篇开始cma没有配置,然后改了设备树,扔SD卡里就直接用了,好神奇。

    4. Zynq7000学习 1.如何在Linux平台上运行DMA模块
    这篇是使用petalinux module 方式将ko编译文件系统了

    5. zynq操作系统:Linux驱动开发AXIDMA补充篇 多路DMA
    多路DMA的使用。

    出错集锦

    展开全文
  • 米尔科技ZYNQ -Linux下的DMA驱动

    千次阅读 2019-08-08 19:15:19
    在米尔科技的z-turn板上实现linux下的DMA驱动,同时对DMA中断进行测试。 二.分析 ZYNQ的AXIDMA有Direct Register Mode和Scatter/Gather Mode,本文使用的是Direct Register Mode。 Vivado上PL端的构造如下图所示...

    一.目标
    在米尔科技的z-turn板上实现linux下的DMA驱动,同时对DMA中断进行测试。
    二.分析
    ZYNQ的AXIDMA有Direct Register Mode和Scatter/Gather Mode,本文使用的是Direct Register Mode。
    Vivado上PL端的构造如下图所示,开启了DMA中断(PL-PS中断)。对于AXI-DMA来说,CPU通过S_AXI_LITE得出DMA地址,通过GP接口与S_AXI_相连,用于写数据,通过HP接口读入数据。
    AXI_DMA_0的物理地址为:0x4040_0000。
    在这里插入图片描述
    对于DMA的操作可以查看手册相关寄存器如下图所示。
    在这里插入图片描述
    这里就不一一说明每个寄存器的功能了,详情请查看手册或查看:
    https://www.cnblogs.com/yiwenbo/p/10500060.html

    三.代码实现
    ①驱动代码

    #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>
    /**
     *DMA驱动程序
     *
     *
     *
     *
     *
     *
     *`
     *
     * **/
    //DMA 基地址
    #define DMA_BASE_ADDR		0X40400000
    
    //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		16384
    
    dma_addr_t axidma_handle;
    volatile unsigned int * axidma_addr;
    
    //DMA interrupt functions
    static irqreturn_t dma_mm2s_irq(int irq,void *dev_id)
    {
        printk("irq=%d\n",irq);
        iowrite32(0x00001000,mm2s_sr);
        return IRQ_HANDLED;
    }
    static irqreturn_t dma_s2mm_irq(int irq,void *dev_id)
    {
        printk("irq=%d\n",irq);
        iowrite32(0x00001000,s2mm_sr);
        return IRQ_HANDLED;
    }
    int major;
    
    static struct class *dma_class   = NULL;
    static int dma_init(void);
    static int dma_exit(void);
    static int dma_open(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,
    };
    /*
     * 初始化,用于module init
     *
     * */
    static int dma_init(void)
    {
        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",major);
    
        mm2s_cr  =  ioremap(DMA_BASE_ADDR+MM2S_DMACR, 4);
        mm2s_sr  =  ioremap(DMA_BASE_ADDR+MM2S_DMASR, 4);
        mm2s_sa  =  ioremap(DMA_BASE_ADDR+MM2S_SA,    4);
        mm2s_len =  ioremap(DMA_BASE_ADDR+MM2S_LENGTH,4);
    
        s2mm_cr  =  ioremap(DMA_BASE_ADDR+S2MM_DMACR, 4);
        s2mm_sr  =  ioremap(DMA_BASE_ADDR+S2MM_DMASR, 4);
        s2mm_da  =  ioremap(DMA_BASE_ADDR+S2MM_DA,    4);
        s2mm_len =  ioremap(DMA_BASE_ADDR+S2MM_LENGTH,4);
    
    
       return 0;
    }
    /*
     *退出 用于 module exit
     *
     * */
    static int 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);
        dma_free_coherent(NULL,DMA_LENGTH,axidma_addr,axidma_handle);
    
        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 0;
    }
    /*
     *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);
    
    	//申请中断
        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);
        return 0;
    }
    /*
     * write 接口函数
     *
     * */
    static int dma_write(struct file *file,const char __user *buf, size_t count,loff_t *ppos)
    {
        int err=0;
        printk("dma write start !\n");
        if(count>DMA_LENGTH)
        {
    	printk("the number of data is too large!\n");
    	return 0;
        }
        memcpy(axidma_addr,buf,count);
        iowrite32(0x00001001,mm2s_cr);//open int & enable DMA
    
        iowrite32(axidma_handle,mm2s_sa);
    
        iowrite32(count,mm2s_len);//write transmission length and DMA start transmission
        printk("dma write is over!\n");
    
        return 0;
    }
    /*
     * read 接口函数
     *
     * */
    static int dma_read(struct file *file,char __user *buf,size_t size,loff_t *ppos)
    {
        int err=0;
        printk("dma read start!\n");
        if(size>DMA_LENGTH)
        {
    	printk("the number of data is not enough!\n");
    	return 0;
        }
    
        iowrite32(0x00001001,s2mm_cr);//open int & enable DMA
    
        iowrite32(axidma_handle,s2mm_da);
    
        iowrite32(size,s2mm_len);//write transmission length and DMA start transmission
        memcpy(buf, axidma_addr, size);
        printk("dma read is over!\n");
    
        return 0;
    }
    
    module_init(dma_init);
    module_exit(dma_exit);
    
    MODULE_AUTHOR("TEST@dma");
    MODULE_DESCRIPTION("dma driver");
    MODULE_ALIAS("dma linux driver");
    MODULE_LICENSE("GPL");
    

    ②测试代码

    #include <fcntl.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    void delay(void)
    {
        int i,j;
        for(i=0;i<20000;i++)
            for(j=0;j<10000;j++);
    }
    unsigned char array[101];
    unsigned char readarray[101];
    unsigned int  test_ary[101];
    unsigned int  test_readary[101];
    int main(int argc , char ** argv)
    {
        int fd;
        int i;
        int val=0;
    
        fd = open("/dev/dma_dev",O_RDWR);
        if(fd<0) {printf("can not open file\n");while(1);}
        else printf("open file sucuss\n");
        for(i=0;i<100;i++)
        {
    	    array[i]=i;
            test_ary[i]=i;
        }
        while(1)
        {
            delay();
            write(fd,array,100);
    	    delay();delay();delay();
    	    read(fd,readarray,100);
            delay();delay();delay();
            printf("------display readarray datas -------\n ");
            for(i=0;i<100;i++)
            {
                printf("%d ",readarray[i]);
                if((i+1)%20==0)printf(" \n");
            }
            printf("------------------------------\n");
    	    for(i=0;i<100;i++)
    	    {
    	        if(array[i]==readarray[i])val++;
    	    }
    	    printf("val = %d \n",val);
    	    printf("readarray[99]=%d\n",readarray[99]);
            printf("-------initial data -------\n");
            for(i=0;i<100;i++)
            {
                printf("%d ",test_ary[i]);
                if((i+1)%20==0)printf("\n");
            }
            delay();
            write(fd,test_ary,400);
            delay();delay();delay();
            read(fd,test_readary,400);
            delay();delay();delay();
            printf("-----display test_readary datas------\n ");
            for(i=0;i<100;i++)
            {
    	        printf("%d ",test_readary[i]);
                if((i+1)%20==0)printf(" \n");
            }
            printf("--------------------------------------\n");
            for(i=0;i<100;i++)
            {
    	        array[i]=i*2;
            }
    	    val=0;
            printf("==========================\n");
            printf("==========================\n");
        }
    
        return 0;
    }
    

    ③Makefile文件

    KDIR = /home/python/Hard_disk_21G/04-Linux_Source/Kernel/linux-xlnx
    PWD := $(shell pwd)
    CC   = $(CROSS_COMPILE)gcc
    ARCH =arm
    MAKE =make
    obj-m:=dma_driver.o
    
    modules:
    	$(MAKE) -C $(KDIR) ARCH=$(ARCH) CROSS_COMPLE=$(CROSS_COMPLE) M=$(PWD) modules
    clean:
    	make -C $(KDIR) ARCH=$(ARCH) CROSS_COMPLE=$(CROSS_COMPLE) M=$(PWD) clean
    

    ④用交叉编译器生成可执行文件,放入开发板测试。
    ⑤测试结果如下:
    在这里插入图片描述
    在这里插入图片描述
    可以看到程序运行结果符合预期情况。

    展开全文
  • ZYNQ跑系统 系列(四) AXI-DMAlinux下运行

    万次阅读 多人点赞 2018-05-30 10:47:42
    AXI-DMAlinux驱动 一、搭建硬件环境 vivado版本2017.4,芯片为7010,不过不管什么版本和芯片大致步骤是一样的 硬件平台PL的搭建同ZYNQ基础系列(六) DMA基本用法,在这个工程的基础上添加SD卡(根据自己的...

    AXI-DMA的linux驱动

    一、搭建硬件环境

    vivado版本2017.4,芯片为7010,不过不管什么版本和芯片大致步骤是一样的
    本文工程文件:https://gitee.com/long_fly/AXIDMA_linux
    硬件平台PL的搭建同ZYNQ基础系列(六) DMA基本用法,在这个工程的基础上添加SD卡(根据自己的开发板硬件选择相应的引脚)
    这里写图片描述
    然后直接生成bit文件,然后记得要导出硬件(包含bit文件)进SDK

    二、生成设备树

    1.解压设备树工具文件夹到一个地方
    https://github.com/Xilinx/device-tree-xlnx下载
    2.菜单栏 –> Xilinx –> Repositories
    添加刚刚解压的位置
    这里写图片描述
    3.菜单栏 –> File –> New –> Board Support Package
    创建BSP,可以发现多了一栏device_tree,直接点确定到下一步
    这里写图片描述
    4.设置环境变量
    这里写图片描述
    内容为:console=ttyPS0,115200 root=/dev/mmcblk0p2 rw rootfstype=ext4 earlyprintk rootwait
    5.最后可以在工程文件夹中找到生成的设备树文件
    这里写图片描述
    待用

    三、生成FSBL引导文件

    1.在SDK中新建一个APP,选择FSBL模板工程,然后完成创建
    这里写图片描述
    这里写图片描述
    2.使能调试信息打印
    这里写图片描述
    添加#define FSBL_DEBUG_INFO后,保存文件,会生成FSBL.elf文件,文件待用

    四、编译u-boot

    0.具体的相关环境(不装会报错)和SDK环境安装(不装没法编译,建议去官网下载)
    参考ZYNQ跑系统 系列(一) 传统方式移植linux,不再赘述;u-boot和kernel直接在https://github.com/Xilinx下载;还有注意以下路径是我自己的,要根据实际修改相应路径
    1.linux超级用户模式,定位settings64.sh文件(在SDK安装文件夹里)
    source /opt/Xilinx/SDK/2017.1/settings64.sh
    2.进入u-boot目录(自己解压的路径)
    cd /home/hlf/mnt/u-boot-xlnx-master
    3.打开GUI配置u-boot
    make menuconfig,load预配置的文件,绝对路径为/home/hlf/mnt/u-boot-xlnx-master/configs/zynq_ax7010_defconfig
    这里写图片描述,观察了一下没什么需要修改的,直接保存并退出
    4.读配置文件(zynq_ax7010_defconfig)
    make CROSS_COMPILE=arm-xilinx-linux-gnueabi- zynq_ax7010_defconfig
    5.编译
    make CROSS_COMPILE=arm-xilinx-linux-gnueabi-
    6.查看 u-boot 文件的不同段的内存分配情况 (可以不看)
    arm-xilinx-linux-gnueabi-objdump -h u-boot
    7.修改后缀为u-boot.elf,待用
    这里写图片描述

    五、编译kernel

    1.进入kernel目录(自己解压的路径)并和之前一样定位文件
    cd /home/hlf/mnt/linux-xlnx-master
    source /opt/Xilinx/SDK/2017.1/settings64.sh
    2.打开GUI配置kernel
    make ARCH=arm menuconfig,load预配置的文件,绝对路径为/home/hlf/mnt/linux-xlnx-master/arch/arm/configs/xilinx_zynq_defconfig,这里不通过GUI方式更改配置,关闭
    3.开启DMA的相关功能
    也可以不通过GUI的方式配置kernel,这里我们直接命令行(要在超级用户模式下,不然没有权限修改):
    gedit /home/hlf/mnt/linux-xlnx-master/arch/arm/configs/xilinx_zynq_defconfig
    打开文件,确保以下选项开启(=y)

    CONFIG_CMA=y
    CONFIG_DMA_CMA=y
    CONFIG_XILINX_DMA_ENGINES=y
    CONFIG_PL330_DMA=y
    CONFIG_XILINX_DMA=y
    CONFIG_XILINX_AXIDMA=y
    CONFIG_XILINX_AXIVDMA=y
    CONFIG_DMA_SHARED_BUFFER=y

    4.读配置
    make ARCH=arm xilinx_zynq_defconfig
    5.编译内核
    make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- uImage LOADADDR=0x00008000
    6.编译完成后,命令行会提示生成的uImage的位置
    uImage拷贝出来待用
    7.生成devicetree.dtb
    将设备树文件夹拷贝到虚拟机的相应路径下
    这里写图片描述
    pl.dtsi中添加:

    axidma_chrdev: axidma_chrdev@0 {
        compatible = "xlnx,axidma-chrdev";
        dmas = <&axi_dma_0 0 &axi_dma_0 1>;
        dma-names = "tx_channel", "rx_channel";
    };

    这里写图片描述
    保存后,生成devicetree.dtb:
    ./scripts/dtc/dtc -I dts -O dtb -o /home/hlf/mnt/device_tree_bsp_0/devicetree.dtb /home/hlf/mnt/device_tree_bsp_0/system-top.dts

    六、准备运行linux

    1.生成BOOT.bin
    之前产生了FSBL.elfu-boot.elfbit文件,直接通过SDK生成BOOT.bin
    2.拷贝文件至SD卡
    将之前产生的BOOT.bindevicetree.dtbuImage拷贝到SD卡
    3.插上串口开机运行
    这里写图片描述
    确保可以运行系统

    七、编译例程

    0.下载例程
    例程下载地址:https://github.com/bperez77/xilinx_axidma或者https://gitee.com/long_fly/AXIDMA_linux
    1.拷贝例程文件夹到kernel文件夹里
    这里写图片描述
    我将文件夹命名为了extra,直接将例程文件夹的内容放到里面,如果没有权限的话,直接命令行chmod 777 文件夹名获取相应权限就可以了
    2.cd到extra文件夹里
    3.编译
    使用交叉编译链,定位到kernel(已经编译好的)的路径,编译driver:
    make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm KBUILD_DIR=/home/hlf/mnt/linux-xlnx-master/ driver
    使用交叉编译链,编译examples:
    make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm examples
    编译完成后,生成文件将出现在outputs文件夹里
    这里写图片描述
    4.将这些文件拷贝到SD卡中,开机
    5.挂载SD卡
    cd ..到达系统目录
    mount /dev/mmcblk0p1 /mnt挂载SD卡
    cd /mnt进入SD目录
    insmod axidma.ko载入刚刚生成的模块
    这里写图片描述
    打印信息提示通道的ID冲突
    6.修改设备树中通道的ID号
    这里写图片描述
    然后按照之前的步骤重新生成devicetree.dtb,将新设备树文件拷贝到SD卡中,然后开机,挂载SD卡,加载模块
    这次没有打印信息提示ID冲突
    7.查看是否成功
    cd /dev到达dev目录
    ls查看内容
    这里写图片描述
    会发现多了一个axidma,然后运行dmesg,可以看到如下信息:
    这里写图片描述
    8.运行例程里的APP1
    这里写图片描述
    发现CMA内存不够,导致接收缓存空间申请不了这么大,在设备树文件夹中修改.dts后缀的文件,添加cma空间的申请
    这里写图片描述
    然后重新生成devicetree.dtb文件,拷贝到SD卡中,开机,挂载SD卡,加载模块,运行APP
    这里写图片描述
    可以测试收发通道的数据速率
    9.运行例程里的APP2
    在SD卡中新建两个文本,在其中一个文本文件中写入内容,另一个为空
    这里写图片描述
    运行应用程序,将文件1的内容通过DMA环路写入文件2,因为文件太小了,所以显示的是0.00Mb
    这里写图片描述
    运行结束后打开文件2,会发现和文件1里的内容完全一致

    八、代码分析与修改及应用到VDMA

    ……

    展开全文
  • Zynq-linux PL与PS通过DMA数据交互

    千次阅读 多人点赞 2019-10-04 10:39:55
    在米尔科技的z-turn板上,采用AXI DMA 实现zynq的PS与PL数据交互。 二、分析 ①PS数据传PL 驱动中的测试程序中给出一堆数据,通过DMA传输到AXI4-Stream Data FIFO ,PL端从DATA FIFO中把数据读出来。 ②PL数据传...

    一、目标
    在米尔科技的z-turn板上,采用AXI DMA 实现zynq的PS与PL数据交互。
    二、分析
    ①PS数据传PL
    驱动中的测试程序中给出一堆数据,通过DMA传输到AXI4-Stream Data FIFO ,PL端从DATA FIFO中把数据读出来。
    ②PL数据传PS
    将PS传入PL的数据回传,在PS端显示出数据,最后将数据乘2再送入DMA。
    ③PL端代码思路
    1)读数据
    在加上DATA FIFO的情况下,PL从DATA FIFO中读取数据。将DATA -FIFO的M_AXIS端引出,得到下面的信号。

    信号名称作用方向
    m_axis_tvalid主机向从机发数据的信号声明,置1表示主机有数据要发向从机。输出
    m_axis_tready主机判断从机是否准备好接收数据,当为1时表示从机准备好接收数据。输入
    m_axis_tdata主机将要发送的数据。输出
    m_axis_tkeep主机发送数据时需拉高。输出
    m_axis_tlast表示主机发送是否是最后一个数据,置1时表示主机正在发送最后一个数据。输出

    从上表可以看出,DATA FIFO接收完数据后,想要从FIFO中读取数据,靠的就是上面5根线,FIFO作主机,PL端作从机。所以FIFO会自动将m_axis_tvalid置1,表明可以从主机中读取数据。PL只需要给出回应m_axis_tready置1,便可以在时钟上升沿来临时读取数据。
    同时,AXI-DMA将PS数据传输完成后有完成标志mm2s_introut置1。通过这个标准来确定是否从FIFO中读取数据。所以这个信号用于PL中断的触发信号。
    2)写数据
    将PL读取出来的数据进行乘2,再传入PS,PS再将数据打印出来。PL端接的是AXI-DMA的S_AXIS_S2MM端口。其信号如下:

    信号名称作用方向
    s_axis_s2mm_tdata从机接收数据线输入
    s_axis_s2mm_tkeep数据有效信号线输入
    s_axis_s2mm_tlast是否最后一个数据输入
    s_axis_s2mm_tready从机准备是否准备好接收数据输出
    s_axis_s2mm_tvalid主机是否有数据发向从机输入

    从信号列表可以看出,此时DMA端口是作从机,PL端口作主机向DMA端口发送数据。PL端想发送数据,通过s_axis_s2mm_tvalid表明有数据发往从机。等待从机响应s_axis_s2mm_tready信号,响应过后便可以发送数据。发送数据时需要将s_axis_s2mm_tkeep拉高,同时当传到最后一个数据时,需要将s_axis_s2mm_tlast置1。
    3)整体架构
    在这里插入图片描述
    局部放大图:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    三、代码实现
    ①pl_read.v

    module pl_read(
    clk,
    rst,
    
    m_axis_tvalid,
    m_axis_tdata,
    m_axis_tkeep,
    m_axis_tlast,
    m_axis_tready,
    
    m_ready,
    m_data,
    m_datavalid,
    m_datalast
    );
    input clk;
    input rst;
    
    input m_axis_tvalid;
    input [31:0]m_axis_tdata;
    input [3:0]m_axis_tkeep;
    input m_axis_tlast;
    output m_axis_tready;
    
    input m_ready;
    output [31:0]m_data;
    output m_datavalid;
    output m_datalast;
    
    reg m_axis_tready;
    reg [31:0]m_data;
    reg m_datavalid;
    reg m_datalast; 
    always@(posedge clk or negedge rst)
    begin
        if(!rst)
        begin
            m_axis_tready <= 0;
            m_data <= 0;
            m_datavalid <= 0;
            m_datalast <= 0;
        end
        else
        begin
            if(m_ready==1)
            begin
                m_axis_tready <= 1;
                if(m_axis_tvalid==1&&m_axis_tkeep==4'b1111)
                begin
                    m_data <= m_axis_tdata;
                    m_datavalid <= 1;
                    if(m_axis_tlast==1) m_datalast <= 1;
                    else m_datalast <= 0;
                end
                else
                begin
                    m_data <= m_data;
                    m_datavalid <= 0;
                    m_datalast <= 0;
                end
            end
            else
            begin
                m_axis_tready <= 0;
                m_data <= m_data;
                m_datavalid <= 0;
                m_datalast <= 0;
            end
        end
    end
    
    endmodule
    

    ②pl_write.v

    module pl_write(
    clk,
    rst,
    
    s_data,
    s_datavalid,
    s_datalast,
    s_ready,
    
    s_axis_tdata,
    s_axis_tkeep,
    s_axis_tlast,
    s_axis_tready,
    s_axis_tvalid
    );
    input clk;
    input rst;
    
    input[31:0] s_data;//data stream
    input s_datalast;//data last flag
    input s_datavalid;//input data valid flag
    output s_ready;//数据可以写入标志
    
    input s_axis_tready;
    output[31:0] s_axis_tdata;
    output[3:0]s_axis_tkeep;
    output s_axis_tlast;
    output s_axis_tvalid;
    
    reg [31:0] s_axis_tdata;
    reg [3:0]s_axis_tkeep;
    reg s_axis_tlast;
    reg s_axis_tvalid;
    reg s_ready;
    
    always@(posedge clk or negedge rst)
    begin
        if(!rst)
        begin
            s_axis_tkeep <= 4'b0000;
            s_axis_tvalid <= 0;
            s_axis_tdata <= 0;
            s_axis_tlast<=0;
            s_ready <= 0;        
        end
        else
        begin
           if(s_axis_tready==1)
            begin
                if(s_datavalid==1)
                begin
                    s_axis_tvalid <= 1;
                    s_axis_tkeep <= 4'b1111;
                    s_axis_tdata <= s_data;
                    if(s_datalast)s_axis_tlast <= 1;
                    else s_axis_tlast <= 0;
                end
                else 
                begin
                    s_axis_tvalid <= 0;
                    s_axis_tkeep <= 4'b0000;
                    s_axis_tdata <= s_axis_tdata;
                    s_axis_tlast<=0;
                end
                s_ready <= 1;
            end
            else 
            begin
                s_axis_tkeep <= 4'b0000;
                s_axis_tvalid <= 0;
                s_axis_tdata <= s_axis_tdata;
                s_axis_tlast<=0;
                s_ready <= 0;
            end
        end
    end
    
    endmodule
    

    ③top.v

    module top(
    );
    wire clk;
    wire rst;
    
    wire m_axis_tvalid;
    wire [31:0]m_axis_tdata;
    wire [3:0]m_axis_tkeep;
    wire m_axis_tlast;
    wire m_axis_tready;
    
    wire m_ready;
    wire [31:0]m_data;
    wire m_datavalid;
    wire m_datalast;
    
    wire s_axis_tready;
    wire[31:0] s_axis_tdata;
    wire[3:0]s_axis_tkeep;
    wire s_axis_tlast;
    wire s_axis_tvalid;
    
    pl_write u1(
    .clk(clk),
    .rst(rst),
    
    .s_data(m_data),
    .s_datalast(m_datalast),
    .s_datavalid(m_datavalid),
    .s_ready(m_ready),
    
    .s_axis_tready(s_axis_tready),
    .s_axis_tdata(s_axis_tdata),
    .s_axis_tkeep(s_axis_tkeep),
    .s_axis_tlast(s_axis_tlast),
    .s_axis_tvalid(s_axis_tvalid)
    );
    pl_read u2(
    .clk(clk),
    .rst(rst),
    
    .m_data(m_data),
    .m_datalast(m_datalast),
    .m_datavalid(m_datavalid),
    .m_ready(m_ready),
    
    .m_axis_tready(m_axis_tready),
    .m_axis_tdata(m_axis_tdata),
    .m_axis_tkeep(m_axis_tkeep),
    .m_axis_tlast(m_axis_tlast),
    .m_axis_tvalid(m_axis_tvalid)
    );
    system_wrapper u3(
    .FCLK_CLK0(clk),
    .peripheral_aresetn(rst),
    .s_axis_aclk(clk),
    .s_axis_aclk_1(clk),
    .s_axis_aresetn(rst),
    .s_axis_aresetn_1(rst),
    
    .s_axis_tready(s_axis_tready),
    .s_axis_tdata(s_axis_tdata),
    .s_axis_tkeep(s_axis_tkeep),
    .s_axis_tlast(s_axis_tlast),
    .s_axis_tvalid(s_axis_tvalid),
    
    .m_axis_tready(m_axis_tready),
    .m_axis_tdata(m_axis_tdata),
    .m_axis_tkeep(m_axis_tkeep),
    .m_axis_tlast(m_axis_tlast),
    .m_axis_tvalid(m_axis_tvalid)
    );
    
    
    endmodule
    

    ④dma驱动代码

    #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>
    /**
     *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;
    volatile unsigned int * axidma_addr;
    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 int dma_exit(void);
    static int dma_open(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,
    };
    /*
     * 初始化,用于module init
     *
     * */
    static int dma_init(void)
    {
        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",major);
    
        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);
    
       return 0;
    }
    /*
     *退出 用于 module exit
     *
     * */
    static int 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);
        dma_free_coherent(NULL,DMA_LENGTH,axidma_addr,axidma_handle);
    
        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 0;
    }
    /*
     *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);
        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);
    
    
        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;
        }
        memcpy(axidma_addr,buf,count);
    
        iowrite32(0x00001001,mm2s_cr);
        iowrite32(axidma_handle,mm2s_sa);
        iowrite32(count,mm2s_len);
    
        mm2s_status = ioread32(mm2s_sr);
        while((mm2s_status&(1<<1))==0)
        {
            mm2s_status = ioread32(mm2s_sr);
        }
        printk("mm2s_status =0x%x\n",mm2s_status);
        printk("dma write is over!\n");
    
        return 0;
    }
    /*
     * read 接口函数
     *DMA读取数据是按照32bit读取的
     * */
    static int dma_read(struct file *file,char __user *buf,size_t size,loff_t *ppos)
    {
        unsigned int s2mm_status=0;
        printk("dma read start!\n");
        if(size>DMA_LENGTH)
        {
    	printk("the number of data is not enough!\n");
    	return 1;
        }
    
        iowrite32(0x00001001,s2mm_cr);
        iowrite32(axidma_handle,s2mm_da);
        iowrite32(size,s2mm_len);
        
        s2mm_status=ioread32(s2mm_sr);
        while((s2mm_status&(1<<1))==0)
        {
            s2mm_status=ioread32(s2mm_sr);
        }
        printk("s2mm_sr=0x%x\n",s2mm_status);
        
        memcpy(buf,axidma_addr,size);
        printk("\ndma read is over!\n");
        return 0;
    }
    
    module_init(dma_init);
    module_exit(dma_exit);
    
    MODULE_AUTHOR("TEST@dma");
    MODULE_DESCRIPTION("dma driver");
    MODULE_ALIAS("dma linux driver");
    MODULE_LICENSE("GPL");
    

    ⑤测试代码

    #include <fcntl.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    void delay(void)
    {
        int i,j;
        for(i=0;i<20000;i++)
            for(j=0;j<10000;j++);
    }
    unsigned int readarray[10001];
    int main(int argc , char ** argv)
    {
        int fd;
        int i=0;
        fd = open("/dev/dma_dev",O_RDWR);
        if(fd<0) {printf("can not open file\n");while(1);}
        else printf("open file sucuss\n");
        delay();
        for(i=0;i<4000;i++)
        {
            readarray[i]=i+1;
        }
        while(1)
        {
            write(fd,readarray,4000*4);
    	if(read(fd,readarray,4000*4)==0)
    	{
    		for(i=0;i<4000;i++)
    		{
                printf(" %d",readarray[i]);
                readarray[i]=readarray[i]*2;
    		}
    		printf("\n=====================================\n");
            printf("======================================\n");
    	}
        delay();delay();
        }
    
        return 0;
    }
    

    ⑥Makefile文件

    KDIR = /home/python/Hard_disk_21G/04-Linux_Source/Kernel/linux-xlnx
    PWD := $(shell pwd)
    CC   = $(CROSS_COMPILE)gcc
    ARCH =arm
    MAKE =make
    obj-m:=dma_driver.o
    
    modules:
    	$(MAKE) -C $(KDIR) ARCH=$(ARCH) CROSS_COMPLE=$(CROSS_COMPLE) M=$(PWD) modules
    clean:
    	make -C $(KDIR) ARCH=$(ARCH) CROSS_COMPLE=$(CROSS_COMPLE) M=$(PWD) clean
    

    ⑦运行结果
    在这里插入图片描述
    在这里插入图片描述
    可以看见程序运行结果,符合预期值。
    四、调试
    在调试数据交互的过程中,遇到了很多坑。

    	第一个大坑就是在DATA-FIFO中。数据位宽设置的8bit,PL将测试数据写入DMA,PS端读出数据,发现数据变得大而且只有前面部分数据不为0,后面数据全是0,后来发现是PS端读DMA是按照字节进行读取的,而PS端读取的数据放在整形数组里面,结果导致是PL端的4个数据合成了PS端一个数据,最后导致PL端发送200个数据,结果PS端只有前50个数据有值,后面全是0。后面将PL的位宽设置为32bit,PS端读出数据就正缺了。	
    	第二大坑就是忽略了tlast信号。这块问题找了很久,最后通过慢慢测试发现了。当时在PL端发送10万个数据,PS端一次性读取10万个数据没问题,然后想测试读取少一点,结果读取一千,两千,一万个数据都可以,同时数据是正确的。到了第二次循环是就出现问题了,第二次读取的数据还是同第一次读取的数据一样。通过读取DMA状态寄存器的值,打印出来是0x4011,判断出DMA内部错误。后来调试出问题是:在传输期间没有tlast信号,所以报出DMA内部错误。再次调试,设置一万个数据给个tlast,读取2万个数据,最后发现只能读取出前面1万个数据,后面全是0,第二轮还是一样,只有前面1万个有数据,后面全是0。最后明白了DMA传输中在一次传输过程中,只能且必须有一次tlast信号,也不能读出tlast信号后的数据。
    	第三个坑就是在模块设计时,报DMA的S_AXIS_S2MM与FIFO的M_AXIS时钟不匹配,还以为是哪儿没弄对,看别人的都没问题。后来把器件全删了,先把fifo与DMA联接起来,在进行自动连线,问题就解决了。
    	第四个坑就在PL端的例化,连线上。在仿真fifo的时候,先编写一个模块与fifo对应,同时在模块里面对fifo的S_AXIS端连线,在simulation文件中将fifo的M_AXIS连线,功能仿真想观察波形,结果咋调,波形都是xxxx,AXI时序修改了又修改,还是出问题。后来发现是出现了两个fifo,一个是模块里连线的fifo,另一个是simulation里的fifo,所以就出现了波形是xxxx的情况。后面改成了,增加一个top.v在top里面进行各个模块的连线,时钟也不要在单独例化在底层模块里,全部在top里面连线,例化。
    

    五、总结
    ①每次进行DMA传输是,读取DMA状态寄存器,根据状态寄存器的值,判断是否发生DMA错误。如果发生DMA内部错误,则是由于DMA传输过程中没有收到tlast信号。
    ②PS是按字节进行读取或写入DMA的,要注意存放数据的数组的变量类型,即整形数组和字符型数组和PL端的位宽匹配好。

    展开全文
  • Zynq MPSoC 官方Linux DMA驱动调试

    千次阅读 2020-05-09 23:29:07
    Zynq MPSoC Linux官方DMA驱动调试 前言 Zynq平台下DMA驱动主要有官方在用户层控制的和某大神写的axi_dma驱动,今天主要用官方的进行测试。 环境 petalinux 19.1 vivado 19.1 开始 首先搭建逻辑,注意这里DMA用64地址...
  • zynq操作系统: Linux驱动开发AXIDMA

    千次阅读 2021-04-12 13:27:37
    先不谈如何实现用户空间的零拷贝DMA传输,光是Linux环境下的DMA传输就已经感觉比较棘手,一方面是对Linux了解不够深入,另一方面则是Linux在相关的使用说明方面的确没有比较好的官方支持。   
  • 内部教程_基于ZYNQDMA与VDMA的应用开发milian教程
  • 1,单个DMA每次只能发送一定量的数据,但对于数据源来说数据时源源不断产生的,所以在单个DMA单次发送完成至下一次传输期间,这段时间的数据流失了,所以采用两个DMA实现循环发送数据,防止数据丢失。自定义一个IP核...
  • Zynq AXIS:完整的DMA系统 此存储库包含使用Xilinx的Zynq FPGA建立基于DMA的项目所需的所有组件。 首先,有一个称为AXIS的硬件模块,可连接到高性能AXI接口端口。 其次,有一个Linux UIO驱动程序,可将低级AXIS控制...
  • 我使用的是ZYNQ芯片,在芯片中跑Linux系统,我想解决的目标是通过DMA驱动从PS端传输数据到PL端。因为DMA驱动位于设备驱动的下一层,用户模式在设备驱动的上一层;而且DMA驱动对硬件的地址有要求,必须分配连续的物理...
  • ZYNQ Linux应用层 利用 AXI DMA 进行数据传输 软件版本: VIVADO2018.2 操作系统: Debian 9 硬件平台: ZYNQ-MZ7100FA 嵌入式操作系统:Debian(4.19.0-xilinx) AXI-DMA驱动:GitHub:bperez77/xilinx_axidma 一、...
  • Zynq-Linux-DMA-master

    2018-01-23 17:25:32
    DMA enabled Zynq PS-PL communication to implement high throughput data transfer between Linux applications and user IP core. (based on Xilinx UG873 chapter 6) This is a simple loop-back project in ...
  • AXI-DMAlinux驱动 一、搭建硬件环境 vivado版本2017.4,芯片为7010,不过不管什么版本和芯片大致步骤是一样的 本文工程文件: https://gitee.com/long_fly/AXIDMA_linux 硬件平台PL的搭建同 ZYNQ基础系列...
  • zynq PS侧DMA驱动

    万次阅读 2016-06-19 23:16:10
    linux中,驱动必然会有驱动对应的设备类型。在linux4.4版本中,其设备是以设备树的形式展现的。 PS端设备树的devicetree表示如下 324 dmac_s: dmac@f8003000 { 325 compatible = "arm,pl330", "arm,primecell"; ...
  • ZYNQ PCIe-DMA源码 例程 PS-PL交互 linux/裸机 verilog C/C++ZYNQ PCIe-DMA的实现过程一、概述二、基础知识三、系统总框架四、工作原理与工作模式五、接口时序六、资源使用情况七、PS-PL交互以及测试程序 ZYNQ PCIe-...
  • ZynqMP SOC是xilinx公司推出的面向AI应用(如:云计算、边缘计算)、高度灵活、高性能的处理器系列,我们选择它作为产品的处理器...本文简要说明在基于Zynq MPSOC的产品开发中,如何在Linux的用户面实现AXI DMA传输。
  •   上一篇的一路双通道DMA的正常收发已经成功实现了,但是实际使用的时候大概率会挂载多路dma,那么我们调用的这个模块能不能支持多路的dma便是第一个要解决的问题   首先阅读初始化部分的代码,自然有了第一个...
  • 本文的部分内容可能来源于网络,该内容归原作者所有,如果侵犯到您的权益,请及时通知我,我将立即删除,...欢迎加入zynq-arm-linux提高交流群:788265722 文档错误可能很多,大家多包涵,主要理解文件的目的就好...
  • ZYNQ DMA linux设备驱动详解

    千次阅读 2020-03-23 00:20:30
    1) 定义struct dma_device 发量并初始化、根据硬件实现必要的回掉函数。 2) 根据 controller 支持的 channel 数,为每个 channel 定义一个 struct dma_chan 发量并初始化后,将每个 channel 都添加到 dma_device 的 ...
  • zynqMP axi-dma详解

    千次阅读 2019-06-27 18:09:59
    AXIDMA: 1.基本介绍 官方解释是为内存与AXI4-Stream外设之间...在ZYNQ中,AXIDMA就是FPGA访问DDR3的桥梁,不过该过程受ARM的监控和管理。 如图1所示,AXIDMA IP有6个接口,S_AXI_LITE是ARM配置dma寄存器的接口...
  • ZYNQ #3 - Linux环境下在用户空间使用AXI-DMA进行传输

    千次阅读 多人点赞 2019-05-15 11:20:44
    本文使用Petalinux搭建相关linux环境,在vivado中搭建了一个简单的PS -> AXI-DMA -> AXI-FIFO ->...使用库相对来说更加方便容易上手,不需要过多的了解linux设备驱动中如何调用DMA进行传输 目录 ...
  • 从零开始zynq linux AXI DMA传输

    万次阅读 热门讨论 2017-04-02 19:24:33
    gsc@gsc-250:~/zynq7000/ZedBoard/projects/linux_kernel/scripts/dtc$ dtc -O dtb -I dts -o devicetree.dtb /home/gsc/zynq7000/ZedBoard/projects/hardware_design/axidma_user/axidma_user.sdk/device_tree_bsp_...
  • 米联客教程:S03_CH01_AXI_DMA_LOOP环路测试 平台:ZedBoard vivado版本:2019.1 petalinux版本:2019.1 vivado方面的具体配置请参考米联客的教程,我这里就不详细介绍了。 放一张我已经做好的整体图片供参考 ...
  • 本文依据个人工作经验整理而成,如有错误请留言。 文章为个人辛苦整理,付费内容,禁止私自转载。 文章专栏:《黑猫的FPGA知识合集》 ...我使用的是ZYNQ芯片的zedboard开发板,在开发板中跑Linux系统,之所以跑linux
  • 由于单个DMA每次只能发送一定量的数据,但对于数据源来说数据时源源不断产生的,所以在单个DMA单次发送完成至下一次传输期间,这段时间的数据流失了,所以采用两个DMA实现循环发送数据,防止数据丢失。 自定义一个IP...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 743
精华内容 297
关键字:

dmalinuxzynq

linux 订阅