DMA驱动程序编写

2024-09-02 07:58
文章标签 编写 驱动程序 dma

本文主要是介绍DMA驱动程序编写,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一.  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);/

这篇关于DMA驱动程序编写的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1129422

相关文章

如何编写Linux PCIe设备驱动器 之二

如何编写Linux PCIe设备驱动器 之二 功能(capability)集功能(capability)APIs通过pci_bus_read_config完成功能存取功能APIs参数pos常量值PCI功能结构 PCI功能IDMSI功能电源功率管理功能 功能(capability)集 功能(capability)APIs int pcie_capability_read_wo

STM32 ADC+DMA导致写FLASH失败

最近用STM32G070系列的ADC+DMA采样时,遇到了一些小坑记录一下; 一、ADC+DMA采样时进入死循环; 解决方法:ADC-dma死循环问题_stm32 adc dma死机-CSDN博客 将ADC的DMA中断调整为最高,且增大ADCHAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_Buffer_Size); 的ADC_Bu

Wondows dos下怎么编写bat批处理文件

最近搞php,在运行时,以Nginx+php-cgi.exe方式运行Wordpress项目 打开dos,先cd到php-cgi.exe文件当前目录下执行启动命令:php-cgi.exe -b 127.0.0.1:9001再打开一个dos,再cd到nginx.exe文件当前目录下执行启动命令:start nginx 大概过程要经过这些步骤,觉得很麻烦,就学下怎么编写一个bat文件,以双击运行代替

用Python编写倒计时程序:详细教程

目录 引言 环境准备 基本概念 代码实现 步骤一:导入必要的库 步骤二:获取用户输入 步骤三:实现倒计时逻辑 步骤四:整合代码 运行程序 高级功能 扩展功能示例:支持分钟和小时输入 扩展功能示例:图形用户界面 (GUI) 总结 引言 倒计时程序是一个非常常见的小工具,广泛用于各种应用场景中,例如考试时间提醒、烹饪计时器、会议倒计时等。Python 作为一种

【Spring boot】编写代码及测试用例入门之 Hello Spring boot _踩坑记

先贴下目录: 这是我从 start.spring.io 里下载的依赖Web的模板 // DemoApplication.javapackage com.abloume.springboot.blog.demo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autocon

windows下使用vscode编写运行以及调试C/C++

vscode支持类似于vs的断点调试c/c++,也可以直接编译&运行c/c++ 先是编译运行 c/c++的方法                              微软官方起初设定的科学做法(这也是现在的科学做法)是通过在vscode集成控制台写命令行的方式来实现编译运行程序的,但也可以通过code runner插件来简化步骤,实现一键编译执行 但无论是什么方法,因为vscod

Python编写简单登录系统的完整指南

在现代应用中,用户认证和登录系统是一个非常重要的功能。通过登录系统,应用能够识别用户的身份,并为其提供相应的权限和服务。本文将介绍如何使用Python编写一个简单的登录系统,包括用户注册、登录验证、密码加密等功能。通过这一教程,将学习如何构建一个基本的用户登录系统,并理解其中的关键技术。 这里插播一条粉丝福利,如果你在学习Python或者有计划学习Python,想在未来人工智能领域吃上一口饭的,

springboot项目编写发送异常日志到企微工具包

1.创建基础Bean public final class ThreadFactory implements java.util.concurrent.ThreadFactory {private static final AtomicInteger poolNumber = new AtomicInteger(1);private final ThreadGroup group;priva

学习硬件测试05:NTC(ADC)+正弦波(DAC)+DMA(ADC+DAC)(P73、P76、P78)

文章以下内容全部为硬件相关知识,鲜有软件知识,并且记的是自己需要的部分,大家可能看不明白。 一、NTC(ADC) 1.1实验现象 本实验用 NTC 采集温度,数码管实时显示温度数据(整数),左下角 USB 小串口每隔 1S 打印温度信息。 1.2硬件电路 NTC 电阻是一个模拟温度传感器,随着温度的升高,电阻值逐渐减小。电路简单介绍如下: 电源滤波电容在 25℃ 室温下 NTC 电

C#通过ACE OLEDB驱动程序访问 Access和 Excel

ACE 代表 Access Connectivity Engine。它是 Microsoft 提供的一组组件,用于访问和操作 Microsoft Access 数据库以及其他类似的文件格式,如 Excel 工作簿。ACE 主要包括以下几部分: ACE OLEDB 驱动程序:用于通过 OLE DB 提供程序访问 Access 数据库和 Excel 文件。例如,Microsoft.ACE.OLED