zedboard axiDMA linux驱动

2023-12-03 12:32
文章标签 linux 驱动 zedboard axidma

本文主要是介绍zedboard axiDMA linux驱动,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

写在前面的话:

本篇是AXI DMA在linux下使用的例子。

包括PL端设计,基于vivado 2015.4,petalinux 2016.1,基于linux 4.4内核。

我在git hub 上托管了代码,https://github.com/shichaog/zynq-dma,如果想加入github上这个项目,给我邮箱发信息shichaog@126.com,方便为你配权限。

1.PL端设计:

PL端设计包括四个AXI DMA IP,它们分别和zynq处理IP的HP口相连接。

这个设计是基于Avnet-Digilent-ZedBoard-v2016.1-final.bsp,由于其它的ip都是xilinx开发环境开发环境就有,所以这里就不详细每一步设计过程了。

这些IP包括AXI interconnect, system reset,axi dma,concat。

注意concat是用来将AXI DMA的中断传递给zynq之用的,这是必须有的,否则在hdf导入时,会出现如下错误:

2 接下来是创建module和app了


这两个命令执行后,会分配在components/apps和components/modules目录下生成dmaBench和ds_axidma两个文件夹,该文件下的两个文件内容使用如下的文件替换。

《dmaBench.c》
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>unsigned long tStart, tEnd;
unsigned long data;unsigned long getTime(){struct timeval temp;gettimeofday(&temp, NULL);return temp.tv_sec * 1000 * 1000 + temp.tv_usec;
}void report(char *msg, unsigned long data, unsigned long time, unsigned long dmaUsed){printf("%s\t%ld\t%ld\t%f\t%d\n", msg, data, time, data * 1.0 / time, dmaUsed);FILE *f = fopen("report.dat", "a");fprintf(f, "%s\t%ld\t%ld\t%f\t%d\n", msg, data, time, data * 1.0 / time, dmaUsed);fclose(f);
}#define REPORT(f, timeStart, timeEnd, dataPtr, msg, dmaUsed) *timeStart = getTime(); *dataPtr = f; *timeEnd = getTime(); report(msg, *dataPtr, *timeEnd - *timeStart, dmaUsed);void checkData(char *bufferIn, char *bufferOut, unsigned int elems){int i;if(!memcmp(bufferIn, bufferOut, elems*sizeof(char))){printf("DMA Ok!\n");}else{for(i=0;i<elems;i++)printf("%d\t%d\t%d\t%d\n", i, bufferIn[i], bufferOut[i], (i==0 ? 0 : bufferOut[i] - bufferOut[i-1]));}
}unsigned long memCpy_ARM(char *bufferIn, char *bufferOut, unsigned long elems, size_t size){int i;for(i=0; i<elems; i++)bufferOut[i] = bufferIn[i];return elems * size;
}unsigned long memCpy_DMA(char *bufferIn, char *bufferOut, unsigned long elems, size_t size, int dmaToUse){#define FIFO_LEN 4000
#define DMA_NUM 4int fd[DMA_NUM];fd[0] = open("/dev/axi_dma_0", O_RDWR);fd[1] = open("/dev/axi_dma_1", O_RDWR);fd[2] = open("/dev/axi_dma_2", O_RDWR);fd[3] = open("/dev/axi_dma_3", O_RDWR);unsigned long byteMoved = 0;unsigned long byteToMove = 0;int i;while(byteMoved!=size * elems){byteToMove = size * elems - byteMoved > FIFO_LEN ? FIFO_LEN : size * elems - byteMoved;for(i=0; i<dmaToUse; i++){write(fd[i], &bufferIn[byteMoved], byteToMove);}for(i=0; i<dmaToUse; i++)read(fd[i], &bufferOut[byteMoved], byteToMove);byteMoved += byteToMove;}close(fd[0]);close(fd[1]);close(fd[2]);close(fd[3]);return elems * size * dmaToUse;
}int main(int argc, char **argv)
{char *bufferIn, *bufferOut_ARM, *bufferOut_DMA;if(argc!=3){printf("Usage: ./dmaBench DATA DMA_TO_USE\n");exit(0);}unsigned long DATA = atoi(argv[1]);unsigned int DMA_TO_USE = atoi(argv[2]);bufferIn = (char *) malloc(sizeof(char) * DATA);bufferOut_ARM = (char *) malloc(sizeof(char) * DATA);bufferOut_DMA = (char *) malloc(sizeof(char) * DATA);int i;for(i=0; i<DATA; i++){bufferIn[i] = i;}memset(bufferOut_ARM, 0, sizeof(char) * DATA);memset(bufferOut_DMA, 0, sizeof(char) * DATA);REPORT(memCpy_ARM(bufferIn, bufferOut_ARM, DATA, sizeof(char)), &tStart, &tEnd, &data, "ARM", 0);for(i=0; i<DMA_TO_USE; i++){REPORT(memCpy_DMA(bufferIn, bufferOut_DMA, DATA/(i+1), sizeof(char), (i+1)), &tStart, &tEnd, &data, "DMA", (i+1));}checkData(bufferIn, bufferOut_ARM, DATA);checkData(bufferIn, bufferOut_DMA, DATA);return 0;
}
和<ds_axidma>

