DMA(Direct Memory Access)驱动
2019-06-05 20:09
100 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_35270493/article/details/90931818
DMA概念:
DMA是一个独立的模块存在于处理器,DMA是不通过CPU而是
直接访问内存,使用DMA,可以释放CPU的"压力",使得它不会一直在做
一件事,使用了DMA也能达到直接使用CPU的效果。
现在假设代码片段:
char *src = AAA;
char *dest = BBB;
int i;
for(i=0;i<size;i++) dest[i] = src[i];
DMA:
①把源告诉DMA
②把目的告诉DMA
③把size告诉DMA
④设置DMA参数
地址递增递减不变
⑤启动DMA
手工启动
外部启动
DMA驱动编写:
①注册DMA中断,分配缓冲区;
②注册字符设备,并提供文件操作集合fops;
③硬件相关操作
/*1、 注册中断,分配缓冲区*/ request_irq(IRQ_DMA3,s3c_dma_irq, 0, "s3c_dma", 1)); //分配SRC缓冲区 src = dma_alloc_writecombine(NULL, BUF_SIZE, &src_phys, GFP_KERNEL); //分配 DST缓冲区 dst = dma_alloc_writecombine(NULL, BUF_SIZE, &dst_phys, GFP_KERNEL) /*2、注册字符设备,提供操作集合*/ major = register_chrdev(0, "s3c_dma", &dma_fops); /*2.1 为了自动创建设备节点*/ cls = class_create(THIS_MODULE, "s3c_dma"); class_device_create(cls, NULL, MKDEV(major, 0), NULL, "dma"); // dev/dma /*3、硬件相关的操作(在ioctl的case分支里)*/ dma_regs = ioremap(0x4B0000C0, sizeof(struct s3c_dma_regs))//先映射 // 把源,目的,长度告诉DMA dma_regs->disrc= src_phys // 源的物理地址 dma_regs->disrcc= (0<<1) | (0<<0) // 源位于AHB总线, 源地址递增 dma_regs->didst= dst_phys //目的的物理地址 dma_regs->didstc= (0<<2) | (0<<1) | (0<<0) //目的位于AHB总线, 目的地址递增 dma_regs->dcon= (1<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<23)|(0<<20)|(BUF_SIZE<<0)//使能中断,单个传输,软件触发 //启动DMA dma_regs->dmasktrig = (1<<1) | (1<<0);
IRQ_DMA3: DMA中断,在arch/arm/machs3c24xx\include\mach\irqs.h
s3c_dma_irq:中断处理函数,一般在这里休眠
src_phys,dst_phys:存放分配后的物理地址,u32类型
BUF_SIZE: 宏,512字节
dma_fops:在linux_Dir\include\linux\fs.h,里面有很多成员,在这里只需要设置它的ioctrl
dma_regs为自定义的结构体:
struct s3c_dma_regs { unsigned long disrc; unsigned long disrcc; unsigned long didst; unsigned long didstc; unsigned long dcon; unsigned long dstat; unsigned long dcsrc; unsigned long dcdst; unsigned long dmasktrig; };
其驱动代码:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/irq.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> #include <asm/arch/regs-gpio.h> #include <asm/hardware.h> #include <linux/poll.h> #include <linux/dma-mapping.h> #define MEM_CPY_NO_DMA 0 #define MEM_CPY_DMA 1 #define BUF_SIZE (512*1024) #define DMA0_BASE_ADDR 0x4B000000 #define DMA1_BASE_ADDR 0x4B000040 #define DMA2_BASE_ADDR 0x4B000080 #define DMA3_BASE_ADDR 0x4B0000C0 struct s3c_dma_regs { unsigned long disrc; unsigned long disrcc; unsigned long didst; unsigned long didstc; unsigned long dcon; unsigned long dstat; unsigned long dcsrc; unsigned long dcdst; unsigned long dmasktrig; };static int major = 0; static char *src; static u32 src_phys; static char *dst; static u32 dst_phys; static struct class *cls; static volatile struct s3c_dma_regs *dma_regs; static DECLARE_WAIT_QUEUE_HEAD(dma_waitq); /* 中断事件标志, 中断服务程序将它置1,ioctl将它清0 */ static volatile int ev_dma = 0; static int s3c_dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int i; memset(src, 0xAA, BUF_SIZE); memset(dst, 0x55, BUF_SIZE); switch (cmd) { case MEM_CPY_NO_DMA : { for (i = 0; i < BUF_SIZE; i++) dst[i] = src[i]; if (memcmp(src, dst, BUF_SIZE) == 0) { printk("MEM_CPY_NO_DMA OK\n"); } else { printk("MEM_CPY_DMA ERROR\n"); } break; } case MEM_CPY_DMA : { ev_dma = 0; /* 把源,目的,长度告诉DMA */ dma_regs->disrc = src_phys; /* 源的物理地址 */ dma_regs->disrcc = (0<<1) | (0<<0); /* 源位于AHB总线, 源地址递增 */ dma_regs->didst = dst_phys; /* 目的的物理地址 */ dma_regs->didstc = (0<<2) | (0<<1) | (0<<0); /* 目的位于AHB总线, 目的地址递增 */ dma_regs->dcon = (1<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<23)|(0<<20)|(BUF_SIZE<<0); /* 使能中断,单个传输,软件触发, */ /* 启动DMA */ dma_regs->dmasktrig = (1<<1) | (1<<0); /* 如何知道DMA什么时候完成? */ /* 休眠 */ wait_event_interruptible(dma_waitq, ev_dma); if (memcmp(src, dst, BUF_SIZE) == 0) { printk("MEM_CPY_DMA OK\n"); } else { printk("MEM_CPY_DMA ERROR\n"); } break; } } return 0; } static struct file_operations dma_fops = { .owner = THIS_MODULE, .ioctl = s3c_dma_ioctl, }; static irqreturn_t s3c_dma_irq(int irq, void *devid) { /* 唤醒 */ ev_dma = 1; wake_up_interruptible(&dma_waitq); /* 唤醒休眠的进程 */ return IRQ_HANDLED; } static int s3c_dma_init(void) { if (request_irq(IRQ_DMA3, s3c_dma_irq, 0, "s3c_dma", 1)) { printk("can't request_irq for DMA\n"); return -EBUSY; } /* 分配SRC, DST对应的缓冲区 */ src = dma_alloc_writecombine(NULL, BUF_SIZE, &src_phys, GFP_KERNEL); if (NULL == src) { printk("can't alloc buffer for src\n"); free_irq(IRQ_DMA3, 1); return -ENOMEM; } dst = dma_alloc_writecombine(NULL, BUF_SIZE, &dst_phys, GFP_KERNEL); if (NULL == dst) { free_irq(IRQ_DMA3, 1); dma_free_writecombine(NULL, BUF_SIZE, src, src_phys); printk("can't alloc buffer for dst\n"); return -ENOMEM; } major = register_chrdev(0, "s3c_dma", &dma_fops); /* 为了自动创建设备节点 */ cls = class_create(THIS_MODULE, "s3c_dma"); class_device_create(cls, NULL, MKDEV(major, 0), NULL, "dma"); /* /dev/dma */ dma_regs = ioremap(DMA3_BASE_ADDR, sizeof(struct s3c_dma_regs)); return 0; } static void s3c_dma_exit(void) { iounmap(dma_regs); class_device_destroy(cls, MKDEV(major, 0)); class_destroy(cls); unregister_chrdev(major, "s3c_dma"); dma_free_writecombine(NULL, BUF_SIZE, src, src_phys); dma_free_writecombine(NULL, BUF_SIZE, dst, dst_phys); free_irq(IRQ_DMA3, 1); } module_init(s3c_dma_init); module_exit(s3c_dma_exit); MODULE_LICENSE("GPL");
测试代码:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <string.h> /* ./dma_test nodma * ./dma_test dma */ #define MEM_CPY_NO_DMA 0 #define MEM_CPY_DMA 1 void print_usage(char *name) { printf("Usage:\n"); printf("%s <nodma | dma>\n", name); } int main(int argc, char **argv) { int fd; if (argc != 2) { print_usage(argv[0]); return -1; } fd = open("/dev/dma", O_RDWR); if (fd < 0) { printf("can't open /dev/dma\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 { print_usage(argv[0]); return -1; } return 0; }
相关文章推荐
- DMA(Direct Memory Access)直接存储器存取
- DMA(Direct Memory Access直接存储器访问)总结
- DMA(direct memory access)控制方式
- DMA(direct memory access)直接内存访问
- DMA (Direct Memory Access,直接内存存取)
- 寒假学习之stm32(15)----DMA(direct memory access)
- linuxMTD子系统之一DMA(Direct Memory Access)
- DMA(direct memory access)直接内存访问
- 寒假学习之stm32(15)----DMA(direct memory access)
- DMA 驱动代码
- Linux DMA驱动构架分析
- Linux DMA Engine framework(3)_dma controller驱动
- DMA驱动框架流程编写
- Linux内核与驱动开发学习总结:DMA与中断(一)
- ARM-Linux驱动--DMA驱动分析(一)
- ZedBoard--(5)嵌入式Linux下的DMA测试(Direct Register Mode)(PS + PL)
- DMA设备驱动(一)————DMA简介
- dma驱动
- Linux 下的显卡驱动 之DRI(Direct Rendering Infrastructure)(1)
- linux驱动之DMA驱动