当前位置: 首页 > news >正文

DMA学习

一、DMA简介

        DMA是一种无需CPU的参与就可以让外设与系统内存之间进行双向数据传输的硬件机制。使用DMA可以使系统CPU从实际的I/O数据传输过程中摆脱出来,从而大大提高系统的吞吐率。

        DMA方式的数据传输由DMA控制器(DMAC)控制,在传输期间,CPU可以并发执行其他任务。当DMA结束后,DMAC通过中断通知CPU数据传输已经结束,然后由CPU执行相应的中断服务程序后进行处理。

二、DMA工作流程

    

 准备阶段:CPU会对DMA控制器和IO接口进行初始化,初始化内容如下:

1、DMA控制器初始化:配置DMA内存缓冲区的首地址、配置DMA的传输方向、配置DMA交换量。

2、接口的初始化:I/O设备的寻址信息

传输请求

1、设备接口->DMA控制器:设备接口向DMA控制器发送“DMA请求”,即请求使用DMA进行数据传输。

2、DMA控制器->CPU:DMA控制器向CPU申请“总线占用”,DMA控制器和CPU只有一个能占用总线。

3、CPU->DMA控制器:CPU批准使用总线,此时CPU会让出一个或多个总线周期用于数据传输。在DMA数据传输期间,CPU停止访问内存,无法执行需要占用总线的指令。

4、DMA控制器->设备接口:DMA批准设备请求,此时DMA控制器将掌握总线控制权。如果是单字节传送,一个总线周期后,DMA归还总线控制权;如果是块传送,连续占用若干个总线周期后,DMA才会归还总线控制权。

数据传送:数据传送期间,DMA控制器会向总线发送读 /写命令、向I/O接口发响应信号。真正的数据交互是内存和设备接口,DMA控制器只是负责控制整个数据传送流程

善后处理:在初始化时,CPU便指定了DMA的交换量,而且DMA控制器内部有一个计数器,只有DMA控制器直到传送是否结束。当传送结束时,DMA控制器向CPU发送一个传输完成的终端,CPU重新接管总线的控制权。

三、DMA与Cache的一致性

        Cache和DMA是两个事物,Cache是一种用于提高数据访问速度的技术,利用程序的空间局部性和时间局部性原理,通过将数据存储在快速访问的存储介质中来减少相对较慢的存储介质的访问次数,从而提高数据的访问速率。而DMA可以用作内存与外设之间传输数据的方式,这种传输方式下,数据并不需要经过CPU的中转。

        当DMA针对内存的目的地址与Cache缓存的对象没有重叠区域时,DMA和Cache之间将相安无事。但如果DMA的目的内存地址和Cache缓存的内存地址之间有重叠区域,经过DMA的操作,Cache缓存对应的内存的数据已经被修改,而CPU本身并不知道,它仍然认为Cache中的数据就是内存中的数据,以后访问Cache映射的内存时,它仍然使用陈旧的Cache数据。这样就发生了Cache与内存之间数据“不一致性”错误。所谓Cache数据与内存数据不一致性,是指在采用Cache的系统中,同样一个数据可能既存在于Cache中,也存在于主存中,Cache与主存中的数据一样则具有一致性,数据若不一样则具有不一致性。

四、Linux下的DMA编程

        简单来说让DMA正常工作分为以下六个步骤:1、使用request_dma()初始化申请DMA。2、配置channel。3、进行DMA传输。4、若使能了对应中断,进行DMA传输后的中断处理。5、释放DMA缓冲区。6、free_dma()释放DMA。

第一步:申请DMA通道。在Linux内核中,这一步骤涉及设置DMA通道的能力,并请求一个符合这些能力的通道。通过dma_cap_zero、dma_cap_set、dma_request_channel三个函数完成。

dma_cap_mask_t mask;
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
tmc_dma_chan = dma_request_channel(mask,NULL,NULL);
if(!tmc_dma_chan)
{printk("dma_request_channel error\n");return -1;
}

        在这段代码中,首先定义了一个dma_cap_mask_t类型的变量mask来存储DMA通道能力的掩码。然后使用dma_cap_zero函数清零掩码,接着使用dma_cap_set函数设置需要的DMA能力。最后,我们调用dma_request_channel函数来请求一个DMA通道,并检查返回值以确保请求成功。