/** Xilinx AXI DMA Driver** Authors: *    Fabrizio Spada - fabrizio.spada@mail.polimi.it*    Gianluca Durelli - durelli@elet.polimi.it*    Politecnico di Milano** This is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.*/#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/mm.h>
#include <asm/io.h>#define MM2S_DMACR	0x00
#define MM2S_DMASR	0x04
#define MM2S_SA	0x18
#define MM2S_LENGTH	0x28#define S2MM_DMACR	0x30
#define S2MM_DMASR	0x34
#define S2MM_DA	0x48
#define S2MM_LENGTH	0x58#define DRIVER_NAME "ds_axidma_pdrv"
#define MODULE_NAME "ds_axidma"#define DMA_LENGTH	(32*1024)static struct class *cl;	// Global variable for the device class struct ds_axidma_device
{phys_addr_t bus_addr;unsigned long bus_size;char *virt_bus_addr;dev_t dev_num;const char *dev_name;struct cdev c_dev;char *ds_axidma_addr;dma_addr_t ds_axidma_handle;struct list_head dev_list;
};
LIST_HEAD( full_dev_list );static struct ds_axidma_device *get_elem_from_list_by_inode(struct inode *i)
{struct list_head *pos;struct ds_axidma_device *obj_dev = NULL;list_for_each( pos, &full_dev_list ) {struct ds_axidma_device *tmp;tmp = list_entry( pos, struct ds_axidma_device, dev_list );if (tmp->dev_num == i->i_rdev){obj_dev = tmp;break;}}return obj_dev;	
}
// static void dmaHalt(void){
// 	unsigned long mm2s_halt = ioread32(virt_bus_addr + MM2S_DMASR) & 0x1;
// 	unsigned long s2mm_halt = ioread32(virt_bus_addr + S2MM_DMASR) & 0x1;
// 	int count = 0;
// 	printk(KERN_INFO "Halting...\n");
// 	iowrite32(0, virt_bus_addr + S2MM_DMACR);
// 	iowrite32(0, virt_bus_addr + MM2S_DMACR);
// 	while( !mm2s_halt || !s2mm_halt){
// 		// mm2s_halt = ioread32(virt_bus_addr + MM2S_DMASR) & 0x1;
// 		mm2s_halt = virt_bus_addr[MM2S_DMASR] & 0x1;
// 		//s2mm_halt = ioread32(virt_bus_addr + S2MM_DMASR) & 0x1;
// 		s2mm_halt = virt_bus_addr[S2MM_DMASR] & 0x1;
// 		count++;
// 		if (count>100 )
// 		{
// 			break;
// 		}
// 	}// 	printk(KERN_INFO "DMA Halted!\n");
// }static int my_strcmp(const char *str1, const char *str2)
{int i;i = 0;while (str1[i] || str2[i]){if (str1[i] != str2[i])return (str1[i] - str2[i]);i++;}return (0);
}static int dmaSynchMM2S(struct ds_axidma_device *obj_dev){//	sleep(6);//	return;unsigned int mm2s_status = ioread32(obj_dev->virt_bus_addr + MM2S_DMASR);while(!(mm2s_status & 1<<12) || !(mm2s_status & 1<<1) ){mm2s_status = ioread32(obj_dev->virt_bus_addr + MM2S_DMASR);}return 0;
}static int dmaSynchS2MM(struct ds_axidma_device *obj_dev){unsigned int s2mm_status = ioread32(obj_dev->virt_bus_addr + S2MM_DMASR);while(!(s2mm_status & 1<<12) || !(s2mm_status & 1<<1)){s2mm_status = ioread32(obj_dev->virt_bus_addr + S2MM_DMASR);}return 0;
}static int ds_axidma_open(struct inode *i, struct file *f)
{/* printk(KERN_INFO "<%s> file: open()\n", MODULE_NAME); */struct ds_axidma_device *obj_dev = get_elem_from_list_by_inode(i);if (!request_mem_region(obj_dev->bus_addr, obj_dev->bus_size, MODULE_NAME)){return -1;}	obj_dev->virt_bus_addr = (char *) ioremap_nocache(obj_dev->bus_addr, obj_dev->bus_size);return 0;
}static int ds_axidma_close(struct inode *i, struct file *f)
{/* printk(KERN_INFO "<%s> file: close()\n", MODULE_NAME); */struct ds_axidma_device *obj_dev = get_elem_from_list_by_inode(i);iounmap(obj_dev->virt_bus_addr);release_mem_region(obj_dev->bus_addr, obj_dev->bus_size);return 0;
}static ssize_t ds_axidma_read(struct file *f, char __user * buf, size_tlen, loff_t * off)
{/* printk(KERN_INFO "<%s> file: read()\n", MODULE_NAME); */struct ds_axidma_device *obj_dev;if (len >= DMA_LENGTH){return 0;}obj_dev = get_elem_from_list_by_inode(f->f_inode);iowrite32(1, obj_dev->virt_bus_addr + S2MM_DMACR);iowrite32(obj_dev->ds_axidma_handle, obj_dev->virt_bus_addr + S2MM_DA);iowrite32(len, obj_dev->virt_bus_addr + S2MM_LENGTH);dmaSynchS2MM(obj_dev);memcpy(buf, obj_dev->ds_axidma_addr, len);return len;
}static ssize_t ds_axidma_write(struct file *f, const char __user * buf,size_t len, loff_t * off)
{/* printk(KERN_INFO "<%s> file: write()\n", MODULE_NAME); */struct ds_axidma_device *obj_dev;if (len >= DMA_LENGTH){return 0;}obj_dev = get_elem_from_list_by_inode(f->f_inode);memcpy(obj_dev->ds_axidma_addr, buf, len);// printk(KERN_INFO "%X\n", ioread32(virt_bus_addr + MM2S_DMASR));// printk(KERN_INFO "%X\n", ioread32(virt_bus_addr + MM2S_DMACR));// printk(KERN_INFO "%X\n", ioread32(virt_bus_addr + S2MM_DMASR));// printk(KERN_INFO "%X\n", ioread32(virt_bus_addr + S2MM_DMACR));iowrite32(1, obj_dev->virt_bus_addr + MM2S_DMACR);iowrite32(obj_dev->ds_axidma_handle, obj_dev->virt_bus_addr + MM2S_SA);iowrite32(len, obj_dev->virt_bus_addr + MM2S_LENGTH);// dmaSynchMM2S(obj_dev);// printk(KERN_INFO "%X\n", ioread32(virt_bus_addr + MM2S_DMASR));// printk(KERN_INFO "%X\n", ioread32(virt_bus_addr + MM2S_DMACR));// printk(KERN_INFO "%X\n", ioread32(virt_bus_addr + S2MM_DMASR));// printk(KERN_INFO "%X\n", ioread32(virt_bus_addr + S2MM_DMACR));	// printk(KERN_INFO "%X\n", bus_addr);// printk(KERN_INFO "%lu\n", bus_size);return len;
}static struct file_operations fops = {.owner = THIS_MODULE,.open = ds_axidma_open,.release = ds_axidma_close,.read = ds_axidma_read,.write = ds_axidma_write,/* .mmap = ds_axidma_mmap, *//* .unlocked_ioctl = ds_axidma_ioctl, */
};static int ds_axidma_pdrv_probe(struct platform_device *pdev)
{/* device constructor */struct ds_axidma_device *obj_dev = (struct ds_axidma_device *)kmalloc( sizeof(struct ds_axidma_device), GFP_KERNEL );obj_dev->bus_addr = pdev->resource[0].start;obj_dev->bus_size = pdev->resource[0].end - pdev->resource[0].start + 1;obj_dev->dev_name = pdev->name + 9;printk(KERN_INFO "<%s> init: registered\n", obj_dev->dev_name);if (alloc_chrdev_region(&(obj_dev->dev_num), 0, 1, obj_dev->dev_name) < 0) {return -1;}if (cl == NULL && (cl = class_create(THIS_MODULE, "chardrv")) == NULL) {unregister_chrdev_region(obj_dev->dev_num, 1);return -1;}if (device_create(cl, NULL, obj_dev->dev_num, NULL, obj_dev->dev_name) == NULL) {class_destroy(cl);unregister_chrdev_region(obj_dev->dev_num, 1);return -1;}cdev_init(&(obj_dev->c_dev), &fops);if (cdev_add(&(obj_dev->c_dev), obj_dev->dev_num, 1) == -1) {device_destroy(cl, obj_dev->dev_num);class_destroy(cl);unregister_chrdev_region(obj_dev->dev_num, 1);return -1;}printk(KERN_INFO "DMA_LENGTH = %u \n", DMA_LENGTH);/* allocate mmap area */obj_dev->ds_axidma_addr =dma_zalloc_coherent(NULL, DMA_LENGTH, &(obj_dev->ds_axidma_handle), GFP_KERNEL);list_add( &obj_dev->dev_list, &full_dev_list );return 0;
}static int ds_axidma_pdrv_remove(struct platform_device *pdev)
{/* device destructor */struct list_head *pos, *q;list_for_each_safe( pos, q, &full_dev_list ) {struct ds_axidma_device *obj_dev;obj_dev = list_entry( pos, struct ds_axidma_device, dev_list );if (!my_strcmp(obj_dev->dev_name, pdev->name + 9)){list_del( pos );cdev_del(&(obj_dev->c_dev));device_destroy(cl, obj_dev->dev_num);unregister_chrdev_region(obj_dev->dev_num, 1);/* free mmap area */if (obj_dev->ds_axidma_addr) {dma_free_coherent(NULL, DMA_LENGTH, obj_dev->ds_axidma_addr, obj_dev->ds_axidma_handle);}kfree(obj_dev);break;}}if (list_empty(&full_dev_list)){class_destroy(cl);}printk(KERN_INFO "<%s> exit: unregistered\n", MODULE_NAME);return 0;
}static int ds_axidma_pdrv_runtime_nop(struct device *dev)
{/* Runtime PM callback shared between ->runtime_suspend()* and ->runtime_resume(). Simply returns success.** In this driver pm_runtime_get_sync() and pm_runtime_put_sync()* are used at open() and release() time. This allows the* Runtime PM code to turn off power to the device while the* device is unused, ie before open() and after release().** This Runtime PM callback does not need to save or restore* any registers since user space is responsbile for hardware* register reinitialization after open().*/return 0;
}static const struct dev_pm_ops ds_axidma_pdrv_dev_pm_ops = {.runtime_suspend = ds_axidma_pdrv_runtime_nop,.runtime_resume = ds_axidma_pdrv_runtime_nop,
};static struct of_device_id ds_axidma_of_match[] = {{ .compatible = "ds_axidma", },{ /* This is filled with module_parm */ },{ /* Sentinel */ },
};
MODULE_DEVICE_TABLE(of, ds_axidma_of_match);
module_param_string(of_id, ds_axidma_of_match[1].compatible, 128, 0);
MODULE_PARM_DESC(of_id, "Openfirmware id of the device to be handled by uio");static struct platform_driver ds_axidma_pdrv = {.probe = ds_axidma_pdrv_probe,.remove = ds_axidma_pdrv_remove,.driver = {.name = DRIVER_NAME,.owner = THIS_MODULE,.pm = &ds_axidma_pdrv_dev_pm_ops,.of_match_table = of_match_ptr(ds_axidma_of_match),},
};module_platform_driver(ds_axidma_pdrv);MODULE_AUTHOR("Fabrizio Spada, Gianluca Durelli");
MODULE_DESCRIPTION("AXI DMA driver");
MODULE_LICENSE("GPL v2");

