开发板:A33,运行linux-3.4.39

主机:Ubuntu 14.04

----------------------------------------------

DMA是Direct Memory Access的缩写,顾名思义,就是绕开CPU直接访问memory的意思。在计算机中,相比CPU,memory和外设的速度是非常慢的,因而在memory和memory(或者memory和设备)之间搬运数据,非常浪费CPU的时间,造成CPU无法及时处理一些实时事件。因此,工程师们就设计出来一种专门用来搬运数据的器件----DMA控制器,协助CPU进行数据搬运。

DMA传输可以是内存到内存、内存到外设和外设到内存。这里的代码通过dma驱动实现了内存到内存的数据传输。linux实现了DMA框架,叫做DMA Engine,内核驱动开发者必须按照固定的流程编码才能正确的使用DMA。

1. DMA用法包括以下的步骤:

1)分配一个DMA通道;

dma_request_channel()

2)设置controller特定的参数;

none

3)获取一个传输描述符;

device_prep_dma_memcpy()

4)提交传输描述符;

tx_submit();

5)dma_async_issue_pending()

2. 测试:

1)交叉编译成ko模块,下载到A33开发板

2)加载模块:insmod dma.ko

3)执行:cat /dev/dma_test

执行此操作会产生一次DMA请求,将src内存数据复制到dst内存区域,复制完后会调用回调函数,复制过程中不需要CPU的参与。

注:在Ubuntu下dma_request_channel()失败,原因未知,所以转到A33下测试。

3. 其它

申请DMA缓冲区:

void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, int flag);

该函数实际获得两个地址,

1、函数的返回值是一个 void *,代表缓冲区的内核虚拟地址

2、相关的总线地址(物理地址),保存在dma_handle中

物理地址和虚拟地址存在映射关系。DMA传输使用物理地址,而CPU操作的是虚拟地址。

如在tx = dev->device_prep_dma_memcpy(chan, dma_dst, dma_src, 512, flags);使用了物理地址

在dma_callback_func()中使用了虚拟地址。

使用DMA传输数据必须要基于DMA缓冲区,不能使用其他的内存区域,如kmalloc开辟的内存。

4. 源码dma.c

/*
Function description:When we call dmatest_read(),it will transmit src memory data
to dst memory,then print dst memory data by dma_callback_func(void) function.
*/
#include<linux/module.h>
#include<linux/init.h>
#include<linux/fs.h>
#include<linux/sched.h>#include<linux/device.h>
#include<linux/string.h>
#include<linux/errno.h>#include<linux/types.h>
#include<linux/slab.h>
#include<linux/dmaengine.h>
#include<linux/dma-mapping.h>#include<asm/uaccess.h>#define DEVICE_NAME "dma_test"unsigned char dmatest_major;
static struct class *dmatest_class;struct dma_chan *chan;//bus address
dma_addr_t dma_src;
dma_addr_t dma_dst;
//virtual address
char *src = NULL;
char *dst = NULL ;
struct dma_device *dev;
struct dma_async_tx_descriptor *tx = NULL;
enum dma_ctrl_flags flags;
dma_cookie_t cookie;//When dma transfer finished,this function will be called.
void dma_callback_func(void)
{int i;printk("dma transfer ok.\n");for (i = 0; i < 512; ){printk("dst[%d]:%c ", i, dst[i]);i += 10;}printk("\n");
}int dmatest_open(struct inode *inode, struct file *filp)
{return 0;
}int dmatest_release(struct inode *inode, struct file *filp)
{return 0;
}static ssize_t dmatest_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{int ret = 0;//alloc a desc,and set dst_addr,src_addr,data_size.tx = dev->device_prep_dma_memcpy(chan, dma_dst, dma_src, 512, flags);if (!tx){printk("Failed to prepare DMA memcpy");}tx->callback = dma_callback_func;//set call back functiontx->callback_param = NULL;cookie = tx->tx_submit(tx); //submit the descif (dma_submit_error(cookie)){printk("Failed to do DMA tx_submit");}printk("begin dma transfer.\n");   dma_async_issue_pending(chan);  //begin dma transferreturn ret;
}static ssize_t dmatest_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{int ret = 0;return ret;
}static const struct file_operations dmatest_fops = {.owner = THIS_MODULE,.read = dmatest_read,.write = dmatest_write,.open = dmatest_open,.release = dmatest_release,
};int dmatest_init(void)
{int i;dma_cap_mask_t mask;//the first parameter 0 means allocate major device number automaticallydmatest_major = register_chrdev(0, DEVICE_NAME, &dmatest_fops);if (dmatest_major < 0) return dmatest_major;//create a dmatest classdmatest_class = class_create(THIS_MODULE,DEVICE_NAME);if (IS_ERR(dmatest_class))return -1;//create a dmatest device from this classdevice_create(dmatest_class,NULL,MKDEV(dmatest_major,0),NULL,DEVICE_NAME);printk("device node create ok.\n");//alloc 512B src memory and dst memorysrc = dma_alloc_coherent(NULL, 512, &dma_src, GFP_KERNEL);printk("src = 0x%x, dma_src = 0x%x\n",src, dma_src);dst = dma_alloc_coherent(NULL, 512, &dma_dst, GFP_KERNEL);printk("dst = 0x%x, dma_dst = 0x%x\n",dst, dma_dst);for (i = 0; i < 512; i++){*(src + i) = 'a';}dma_cap_zero(mask);dma_cap_set(DMA_MEMCPY, mask);    //direction:memory to memorychan = dma_request_channel(mask,NULL,NULL);    //request a dma channelif(chan)printk("dma channel id = %d\n",chan->chan_id);else{printk("dma_request_channel faild.\n");return -1;}flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;dev = chan->device;return 0;
}void dmatest_exit(void)
{unregister_chrdev(dmatest_major,DEVICE_NAME);//release major device numberdevice_destroy(dmatest_class,MKDEV(dmatest_major,0));//destroy globalmem deviceclass_destroy(dmatest_class);//destroy globalmem class//free memory and dma channeldma_free_coherent(NULL, 512, src, &dma_src);dma_free_coherent(NULL, 512, dst, &dma_dst);dma_release_channel(chan);
}module_init(dmatest_init);
module_exit(dmatest_exit);MODULE_LICENSE("GPL");