第二步:配置DMA通道。一旦成功申请到DMA通道,接下来的步骤是对通道进行配置,以匹配外设或内存缓冲区的特定需求。这包括设置源地址和目标地址、定义数据传输的宽度以及传输方向。

struct dma_slave_config conf;
char *dma_test_src_buf;
char *dma_test_dst_buf;
dma_test_src_buf = kmalloc(1005,GFP_KERNEL);
dma_test_dst_buf = kmalloc(1005,GFP_KERNEL);
src_addr = dma_map_single(tmc_dma_chan->device->dev, dma_test_src_buf, len, DMA_FROM_DEVICE);
dst_addr = dma_map_single(tmc_dma_chan->device->dev, dma_test_dst_buf, len, DMA_TO_DEVICE);
conf.src_addr = src_addr;
conf.src_addr_width = DMA_SLAVE_BUSWIDTH_8_BYTES;
conf.dst_addr = dst_addr;
conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
if (dmaengine_slave_config(tmc_dma_chan, &conf)) {printk("failed to configure dma channel\n");return -1;
}

        在这段代码中,我们为conf设置了源地址src_addr和目标地址dst_addr,这些地址通常是外设寄存器或内存缓冲区的物理地址。此外,我们还定义了在源地址和目标地址上进行数据传输时的数据宽度。最后使用dmaengine_slave_config函数将这些配置应用到之前申请的DMA通道上。如果配置失败,函数将返回非0值,并打印错误信息。

第三步: 进行DMA传输。在DMA通道配置完成后,下一步是准备并执行DMA的传输。这涉及到创建一个DMA传输描述符,提交该描述符,以及触发DMA引擎来执行传输。

1、准备DMA传输描述符:使用dmaengine_prep_dma_memcpy函数创建一个DMA传输描述符。这个函数会根据提供的源地址、目标地址、传输长度等信息来配置传输。

2、提交DMA传输描述符:通过dmaengine_submit函数将传输描述符提交给DMA引擎。这一步不会立即启动传输,而是将传输描述符放入DMA通道的待处理队列中。

3、触发DMA传输:调用dma_async_issue_pending函数来启动DMA通道上所有挂起的传输。如果通道处于空闲状态,这个调用会启动传输描述符中定义的DMA传输。

struct dma_async_tx_descriptor *desc;
desc = dmaengine_prep_dma_memcpy(tmc_dma_chan, dst_addr, src_addr, len, 0);
dmaengine_submit(desc);
dma_async_issue_pending(tmc_dma_chan);

第四步: DMA中断处理。在linux中,使用DMA传输时,可以配置中断回调函数来处理完成后的事件。只需要额外定义一个中断回调函数,并在传输描述符中相应字段定义即可。

void irq_tasklet_func(struct tasklet_struct *unused)
{dma_release_channel(tmc_dma_chan);kfree(dma_test_src_buf);kfree(dma_test_dst_buf);printk("release resources");
}
DECLARE_TASKLET(irq_tasklet,irq_tasklet_func);
void dma_transfer_complete(void *arg)
{// 处理传输完成的逻辑printk(KERN_INFO "DMA transfer completed\n");tasklet_schedule(&irq_tasklet);
}
{/* 其他代码 */desc->callback = dma_transfer_complete;desc->callback_param = NULL;/* 其他代码 */
}

        其中的tasklet_scheduleLinux内核中断下半部的一种实现机制。中断上下半部具体内容可查阅:linux开发板引脚中断编程-CSDN博客。由此我们就把与中断相关的相对无关紧要的资源释放函数交给了tasklet机制去处理,从而使得内核可以迅速完成这个中断的关键工作(例如设置寄存器等)。而释放资源等其他工作就交给tasklet去处理。

