博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
dma.c
阅读量:5161 次
发布时间:2019-06-13

本文共 5152 字,大约阅读时间需要 17 分钟。

/* 重复了一下以前的代码,对于理解是比较有价值的 ,由于自己电脑联网的原因没有在板子上跑,这里先到这里 *//* * 目的:用for循环语句copy内存的数据到内存的另外一个地方;用dma实现同样的功能. *         对比普通的copy 和 用dma功能的区别. * 提示: *         一次dma传输完成之后让进程休眠,然后在中断服务程序中唤醒. *        (对于睡眠理解:app->ioctl->驱动中ioctl执行dma启动,dma控制器就开始搬移数据了,然后睡眠,虽然app睡眠但dmacontroler并没有停) */#include 
#include
#include
#include
#include
#include
#include
#define MEM_CPY_NO_DMA 0#define MEM_CPY_DMA 1static char *src;static u32 src_phyc;static char *dst;static u32 dst_phyc;#define BUFF_SIZE (512 * 1024)static int major = 0;static struct class * dma_class;#define DMA0_BASE_ADDR 0x4B000000#define DMA1_BASE_ADDR 0x4B000040#define DMA2_BASE_ADDR 0x4B000080#define DMA3_BASE_ADDR 0x4B0000c0struct dma_regs { unsigned int disrc ; unsigned int disrcc ; unsigned int didst ; unsigned int didstc ; unsigned int dcon ; unsigned int dstat ; unsigned int dcsrc ; unsigned int dcdst ; unsigned int dmasktrig; };static volatile struct dma_regs * dma_regp = NULL;static wait_queue_head_t dma_wqh; /* 定义等待队列头变量 */static volatile int ev_dma = 0 ; /* 中断处理函数将它置为1 */static int dma_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ int i; memset(src,0xAA,BUFF_SIZE); memset(dst,0x55,BUFF_SIZE); switch(cmd) { case MEM_CPY_NO_DMA: { for(i = 0 ; i < BUFF_SIZE ; i++) { dst[i] = src[i]; } if(memcmp(src,dst,BUFF_SIZE) == 0) printk("MEM_CPY_NO_DMA OK! \n"); else printk("MEM_CPY_NO_DMA ERROR! \n"); break; } case MEM_CPY_DMA: { /* 设置dma控制寄存器 */ dma_regp->disrc = src_phyc; dma_regp->disrcc = (0 << 1) | (0 << 0); /* 源在内存,地址递增(如果是如uart等外设需要设为地址固定) */ dma_regp->didst = dst_phyc; dma_regp->didstc = (0 << 2) | (0 << 1) | (0 << 0); /* TC = 0时产生中断,本例子里不需要自动加载源,目的, 大小参数 */ /*dcon * [31]: 0 软件触发,故选择Demand mode , 如果是外设如 iis就要用握手模式,req 和 ack引脚要工作; * [30]: 本实例不用管; * [29]: 1 使能中断; * [28]: TSZ , 0 单个传输,其实突发传输应该也可以; * [27]: 0 但服务方式,这样不会完全霸占总线; * [26:24]: 本实例不管,本实验是软件实验,和外设没有关系; * [23]: 0 software request mode; * [22]: 0 本实验不需要重新加载; * [21:20]: DSZ , 00 和[28]配合设置(一致); * [19:0] : TC ,传输次数 总长度 = TC * TSZ(1或4) * DSZ; */        //这里修改过,[27]还要仔细思考?设为0未必就会失败, [30]ram-ram的dma操作,ram是在系统的AHB总线上的. //dma_regp->dcon = (0 << 31) |(1 << 29) |(0 << 27) |(0 << 28) | (0 << 23) |(0 << 20 ) |(BUFF_SIZE); dma_regp->dcon = (0 << 31) |(1<<30)|(1 << 29) |(1 << 27) |(0 << 28) | (0 << 23) |(0 << 20 ) |(BUFF_SIZE); /* 启动dma * 每传输一次就会进行一次dma request,知道数据传完, * 传输完TC = 0 引起中断,所以需要注册一个中断 */ dma_regp->dmasktrig = (1<< 1) |(1<<0); /* dma启动之后就让应用程序休眠了,但是dma控制器还在不停第搬移数据,完成后引起中断,在中断服务程序中再次唤醒该进程 */ wait_event_interruptible(dma_wqh, ev_dma); /* ev_dma = 0则进程睡眠 */ if(memcmp(src,dst,BUFF_SIZE) == 0) printk("MEM_CPY_DMA OK! \n"); else printk("MEM_CPY_DMA ERROR! \n"); break; } default: break; } return 0;}static const struct file_operations dma_operation = { .owner = THIS_MODULE, .ioctl = dma_ioctl,};static irqreturn_t dma_irq_handler(int irq, void *dev_id){ ev_dma = 1; /* ev_dma可不可以不设为1?,自己分析这要看应用程序了*/ wake_up_interruptible(&dma_wqh); return IRQ_HANDLED;}static int __init dma_init(void){ int ret; major = register_chrdev(0, "mydma", &dma_operation); dma_class = class_create(THIS_MODULE, "DMA_CLASS"); device_create(dma_class, NULL,MKDEV(major,0), NULL, "DMADEV"); /* 由于内核 dma特殊的操作特性,src , src_phyc都是有内核机制给提供的 */ src = dma_alloc_writecombine(NULL, BUFF_SIZE, &src_phyc, GFP_KERNEL); if(NULL == src) { printk("can't alloc buff for src !"); return -ENOMEM; } dst = dma_alloc_writecombine(NULL, BUFF_SIZE, &dst_phyc, GFP_KERNEL); if(NULL == src) { printk("can't alloc buff for dst !"); return -ENOMEM; } dma_regp = ioremap(DMA3_BASE_ADDR , sizeof(struct dma_regs)); ret = request_irq(IRQ_DMA3, dma_irq_handler, IRQF_TRIGGER_NONE, "dma_irq", NULL); if(ret) { printk(" can't request_irq for DMA \n"); return -EBUSY; } init_waitqueue_head(&dma_wqh); return 0;}static void __exit dma_exit(void){ free_irq(IRQ_DMA3, NULL); iounmap(dma_regp); dma_free_writecombine(NULL,BUFF_SIZE,dst,dst_phyc); dma_free_writecombine(NULL,BUFF_SIZE,src,src_phyc); device_destroy(dma_class, MKDEV(major,0)); class_destroy(dma_class); unregister_chrdev(major, "mydma");}module_init(dma_init);module_exit(dma_exit);MODULE_LICENSE("GPL"); ********************************************************************************************************************************************* 测试程序:
/* * ./dma_test nodma * ./dam_test dma */#include 
#include
#include
#include
#include
#include
#define MEM_CPY_NO_DMA 0#define MEM_CPY_DMA 1void printt_usage(char *name){ printf("Usage:\n"); printf("%s
\n", name);}int main(int argc , char *argv[]){ int cnt; int fd; if(argc != 2) { printt_usage(argv[0]); return -1; } fd = open("/dev/dma",O_RDWR); if(fd < 0) { printf("Can't open /dev/dma file \n"); return -1; } if(strcmp(argv[1] , "nodma") == 0) { while(1) { ioctl(fd,MEM_CPY_NO_DMA); } } else if(strcmp(argv[1] , "dma") == 0) { while(1) { ioctl(fd,MEM_CPY_DMA); } } else printt_usage(argv[0]); return 0; }
 

转载于:https://www.cnblogs.com/tureno/articles/6045255.html

你可能感兴趣的文章
搞JAVA在北京月薪15K的朋友来到厦门却很难找到工作
查看>>
冒泡数组排序
查看>>
kibana5画图
查看>>
类的加载和反射
查看>>
Linux学习笔记四
查看>>
JavaScript
查看>>
[转]getHibernateTemplate出现的所有find方法的总结
查看>>
【转】HTTP中的长连接和短连接分析
查看>>
scala 基本语法
查看>>
2019.08.02 学习整理
查看>>
JavaScript面向对象基础语法总结
查看>>
页面输入模糊数据---异步后台查询
查看>>
Java基础入门(二)
查看>>
Numpy数组
查看>>
数据库设计(1)
查看>>
Cocos2d-x 脚本语言Lua基本数据结构-表(table)
查看>>
BZOJ.4695.最假女选手(线段树 Segment tree Beats!)
查看>>
迭代器&&生成器
查看>>
js中的事件委托或是事件代理详解
查看>>
如何显示超大图像
查看>>