3.编译,生成BOOT.BIN文件


images/linux/目录下将生成的BOOT.BIN和image.ub文件拷贝到SD卡,插上SD卡。启动串口敲入用户名和密码(均root):


这里可以看到ds_axidma.ko这个内核module。同时可以看到apps


测试方法如下:


至此,DMA的简单实例就完成了,PS侧的DMA可以参考Audio侧,另外,如果有一些文件挂载分区,则如下:

这篇关于zedboard axiDMA linux驱动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/449455

相关文章

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法

《ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法》本文介绍了Elasticsearch的基本概念,包括文档和字段、索引和映射,还详细描述了如何通过Docker... 目录1、ElasticSearch概念2、ElasticSearch、Kibana和IK分词器部署

Linux流媒体服务器部署流程

《Linux流媒体服务器部署流程》文章详细介绍了流媒体服务器的部署步骤,包括更新系统、安装依赖组件、编译安装Nginx和RTMP模块、配置Nginx和FFmpeg,以及测试流媒体服务器的搭建... 目录流媒体服务器部署部署安装1.更新系统2.安装依赖组件3.解压4.编译安装(添加RTMP和openssl模块

linux下多个硬盘划分到同一挂载点问题

《linux下多个硬盘划分到同一挂载点问题》在Linux系统中,将多个硬盘划分到同一挂载点需要通过逻辑卷管理(LVM)来实现,首先,需要将物理存储设备(如硬盘分区)创建为物理卷,然后,将这些物理卷组成... 目录linux下多个硬盘划分到同一挂载点需要明确的几个概念硬盘插上默认的是非lvm总结Linux下多

linux进程D状态的解决思路分享

《linux进程D状态的解决思路分享》在Linux系统中,进程在内核模式下等待I/O完成时会进入不间断睡眠状态(D状态),这种状态下,进程无法通过普通方式被杀死,本文通过实验模拟了这种状态,并分析了如... 目录1. 问题描述2. 问题分析3. 实验模拟3.1 使用losetup创建一个卷作为pv的磁盘3.

Linux环境变量&&进程地址空间详解

《Linux环境变量&&进程地址空间详解》本文介绍了Linux环境变量、命令行参数、进程地址空间以及Linux内核进程调度队列的相关知识,环境变量是系统运行环境的参数,命令行参数用于传递给程序的参数,... 目录一、初步认识环境变量1.1常见的环境变量1.2环境变量的基本概念二、命令行参数2.1通过命令编程

Linux之进程状态&&进程优先级详解

《Linux之进程状态&&进程优先级详解》文章介绍了操作系统中进程的状态,包括运行状态、阻塞状态和挂起状态,并详细解释了Linux下进程的具体状态及其管理,此外,文章还讨论了进程的优先级、查看和修改进... 目录一、操作系统的进程状态1.1运行状态1.2阻塞状态1.3挂起二、linux下具体的状态三、进程的

Linux编译器--gcc/g++使用方式

《Linux编译器--gcc/g++使用方式》文章主要介绍了C/C++程序的编译过程,包括预编译、编译、汇编和链接四个阶段,并详细解释了每个阶段的作用和具体操作,同时,还介绍了调试和发布版本的概念... 目录一、预编译指令1.1预处理功能1.2指令1.3问题扩展二、编译(生成汇编)三、汇编(生成二进制机器语

Rsnapshot怎么用? 基于Rsync的强大Linux备份工具使用指南

《Rsnapshot怎么用?基于Rsync的强大Linux备份工具使用指南》Rsnapshot不仅可以备份本地文件,还能通过SSH备份远程文件,接下来详细介绍如何安装、配置和使用Rsnaps... Rsnapshot 是一款开源的文件系统快照工具。它结合了 Rsync 和 SSH 的能力,可以帮助你在 li

Linux部署jar包过程

《Linux部署jar包过程》文章介绍了在Linux系统上部署Java(jar)包时需要注意的几个关键点,包括统一JDK版本、添加打包插件、修改数据库密码以及正确执行jar包的方法... 目录linux部署jar包1.统一jdk版本2.打包插件依赖3.修改密码4.执行jar包总结Linux部署jar包部署