第五步、第六步:释放DMA缓冲区和释放DMA通道。 在DMA传输完成后,为了释放分配的资源并避免内存泄漏,需要释放之前申请的DMA缓冲区和DMA通道。这是设备驱动程序中资源管理的重要组成部分。

释放DMA缓冲区:在linux内核中,如果使用kmalloc或dma_alloc_coherent分配的内存,传输完成后应使用kfree或相应的函数释放内存。

释放DMA通道:使用dma_release_channel函数释放之前申请的DMA通道,使其可以被其他驱动程序或应用程序重用。

int dht11_release(struct inode *node, struct file *filp)
{dma_release_channel(tmc_dma_chan);kfree(dma_test_src_buf);kfree(dma_test_dst_buf);return 0;
};

在本文中,关闭设备时才对dma通道及相关缓冲区资源进行释放。

         以上代码实现的功能逻辑是,在内存开辟两块空间,分别叫做dma_test_src_buf和dma_test_dst_buf。分别当作数据源地址和目标地址。同时给源地址赋值“abcdef......”。随后申请DMA通道并进行配置。设置源地址、目标地址和传输数据长度。提交DMA传输描述符,并开启DMA传输。最后就可以观察到通过DMA传输后,字符串数据被成功传输到目标地址。

相关文章:

DMA学习

一、DMA简介 DMA是一种无需CPU的参与就可以让外设与系统内存之间进行双向数据传输的硬件机制。使用DMA可以使系统CPU从实际的I/O数据传输过程中摆脱出来,从而大大提高系统的吞吐率。 DMA方式的数据传输由DMA控制器(DMAC)控制,在传…...

C语言18--头文件

头文件的作用 通常,一个常规的C语言程序会包含多个源码文件(.c),当某些公共资源需要在各个源码文件中使用时,为了避免多次编写相同的代码,一般的做法是将这些大家都需要用到的公共资源放入头文件&#xff…...

vscode软件在 C发中常用插件

一. 简介 本文简单介绍一下,当做 C开发时 vscode软件常用的插件。 vscode软件是 微软公司目前提供的一款免费的开发软件,可以通过 vscode官网下载 vscode。 二. vscode软件在 C开发中常用插件 注意:vscode软件安装后,可以直接…...

【C++ Primer Plus习题】17.2

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: #include <iostream> #include <fstream> using namesp…...

Vue Props传值

Props用于父组件向子组件传值 定义类型 // 定义一个接口,用来限制Teacher的属性 export interface Teacher {name: string;age: number;gender: string; }export type teacherList Teacher[];// 一个自定义类型 export type Teachers Array<Teacher>;父组件 <scr…...

FreeSWITCH event_socket 配置从其他地址连接

FreeSWITCH 默认配置只能 在本机连接, 要从 其他ip连接, 需要如下配置&#xff1a; 1、修改event_socket.conf.xml 1 <configuration name"event_socket.conf" description"Socket Client">2 <settings>3 <param name"nat-map&…...

信息安全数学基础(19)同余式的基本概念及一次同余式

一、同余式概念 同余式是数论中的一个基本概念&#xff0c;用于描述两个数在除以某个数时所得的余数相同的情况。具体地&#xff0c;设m是一个正整数&#xff0c;a和b是两个整数&#xff0c;如果a和b除以m的余数相同&#xff0c;则称a和b模m同余&#xff0c;记作a≡b(mod m)。反…...

网关过滤器:Spring Cloud Gateway

在Java中&#xff0c;实现网关过滤器&#xff08;Gateway Filter&#xff09;通常与Spring Cloud Gateway相关。Spring Cloud Gateway是一个基于Spring Framework 5、Project Reactor和Spring WebFlux构建的API网关&#xff0c;它为微服务架构提供了一种简单而有效的方式来路由…...

力扣最热一百题——除自身以外数组的乘积

目录 题目链接&#xff1a;238. 除自身以外数组的乘积 - 力扣&#xff08;LeetCode&#xff09; 题目描述 示例 提示&#xff1a; 解法一&#xff1a;左右数组&#xff08;小型动态规划&#xff09; 实现思路 Java写法&#xff1a; 运行时间 C写法&#xff1a; 运行时…...

