DMA学习

news2024/11/13 8:36:38

一、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传输后,字符串数据被成功传输到目标地址。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2148038.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

sensitive-word 敏感词 v0.20.0 数字全部匹配,而不是部分匹配

敏感词系列 sensitive-word-admin 敏感词控台 v1.2.0 版本开源 sensitive-word-admin v1.3.0 发布 如何支持分布式部署? 01-开源敏感词工具入门使用 02-如何实现一个敏感词工具?违禁词实现思路梳理 03-敏感词之 StopWord 停止词优化与特殊符号 04-…

AAAI2024--频谱在多模态表示和融合中的作用更为有效:A Multimodal Spectrum Rumor Detector

https://github.com/dm4m/FSRU 多模态内容,如将文本与图像混合,对社交媒体中的谣言检测提出了重大挑战。现有的多模态谣言检测侧重于在空间和序列位置之间混合令牌进行单模态表示,或者在模态间融合谣言真实性的线索。然而,它们受…

将本地离线Jar包上传到Maven远程私库上,供项目编译使用

背景 因项目对接需求,需对接第三方Jar(海康人脸识别服务网关API),在项目集成时,处于本地编译、远程持续构建的需要将离线Jar推送到远程Maven仓库。 实施步骤 进入到离线Jar包同文件夹下 配置Maven配置文件中远程账户信息 需要在Idea配置的…

Java 数据类型转换详解:隐式转换(自动转换)与强制转换(手动转换)

目录 前言 取值范围从小到大的关系: 隐式转换(自动转换) 📜示例 1:基本类型隐式转换 📜示例 2:算术运算中的类型提升 📜示例 3:byte、short 和 char 的自动转换 隐…

Hive基本原理与数据开发

目录 1.什么是Hive 2.Hive的特点和优势 2.1.Hive的特点 2.1.1.易用性 2.1.2.高效性 2.1.3.兼容性 2.1.4.可扩展性 2.1.5.容错性 2.2.与传统数据库的区别 3.hive的架构 3.1.hive的核心组件(如 Metastore、Driver、Query Compiler、Execution Engine 等) 3.1.1.用户接…

Apache的ab压力测试工具与性能监控

【图书介绍】《软件性能测试、分析与调优实践之路(第2版)》_软件性能测试分析与调优实践之路-CSDN博客《软件性能测试、分析与调优实践之路(第2版)》(张永清)【摘要 书评 试读】- 京东图书 (jd.com) Apache的ab压力测试工具 A…

go语言中的切片详解

1.概念 在Go语言中,切片(Slice)是一种基于数组的更高级的数据结构,它提供了一种灵活、动态的方式来处理序列数据。切片在Go中非常常用,因为它们可以动态地增长和缩小,这使得它们比固定大小的数组更加灵活。…

电子看板实时监控数据可视化助力工厂精细化管理

在当今竞争激烈的制造业领域,工厂的精细化管理成为提高竞争力的关键。而电子看板实时监控数据可视化作为一种先进的管理工具,正为工厂的精细化管理带来巨大的助力。 一、工厂精细化管理的挑战 随着市场需求的不断变化和客户对产品质量要求的日益提高&am…

记一次键盘f2和f5键被自动触发情况

背景: 联想小新笔记本电脑内置键盘,其中f2键和f5键一直被自动触发,已尝试过更换输入法,重装系统,拆开键帽清灰依旧无效。考虑维修费或者更换键盘(内置)费都挺贵的,而且f2和f5作用也…

音视频入门基础:AAC专题(10)——FFmpeg源码中计算AAC裸流每个packet的pts、dts、pts_time、dts_time的实现

音视频入门基础:AAC专题系列文章: 音视频入门基础:AAC专题(1)——AAC官方文档下载 音视频入门基础:AAC专题(2)——使用FFmpeg命令生成AAC裸流文件 音视频入门基础:AAC…

uniapp小程序使用canvas画圆

