DMA驱动程序编写

本文介绍了DMA(直接内存存取)技术的引入原因及其优势,详细阐述了如何编写DMA驱动程序,包括字符设备驱动的构造、DMA驱动的初步框架、填充框架以及完整的驱动程序示例。还提到了DMA测试程序的编写和执行过程,展示了如何利用DMA提高数据传输效率并减少CPU负载。
摘要由CSDN通过智能技术生成

一.  DMA的引入

    假设我们让2440来拷贝一段数据, 从内存的src拷贝到dst,拷贝的长度为size.

char *src = AAA;

char *dst = BBB;

int i;

for (i = 0; i <size; i++)

    dst[i] = src[i];

    这写出来的代码是让cpu来执行数据的拷贝工作, 显然,cpu在执行这个过程中,同一时间内只能做一件事情,如果要拷贝的数据很大的话,cpu在拷贝的过程中就不能做其他事情了,这样就会引起卡顿.


    所以我们就引入了DMA (Direct Memory Access,直接内存存取), 它允许不同速度的硬件装置来沟通, 而不需要依赖于 CPU 的大量中断负载.

    1. 把源告诉DMA;

    2. 把目的告诉DMA;

    3. 把size告诉DMA;

    4. 设置DMA参数 a. 地址递增/递减/不变; b. 手工启动(设置某些寄存器让它自动的启动DMA去拷贝这些数据), 外部启动(麦克MIC得到数据存在I2S的数据缓冲区里,当这个缓冲区里有了数据之后就会去触发DMA产生一个DMA请求, 由DMA将数据拷贝到内存里, 这时的源就是I2S的缓冲区, 目的就是内存的某个地址处)

    5.启动DMA.

    启动DMA之后, DMA就会将数据拷从src拷贝到dst,拷贝完之后就会发出一个中断告诉cpu数据拷贝完成.


二. DMA驱动程序编写

(一). 怎么写字符设备驱动

    应用程序APP要open, 要read, 要write等 ;应用程序就提供对映的drv_open, drv_read, drv_write等. 为了便于管理引入一个 file_operations 结构体, 把这些open, read等函数放入这个结构体. 构造好file_operations 结构体之后要用起来, 要注册进内核:register_chrdev(主设备号, 名字, file_operations);

    0. 确定主设备号;

    1. 构造file_operations 结构体

    2. 注册:register_chrdev(主设备号, 名字, file_operations);

    3. 入口

    4. 出口

    分配缓冲区不能用kmalloc来分配, 因为kmalloc分配出来的内存是虚拟地址上连续的, 物理地址上并非连续. 而想用DMA的话就必须用连续的物理内存, 这个DMA没那么高的智能, 它只能处理物理地址连续的内存.


(二). DMA驱动初步框架

dma.c

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          #include 
         
           #include 
          
            #include 
           
             #include 
            
              #include 
             
               #include 
              
                static int major = 0; #define MEM_CPY_NO_DMA 0 #define MEM_CPY_DMA 1 static char *src; /* 源 */ static u32 src_phys; /* 源的物理地址 */ static char *dst; /* 目的 */ static u32 dst_phys; /* 目的的物理地址 */ static struct class *cls; #define BUF_SIZE (512*1024) //512k static int s3c_dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { switch (cmd) { case MEM_CPY_NO_DMA : { break; } case MEM_CPY_DMA : { break; } } return 0; } /* 构造file_operations结构体 */ static struct file_operations dma_fops = { .owner = THIS_MODULE, .ioctl = s3c_dma_ioctl, }; static int s3c_dma_init(void) { /* 分配SRC, DST对应的缓冲区 */ src = dma_alloc_writecombine(NULL, BUF_SIZE, &src_phys, GFP_KERNEL); if (NULL == src) { printk("can't alloc buffer for src\n"); return -ENOMEM; } dst = dma_alloc_writecombine(NULL, BUF_SIZE, &dst_phys, GFP_KERNEL); if (NULL == dst) { 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 */ return 0; } static void s3c_dma_exit(void) { 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); } module_init(s3c_dma_init); module_exit(s3c_dma_exit); MODULE_LICENSE("GPL"); 
               
              
             
            
           
          
         
       
      
      
     
     
    
    
   
   

     注: 第66行里所说的内存泄漏是指, 这块内存被分配了, 却没有被调用,也没有被释放.

    上面的代码里只分配了两块内存,我们把重点的东西放在s3c_dma_ioctl里, 下面再来写.

(三). DMA驱动填充框架

      在开发板上执行# ls /dev/dma*  查看开发板上有没有这个设备节点, 没有继续, 有就去掉这个设备节点.

      填充s3c_dma_ioctl, 不用DMA:

static int s3c_dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	int i;

	memset(src, 0xAA, BUF_SIZE);/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值