mini2440 简单的dma工作原理实验

发布者:码字奇思最新更新时间:2022-10-14 来源: csdn关键字:mini2440  dma  数据 手机看文章 扫描二维码
随时随地手机看文章

以驱动方式测试dma的工作原理,用户层程序不停调用ioctl触发驱动里面完成的dma操作,把内存的数据块从一个连续地址搬到另一个连续地址,然后用memcmp测试搬移后的数据和搬移前是不是完全一样。


简单的驱动代码:


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

 

#define MEM_CPY_NO_DMA 0

#define MEM_CPY_USE_DMA 1

#define DMA_BUF_SIZE (512*1024)

#define GRH_MODULE_NAME "grh_dma"

 

#define DMA_REG_BASE_ADDR_0 0x4B000000

#define DMA_REG_BASE_ADDR_1 0x4B000040

#define DMA_REG_BASE_ADDR_2 0x4B000080

#define DMA_REG_BASE_ADDR_3 0x4B0000C0

 

 

static struct dma_regs{

volatile unsigned long *disrc;

volatile unsigned long *disrcc;

volatile unsigned long *didst;

volatile unsigned long *didstc;

volatile unsigned long *dcon;

volatile unsigned long *dstat;

volatile unsigned long *dcsrc;

volatile unsigned long *dcdst;

volatile unsigned long *dmasktrig;

};

 

static struct dma_regs dma_regs_ins;

 

 

static int major = 0;

 

static char *src;

static char *dst;

static unsigned int src_phys; //数据源的物理地址

static unsigned int dst_phys; //目标位置的物理地址

 

 

static struct class *dma_class;

static struct class_device *dma_class_device; 

 

//dma中断处理的相关数据

static DECLARE_WAIT_QUEUE_HEAD(dma_waitq); //休眠的进程队列头

static volatile int sleep_for_dma; //这个变量为0的时候ioctl函数会休眠,中断里面将其置1,read函数末尾将其设置为0

 

 

