【JZ2440笔记】DMA

发布者:tnzph488最新更新时间:2022-10-27 来源: csdn关键字:JZ2440  DMA 手机看文章 扫描二维码
随时随地手机看文章

一、前言

DMA可以独立于CPU之外进行数据的搬移操作,因此在大量数据需要进行迁移时可以利用DMA的优势,减轻CPU的负担,从而提高系统的性能。


二、实验目标

使用DMA模块将一片RAM内存的数据搬移到另外一片内存。


三、实验分析

S3C2440A 支持 4 通道处于系统总线和外设总线间的 DMA 控制器。DMA 控制器的每个通道都可以无限制的执行系统总线与/或外设总线之间设备的数据移动。换句话说,每个通道都可以处理以下 4 种情况:


(1) 源和目标都在系统总线上


(2) 当目标在外设总线上时源在系统总线上


(3))当目标在系统总线上时源在外设总线上


(4))源和目标都在外设总线上


DMA 的主要优点是在无 CPU 干预的情况下能进行数据传输。DMA 的运行可以由软件开始,也可以来自内部外设或外部请求引脚的请求。

配置DMA无非就是要确定几个条件:源地址、进行一次搬移的数据长度、要搬移数据的总共大小、目标地址。


四、程序编写

代码分为以下几个文件:


head.S:启动文件。


init.c:初始化函数,关闭看门狗,初始化系统时钟。


main.c:DMA实验相关函数。


Makefile:用来编译代码。


各个文件内容分别如下:


head.S


@*************************************************************************

@ File:head.S

@ 功能:设置FCLK到400MHz

@*************************************************************************       

.text

.global _start

_start:

ldr sp, =4096                       @设置堆栈,因为要调用C语言函数 

bl disable_watch_dog               @关WATCH DOG

bl init_system_clk                 @初始化系统时钟,FCLK=400MHz,HCLK=100MHz,PCLK=50MHz

    bl main                            @跳转执行main函数

halt_loop:

    b       halt_loop

 

init.c


/* WOTCH DOG register */

#define REG_WTCON               (*(volatile unsigned long *)0x53000000)

 

/* Sys Clk Config */

#define REG_CLKDIVN             (*(volatile unsigned long *)0x4C000014)

#define REG_CAMDIVN             (*(volatile unsigned long *)0x4C000018)

#define REG_MPLLCON             (*(volatile unsigned long *)0x4C000004)

 

void disable_watch_dog();

void init_system_clk();

 

/*上电后,WATCH DOG默认是开着的,要把它关掉 */

void disable_watch_dog()

{

REG_WTCON = 0;

}

 

void init_system_clk()

{

    //HCLK = FCLK/4, 当 CAMDIVN[9] = 0 时

    //PCLK 设置为 HCLK/2 

    //完成配置FCLK : HCLK : PCLK = 1 : 1/4 : 1/8,DIVN_UPLL是USB的时钟不用管

    REG_CLKDIVN = (2 << 1) | (1 << 0);

 

    /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */

__asm__(

    "mrc    p15, 0, r1, c1, c0, 0n"        /* 读出控制寄存器 */ 

    "orr    r1, r1, #0xc0000000n"          /* 设置为“asynchronous bus mode” */

    "mcr    p15, 0, r1, c1, c0, 0n"        /* 写入控制寄存器 */

    );

 

    //m=MDIV+8, p=PDIV+2, s=SDIV, Mpll = ( 2 × m × Fin ) / ( p × 2^s )

    //FCLK = (2 * (92 + 8) * 12000000) / ((1 + 2) * 2) = 400000000 = 400MHz

    //配置完MPLL后时钟停振,CPU停止运行等待时钟输出稳定,之后FCLK=400MHz,HCLK=100MHz,PCLK=50MHz */

    REG_MPLLCON = (92<<12)|(1<<4)|(1<<0);

}


main.c


#define BYTE unsigned char

#define WORD unsigned short

#define DWORD unsigned int

 

/* GPIO Configure*/

#define GPFCON (*(volatile unsigned long *)0x56000050)

#define GPFDAT (*(volatile unsigned long *)0x56000054)

#define GPFUP (*(volatile unsigned long *)0x56000058)

 

/* DMA */

#define REG_DISRC0 (*(volatile unsigned long *)0x4B000000)

#define REG_DISRCC0 (*(volatile unsigned long *)0x4B000004)

#define REG_DIDST0 (*(volatile unsigned long *)0x4B000008)

#define REG_DIDSTC0 (*(volatile unsigned long *)0x4B00000C)

#define REG_DCON0 (*(volatile unsigned long *)0x4B000010)

#define REG_DSTAT0 (*(volatile unsigned long *)0x4B000014)

#define REG_DMASKTRIG0 (*(volatile unsigned long *)0x4B000020)

 

void wait(volatile unsigned long dly)

{

for(; dly > 0; dly--);

}

 

void init_led(void)