监控易监测对象及指标之:全面监控SQL Server数据库

随着企业信息化建设的深入&#xff0c;数据库作为核心数据资产的管理中心&#xff0c;其性能和稳定性直接关系到业务的连续性和企业的运营效率。SQL Server作为一款功能强大、性能稳定的关系型数据库管理系统&#xff0c;广泛应用于各类业务场景中。 为了确保SQL Server数据库的…...

计算机视觉的应用34-基于CV领域的人脸关键点特征智能提取的技术方法

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用34-基于CV领域的人脸关键点特征智能提取的技术方法。本文主要探讨计算机视觉领域中人脸关键点特征智能提取的技术方法。详细介绍了基于卷积神经网络模型进行人脸关键点提取的过程&#xff0c;包括使…...

What is new in .NET 8 and C#12

目录 What is new in .NET 8? .NET Aspire Core .NET Libraries Metrics软件度量 Networking Extension Libraries Garbage Collection Reflection Improvements Native AOT Support NET SDK What is new in C# 12 ? Primary Constructors Collection Expressio…...

基于R语言的统计分析基础:使用键盘输入数据

在R语言中&#xff0c;键盘输入数据是一种灵活且直接的数据获取方式&#xff0c;适用于处理小数据集或需要即时用户交互的场景。通常用于交互式数据探索和分析、临时数据处理、交互式图形绘制、脚本自动化中的用户交互、特定应用场景下的数据录入中。 比如利用readline()函数根…...

unity3d入门教程九

unity3d入门教程九 20.2播放音频20.3在代码中播放21.1延时调用21.2invoke API21.3消息调用22.1交互界面22.2添加canvas22.3canavas的位置22.4添加text 这里给一个资源网站&#xff0c;可以部分免费下载&#xff0c;音乐和音效超多&#xff0c;支持检索 爱给网 https://www.aige…...

着色器 简介

着色器&#xff08;Shader&#xff09;是运行在 GPU 上的小程序。这些小程序为图形渲染管线的某个特定部分而运行。从基本意义上来说&#xff0c;着色器只是一种把输入转化为输出的程序。着色器也是一种非常独立的程序&#xff0c;因为它们之间不能相互通信&#xff1b;它们之间…...

redis单点、主从、哨兵、集群的不同

redis哨兵模式有几个&#xff1a; 单点主从哨兵集群 区别 主从模式&#xff1a;读写分离。 哨兵模式&#xff1a;哨兵模式是在主从模式的基础上添加了故障检测和自动故障转移的功能。还是读写分离。 哨兵节点负责监控主节点和从节点的状态&#xff0c;并在主节点宕机时选举新…...

notepad++的json查看

json文件查看 因为接触到3dtile模型&#xff0c;所以经常需要和json打交道&#xff0c;但是很多模型是下面这种情况&#xff0c;不好阅读&#xff0c;所以可以使用notepad的插件查看 正常打开是这样的 加载notepad插件 搜索json下载安装就可以了 如果网络抽象&#xff0c;下载…...

基于无人机影像的可见光单木分割数据集-json格式

基于无人机影像的可见光单木分割数据集&#xff0c;共1700张影像&#xff0c;数据集大小3.6GB&#xff0c;分割标注采用标准json格式。 该数据集是一个专门用于基于无人机可见光影像进行单木分割的数据集&#xff0c;旨在帮助研究人员和开发者训练和评估基于深度学习的图像分割…...

毕业设计选题:基于ssm+vue+uniapp的捷邻小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…...

【毕业设计】基于 PHP 开发的社区交流系统

基于 PHP 开发的社区交流系统可以是一个论坛、博客平台或是问答网站等形式的在线平台&#xff0c;用于用户之间的互动交流。以下是一个简单的 PHP 社区交流系统的示例&#xff0c;包括用户注册、登录、发布帖子、回复帖子等功能。 技术栈 前端&#xff1a;HTML, CSS, JavaScr…...

RK3568 解决Ubuntu加载驱动模块报错以及开机启动如何自动加载模块