linux dmaengine编程相关推荐

  1. Linux网络编程--进程间通信(一)

    进程间通信简介(摘自<Linux网络编程>p85) AT&T 在 UNIX System V 中引入了几种新的进程通讯方式,即消息队列( MessageQueues),信号量( s ...

  2. Linux io模型及函数调用,Linux 网络编程的5种IO模型:信号驱动IO模型

    Linux 网络编程的5种IO模型:信号驱动IO模型 背景 这一讲我们来看 信号驱动IO 模型. 介绍 情景引入: 在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个 ...

  3. 外网访问arm嵌入式linux_嵌入式Linux系统编程——文件读写访问、属性、描述符、API

    Linux 的文件模型是从 Unix 的继承而来,所以 Linux 继承了 UNIX 本身的大部分特性,然后加以扩展,本章从 UNIX 系统接口来描述 Linux 系统结构的特性. 操作系统是通过一系 ...

  4. linux高性能网络编程,Linux高性能网络编程的介绍

    Linux高性能网络编程 一.课程目标 本次课程深入讲解Linux下的socket编程,并以此为基础,着重讨论如何提高网络服务端应用的性能,通过本次课程的学习,学员将收获以下方面的成果: 熟练使用so ...

  5. linux web高级编程,寒假学习 第16.17天 (linux 高级编程)

    寒假学习 第16.17天 (linux 高级编程) 笔记 总结 一.进程的基本控制(进程的同步) 1.进程的常见控制函数 pause   sleep/usleep atexit   on_exit i ...

  6. Linux网络编程实例分析

    最近由于工作原因需要温习一下Linux网络编程的部分基础知识,因此对之前写的Socket网络通信的代码进行了进一步优化和拓展,在不关闭一次Socket连接的基础上,对服务端加入循环读写的功能,同时加入 ...

  7. Linux多任务编程之五:exit()和_exit()函数(转)

    来源:CSDN  作者:王文松   转自:Linux公社 ----------------------------------------------------------------------- ...

  8. Linux网络编程必看书籍推荐

    首先要说讲述计算机网络和TCP/IP的书很多. 先要学习网络知识才谈得上编程 讲述计算机网络的最经典的当属Andrew S.Tanenbaum的<计算机网络>第五版,这本书难易适中. &l ...

  9. linux系统发送信号的系统调用是,linux系统编程之信号:信号发送函数sigqueue和信号安装函数sigaction...

    信号发送函数sigqueue和信号安装函数sigaction sigaction函数用于改变进程接收到特定信号后的行为. sigqueue()是比较新的发送信号系统调用,主要是针对实时信号提出的(当然 ...

最新文章

  1. 产品经理在创造AI,到底在创造什么
  2. vt Hypervisor Framework
  3. 光敏电阻控制led亮度程序_利用光敏电阻加声音传感器制作声控灯
  4. QThread: Destroyed while thread is still running
  5. IdentityServer4-EF动态配置Client和对Claims授权(二)
  6. Party at Hali-Bula(树形DP+判断方案数是否唯一)
  7. 性能测试工具curl-loader(linux)
  8. node.js的下载,安装以及卸载
  9. 安装,使用node和npm,切换镜像源cnpm
  10. 高仿蓝奏云单页下载页面源码
  11. flutter 拖拽布局_Flutter 史上最牛拖动控件 Draggable
  12. 全心加入web前端开发,向上吧!
  13. android-async-http框架之与服务器进行数据交互
  14. netconsole 重定向kernel日志到远程服务器
  15. vulhub Tomcat8漏洞复现
  16. W3Cschoool菜鸟教程
  17. 在前端实现excel导入,在线编辑,导出,打印等功能
  18. iOS-----GitHub上比较齐全的iOS 工具和App
  19. 以优质氘代产品为刃,劈开生物原材料市场壁垒
  20. 了解Windows 10中的新开始菜单

热门文章

  1. Angular定义服务-Learn By Doing
  2. poj2337 欧拉路径
  3. 要鼓励周鸿祎做360搜索
  4. Windows Server 2008 IIS7.0 发布html和Asp.net网站
  5. python 表格处理软件_基于Python的Excel处理工具
  6. java 加日志_java中添加日志
  7. java 图片压缩100k_如何将图片压缩到100K以内,教你几种免费方法
  8. Task On The Board CodeForces - 1367D(思维)
  9. so easy(2019徐州icpc网络赛B)
  10. 服务器位置缩写,服务器地区缩写