{

GPFCON &= ~((DWORD)(3 << (2 * 4)) | (3 << (2 * 5)) | (3 << (2 * 6)));

GPFCON |= ((DWORD)(1 << (2 * 4)) | (1 << (2 * 5)) | (1 << (2 * 6))); //GPF4、GPF5、GPF6输出模式

 

GPFDAT |= (1 << 4) | (1 << 5) | (1 << 6);   //输出高电平,LED全灭

}

 

int main()

{

WORD i;

DWORD dwSrc[100];

DWORD dwDst[100];

 

init_led();

 

//填充原始数据

for (i = 0; i < sizeof(dwSrc) / sizeof(dwSrc[0]); i++)

{

dwSrc[i] = i + 1;

dwDst[i] = 0;

}

 

//配置DMA传输

//设置源地址

REG_DISRC0 = (DWORD)&dwSrc[0];

//源位于AHB总线, 源地址递增

REG_DISRCC0 = (0<<1) | (0<<0);

//设置目标地址

REG_DIDST0 = (DWORD)&dwDst[0];

//在 TC 到达 0 时发生中断, 目的位于AHB总线, 目的地址递增

REG_DIDSTC0 = (0<<2) | (0<<1) | (0<<0);

//AHP总线同步,禁止中断,全速传输(BIT27),软件触发(BIT23)

REG_DCON0 = (1<<30)|(0<<29)|(0<<28)|(1<<27)|(0<<23)|(0<<20)|(sizeof(dwSrc)<<0);  

//打开通道,软件启动DMA

REG_DMASKTRIG0 = (1<<1) | (1<<0);  

 

//等待DMA传输完成

while(REG_DSTAT0 != 0);

GPFDAT &= ~((DWORD)1 << 4); //亮第1个灯,表示DMA传输完成

 

//检验数据

for (i = 0; i < (sizeof(dwSrc) / sizeof(dwSrc[0])); i++)

{

if(dwSrc[i] != dwDst[i])

{

while(1);

}

}

 

//判断数据传输是否正确

if(i != (sizeof(dwSrc) / sizeof(dwSrc[0])))

{

i = 5;  //传输错误,第2个灯闪烁

}

else

{

i = 6;  //传输正确,第3个灯闪烁

}

 

 

while(1)

{

//对应LED闪烁

GPFDAT ^= (DWORD)1 << i;

wait(30000);

}

return 0;


Makefile


objs := head.o init.o main.o

 

DMA.bin: $(objs)

 

arm-linux-ld -Ttext 0x0000000 -g -o DMA_elf $^

arm-linux-objcopy -O binary -S DMA_elf $@

arm-linux-objdump -D -m arm DMA_elf > DMA.dis

%.o:%.c

arm-linux-gcc -Wall -O2 -c -o $@ $<

 

%.o:%.S

arm-linux-gcc -Wall -O2 -c -o $@ $<

 

clean:

rm -f DMA.bin DMA_elf DMA.dis *.o


main函数中定义了两个数组dwSrc和dwDst,它们都是400字节的数组,一开始时dwSrc先赋值为1~400的整数,然后将dwDst清0,接下来配置DMA传输,代码中卡了一个while循环来等待DMA传输完毕,其实在这段时间里CPU可以去做其他的事情,DMA传输完毕后,再去比较dwSrc和dwDst两个数组的数据是否相等来判断DMA是否传输正确,因为没接串口,所以实验是否成功的依据是开发板上3个LED的状态,第1个LED亮代表DMA传输完毕,之后如果第2个LED在闪烁代表传输数据不匹配即传输错误,若是第3个LED在闪烁代表数据匹配DMA传输正确,


执行make命令后将生成的bin文件烧写到开发板的NandFlash中,然后选择Nand启动即可看到正确的现象。


五、实验总结

DMA是CPU的好帮手,可以有效的提高系统性能。

关键字:JZ2440  DMA 引用地址:【JZ2440笔记】DMA

上一篇:【JZ2440笔记】串口通信
下一篇:【JZ2440笔记】定时器

推荐阅读最新更新时间:2024-11-13 11:24

STM32单片机串口DMA解析
讨论三个问题:1、什么叫串口DMA 请求;2、串口简要复习;3、串口DMA发送流程。 1、什么叫串口DMA 请求(战舰STM32开发板) 说这个问题之前先简单回顾DMA的基本特性。先导出原子哥的PPT内容: DMA全称Direct Memory Access,即直接存储器访问。 DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。 STM32有两个DMA控制器(DMA2只存在于大容量产品中),DMA1有7个通道,DMA2有5个通道,每个通道专门用来管理来自于一个或者多个外设对存储器的访问请求。还有一个仲裁器来协调各个DMA请求的优先权。 作用:为CPU减负
[单片机]
STM32单片机串口<font color='red'>DMA</font>解析
STM32F103单片机使用DMA功能读取ADC采样数据
使用DMA功能操作外设时,可以极大的简化代码,提高程序的执行效率。特别是在需要频繁操作的外设上。比如现在要采集单片机16个ADC通道的电压值,就可以使用DMA功能,直接将ADC通道转换好的值,传输到数组中。需要操纵ADC的值时,直接去数组中拿数据就行。不需要再去判断ADC数据转换是否结束。下面直接通过代码来实现。 首先初始化ADC,这里将ADC的16个采样通道全部开启。 void ADC1_Init ( void ) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; RCC_APB2PeriphCloc
[单片机]
STM32H7实现8通道ADC采集(软件触发+DMA传输)
使用CubeMX工具,对DMA进行配置。 dma相关的配置比较简单,主要是adc配置相关的修改: 数据要设置成DMA循环模式ADC_CONVERSIONDATA_DMA_CIRCULAR; 溢出操作要设置为覆盖ADC_OVR_DATA_OVERWRITTEN; 主函数逻辑代码如下: #include sys.h #include delay.h #include usart.h #include adc.h #include dma.h u16 buffer ; int main(void) { u16 adcx; //Cache_Enable(); //打开L1-Cache HAL
[单片机]
STM32H7实现8通道ADC采集(软件触发+<font color='red'>DMA</font>传输)
jz2440 ----移植自制的USB RTL8188EUS网卡驱动
1:google 下载rtl8188eus的网卡驱动源码 https://github.com/quickreflex/rtl8188eus 2.解压缩下载的文件,把驱动文件rtl8192_8188eus_linux_xxx.tar.gz(xxx是版本号)添加到要编译的内核树里面去 (1)假定你的内核位置为/root/linux-kernel,解压缩驱动文件,并且把解压缩后的驱动文件夹名改为rtl8192eus。 (2)把改好名字的驱动文件夹rtl8192eus复制到/root/linux-kernel/drivers/net/wireless/下。 (3)修改/root/linux-kernel/driver
[单片机]
<font color='red'>jz2440</font> ----移植自制的USB RTL8188EUS网卡驱动
STM32 HAL+PWM+DMA方式驱动WS2812灯珠波形分析
1. 在DMA传送完PWM波形后不关闭PWM的DMA输出 灯珠显示效果: 灯珠会错乱显示(没有按正常设定的颜色显示) 示波器显示如下: 2. 在DMA传送完PWM波形后,在PWM传输完成后回调函数中关闭PWM的DMA输出 灯珠显示效果: 会按照设定的颜色正常显示,但灯带的起始位置会有绿色的余光(基于自己测试时使用的灯带) 示波器显示如下 3. 在DMA传送完PWM波形后,在DMA中断函数中关闭PWM的DMA输出 灯珠显示效果: 按照设定的颜色模式正常显示 示波器显示效果如下: 分析 方式1在pwm通过DMA的方式传输完成后会保持高电平,且会产生杂波,可能是导致灯珠显示错乱的主要原因. 方式2在DMA传输完成的回调函数关
[单片机]
STM32 HAL+PWM+<font color='red'>DMA</font>方式驱动WS2812灯珠波形分析
JZ2440开发板裸板烧写方法
1、启动nor/nand flash上的uboot烧写裸板: 设置开发板为nor flash启动,上电按空格进入uboot,如下: ##### 100ask Bootloader for OpenJTAG ##### Download u-boot to Nand Flash Download u-boot to Nor Flash Download Linux kernel uImage Download root_jffs2 image Download root_yaffs image Download to SDRAM & Run Download zImage into RAM Boot linux fr
[单片机]
STM32L431之SPI从模式使用DMA时数据偏移3个字节
环境: 将SPI3配置成从模式,并且使用DMA来传输数据,在初始化完SPI3后,就立即配置DMA,将待传输的数据准备好。 主机还未读取时,就重新更新数据,更新数据的方法为直接调用Spi3TxDmaStart static void Spi3TxDmaStart(void * buf,unsigned int len,int enableInterrupt){ DMA2_Channel2- CCR &= 0xFFFFFFFE; // disable DMA first DMA2_Channel2- CMAR = (unsigned int)buf; DMA2_Channel2- CNDTR = len & 0xFF
[单片机]
STM32L431之SPI从模式使用<font color='red'>DMA</font>时数据偏移3个字节
S3C2410的linux下DMA驱动程序开发
网上介绍LINUX下的一般驱动程序开发示例浩如烟海,或是因为简单,关于DMA驱动的介绍却寥寥无几;近期zhaoyang因工作需要,花了几日时间开发了某设备在S3C2410处理器Linux下DMA通信的驱动程序,有感于刚接手时无资料借鉴的茫然,故写点介绍,期待能给有DMA开发任务的网友们一点帮助。 本文将包括如下内容: DMA驱动主要函数功能 驱动中关键技术分析 具体的DMA实例分析 申明:本DMA驱动开发介绍仅适合S3C2410处理器类型,分析源码为韩国MIZI研究中心维护的dma驱动代码: linux/arch/arm/mach-s3c2410/dma.h,linux/arch/arm/mach-s3c2410/dma.c,其它
[单片机]
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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