蜕变成蝶~Linux设备驱动之DMA

一口Linux 2021-03-17 00:00

DMA概述

    DMA是一种无需CPU的参加就可以让外设与系统内存之间进行双向数据传输的硬件机制。它可以使系统CPU从实际的I/O数据传输过程中摆脱出来,大大提高系统的吞吐率,并且在传输期间,CPU还可以并发执行其他任务。


DMA与cache的一致性

    cache用作CPU针对内存的缓存,避免CPU每一次都要与相对来说慢点的内存交互数据,从而来提高数据的访问速率,而DMA可以用作内存与外设之间传输数据的方式,数据不需要经过CPU周转。


    “假设设备驱动程序把一些数据填充到内存缓冲区中,然后立刻命令硬件设备利用DMA传送方式读取该数据。如果DMA访问这些物理RAM内存单元,而相应的硬件高速缓存行的内容还没有写入RAM中,那么硬件设备所读取的至就是内存缓冲区中的旧值。”


现在有两种方法来处理DMA缓冲区:

一致性DMA映射:

    书上讲的比较抽象,通俗地说就是任何对DMA缓冲区的改写都会直接更新到内存中,也称之为“同步的”或者“一致的”。


流式DMA映射:

    根据个人的理解,这里的流即输入输出流,我们需要事先指定DMA缓冲区的方向。

    启动一次流式DMA数据传输分为如下步骤(本DMA驱动开发介绍仅适合S3C2410处理器类型):


1.分配DMA缓冲区

    在DMA设备不采用S/G(分散/聚集)模式的情况下,必须保证缓冲区是物理上连续的,linux内核有两个函数用来分配连续的内存:kmalloc()和__get_free_pages()。这两个函数都有分配连续内存的最大值,kmalloc以分配字节为单位,最大约为64KB,__get_free_pages()以分配页为单位,最大能分配2^order数目的页,order参数的最大值由include/linux/Mmzone.h文件中的MAX_ORDER宏决定(在默认的2.6.18内核版本中,该宏定义为10。也就是说在理论上__get_free_pages函数一次最多能申请1<<10 * 4KB也就是4MB的连续物理内存,在Xilinx Zynq Linux内核中,该宏定义为11)。


2. 建立流式映射

    在对DMA冲区进行读写访问之后,且在启动DMA设备传输之前,启用dma_map_single()函数建立流式DMA映射,这两个函数接受缓冲区的线性地址作为其参数并返回相应的总线地址。


3. 释放流式映射

    当DMA传输结束之后我们需要释放该映射,这时调用dma_unmap_single()函数。


注意:

(1). 为了避免高速缓存一致性问题,驱动程序在开始从RAM到设备的DMA数据传输之前,如果有必要,应该调用dma_sync_single_for_device()函数刷新与DMA缓冲区对应的高速缓存行。


(2). 从设备到RAM的一次DMA数据传送完成之前设备驱动程序是不可以访问内存缓冲区的,但如果有必要的话,驱动程序在读缓冲区之前,应该调用dma_sync_single_for_cpu()函数使相应的硬件高速缓存行无效。


(3). 虽然kmalloc底层也是用__get_free_pages实现的,不过kmalloc对应的释放缓冲区函数为kfree,而__get_free_pages对应的释放缓冲区函数为free_pages。具体与__get_free_pages有关系的几个申请与释放函数如下:


申请函数:

alloc_pages(gfp_mask,order)返回第一个所分配页框描述符的地址,或者如果分配失败则返回NULL__get_free_pages(gfp_mask,order)类似于alloc_pages(),但它返回第一个所分配页的线性地址。如果需要获得线性地址对应的页框号,那么需要调用virt_to_page(addr)宏产生线性地址。


释放函数:

__free_pages(page,order)这里主要强调page是要释放缓冲区的线性首地址所在的页框号free_pages(page,order)这个函数类似于__free_pages(page,order),但是它接收的参数为要释放的第一个页框的线性地址addr


DMA驱动主要数据结构:

1DMA单个内核缓冲区数据结构:

typedef struct dma_buf_s {int size; /* buffer size:缓冲大小 */dma_addr_t dma_start; /* starting DMA address :缓冲区起始物理地址*/int ref; /* number of DMA references 缓冲区起始虚拟地址*/void *id; /* to identify buffer from outside 标记 */int write; /* 1: buf to write , 0: buf to read DMA读还是写*/struct dma_buf_s *next; /* next buf to process 指向下一个缓冲区结构*/} dma_buf_t;


2DMA寄存器数据结构:

/* DMA control register structure */typedef struct {volatile u_long DISRC;/源地址寄存器volatile u_long DISRCC;//源控制寄存器volatile u_long DIDST;//目的寄存器volatile u_long DIDSTC;//目的控制寄存器volatile u_long DCON;//DMA控制寄存器volatile u_long DSTAT;//状态寄存器volatile u_long DCSRC;//当前源volatile u_long DCDST;//当前目的volatile u_long DMASKTRIG;//触发掩码寄存器} dma_regs_t;


3DMA设备数据结构

/* DMA device structre */typedef struct {dma_callback_t callback;//DMA操作完成后的回调函数,在中断处理例程中调用u_long dst;//目的寄存器内容u_long src;//源寄存器内容u_long ctl;//此设备的控制寄存器内容u_long dst_ctl;//目的控制寄存器内容u_long src_ctl;//源控制寄存器内容} dma_device_t;


4DMA通道数据结构

/* DMA channel structure */typedef struct {dmach_t channel;//通道号:可为0,1,2,3unsigned int in_use; /* Device is allocated 设备是否已*/const char *device_id; /* Device name 设备名*/dma_buf_t *head; /* where to insert buffers 该DMA通道缓冲区链表头*/dma_buf_t *tail; /* where to remove buffers该DMA通道缓冲区链表尾*/dma_buf_t *curr; /* buffer currently DMA'ed该DMA通道缓冲区链表中的当前缓冲区*/unsigned long queue_count; /* number of buffers in the queue 链表中缓冲区个数*/int active; /* 1 if DMA is actually processing data 该通道是否已经在使用*/dma_regs_t *regs; /* points to appropriate DMA registers 该通道使用的DMA控制寄存器*/int irq; /* IRQ used by the channel //通道申请的中断号*/dma_device_t write; /* to write //执行读操作的DMA设备*/dma_device_t read; /* to read 执行写操作的DMA设备*/} s3c2410_dma_t;


DMA驱动主要函数功能分析:

    写一个DMA驱动的主要工作包括:DMA通道申请、DMA中断申请、控制寄存器设置、挂入DMA等待队列、清除DMA中断、释放DMA通道.

int s3c2410_request_dma(const char *device_id, dmach_t channel,dma_callback_t write_cb, dma_callback_t read_cb) (s3c2410_dma_queue_buffer);

函数描述:申请某通道的DMA资源,填充s3c2410_dma_t 数据结构的内容,申请DMA中断。


输入参数:device_id DMA 设备名;channel 通道号;

write_cb DMA写操作完成的回调函数;

read_cb DMA读操作完成的回调函数


输出参数:若channel通道已使用,出错返回;否则,返回0


int s3c2410_dma_queue_buffer(dmach_t channel, void *buf_id,dma_addr_t data, int size, int write) (s3c2410_dma_stop);

函数描述:这是DMA操作最关键的函数,它完成了一系列动作:分配并初始化一个DMA内核缓冲区控制结构,并将它插入DMA等待队列,设置DMA控制寄存器内容,等待DMA操作触发


输入参数:channel 通道号;buf_id,缓冲区标识

dma_addr_t data DMA数据缓冲区起始物理地址;

size DMA数据缓冲区大小;

write 是写还是读操作


输出参数:操作成功,返回0;否则,返回错误号


int s3c2410_dma_stop(dmach_t channel)

函数描述:停止DMA操作。


int s3c2410_dma_flush_all(dmach_t channel)

函数描述:释放DMA通道所申请的所有内存资源


void s3c2410_free_dma(dmach_t channel)

函数描述:释放DMA通道


    因为各函数功能强大,一个完整的DMA驱动程序中一般只需调用以上3个函数即可。可在驱动初始化中调用s3c2410_request_dma,开始DMA传输前调用s3c2410_dma_queue_buffer,释放驱动模块时调用s3c2410_free_dma。


·················· END ··················

点击关注公众号,回复【1024】免费领学习资料


推荐阅读
所有原创
Linux驱动
粉丝问答
C语言
从0学ARM
计算机网络


一口Linux 写点代码,写点人生!
评论
  • 2024年12月09日 环洋市场咨询机构出版了一份详细的、综合性的调研分析报告【全球电机控制系统芯片 (SoC)行业总体规模、主要厂商及IPO上市调研报告,2024-2030】。本报告研究全球电机控制系统芯片 (SoC)总体规模,包括产量、产值、消费量、主要生产地区、主要生产商及市场份额,同时分析电机控制系统芯片 (SoC)市场主要驱动因素、阻碍因素、市场机遇、挑战、新产品发布等。报告从电机控制系统芯片 (SoC)产品类型细分、应用细分、企业、地区等角度,进行定量和定性分析,包括产量、产值、均价
    GIRtina 2024-12-09 11:32 166浏览
  • 在驾驶培训与考试的严谨流程中,EST580驾培驾考系统扮演着至关重要的数据角色。它不仅集成了转速监控、车速管理、转向角度测量、转向灯光控制以及手刹与安全带状态检测等多项功能,还通过高精度的OBD数据采集器实时捕捉车辆运行状态,确保学员在模拟及实际驾驶中的每一步操作都精准无误。EST580驾培驾考转速车速转向角转向灯光手刹安全带OBD数据采集器系统的重要性及其功能:1、提高评判效率:通过原车CAN协议兼容,不同车型通过刷写固件覆盖,不仅提高了考试的数字化、自动化程度,还减少了人为干预的安装需要,从
    lauguo2013 2024-12-09 16:51 97浏览
  • 我的一台很多年前人家不要了的九十年代SONY台式组合音响,接手时只有CD功能不行了,因为不需要,也就没修,只使用收音机、磁带机和外接信号功能就够了。最近五年在外地,就断电闲置,没使用了。今年9月回到家里,就一个劲儿地忙着收拾家当,忙了一个多月,太多事啦!修了电气,清理了闲置不用了的电器和电子,就是一个劲儿地扔扔扔!几十年的“工匠式”收留收藏,只能断舍离,拆解不过来的了。一天,忽然感觉室内有股臭味,用鼻子的嗅觉功能朝着臭味重的方向寻找,觉得应该就是这台组合音响?怎么会呢?这无机物的东西不会腐臭吧?
    自做自受 2024-12-10 16:34 67浏览
  • 全球知名半导体制造商ROHM Co., Ltd.(以下简称“罗姆”)宣布与Taiwan Semiconductor Manufacturing Company Limited(以下简称“台积公司”)就车载氮化镓功率器件的开发和量产事宜建立战略合作伙伴关系。通过该合作关系,双方将致力于将罗姆的氮化镓器件开发技术与台积公司业界先进的GaN-on-Silicon工艺技术优势结合起来,满足市场对高耐压和高频特性优异的功率元器件日益增长的需求。氮化镓功率器件目前主要被用于AC适配器和服务器电源等消费电子和
    电子资讯报 2024-12-10 17:09 46浏览
  •         霍尔传感器是根据霍尔效应制作的一种磁场传感器。霍尔效应是磁电效应的一种,这一现象是霍尔(A.H.Hall,1855—1938)于1879年在研究金属的导电机构时发现的。后来发现半导体、导电流体等也有这种效应,而半导体的霍尔效应比金属强得多,利用这现象制成的各种霍尔元件,广泛地应用于工业自动化技术、检测技术及信息处理等方面。霍尔效应是研究半导体材料性能的基本方法。通过霍尔效应实验测定的霍尔系数,能够判断半导体材料的导电类型、载流子浓度及载流子
    锦正茂科技 2024-12-10 11:07 49浏览
  •         在有电流流过的导线周围会感生出磁场,再用霍尔器件检测由电流感生的磁场,即可测出产生这个磁场的电流的量值。由此就可以构成霍尔电流、电压传感器。因为霍尔器件的输出电压与加在它上面的磁感应强度以及流过其中的工作电流的乘积成比例,是一个具有乘法器功能的器件,并且可与各种逻辑电路直接接口,还可以直接驱动各种性质的负载。因为霍尔器件的应用原理简单,信号处理方便,器件本身又具有一系列的du特优点,所以在变频器中也发挥了非常重要的作用。  &nb
    锦正茂科技 2024-12-10 12:57 43浏览
  • 智能汽车可替换LED前照灯控制运行的原理涉及多个方面,包括自适应前照灯系统(AFS)的工作原理、传感器的应用、步进电机的控制以及模糊控制策略等。当下时代的智能汽车灯光控制系统通过车载网关控制单元集中控制,表现特殊点的有特斯拉,仅通过前车身控制器,整个系统就包括了灯光旋转开关、车灯变光开关、左LED前照灯总成、右LED前照灯总成、转向柱电子控制单元、CAN数据总线接口、组合仪表控制单元、车载网关控制单元等器件。变光开关、转向开关和辅助操作系统一般连为一体,开关之间通过内部线束和转向柱装置连接为多,
    lauguo2013 2024-12-10 15:53 49浏览
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-10 16:13 63浏览
  • 本文介绍Linux系统(Ubuntu/Debian通用)挂载exfat格式U盘的方法,触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。修改对应的内核配置文件# 进入sdk目录cdrk3562_linux# 编辑内核配置文件vi./kernel-5.10/arch/arm64/configs/rockchip_linux_defconfig注:不清楚内核使用哪个defc
    Industio_触觉智能 2024-12-10 09:44 78浏览
  • 开发板在默认情况下,OpenHarmony系统开机后 30 秒会自动息屏,自动息屏会让不少用户感到麻烦,触觉智能教大家两招轻松取消自动息屏。使用触觉智能Purple Pi OH鸿蒙开发板演示,搭载了瑞芯微RK3566四核处理器,Laval鸿蒙社区推荐开发板,已适配全新OpenHarmony5.0 Release系统,SDK源码全开放!SDK源码中修改修改以下文件参数:base/powermgr/power_manager/services/native/profile/power_mode_co
    Industio_触觉智能 2024-12-09 11:39 108浏览
  • 【萤火工场CEM5826-M11测评】OLED显示雷达数据本文结合之前关于串口打印雷达监测数据的研究,进一步扩展至 OLED 屏幕显示。该项目整体分为两部分: 一、框架显示; 二、数据采集与填充显示。为了减小 MCU 负担,采用 局部刷新 的方案。1. 显示框架所需库函数 Wire.h 、Adafruit_GFX.h 、Adafruit_SSD1306.h . 代码#include #include #include #include "logo_128x64.h"#include "logo_
    无垠的广袤 2024-12-10 14:03 48浏览
  • 肖特基具有很多的应用场景, 可以做同步整流,防止电流倒灌和电源反接等,但是随着电源电流的增大,肖特基导通正向压降0.3~0.7v的劣势也越发明显,产生了很多的热,对于工程师的散热设计是个考验,增加了工程师的设计难度和产品成本,目前一种新的理想二极管及其控制器,目前正在得到越来越广泛的应用- BMS,无人机,PLC,安防,家电,电动工具,汽车等都在快速普及理想二极管有三种架构,内置电荷泵的类似无锡明芯微MX5050T这种,驱动能力会弱点,静态功耗200uA,外置电荷泵MX74700T的这种驱动能力
    王萌 2024-12-10 08:51 79浏览
  • 概述 通过前面的研究学习,已经可以在CycloneVGX器件中成功实现完整的TDC(或者说完整的TDL,即延时线),测试结果也比较满足,解决了超大BIN尺寸以及大量0尺寸BIN的问题,但是还是存在一些之前系列器件还未遇到的问题,这些问题将在本文中进行详细描述介绍。 在五代Cyclone器件内部系统时钟受限的情况下,意味着大量逻辑资源将被浪费在于实现较大长度的TDL上面。是否可以找到方法可以对此前TDL的长度进行优化呢?本文还将探讨这个问题。TDC前段BIN颗粒堵塞问题分析 将延时链在逻辑中实现后
    coyoo 2024-12-10 13:28 56浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