<view class"container"><canvas canvas-id"arcCanvas" id"arcCanvas" class"arc-canvas" width"300" height"300"></canvas> </view> 最开始我使用…

【华为杯】第二十一届中国研究生数学建模竞赛

“华为杯”第二十一届中国研究生数学建模竞赛即将开始&#xff0c;梦想科研社给大家整理一些比赛信息&#xff0c;在正式开赛后&#xff0c;我们也会持续分享一些课题的分析以及代码&#xff0c;有需要的可以联系我们获取资料信息哦 一、时间节点 1.加密赛题开始下载时间&…

DPDK 简易应用开发之路 1:数据包接收与解析

本机环境为 Ubuntu20.04 &#xff0c;dpdk-stable-20.11.10 DPDK 应用基础 DPDK应用程序的一般处理流程如下&#xff1a; 初始化DPDK环境&#xff1a;调用rte_eal_init()初始化DPDK环境抽象层&#xff08;EAL&#xff09;&#xff0c;设置运行时环境和配置。 配置和绑定网卡…

2024最新版 Tuxera NTFS for Mac 2023绿色版图文安装教程

​ 在数字化时代&#xff0c;数据的存储和传输变得至关重要。Mac用户经常需要在Windows NTFS格式的移动硬盘上进行读写操作&#xff0c;然而&#xff0c;由于MacOS系统默认不支持NTFS的写操作&#xff0c;这就需要我们寻找一款高效的读写软件。Tuxera NTFS for Mac 2023便是其中…

超详图解 Apache HTTP Server(httpd)安装与验证

在OpenEuler 24.03系统中安装验证 Apache HTTP Server&#xff08;httpd&#xff09;的过程通常涉及以下步骤&#xff1a; 一、Apache HTTP Server&#xff08;httpd&#xff09;安装 1.检查是否已安装httpd: rpm -q httpd 2.更新系统包索引&#xff1a;更新您的系统包索引以…

基于深度学习的药品三期OCR字符识别

在药品生产线上,药品三期的喷码与条形码识别是保证药品追溯和安全管理的重要环节。传统的识别方法依赖于人工操作,不仅效率低下且容易出错。随着深度学习技术的不断发展,基于OCR(Optical Character Recognition,光学字符识别)的自动化识别系统逐渐成为主流。本文将以哪吒…

【Godot4.2】基于EasyTreeData解析的扩展Tree控件 - ETDTree

概述 基于EasyTreeData解析的扩展Tree控件。 EasyTreeData&#xff08;ETD&#xff09; EasyTreeData&#xff08;ETD&#xff09;是一种基于Tab缩进的简单层级结构数据&#xff0c;可以用于描述树形结构。能够被解析为Tree控件或表示树形结构的其他类或控件。 根目录 | 0节…

cadence SPB17.4 - allegro - 用板子外形创建整板铺铜

文章目录 cadence SPB17.4 - allegro - 用板子外形创建整板铺铜概述笔记先确定自己板子的 board Geometry/Design_Outline 是否有外形shape为了将软件提示看得更清楚&#xff0c;在每个操作之前&#xff0c;先将命令提示区内容先删了用Z-copy从外形层生成整板的铺铜备注END cad…

Maven 和 gradle JavaFX 项目的休眠行为差异

我一直在尝试将Hibernate与我的JavaFX Maven项目集成。它与Hibernate社区包、Jakarta和xerial配合得很好。我还将persistence.xml文件放在了src/main/resources/META-INF/persistence.xml。 我还尝试使用gradle创建另一个项目&#xff0c;并按照此maven项目的步骤操作&#xf…

《高等代数》行列式转置(应用)

说明&#xff1a;此文章用于本人复习巩固&#xff0c;如果也能帮助到大家那就更加有意义了。 注&#xff1a;1&#xff09;“行列式转置值不变”这一性质在求解行列式的过程中也有极大的作用。