遇到问题是,当我在buildroot文件系统跑这个ko文件,是可以正常使用的,但是在Ubuntu上却跑不了,提示:insmod: ERROR: could not insert module analyze_inode.ko: Operation not permitted 参考其他博主的博客,其实只要添加sudo即可,可能是权限问题导致无法加载,这里记录…...

Fyne ( go跨平台GUI )中文文档-Fyne总览(二)

本文档注意参考官网(developer.fyne.io/) 编写, 只保留基本用法 go代码展示为Go 1.16 及更高版本, ide为goland2021.2​​​​​​​ 这是一个系列文章&#xff1a; Fyne ( go跨平台GUI )中文文档-入门(一)-CSDN博客 Fyne ( go跨平台GUI )中文文档-Fyne总览(二)-CSDN博客 Fyne…...

微服务常见面试题总结

文章目录 1 概念1.1 你对微服务是怎么理解的1.2 微服务带来了哪些挑战&#xff1f;1.3 说下微服务有哪些组件&#xff1f;&#x1f525; 2 注册中心2.1 注册中心有什么用&#xff1f;&#x1f525;2.2 SpringCloud可以选择哪些注册中心&#xff1f;2.3 说下Eureka 和 Nacos的区…...

汽车电子零部件(16):ZCU区域控制器

ZCU(Zone Control Unit,区域控制器),功能主要包括哦数据交互、信号控制及电力分配等,是智能网联汽车中不可或缺的关键组件,ECU负责车身、车门、车窗、天窗、车灯(外大灯、内氛围灯)、座椅(可能包括座椅音响)、雷达甚至后排娱乐系统等控制执行单元的集中化。 CCU(centr…...

如何在Java服务中实现数据一致性:事务与锁机制的综合应用

如何在Java服务中实现数据一致性&#xff1a;事务与锁机制的综合应用 大家好&#xff0c;我是微赚淘客返利系统3.0的小编&#xff0c;是个冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;在Java服务端开发中&#xff0c;确保数据一致性是构建稳定可靠系统的关键。尤…...

记录一下ElementUI 3 在浏览器导入, table表格显示问题

当时问题忘了截图, 现在通过文字记录一下问题 我直接在html了引入 vue3 和 ElementUI 3 , 使用了table组件, 但是表格的td 总是只显示一列, 问题是我的 el-table-column 标签 没有结束标签 , 在vue文件模块化里写不需要结束标签, 在浏览器里无法直接识别出来, 所以他是渲染了第…...

【JavaScript】数据结构之堆

什么是堆&#xff1f; 堆都能用树来表示&#xff0c;一般树的实现都是利用链表。而 二叉堆 是一种特殊的堆&#xff0c;它用完全二叉树来表示&#xff0c;却可以利用数组实现。平时使用最多的是二叉堆。二叉堆易于存储&#xff0c;并且便于索引。堆数据结构像树&#xff0c;但…...

工程车辆目标检测、程车检测算法、工程车辆类型检测算法

工程车检测算法主要用于智能交通系统、建筑工地管理、矿山开采、物流运输等领域&#xff0c;通过图像识别技术来检测和识别工程车&#xff0c;以提高安全管理、交通流量管理和资源调度的效率。以下是关于工程车检测算法的技术实现、应用场景及优势的详细介绍。 一、技术实现 工…...

【技术文章】ArcGIS Pro如何批量导出符号和工程样式?

目录 1.确定Pro软件版本 2.共享工程样式 3.管理和调用项目样式 制作好的地图&#xff0c;如何快速分享地图中的符号样式用于其它地图的制作&#xff1f; 在ArcMap软件中&#xff0c;可以通过命令一键批量导出所有符号。ArcGIS Pro软件是否也可以批量导出符号用于其它地图…...

javascript的闭包学习

为什么要产生闭包的概念&#xff0c;通俗来说一下。 公司有一个项目&#xff0c;分为两个部分&#xff0c;张三、李四各分配一个部分。 张三.js代码&#xff1a; var key我要吃肉 function fn(){console.log(key); } 李四.js代码&#xff1a; var key我要喝酒 function fn…...