精华内容
下载资源
问答
  • 1、在注册SPI驱动时,在SPI write时 不能直接申请 char buff[1024];必须已以下方式申请buff char *buff; buff = kzalloc(buf_len, GFP_KERNEL | GFP_DMA); ...

    1、在注册SPI驱动时,在SPI write时

            不能直接申请 char buff[1024];必须已以下方式申请buff

                    char *buff;

                    buff = kzalloc(buf_len, GFP_KERNEL | GFP_DMA);

            

        

    展开全文
  • 书接上文,开始折腾ADC的DMA传输。因为大家都在说DMA,就连ST的例子里边也是使用DMA的。  ADC采集到的数据都存储在一个固定的寄存器中。当常规采样方式采样多个通道时候,使用DMA可以较好地避免将采集到的数据丢失...

    书接上文,开始折腾ADC的DMA传输。因为大家都在说DMA,就连ST的例子里边也是使用DMA的。

            ADC采集到的数据都存储在一个固定的寄存器中。当常规采样方式采样多个通道时候,使用DMA可以较好地避免将采集到的数据丢失。当ADC的DMA功能被使能的时候,每个通道转换完毕时都会发出一个DMA请求。DMA方式也不能完全避免数据丢失问题,要实现数据不丢失需要在DMA的同时开启OVERRUN模式,当数据丢失时就停止数据转换。我们只需要检测是否有OVR时间发生,就能解决采样数据丢失造成的问题。比如,通道错位什么的。

    在STM32F4的Reference manual中可以查到ADC1 的DMA映射在DMA1、CH0、Stream0上。

    【实验1、DMA方式采集单一通道数据】

           配置ADC1的DMA初始化设置如下:

    //DMA初始化
    DMA_InitStructure.DMA_BufferSize = 4;
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&adcvalue1;   //目标数据位
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_BASE+0x4C;  //ADC->DR地址
    DMA_InitStructure.DMA_PeripheralBurst =DMA_PeripheralBurst_Single;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_Init(DMA2_Stream0,&DMA_InitStructure);
    DMA_Cmd(DMA2_Stream0,ENABLE);

    在ADC寄存器中开启DMA传输,使用两个函数一个是设置CR2的DDS位,使得每次ADC数据更新时开启DMA传输;

    另一个是设置ADC CR2的DMA位,使能ADC的DMA传输。

    分别使用以下两个函数:

    ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE); //源数据变化时开启DMA传输
    ADC_DMACmd(ADC1,ENABLE);//使能ADC的DMA传输

    最后,还是在adcvalue中读出ADC的采样值,可以看到,没有使用函数ADC_GetConversionValue来读ADC的DR寄存器,照样能输出ADC采样到的值:

      while(1)
      {
        for(i = 0;i<10000;i++)
        {
            sum += adcvalue1;
          if(i ==9999)
          {
             avgvota = sum/10000;
             sum = 0;
            printf("avg vota is: %d\r\n",avgvota*3300/0xfff);
          }
        }
      }

    【实验2、DMA方式采集4个通道数据】

    同时采样两路数据首先要将ADC_InitStructyre中的ADC_NbrOfConversion 改变。之后再用ADC_RegularChannelConfig将通道0添加到扫描通道序列即可。

    从一路变成4路,总共改了一行代码,添加3行代码:

    ADC_InitStructyre.ADC_NbrOfConversion = 2;

    ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_144Cycles);
    ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_144Cycles);
    ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_144Cycles);
    ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_144Cycles);

    实验时候,将PA0、PA1、PA2、PA3的输入接地或者接3.3伏电源,可在电脑端看到两个数据在跳变:0和3300.说明采样到了数据。

    【附注】

    在进行这个实验时候,遇到了一个小插曲。

    在对PA端口进行初始化的时候,我是这样写的:

    GPIO_InitStructure.GPIO_Pin = GPIO_PinSource0 | GPIO_PinSource1 | GPIO_PinSource2 | GPIO_PinSource3;

    这个问题导致了GPIO初始化的失败,是的ADC采样不到相应引脚的值。我一直在找DMA和ADC的配置问题,偶然才发现不能这么些。

    GPIO_PinSource0 和 GPIO_Pin_0 是不一样的。引脚初始化的时候应该用GPIO_Pin_0。查看库里边的宏定义,两个值是不一样的。

    GPIO_PinSource0 指的是引脚号,GPIO_Pin_0却是GPIo寄存器里边对应的位。一定要分清楚

    改过来之后就一切正常了,可以完美采样四路输入的数据。

    展开全文
  • 1,单个DMA每次只能发送一定量的数据,但对于数据源来说数据时源源不断产生的,所以在单个DMA单次发送完成至下一次传输期间,这段时间的数据流失了,所以采用两个DMA实现循环发送数据,防止数据丢失。自定义一个IP核...

    1,单个DMA每次只能发送一定量的数据,但对于数据源来说数据时源源不断产生的,所以在单个DMA单次发送完成至下一次传输期间,这段时间的数据流失了,所以采用两个DMA实现循环发送数据,防止数据丢失。自定义一个IP核用于产生源源不断的测试数据模拟数据源,再自定义一个IP用于切换DMA发送数据。通过axi-gpio启动数据源产生数据,数据流再通过DMA切换模块分批次将数据送往DMA。每个DMA发送20万个数据便进行切换,所以数据源采用从1开始累加产生数据,每次在DMA中断中验证最后一个数据是否正确。

    2,添加驱动

    在Kconfig中,发现 XILINX_DMA

       config ALINX_ADC_DMA
        tristate "ALINX ADC DMA Test client for AXI DMA"
        depends on XILINX_DMA
        help
              ALINX ADC DMA  client.

     

    在Makefile中发现

    obj-$(CONFIG_XILINX_DMA) += xilinx_dma.o

     

    对应于/home/alinx/linux-xlnx-xilinx-v2017.4/drivers/dma/xilinx/xilinx_dma.c中

    设备树代码 pl.dtsi

    / {
        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_s2mm_aclk";
                clocks = <&clkc 15>, <&clkc 15>;
                compatible = "xlnx,axi-dma0";
                interrupt-names = "s2mm_introut";
                interrupt-parent = <&intc>;
                interrupts = <0 29 4>;
                reg = <0x40400000 0x10000>;
                xlnx,addrwidth = <0x20>;
                xlnx,sg-length-width = <0x14>;
                dma-channel@40400030 {
                    compatible = "xlnx,axi-dma-s2mm-channel";
                    dma-channels = <0x1>;
                    interrupts = <0 29 4>;
                    xlnx,datawidth = <0x20>;
                    xlnx,device-id = <0x0>;
                };
            };
            axi_dma_1: dma@40410000 {
                #dma-cells = <1>;
                clock-names = "s_axi_lite_aclk", "m_axi_s2mm_aclk";
                clocks = <&clkc 15>, <&clkc 15>;
                compatible = "xlnx,axi-dma1";
                interrupt-names = "s2mm_introut";
                interrupt-parent = <&intc>;
                interrupts = <0 30 4>;
                reg = <0x40410000 0x10000>;
                xlnx,addrwidth = <0x20>;
                xlnx,sg-length-width = <0x14>;
                dma-channel@40410030 {
                    compatible = "xlnx,axi-dma-s2mm-channel";
                    dma-channels = <0x1>;
                    interrupts = <0 30 4>;
                    xlnx,datawidth = <0x20>;
                    xlnx,device-id = <0x1>;
                };
            };
            axi_gpio_0: gpio@41200000 {
                #gpio-cells = <3>;
                clock-names = "s_axi_aclk";
                clocks = <&clkc 15>;
                compatible = "xlnx,axi-gpio-test";
                gpio-controller ;
                reg = <0x41200000 0x10000>;
                xlnx,all-inputs = <0x0>;
                xlnx,all-inputs-2 = <0x0>;
                xlnx,all-outputs = <0x1>;
                xlnx,all-outputs-2 = <0x0>;
                xlnx,dout-default = <0x00000000>;
                xlnx,dout-default-2 = <0x00000000>;
                xlnx,gpio-width = <0x1>;
                xlnx,gpio2-width = <0x20>;
                xlnx,interrupt-present = <0x0>;
                xlnx,is-dual = <0x0>;
                xlnx,tri-default = <0xFFFFFFFF>;
                xlnx,tri-default-2 = <0xFFFFFFFF>;
            };
        };
    };

    3,gpio驱动代码gpio_driver.c

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/kernel.h>
    #include <linux/types.h>
    #include <linux/ioport.h>
    #include <linux/interrupt.h>
    #include <linux/fcntl.h>
    #include <linux/init.h>
    #include <linux/poll.h>
    #include <linux/proc_fs.h>
    #include <linux/seq_file.h> /* Needed for Sequence File Operations */
    #include <linux/mutex.h>
    #include <linux/sysctl.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include "linux/device.h"
    #include "linux/miscdevice.h"
    #include <linux/platform_device.h>
    #include <linux/clk.h>
    #include <linux/of_irq.h>
    #include <linux/slab.h>
    #include <linux/bitops.h>
    #include <linux/dmapool.h>
    #include <linux/of_dma.h>
    #include <linux/dma-mapping.h>
    #include <linux/kfifo.h>

    #include "linux/kthread.h"
    #include "linux/wait.h"
    #include "linux/completion.h"
    #include "linux/workqueue.h"
    #include <linux/io.h>
    #include <linux/uaccess.h>

    int major;
    static struct class *gpio_class   = NULL;
    void __iomem *base_regs;

    /*
     *open 接口函数
     *
     * */
    static int axi_gpio_open(struct inode *inode,struct file *file)
    {
        printk("enter axi_gpio_open \r\n");
        return 0;
    }
    /*
     * write 接口函数
     *
     * */
    static int axi_gpio_write(struct file *file,const char __user *buf, size_t count,loff_t *ppos)
    {
        unsigned int ret=0;
        int data;
        printk("gpio write start !\n");
        ret=copy_from_user(&data,buf,count);
        if(ret!=0)
        {
            printk("data read fail\n");
            return -1;
        }
        iowrite32(data,base_regs);

        return 0;
    }
    /*
     * read 接口函数
     *
     * */
    static int axi_gpio_read(struct file *file,char __user *buf,size_t size,loff_t *ppos)
    {

        printk("gpio read start!\n");
        return 0;
    }

    static struct file_operations axi_gpio_fops={
        .owner = THIS_MODULE,
        .read  = axi_gpio_read,
        .write = axi_gpio_write,
        .open  = axi_gpio_open,
    };
    unsigned int irq_num;
    static int gpio_probe(struct platform_device *pdev)
    {
        struct resource *io;
        printk("enter gpio probe\r\n");
        //从设备树中获取gpio基地址,同时进行地址映射,虚拟地址保存在 base_regs 中
        io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        base_regs = devm_ioremap_resource(&pdev->dev, io);
        printk("gpio base address is: 0X:%x\r\n",base_regs);
        iowrite32(0x0,base_regs);
        major         = register_chrdev( 0 , "axi_gpio_dev" , &axi_gpio_fops);
        gpio_class     = class_create (THIS_MODULE , "axi_gpio_dev");
        device_create(gpio_class, NULL, MKDEV(major,0), NULL, "axi_gpio_dev");
        printk("major dev number= %d",major);
        return 0;
    }
    static int gpio_remove(struct platform_device *pdev)
    {
        unregister_chrdev(major,"axi_gpio_dev");
        device_destroy(gpio_class,MKDEV(major,0));
        class_destroy(gpio_class);

        iounmap(base_regs);
        return 0;
        
    }
    static const struct of_device_id my_axigpio_of_ids[] = {
        { .compatible = "xlnx,axi-gpio-test",},
        {}
    };

    static struct platform_driver my_axigpio_driver = {
        .driver = {
            .name = "my_axi_gpio",
            .of_match_table = my_axigpio_of_ids,
        },
        .probe  = gpio_probe,
        .remove = gpio_remove,
    };

    module_platform_driver(my_axigpio_driver);

    MODULE_AUTHOR("TES@gpio");
    MODULE_DESCRIPTION("my gpio driver");
    MODULE_ALIAS("my gpio linux driver");
    MODULE_LICENSE("GPL");
    4,dma驱动代码dma_driver.c

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/kernel.h>
    #include <linux/types.h>
    #include <linux/ioport.h>
    #include <linux/interrupt.h>
    #include <linux/fcntl.h>
    #include <linux/init.h>
    #include <linux/poll.h>
    #include <linux/proc_fs.h>
    #include <linux/seq_file.h> /* Needed for Sequence File Operations */
    #include <linux/mutex.h>
    #include <linux/sysctl.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include "linux/device.h"
    #include "linux/miscdevice.h"
    #include <linux/platform_device.h>
    #include <linux/clk.h>
    #include <linux/of_irq.h>
    #include <linux/slab.h>
    #include <linux/bitops.h>
    #include <linux/dmapool.h>
    #include <linux/of_dma.h>
    #include <linux/dma-mapping.h>
    #include <linux/kfifo.h>

    #include "linux/kthread.h"
    #include "linux/wait.h"
    #include "linux/completion.h"
    #include "linux/workqueue.h"
    #include <linux/io.h>
    #include <linux/uaccess.h>
    /**
     *DMA驱动程序
     *
     * **/
    //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_BUF_SIZE  1024*1024
    void __iomem *base_regs;
    int major;
    dma_addr_t phyaddr;//物理地址
    char *buf;//虚拟地址
    static struct class *dma_class   = NULL;
    //DMA interrupt functions
    int dma_flag=0;
    unsigned int status=0;
    static int irq_cnt=0;
    static irqreturn_t dma0_s2mm_irq(int irq,void *dev_id)
    {
        unsigned int data;
        irq_cnt++;
        if(irq_cnt%5==0)
        {
        data = (buf[399999]<<24)|(buf[399998]<<16)|(buf[399997]<<8)|(buf[399996]);
        printk(" %d",data);
        }
        iowrite32(0x0000f000,base_regs  +  S2MM_DMASR);
        iowrite32(0x00001001,base_regs  +  S2MM_DMACR);//open int & enable DMA
        iowrite32(phyaddr   ,base_regs  +  S2MM_DA);
        iowrite32(4000000   ,base_regs  +  S2MM_LENGTH);//write transmission length and DMA start transmission
        return IRQ_HANDLED;
    }


    /*
     *open 接口函数
     *
     * */
    static int axi_dma_open(struct inode *inode,struct file *file)
    {
        printk("enter axi_dma_open \r\n");
        iowrite32(0x00001001,base_regs  +  S2MM_DMACR);//open int & enable DMA
        iowrite32(phyaddr   ,base_regs  +  S2MM_DA);
        iowrite32(400000   ,base_regs  +  S2MM_LENGTH);//write transmission length and DMA start transmission
        return 0;
    }
    /*
     * write 接口函数
     *
     * */
    static int axi_dma_write(struct file *file,const char __user *buff, size_t count,loff_t *ppos)
    {

        printk("dma write start !\n");
        return 0;
    }
    /*
     * read 接口函数
     *
     * */
    static int axi_dma_read(struct file *file,char __user *buff,size_t size,loff_t *ppos)
    {

        printk("dma read start !\n");
        return 0;
    }
    static unsigned int axi_dma_poll(struct file *file, poll_table *wait)
    {
        printk("enter axi_dma_poll \r\n");
        return 0;        
    }
    static int axi_dma_mmap (struct file *file, struct vm_area_struct *vma)
    {
        printk("enter axi_dma_mmap \r\n");
        vma->vm_flags |= VM_IO;
        vma->vm_flags |= VM_LOCKED;
        vma->vm_pgoff = phyaddr >> PAGE_SHIFT;
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);

        if(remap_pfn_range(vma, vma->vm_start,vma->vm_pgoff, vma->vm_end-vma->vm_start, vma->vm_page_prot)){
            printk("axi_dma_mmap failed.\n");
            return -EAGAIN;
        }
        printk("base start=0x%08lx, \n",(unsigned long)phyaddr);
        printk("vma start=0x%08lx, size=%ld.\n",
            (unsigned long)vma->vm_start,
            (unsigned long)vma->vm_end - (unsigned long)vma->vm_start);   
        return 0;
    }
    static struct file_operations axi_dma_fops={
        .owner = THIS_MODULE,
        .read  = axi_dma_read,
        .write = axi_dma_write,
        .open  = axi_dma_open,
        .mmap = axi_dma_mmap,               /* mmap method */
    };
    unsigned int irq_num;
    static int my_dma_probe(struct platform_device *pdev)
    {
        struct resource *io;
        struct device_node *node = pdev->dev.of_node;
        struct device_node *child;
        int err;
        struct device *dev;
        //从设备树中获取dma基地址,同时进行地址映射,虚拟地址保存在 base_regs 中
        io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        base_regs = devm_ioremap_resource(&pdev->dev, io);
        printk("dma base address is: 0X:%x\r\n",base_regs);
        //申请中断
        for_each_child_of_node(node, child){
            if(of_device_is_compatible(child, "xlnx,axi-dma-s2mm-channel"))
            {
                printk("axi dma s2mm valid\r\n");
                irq_num = irq_of_parse_and_map(child, 0);
                err = request_irq(irq_num, dma0_s2mm_irq, IRQF_TRIGGER_RISING, "dma0_s2mm_irq", NULL);
                if (err)
                {
                    printk( "dma0 unable to request IRQ %d\n", irq_num);
                    return err;
                }
            }
            else
            {
                printk("dma0 Invalid channel compatible node\n");
                return -EINVAL;
            }
        }
        ///申请dma缓冲区--起始
        dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
        if (!dev)
            return -ENOMEM;
        dev = &pdev->dev;
        dev->coherent_dma_mask = 0xffffffff;
        buf = dma_alloc_coherent(dev, PAGE_ALIGN(DMA_BUF_SIZE), &phyaddr, GFP_KERNEL);
        if(!buf)
        {
            printk("axi vdma  buffer memory allocation failed\r\n");
                return -ENOMEM;
        }
        else
        {
            printk("buf=0x%x\n",buf);
            printk(" phyaddr=0x%x\r\n",phyaddr);
        }
        ///申请dma缓冲区--结束
        major         = register_chrdev( 0 , "axi_dma0_dev" , &axi_dma_fops);
        dma_class     = class_create (THIS_MODULE , "axi_dma0_dev");
        device_create(dma_class, NULL, MKDEV(major,0), NULL, "axi_dma0_dev");
        printk("major dev number= %d",major);
        return 0;
    }
    static int my_dma_remove(struct platform_device *pdev)
    {
        unregister_chrdev(major,"axi_dma0_dev");
        device_destroy(dma_class,MKDEV(major,0));
        class_destroy(dma_class);
        free_irq(irq_num,NULL);
        dma_free_coherent(NULL, PAGE_ALIGN(DMA_BUF_SIZE), buf, phyaddr);
        iounmap(base_regs);
        return 0;
        
    }
    static const struct of_device_id my_dma_of_ids[] = {
        { .compatible = "xlnx,axi-dma0",},
        {}
    };

    static struct platform_driver my_dma_driver = {
        .driver = {
            .name = "my_axi_dma0",
            .of_match_table = my_dma_of_ids,
        },
        .probe  = my_dma_probe,
        .remove = my_dma_remove,
    };

    module_platform_driver(my_dma_driver);

    MODULE_AUTHOR("TEST@dma0");
    MODULE_DESCRIPTION("dma0 driver");
    MODULE_ALIAS("dma0 linux driver");
    MODULE_LICENSE("GPL");

    5,测试文件 test_my_dma.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
    #include <getopt.h>           
    #include <fcntl.h>            
    #include <unistd.h>
    #include <errno.h>
    #include <malloc.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <sys/mman.h>
    #include <sys/ioctl.h>

    #define DMA_BUF_SIZE  1024*1024

    void delay()
    {
        int i=0,j=0;
        for(i=0;i<10000;i++)
            for(j=0;j<1000;j++)j++;
    }
    int main()
    {
        int dma0_fd,dma1_fd,gpio_fd;
        int i=0,j=0;
        unsigned int * dma0_mmapBuf;
        unsigned int * dma1_mmapBuf;
        int dma0_flag,dma1_flag,gpio_flag;
        int *dest;
        dma0_fd = open("/dev/axi_dma0_dev", O_RDWR, 0);
        if (dma0_fd < 0) {
                printf("Open %s failed\n", "/dev/axivdma_dev");
                return -1;
        }
        dma0_mmapBuf = mmap(NULL, DMA_BUF_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, dma0_fd, 0);
        
        dma1_fd = open("/dev/axi_dma1_dev", O_RDWR, 0);
        if (dma1_fd < 0) {

                printf("Open %s failed\n", "/dev/axivdma_dev");

                return -1;

        }
        dma1_mmapBuf = mmap(NULL, DMA_BUF_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, dma1_fd, 0);
        

        gpio_fd = open("/dev/axi_gpio_dev", O_RDWR, 0);
        if (gpio_fd < 0) {
                printf("Open %s failed\n", "/dev/axi_gpio_dev");
                return -1;
        }
        gpio_flag=1;
        printf("======start====\r\n");

        delay();

        write(gpio_fd,&gpio_flag,4);

        delay();

        while(1);

        printf("dma test Done.\n");

        return 0;

    }

     

     

    展开全文
  • 由于单个DMA每次只能发送一定量的数据,但对于数据源来说数据时源源不断产生的,所以在单个DMA单次发送完成至下一次传输期间,这段时间的数据流失了,所以采用两个DMA实现循环发送数据,防止数据丢失。 自定义一个IP...

    一.目标
    在米尔科技的z-turn 开发板上实现PL数据流送往PS。
    二.流程分析
    由于单个DMA每次只能发送一定量的数据,但对于数据源来说数据时源源不断产生的,所以在单个DMA单次发送完成至下一次传输期间,这段时间的数据流失了,所以采用两个DMA实现循环发送数据,防止数据丢失。
    自定义一个IP核用于产生源源不断的测试数据模拟数据源,再自定义一个IP用于切换DMA发送数据。
    系统框图如下:
    在这里插入图片描述
    通过axi-gpio启动数据源产生数据,数据流再通过DMA切换模块分批次将数据送往DMA。每个DMA发送10万个数据便进行切换,所以数据源采用从1开始累加产生数据,每次在DMA中断中验证最后一个数据是否是10万,20万,30万等等。
    三.代码
    ①数据源模块data_product.v

    module data_product(
    clk,
    rst,
    enable,
    data_out,
    data_enable,
    cnt
    );
    input clk;
    input rst;
    input enable;
    output [31:0]data_out;
    output data_enable;
    output[3:0]cnt;
    reg [31:0]data_out;
    reg data_enable;
    reg[3:0]cnt;
    always@(posedge clk or negedge rst)
    begin
        if(!rst)
        begin
            data_out <= 0;
            data_enable <= 0;
            cnt <= 0;
        end
        else
        begin
            if(enable)
            begin
                if(cnt>=13)cnt <= 0;
                else cnt <= cnt + 1;
                if(cnt>=1&&cnt<=8)
                begin
                    data_out <= data_out + 1;
                    data_enable <= 1;
                end
                else
                begin
                    data_out <= data_out;
                    data_enable <= 0;
                end
            end
            else
            begin
                data_enable <= 0;
                data_out   <= data_out;
                cnt <= cnt;
            end
        end
    end
    endmodule
    

    ②DMA切换模块:selet_dma.v

    module selet_dma(
     clk,
     rst,
     data_valid,
     data_in,
     //dma1
     dma1_tvalid,
     dma1_tkeep,
     dma1_tlast,
     dma1_tready,
     dma1_tdata,
     //dma2
     dma2_tvalid,
     dma2_tkeep,
     dma2_tlast,
     dma2_tready,
     dma2_tdata,
     //
     count_dma1,
     count_dma2
    );
    input clk;
    input rst;
    input data_valid;
    input [31:0]data_in;
    //dma1
    output dma1_tvalid;
    output [3:0]dma1_tkeep;
    output dma1_tlast;
    output [31:0]dma1_tdata;
    input dma1_tready;
    //dma2
    output dma2_tvalid;
    output [3:0]dma2_tkeep;
    output dma2_tlast;
    output [31:0]dma2_tdata;
    input dma2_tready;
    //count data
    output[19:0]count_dma1;//数据输出个数
    output[19:0]count_dma2;
    //
    reg dma1_tvalid;
    reg [3:0]dma1_tkeep;
    reg dma1_tlast;
    reg [31:0]dma1_tdata;
    //
    reg dma2_tvalid;
    reg [3:0]dma2_tkeep;
    reg dma2_tlast;
    reg [31:0]dma2_tdata;
    //
    reg[19:0]count_dma1;//数据输出个数
    reg[19:0]count_dma2;
    reg selet;
    reg temp_selet;
    always@(negedge clk or negedge rst)
    begin
        if(!rst)selet <= 0;
        else selet <= temp_selet;
    end
    always@(negedge clk or negedge rst)
    begin
        if(!rst)temp_selet <= 0;
        else
        begin
            if(count_dma1==20'd99999) temp_selet <= 1;
            else if(count_dma2==20'd99999)temp_selet <= 0;
            else temp_selet <= temp_selet;
        end
    end
    always@(negedge clk or negedge rst)
    begin
        if(!rst)
        begin
            count_dma1 <= 0;
            count_dma2 <= 0;
        end
        else
        begin
            if(selet==0 && dma1_tready==1 && data_valid==1 )
            begin
                count_dma2 <= 0;
                count_dma1 <= count_dma1 + 1;
            end
            else if(selet==1 && dma2_tready==1 && data_valid==1)
            begin
                count_dma1 <= 0;
                count_dma2 <= count_dma2 + 1;
            end
            else
            begin
                count_dma2 <= count_dma2;
                count_dma1 <= count_dma1;
            end
        end
    end
    always@(negedge clk or negedge rst)
    begin
        if(!rst)
        begin
            dma1_tvalid <= 0;
            dma1_tkeep  <= 0;
            dma1_tlast  <= 0;
            dma1_tdata  <= 0;
            
            dma2_tvalid <= 0;
            dma2_tkeep  <= 0;
            dma2_tlast  <= 0;
            dma2_tdata  <= 0;
        end
        else
        begin
            if(data_valid)
            begin
                if(selet==0)//dma1
                begin
                    dma1_tvalid <= 1;
                    dma1_tkeep  <= 4'b1111;
                    dma1_tdata  <= data_in;
                    
                    dma2_tvalid <= 0;
                    dma2_tkeep  <= 0;
                    dma2_tlast  <= 0;
                    dma2_tdata  <= 0;
                                   
                    if(count_dma1>=20'd99999)
                    begin
                        dma1_tlast <= 1;
                    end
                    else
                    begin
                        dma1_tlast <= 0;
                    end    
                end
                else //dma2
                begin
                    dma2_tvalid <= 1;                    
                    dma2_tkeep  <= 4'b1111;              
                    dma2_tdata  <= data_in;              
                                                         
                    dma1_tvalid <= 0;                    
                    dma1_tkeep  <= 0;                    
                    dma1_tlast  <= 0;                    
                    dma1_tdata  <= 0;                    
                                                                    
                    if(count_dma2>=20'd99999)        
                    begin                                      
                        dma2_tlast <= 1;   
                    end                              
                    else                             
                    begin                            
                        dma2_tlast <= 0;     
                    end                                                             
                end
            end
            else
            begin           
                dma1_tvalid <= 0;
                dma1_tkeep  <= 0;
                dma1_tdata  <= dma1_tdata;
                dma1_tlast  <= dma1_tlast;
                
                dma2_tvalid <= 0;         
                dma2_tkeep  <= 0;         
                dma2_tdata  <= dma2_tdata;
                dma2_tlast  <= dma2_tlast;         
            end
        end
    end
    endmodule
    

    ③设备树代码 pl.dtsi

    / {
    	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_s2mm_aclk";
    			clocks = <&clkc 15>, <&clkc 15>;
    			compatible = "xlnx,axi-dma0";
    			interrupt-names = "s2mm_introut";
    			interrupt-parent = <&intc>;
    			interrupts = <0 29 4>;
    			reg = <0x40400000 0x10000>;
    			xlnx,addrwidth = <0x20>;
    			xlnx,sg-length-width = <0x14>;
    			dma-channel@40400030 {
    				compatible = "xlnx,axi-dma-s2mm-channel";
    				dma-channels = <0x1>;
    				interrupts = <0 29 4>;
    				xlnx,datawidth = <0x20>;
    				xlnx,device-id = <0x0>;
    			};
    		};
    		axi_dma_1: dma@40410000 {
    			#dma-cells = <1>;
    			clock-names = "s_axi_lite_aclk", "m_axi_s2mm_aclk";
    			clocks = <&clkc 15>, <&clkc 15>;
    			compatible = "xlnx,axi-dma1";
    			interrupt-names = "s2mm_introut";
    			interrupt-parent = <&intc>;
    			interrupts = <0 30 4>;
    			reg = <0x40410000 0x10000>;
    			xlnx,addrwidth = <0x20>;
    			xlnx,sg-length-width = <0x14>;
    			dma-channel@40410030 {
    				compatible = "xlnx,axi-dma-s2mm-channel";
    				dma-channels = <0x1>;
    				interrupts = <0 30 4>;
    				xlnx,datawidth = <0x20>;
    				xlnx,device-id = <0x1>;
    			};
    		};
    		axi_gpio_0: gpio@41200000 {
    			#gpio-cells = <3>;
    			clock-names = "s_axi_aclk";
    			clocks = <&clkc 15>;
    			compatible = "xlnx,axi-gpio-test";
    			gpio-controller ;
    			reg = <0x41200000 0x10000>;
    			xlnx,all-inputs = <0x0>;
    			xlnx,all-inputs-2 = <0x0>;
    			xlnx,all-outputs = <0x1>;
    			xlnx,all-outputs-2 = <0x0>;
    			xlnx,dout-default = <0x00000000>;
    			xlnx,dout-default-2 = <0x00000000>;
    			xlnx,gpio-width = <0x1>;
    			xlnx,gpio2-width = <0x20>;
    			xlnx,interrupt-present = <0x0>;
    			xlnx,is-dual = <0x0>;
    			xlnx,tri-default = <0xFFFFFFFF>;
    			xlnx,tri-default-2 = <0xFFFFFFFF>;
    		};
    	};
    };
    

    ④gpio驱动代码gpio_driver.c

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/kernel.h>
    #include <linux/types.h>
    #include <linux/ioport.h>
    #include <linux/interrupt.h>
    #include <linux/fcntl.h>
    #include <linux/init.h>
    #include <linux/poll.h>
    #include <linux/proc_fs.h>
    #include <linux/seq_file.h> /* Needed for Sequence File Operations */
    #include <linux/mutex.h>
    #include <linux/sysctl.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include "linux/device.h"
    #include "linux/miscdevice.h"
    #include <linux/platform_device.h>
    #include <linux/clk.h>
    #include <linux/of_irq.h>
    #include <linux/slab.h>
    #include <linux/bitops.h>
    #include <linux/dmapool.h>
    #include <linux/of_dma.h>
    #include <linux/dma-mapping.h>
    #include <linux/kfifo.h>
    
    #include "linux/kthread.h"
    #include "linux/wait.h"
    #include "linux/completion.h"
    #include "linux/workqueue.h"
    #include <linux/io.h>
    #include <linux/uaccess.h>
    
    int major;
    static struct class *gpio_class   = NULL;
    void __iomem *base_regs;
    
    /*
     *open 接口函数
     *
     * */
    static int axi_gpio_open(struct inode *inode,struct file *file)
    {
        printk("enter axi_gpio_open \r\n");
        return 0;
    }
    /*
     * write 接口函数
     *
     * */
    static int axi_gpio_write(struct file *file,const char __user *buf, size_t count,loff_t *ppos)
    {
        unsigned int ret=0;
    	int data;
        printk("gpio write start !\n");
    	ret=copy_from_user(&data,buf,count);
    	if(ret!=0)
    	{
    		printk("data read fail\n");
    		return -1;
    	}
        iowrite32(data,base_regs);
    
        return 0;
    }
    /*
     * read 接口函数
     *
     * */
    static int axi_gpio_read(struct file *file,char __user *buf,size_t size,loff_t *ppos)
    {
    
        printk("gpio read start!\n");
        return 0;
    }
    
    static struct file_operations axi_gpio_fops={
    	.owner = THIS_MODULE,
    	.read  = axi_gpio_read,
    	.write = axi_gpio_write,
    	.open  = axi_gpio_open,
    };
    unsigned int irq_num;
    static int gpio_probe(struct platform_device *pdev)
    {
    	struct resource *io;
    	printk("enter gpio probe\r\n");
    	//从设备树中获取gpio基地址,同时进行地址映射,虚拟地址保存在 base_regs 中
    	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    	base_regs = devm_ioremap_resource(&pdev->dev, io);
    	printk("gpio base address is: 0X:%x\r\n",base_regs);
    	iowrite32(0x0,base_regs);
    	major         = register_chrdev( 0 , "axi_gpio_dev" , &axi_gpio_fops);
        gpio_class     = class_create (THIS_MODULE , "axi_gpio_dev");
        device_create(gpio_class, NULL, MKDEV(major,0), NULL, "axi_gpio_dev");
    	printk("major dev number= %d",major);
    	return 0;
    }
    static int gpio_remove(struct platform_device *pdev)
    {
    	unregister_chrdev(major,"axi_gpio_dev");
        device_destroy(gpio_class,MKDEV(major,0));
        class_destroy(gpio_class);
    
    	iounmap(base_regs);
    	return 0;
    	
    }
    static const struct of_device_id my_axigpio_of_ids[] = {
    	{ .compatible = "xlnx,axi-gpio-test",},
    	{}
    };
    
    static struct platform_driver my_axigpio_driver = {
    	.driver = {
    		.name = "my_axi_gpio",
    		.of_match_table = my_axigpio_of_ids,
    	},
    	.probe  = gpio_probe,
    	.remove = gpio_remove,
    };
    
    module_platform_driver(my_axigpio_driver);
    
    MODULE_AUTHOR("TES@gpio");
    MODULE_DESCRIPTION("my gpio driver");
    MODULE_ALIAS("my gpio linux driver");
    MODULE_LICENSE("GPL");
    

    ⑥dma驱动代码dma0_driver.c

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/kernel.h>
    #include <linux/types.h>
    #include <linux/ioport.h>
    #include <linux/interrupt.h>
    #include <linux/fcntl.h>
    #include <linux/init.h>
    #include <linux/poll.h>
    #include <linux/proc_fs.h>
    #include <linux/seq_file.h> /* Needed for Sequence File Operations */
    #include <linux/mutex.h>
    #include <linux/sysctl.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include "linux/device.h"
    #include "linux/miscdevice.h"
    #include <linux/platform_device.h>
    #include <linux/clk.h>
    #include <linux/of_irq.h>
    #include <linux/slab.h>
    #include <linux/bitops.h>
    #include <linux/dmapool.h>
    #include <linux/of_dma.h>
    #include <linux/dma-mapping.h>
    #include <linux/kfifo.h>
    
    #include "linux/kthread.h"
    #include "linux/wait.h"
    #include "linux/completion.h"
    #include "linux/workqueue.h"
    #include <linux/io.h>
    #include <linux/uaccess.h>
    /**
     *DMA驱动程序
     *
     * **/
    //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_BUF_SIZE  1024*1024
    void __iomem *base_regs;
    int major;
    dma_addr_t phyaddr;//物理地址
    char *buf;//虚拟地址
    static struct class *dma_class   = NULL;
    //DMA interrupt functions
    int dma_flag=0;
    unsigned int status=0;
    static int irq_cnt=0;
    static irqreturn_t dma0_s2mm_irq(int irq,void *dev_id)
    {
    	unsigned int data;
    	irq_cnt++;
    	if(irq_cnt%5==0)
    	{
    	data = (buf[399999]<<24)|(buf[399998]<<16)|(buf[399997]<<8)|(buf[399996]);
    	printk(" %d",data);
    	}
    	iowrite32(0x0000f000,base_regs  +  S2MM_DMASR);
    	iowrite32(0x00001001,base_regs  +  S2MM_DMACR);//open int & enable DMA
    	iowrite32(phyaddr   ,base_regs  +  S2MM_DA);
    	iowrite32(4000000   ,base_regs  +  S2MM_LENGTH);//write transmission length and DMA start transmission
        return IRQ_HANDLED;
    }
    
    
    /*
     *open 接口函数
     *
     * */
    static int axi_dma_open(struct inode *inode,struct file *file)
    {
        printk("enter axi_dma_open \r\n");
    	iowrite32(0x00001001,base_regs  +  S2MM_DMACR);//open int & enable DMA
    	iowrite32(phyaddr   ,base_regs  +  S2MM_DA);
    	iowrite32(400000   ,base_regs  +  S2MM_LENGTH);//write transmission length and DMA start transmission
        return 0;
    }
    /*
     * write 接口函数
     *
     * */
    static int axi_dma_write(struct file *file,const char __user *buff, size_t count,loff_t *ppos)
    {
    
        printk("dma write start !\n");
        return 0;
    }
    /*
     * read 接口函数
     *
     * */
    static int axi_dma_read(struct file *file,char __user *buff,size_t size,loff_t *ppos)
    {
    
        printk("dma read start !\n");
        return 0;
    }
    static unsigned int axi_dma_poll(struct file *file, poll_table *wait)
    {
    	printk("enter axi_dma_poll \r\n");
    	return 0;		
    }
    static int axi_dma_mmap (struct file *file, struct vm_area_struct *vma)
    {
    	printk("enter axi_dma_mmap \r\n");
    	vma->vm_flags |= VM_IO;
        vma->vm_flags |= VM_LOCKED;
        vma->vm_pgoff = phyaddr >> PAGE_SHIFT;
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
    
        if(remap_pfn_range(vma, vma->vm_start,vma->vm_pgoff, vma->vm_end-vma->vm_start, vma->vm_page_prot)){
            printk("axi_dma_mmap failed.\n");
            return -EAGAIN;
        }
        printk("base start=0x%08lx, \n",(unsigned long)phyaddr);
        printk("vma start=0x%08lx, size=%ld.\n",
            (unsigned long)vma->vm_start,
            (unsigned long)vma->vm_end - (unsigned long)vma->vm_start);   
    	return 0;
    }
    static struct file_operations axi_dma_fops={
    	.owner = THIS_MODULE,
    	.read  = axi_dma_read,
    	.write = axi_dma_write,
    	.open  = axi_dma_open,
    	.mmap = axi_dma_mmap,               /* mmap method */ 
    };
    unsigned int irq_num;
    static int my_dma_probe(struct platform_device *pdev)
    {
    	struct resource *io;
    	struct device_node *node = pdev->dev.of_node;
    	struct device_node *child;
    	int err;
    	struct device *dev;
    	//从设备树中获取dma基地址,同时进行地址映射,虚拟地址保存在 base_regs 中
    	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    	base_regs = devm_ioremap_resource(&pdev->dev, io);
    	printk("dma base address is: 0X:%x\r\n",base_regs);
    	//申请中断
    	for_each_child_of_node(node, child){
    		if(of_device_is_compatible(child, "xlnx,axi-dma-s2mm-channel"))
    		{
    			printk("axi dma s2mm valid\r\n");
    			irq_num = irq_of_parse_and_map(child, 0);
    			err = request_irq(irq_num, dma0_s2mm_irq, IRQF_TRIGGER_RISING, "dma0_s2mm_irq", NULL);
    			if (err) 
    			{
    				printk( "dma0 unable to request IRQ %d\n", irq_num);
    				return err;
    			}
    		}
    		else
    		{
    			printk("dma0 Invalid channel compatible node\n");
    			return -EINVAL;
    		}
    	}
    	///申请dma缓冲区--起始
    	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
    	if (!dev)
    		return -ENOMEM;
    	dev = &pdev->dev;
    	dev->coherent_dma_mask = 0xffffffff;
    	buf = dma_alloc_coherent(dev, PAGE_ALIGN(DMA_BUF_SIZE), &phyaddr, GFP_KERNEL);
    	if(!buf)
    	{
    		printk("axi vdma  buffer memory allocation failed\r\n");
            	return -ENOMEM;
    	}
    	else
    	{
    		printk("buf=0x%x\n",buf);
    		printk(" phyaddr=0x%x\r\n",phyaddr);
    	}
    	///申请dma缓冲区--结束
    	major         = register_chrdev( 0 , "axi_dma0_dev" , &axi_dma_fops);
        dma_class     = class_create (THIS_MODULE , "axi_dma0_dev");
        device_create(dma_class, NULL, MKDEV(major,0), NULL, "axi_dma0_dev");
    	printk("major dev number= %d",major);
    	return 0;
    }
    static int my_dma_remove(struct platform_device *pdev)
    {
    	unregister_chrdev(major,"axi_dma0_dev");
        device_destroy(dma_class,MKDEV(major,0));
        class_destroy(dma_class);
        free_irq(irq_num,NULL);
    	dma_free_coherent(NULL, PAGE_ALIGN(DMA_BUF_SIZE), buf, phyaddr);
    	iounmap(base_regs);
    	return 0;
    	
    }
    static const struct of_device_id my_dma_of_ids[] = {
    	{ .compatible = "xlnx,axi-dma0",},
    	{}
    };
    
    static struct platform_driver my_dma_driver = {
    	.driver = {
    		.name = "my_axi_dma0",
    		.of_match_table = my_dma_of_ids,
    	},
    	.probe  = my_dma_probe,
    	.remove = my_dma_remove,
    };
    
    module_platform_driver(my_dma_driver);
    
    MODULE_AUTHOR("TEST@dma0");
    MODULE_DESCRIPTION("dma0 driver");
    MODULE_ALIAS("dma0 linux driver");
    MODULE_LICENSE("GPL");
    

    ⑦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:=dma0_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
    

    ⑧测试文件 test_my_dma.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
    #include <getopt.h>           
    #include <fcntl.h>            
    #include <unistd.h>
    #include <errno.h>
    #include <malloc.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <sys/mman.h>
    #include <sys/ioctl.h>
    
    #define DMA_BUF_SIZE  1024*1024
    
    void delay()
    {
    	int i=0,j=0;
    	for(i=0;i<10000;i++)
    		for(j=0;j<1000;j++)j++;
    }
    int main()
    {
    	int dma0_fd,dma1_fd,gpio_fd;
    	int i=0,j=0;
    	unsigned int * dma0_mmapBuf;
    	unsigned int * dma1_mmapBuf;
    	int dma0_flag,dma1_flag,gpio_flag;
    	int *dest;
    	dma0_fd = open("/dev/axi_dma0_dev", O_RDWR, 0);
    	if (dma0_fd < 0) {
            	printf("Open %s failed\n", "/dev/axivdma_dev");
            	return -1;
    	}
    	dma0_mmapBuf = mmap(NULL, DMA_BUF_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, dma0_fd, 0);
    	
    	dma1_fd = open("/dev/axi_dma1_dev", O_RDWR, 0);
    	if (dma1_fd < 0) {
    
            	printf("Open %s failed\n", "/dev/axivdma_dev");
    
            	return -1;
    
    	}
    	dma1_mmapBuf = mmap(NULL, DMA_BUF_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, dma1_fd, 0);
    	
    
    	gpio_fd = open("/dev/axi_gpio_dev", O_RDWR, 0);
    	if (gpio_fd < 0) {
            	printf("Open %s failed\n", "/dev/axi_gpio_dev");
            	return -1;
    	}
    	gpio_flag=1;
    	printf("======start====\r\n");
    
    	delay();
    
    	write(gpio_fd,&gpio_flag,4);
    
    	delay();
    
    	while(1);
    
    	printf("dma test Done.\n");
    
    	return 0;
    
    }
    

    四.linux设备树编译
    ①在Ubuntu里下载device-tree-xlnx,执行下面代码

    git clone https://github.com/Xilinx/device-tree-xlnx.git
    cd device-tree-xlnx
    git checkout xilinx-v2015.4
    

    会得到下面文件
    在这里插入图片描述在这里插入图片描述
    将其拷贝到windows上,进入SDK进行配置,可以得到以下文件
    在这里插入图片描述
    其中pl.dtsi为使用的设备树驱动文件。将pcw.dtsi、pl.dtsi、system-top.dts、zynq-7000.dtsi拷贝到ubuntu中,使用内核自带工具dtc工具(位于linux-xlnx/scripts/dtc/dtc下)将其编译成设备树。但需要先将system-top.dts修改成如下

    /dts-v1/;
    /include/ "zynq-7000.dtsi"
    /include/ "pl.dtsi"
    /include/ "pcw.dtsi"
    

    再使用dtc工具编译设备树,指令如下:

    Kernel/linux-xlnx/scripts/dtc/dtc -I dts -O dtb -o devicetree.dtb system-top.dts
    

    五.下板验证
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在DMA0驱动中,每次传输完成在中断里进行计数,每5次中断输出一次数据,可以看见结果符合预期。

    展开全文
  •  数据通过单片机dma转发后数据异常,通过检查发现 dma优先级不够高,导致dma数据通道占用的时候数据丢失,更改数据优先级后问题解决。 dma fifo的作用,如果开启fifo为4字节,加入你要传输10字节,就要进...
  • FIFO and DMA

    2018-08-10 16:07:12
     SPI端口增加了FIFO,使得传输数据有了缓冲区间。  FIFO存储器是一个先入先出的双口缓冲器,即第一个进入其内的数据第一个被移出,其中一个存储器的输入口,另一个口是存储器的输出口。主要有三个方面的作用:1)...
  • FIFO和DMA

    万次阅读 2012-11-21 02:04:04
     SPI端口增加了FIFO,使得传输数据有了缓冲区间。  FIFO存储器是一个先入先出的双口缓冲器,即第一个进入其内的数据第一个被移出,其中一个存储器的输入口,另一个口是存储器的输出口。主要有三个方面的作用:1)...
  • FIFO与DMA

    千次阅读 2009-12-23 21:46:00
    FIFO存储器是一个先入先出的双口缓冲器,即第一个进入其内的数据第一个被移出,其中一个存储器的输入口,另一个口是存储器的输出口。主要有三个方面的作用:1...这是至关重要的一点,如果不采用DMA操作,数据传输将达不
  • 转:FIFO和DMA

    2018-05-22 15:58:00
    SPI端口增加了FIFO,使得传输数据有了缓冲区间。 FIFO存储器是一个先入先出的双口缓冲器,即第一个进入其内的数据第一个被移出,其中一个存储器的输入口,另一个口是存储器的输出口。主要有三个方面的作用:1)对...
  • 目的:对5个通道信号进行采集,转换结果显示在oled显示屏上。...ADC(DMA传输) 由于要实现多通道信号同时采集,必须使用DMA方式,不然可能会导致数据采集过程中的丢失,使采集精度不准确。 adc.h代码如下: #i...
  • 由于项目需要使用485总线传输采集数据,所以采用手拉手模式,实现主从通信。在调试的过程中,遇到一些...最先想到的办法就是在使用485发送的时候,将DMA发送数据的长度增加2,效果立竿见影,没有数据丢失了。现在...
  • UART+FIFO+DMA for 44b0

    千次阅读 2010-06-02 16:31:00
    在搞启用fifo和BDMA的UART时,确实走了不少弯路。昨天一下午的时间我都在用轮询法检测DMA的运行情况,加上BDMA配置上犯了这样那样的错误,...本身BDMA的数据传输就不经过CPU,而执行计数函数前又要执行其他函数或中断
  • 8.2.7DMA传输模式… 88 8.2.8DMA优先级. 8.2.9字节或字传输 ::.::::::::::日日:日1:.:a..::::::a:E:::::::::::::日 88 8.2.10屮断屏蔽 88 8.2.11模式8设置 88 8.3DMA配置安装 88 8.4停止DMA传输… 89 8.5DMA中断 ∴...
  • stm32f4_6通道串口收发

    2018-08-23 19:14:07
    stm32的DMA可以进行数据的传输,而不用内存的参与。stm32通过DMA向串口发送和就收数据,数据丢失少。
  • 这里采用 DMA方式传输数据,可实现大量数据的突发传输而不丢失,数据通过 PCI 9054内部的 FIFO进行双向传输。为此,核心控制芯片 FPGA内部专门设计了与 PCI 9054进行数据通信的逻辑控制单元,通过查询 FIFO的当前...
  • 基于解决1394b和PCI的跨速率条件下通信数据易丢失,软硬件交互产生误码的目的。...通过实验验证,该驱动程序实现了软硬件的协调工作、提高了软件对硬件操作的操作安全性、提高了传输数据的可靠性以及实时性等。
  • AT91RM9200添加串口驱动

    千次阅读 2010-12-30 14:25:00
    陈儒军在嵌入式控制系统采集站的设计方案中,需要用到AT91RM9200的5个UART串口,就会涉及到多个中断的优先级分配问题,而且也可能造成串行通信的中断不能及时响应,从而造成数据丢失。在Linux2.6.21内核中,UART驱动...
  • DMA(直接存储器访问方式),DMA数据从一个地址空间复制到另外一个地址空间时,CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来执行和完成。 解析: 解析: 同样的发明创造只能被授予一项专利...
  • 前面7.4节我们给用户讲解了PCIe下的FIFO DMA高速传输通道的用法,FIFO顾名思义就是在保证数据丢失的情况下,高速传输,特别适合那些数据采集、图像采集、波形回放等应用;本节我们给用户介绍另外一种相对慢速的...
  • 项目场景: ...例如:数据传输过程中数据不时出现丢失的情况,偶尔会丢失一部分数据 APP 中接收数据代码: 原因分析: 首先先分析导致这个问题产生的模块,PDB进入错误序列的与原因是当触发完AD值
  • 操作系统精髓与设计原理答案

    热门讨论 2011-11-19 15:15:08
    但是,DMA可能从或者向设备(例如磁盘或磁带)以数据流的方式接收或者传输数据并且这是不能被打断的。否则,如果DMA设备被挂起(拒绝继续访问主存),数据可能会丢失。 1.9、一台计算机包括一个CPU和一台I/O设备D,...
  • 46 设异步传输时,每个字符对应1个起始位,7个信息位,1个奇偶校验位和1个停止位,如果波特率为9600b/s,则每秒钟传输的最大字符数为( )。 A.9600 B.96 C.960 D. 1200 47 在数据传送的控制方式中,( )对...
  • 4、修复“安全删除硬件”图标丢失问题 5、删除电脑U盘使用记录(U盘使用痕迹清理) 6、强制弹出正常情况无法删除的USB设备 弹U专家 ----------------------------------------------------------------- 方便...
  • 7.4.1 唤醒丢失问题 7.4.2 巨群问题 7.5 信号灯 7.5.1 提供互斥访问的信号灯 7.5.2 使用的信号灯的事件等待 7.5.3 用于控制可计数资源的信号灯 7.5.4 信号灯的缺点 7.5.5 护卫 7.6 自旋锁 7.6.1 自旋锁的使用 7.7 ...
  • 编写设备驱动程序

    2013-04-02 13:37:53
    介绍了一种常用的驱动程序编写方法,该方法允许在编写驱动程序时忽略特定于平台的问题,如字节存储顺序(endianness)和数据排序等。 其他主题包括:强化Solaris驱动程序;电源管理;驱动程序自动配置;程控I/O;直接...

空空如也

空空如也

1 2
收藏数 29
精华内容 11
关键字:

dma传输数据丢失