static int dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){

int i;

memset(src, 0xaa, DMA_BUF_SIZE);

memset(dst, 0x55, DMA_BUF_SIZE);

 

switch(cmd){

case MEM_CPY_NO_DMA:{

for(i=0; i dst[i] = src[i];

if(0 == memcmp(src, dst, DMA_BUF_SIZE))

printk(KERN_EMERG"dma success!n");

else

printk(KERN_EMERG"dma fail!n");

break;

}

case MEM_CPY_USE_DMA:{

*(dma_regs_ins.disrc) = src_phys; //将数据源的物理地址存入disrc寄存器

*(dma_regs_ins.disrcc) = (0<<0) | (0<<1); //源数据和目的位置是位于主存上的,设置dma的地址递增

*(dma_regs_ins.didst) = dst_phys; 将目标物理地址存入didst寄存器

*(dma_regs_ins.didstc) = (0<<0) | (0<<1) | (0<<2); //不使用自动加载,地址递增,目的地址是位于主存中的

*(dma_regs_ins.dcon) = (1<<30) | (1<<29) | (0<<28) | (1<<27) | (0<<23) | (0<<20) | (DMA_BUF_SIZE<<0); //使能中断,不使用突发传输,dma为软件触发,传输的最小单位是1字节

//启动dma

*(dma_regs_ins.dmasktrig) = (1<<1) | (1<<0);

 

//休眠进程

wait_event_interruptible(dma_waitq, sleep_for_dma);

sleep_for_dma = 0;

 

if(0 == memcmp(src, dst, DMA_BUF_SIZE))

printk(KERN_EMERG"dma success!n");

else

printk(KERN_EMERG"dma fail!n");

 

break;

}

}

return 0;

}

 

 

static struct file_operations dma_fops = {

.owner = THIS_MODULE,

.ioctl = dma_ioctl,

};

 

 

//dma中断处理函数

static irqreturn_t grh_handle_dma_int(int irq, void *dev_id){

printk(KERN_EMERG"dma interrupt happened!n");

sleep_for_dma = 1;

wake_up_interruptible(&dma_waitq);

return IRQ_HANDLED;

}

 

static int dma_init(void){

unsigned long *p_start;

unsigned long **pp;

int i;

 

//分配dma使用的缓存空间

src = dma_alloc_writecombine(NULL, DMA_BUF_SIZE, &src_phys, GFP_KERNEL);

dst = dma_alloc_writecombine(NULL, DMA_BUF_SIZE, &dst_phys, GFP_KERNEL);

if(NULL==src){

printk(KERN_EMERG"allocate buffer for dma error!n");

return -ENOMEM;

}

if(NULL==dst){

dma_free_writecombine(NULL, DMA_BUF_SIZE, src, src_phys);

printk(KERN_EMERG"allocate buffer for dma error!n");

return -ENOMEM;

}

 

//进行地址映射

p_start = (unsigned long*)ioremap(DMA_REG_BASE_ADDR_0, sizeof(struct dma_regs));

pp = &(dma_regs_ins.disrc);

for(i=0; i<9; i++){

*(pp++) = p_start++;

}

//申请dma的中断

if(request_irq(IRQ_DMA0, grh_handle_dma_int, 0, "dma0", 1)){

printk(KERN_EMERG"request irq for dma error!n");

return -ENOMEM;

}

 

//默认会等待dma进行休眠

sleep_for_dma = 0;

 

 

major = register_chrdev(0, GRH_MODULE_NAME, &dma_fops);

//create my own device class

dma_class = class_create(THIS_MODULE, "grh_dma_class");

//create my device of my own class

dma_class_device = device_create(dma_class, NULL, MKDEV(major,0), NULL, "grh_dma_device");

 

return 0;

}

 

static void dma_exit(void){

unregister_chrdev(major, GRH_MODULE_NAME);

device_unregister(dma_class_device);

class_destroy(dma_class);

iounmap(dma_regs_ins.disrc);

dma_free_writecombine(NULL, DMA_BUF_SIZE, src, src_phys);

dma_free_writecombine(NULL, DMA_BUF_SIZE, dst, dst_phys);

free_irq(IRQ_DMA0, 1); //释放dma中断

}

 

module_init(dma_init);

module_exit(dma_exit);

 

MODULE_AUTHOR("GRH");

MODULE_VERSION("1.0");

MODULE_DESCRIPTION("DMA DRIVER");

MODULE_LICENSE("GPL");



//用户层测试程序

#include

#include

#include

#include

#include

#include

#include

 

 

#define MEM_CPY_NO_DMA 0

#define MEM_CPY_USE_DMA 1

 

void print_usage(const char *command){

printf("usage: %s n", command);

}

 

int main(int argc, char *argv[]){

int count;

int fd;

 

fd = open("/dev/grh_dma_device", O_RDWR);

if(fd < 0){

printf("open device error!n");

return -1;

}

 

if(2 != argc){

printf("command format error!n");

print_usage(argv[0]);

return -1;

}

 

if(0 == strcmp(argv[1],"nodma")){

while(1){

ioctl(fd, MEM_CPY_NO_DMA);

}

}

else if(0 == strcmp(argv[1],"dma")){

while(1){

ioctl(fd, MEM_CPY_USE_DMA);

}

}

else{

printf("parameter error!n");

print_usage(argv[0]);

return -1;

}

 

close(fd);

return 0;

}



运行结果:使用dma时和不使用dma时数据搬移的效率明显加快,cpu消耗量锐减,系统响应速度提升。


关键字:mini2440  dma  数据 引用地址:mini2440 简单的dma工作原理实验

上一篇:mini2440 按键驱动添加输入子系统,让按键可以真正当做键盘一样用
下一篇:简单外中断实验(最近又要搞arm相关的东西,复习一下中断)

推荐阅读最新更新时间:2024-11-09 11:50

超高数据流通量FPGA新品类中的Block RAM级联架构
概述 随着数据中心、人工智能、自动驾驶、5G、计算存储和先进测试等应用的数据量和数据流量不断增大,不仅需要引入高性能、高密度FPGA来发挥其并行计算和可编程硬件加速功能,而且还对大量数据在FPGA芯片内外流动提出了更高的要求。于是,在FPGA芯片中集成包括片上二维网络(2D NoC)和各种最新高速接口的新品类FPGA芯片应运而生,成为FPGA产业和相关应用的新热点。 拉开这场FPGA芯片创新大幕的是全球最大的独立FPGA技术和产品提供商Achronix半导体公司,其采用7nm工艺打造的Achronix Speedster7t FPGA不仅拥有诸多高性能外围Hard IP,而且是全球首次在FPGA的逻辑阵列上集成了2D N
[嵌入式]
超高<font color='red'>数据</font>流通量FPGA新品类中的Block RAM级联架构
修改HAL标准库用printf函数发送数据直接输出
主函数文件,请直接关注自己写上去的代码: 直接看43行代码:#include stdio.h //要添加这个头文件 还有97行到112行:实现用HAL库函数和printf函数发送数据 1 /** 2 ****************************************************************************** 3 * File Name : main.c 4 * Description : Main program body 5 *************************************************************
[单片机]
修改HAL标准库用printf函数发送<font color='red'>数据</font>直接输出
直接存储器存取(Direct Memory Access,DMA)详细讲解
一、理论理解部分。 1、直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。 2、无须CPU干预,数据可以通过DMA快速移动,这就节省了CPU的资源来做其他操作。 3、两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自一个或者多个外设对存储器访问的请求。 4、还有一个冲裁器协调各个DMA请求的优先权。在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中和低),优先权设置相等时由硬件决定(请求0优先请求1,) 5、每个通道都有三个事件标志(DMA半传输、DMA传输完成和DMA传输出错),这三个事件标志逻辑或成为一个单独的
[单片机]
直接存储器存取(Direct Memory Access,<font color='red'>DMA</font>)详细讲解
使用u-boot_2016_01启动mini2440(一)启动代码
mini2440的soc用的是s3c2440,因为板子买回来烧写过NOR,而且NOR启动也过于简单,所以我主要记录下NAND启动。s3c2440的NAND启动原理,是硬件通过引脚判断NAND启动后,会搬运NAND从0地址开始的前4K内容到SRAM上,然后在SRAM上运行起来,这段4K的代码,必须至少要初始化DDR,并且搬运bootloader到DDR,才能运行接下来的代码。普通的arm bootloader的启动流程来看,board_init_f应该在relocate_code之前运行,用来计算将要搬运的目的地址和栈寄存器地址等等,但是因为board_init_f代码段太大,编译不进前4K,所以,网上通用的做法好像是先预设relo
[单片机]
[ANT+][nrf51422][s210] 自行车车灯 数据页1–灯光状态1(0x01)
数据页1是ANT+自行车灯广播的主要数据页之一。所有ANT+自行车灯应在数据页旋转开始时和状态改变后立即发送此页(例如,当收到新命令时)。此信息中的所有字段应按表7-3所述进行设置。 Table 7-3. 数据页1格式-灯光状态1 Table 7-4. 数据公用格式第1页 /* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved. * * The information contained herein is property of Nordic Semiconductor ASA. * Terms and conditions of usag
[单片机]
[ANT+][nrf51422][s210] 自行车车灯 <font color='red'>数据</font>页1–灯光状态1(0x01)
导远定位感知2.0方案亮相,实现实时3D场景数据闭环
4月18日,导远电子在2023上海车展展示定位感知2.0方案,即城区智能出行全套定位感知解决方案,解锁高精度定位新方法。 这也是首个由高精度定位企业打造的定位+感知融合的方案,旨在用一套集硬件、软件、云端于一体的工具箱,助智能设备和汽车实现实时的3D场景数据闭环,让自动驾驶技术渗透到城市和产业的各个角落。 新方案体现了高精度定位行业正由狭义的定位自己到实现更广义、深层次的定位自己+环境的定位感知发展,这在智能驾驶逐步进入城区领航辅助驾驶阶段显得尤为重要。 对于包括主机厂在内的用户来说,导远的定位感知2.0方案也是一套性价比更高的轻量、实时实现3D场景数据采集、处理、应用的闭环工具箱。其有助于用户提升自动驾驶,特别是规划
[汽车电子]
导远定位感知2.0方案亮相,实现实时3D场景<font color='red'>数据</font>闭环
STM32CUBEMX开发GD32F303(11)----ADC在DMA模式下扫描多个通道
概述 本章STM32CUBEMX配置STM32F103,并且在GD32F303中进行开发,同时通过GD32303C_START开发板内进行验证。 需要GD样片的可以加Q_QUN申请:6_15061293。 本章主要配置,双ADC轮询模式扫描多个通道,通过串口进行打印。 查阅手册可以得知,PA9、PA10为串口0的输出和输入口。 ADC通道配置 生成例程 这里准备了GD32303C_START开发板进行验证。 视频教学 https://www.bilibili.com/video/BV1hG41187Ah/ STM32CUBEMX配置 勾选中断。 ADC1配置。 ADCs_Common_Setti
[单片机]
STM32CUBEMX开发GD32F303(11)----ADC在<font color='red'>DMA</font>模式下扫描多个通道
CTSD精密ADC—利用异步采样速率转换(ASRC)简化数字数据接口
CTSD Precision ADCs—Digital Data Interface Simplification with Asynchronous Sample Rate Conversion (ASRC) CTSD精密ADC—利用异步采样速率转换(ASRC)简化数字数据接口 本系列文章已突出介绍了连续时间Σ-Δ(CTSD)模数转换器(ADC)调制器环路的架构特性,这种架构能够简化ADC模拟输入端的信号链设计。现在讨论将ADC数据与外部数字主机接口以对此数据执行应用相关处理的简单但创新的方法。对任何应用而言,数字数据输出采样速率都是ADC信号链的一个关键参数。但是,不同应用有不同的采样速率要求。本文章介绍一种新型片内
[模拟电子]
CTSD精密ADC—利用异步采样速率转换(ASRC)简化数字<font color='red'>数据</font>接口
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved