您的位置:首页 > 其它

FL2440无操作系统应用程序编写测试012——DMA

2011-12-07 12:14 253 查看
Subject:FL2440无操作系统应用程序编写测试012——DMA
Date: 7-Dec-2011

By: Calvinlee1984@163.com

1.DMA介绍

高速外设(I/O)与系统内存(Memory)或者在系统内存不同区域之间进行大量数据的快速传送时,轮询方式和中断方式可能无法满足传送要求。采用直接存储器存取(Direct Memory Access)方式,在某一时间段内,DMAC取代CPU,获得总线控制权,负责数据的传送,因此省去了CPU取指令、取数、送数等操作。在数据传送过程中,没有保存/恢复现场之类的工作,内存地址修改,传送字计数等也是用硬件线路直接实现的,所以DMA方式能满足高速I/O设备的请求,也有利于CPU效率的发挥。

1)DMA系统组成



DREQ(DMA Request): DMA请求输入信号,是外部电路为取得DMA服务而送到各DMA通道的请求信号,在相应的DACK信号产生前DREQ必须维持有效;

HRQ(Hold Request): 保持请求信号,通常接到CPU的HOLD引脚,用来向CPU请求对系统总线的控制权。在HRQ有效之后,至少等待一个时钟周期,HLDA信号才会有效;

HLDA(Hold Acknowledge):保持响应信号,来自CPU的同意让出总线响应信号,表示CPU已经让出对总线控制权而交给DMAC;

DACK(DMA acknowledge):DMA响应输出信号,DMAC利用这个信号通知外部设备已经被授予一个DMA周期了,可利用有效的DACK信号作为I/O接口的选通信号。

2)DMA工作过程:



◆外部I/O设备向DMAC发出DMA传送请求;

◆DMAC通过连接到CPU的HOLD信号向CPU提出DMA传送请求;

◆CPU在完成当前总线操作后立即对DMA请求做出响应,放弃总线控制权并将有效的HLDA信号加到DMAC上,以通知DMAC CPU已经放弃总线控制权;

◆DMAC接管系统总线的控制权,并向外部I/O设备送出DMA的应答信号;

◆DMAC送出地址和控制信号,实现外设与内存或内存之间数据的快速传送;

◆DMAC将规定的数据传送完之后,通过向CPU发HOLD信号,撤消对CPU的DMA请求。CPU收到此信号,一方面使HLDA无效,另一方面又重新开始控制总线。

3)DMAC与CPU分时使用内存的方式:

◆停止CPU访问内存

当外围设备要求传送一批数据时,由DMC发一个请求信号给CPU,要求CPU放弃对地址总线、数据总线和有关控制总线的使用权。DMAC获得控制权后,开始进行数据传送,传送完毕后,DMAC通知CPU可以使用内存,并把总线控制权交还给CPU。外围设备传送两个数据之间的间隔一般总是大于内存存储周期,例如软盘读出一个8位二制数大约需要32us,而半导体内存的存储周期小于0.5us,因此在DMAC访问阶段,许多空闲的存储周期不能被CPU利用,内在的效能没有充分发挥。



◆周期挪用

I/O设备无DMA请求时,CPU按程序要求访问内存,一旦I/O设备有DMA请求,则由I/O设备挪用一个或几个内存周期。I/0设备要求DMA传送可能遇到两种情况1)CPU不需要访内,如CPU正在执行乘法指令,此时I/O设备挪用一二个内存周期对CPU执行程序没有任何影响。2)I/O设备要求访内时CPU也要求访内,产生访内冲突,这种情况下I/O设备访内优先,因为I/O访内有时间要求,前一个I/O数据必须在下一个访内请求到来之前存取完毕。这种情况下I/O设备挪用一二个内存周期,意味着CPU延缓了对指令的执行,或者说在CPU执行访内指令的过程中插入DMA请求,挪用了一二个内存周期。



◆DMA与CPU交替访内

如果CPU的工作周期比内存存取周期长很多,此时采用交替访内的方法可以使DMA和CPU同时发挥最高的效率。一个CPU工作周期被分为C1及C2分周期,C1供DMAC访内,C2专供CPU访内。该种方式不需要总线使用权的申请、建立及归还过程,总线使用权是通过C1,C2分时制的。CPU及DMAC各有自己的访内地址寄存器、数据寄存器和读、写信号等控制寄存器。对于总线控制权的转移是通过硬件实现的,几乎不需要什么时间,所以对DMA传送来讲效率是很高的。在该种DMA方式下工作,CPU既不停止主程序的运行也不进入等待状态,是一种高效的工作方式。当然,相应的硬件逻辑也更加复杂。



2.S3C2440A DMA控制器

S3C2440A支持4通道DMA控制器,每个DMA通道都能没有约束地实现系统总线或者外围总线之间的数据传输。

1)DMA请求源



2)DMA传输方式

◆单步模式(Single service):有两个DMA应答周期分别指示读或写,这种模式通常用在测试或者调试的时候,因为在读与写之间系统总线占有权可以交给其它的主控制器。在读写周期之间,总线控制器重新估计优先级来决定新的总线控制者;

◆完整服务模式(Whole servie):如果DMA传输数量太大的话,由于其它的总线服务不能进行,此时长时间的总线占用可能会带来一些问题。为了解决这类问题,提出了完整服务模式,DMA在每个UNIT传输完成时释放总线控制权,此时其他的总线控制器(比如CPU,其他的DMA和外部总线控制器)将会获得总线的控制权。完整服务模式的这个特征可以提供最佳的总线分配状况,防止总线的使用权被某个DMA所垄断。

3)外部DMA 请求/应答协议

◆基本时序



◆需求模式及握手模式比较



需求模式(Demand mode):只要DMA请求信号持续,就会有连续的DMA传输周期。在这种模式下,在一个DMA周期中,将不允许把总线使用权交给其他提出DMA请求的优先级高的总线控制器,也就是任何其他总线控制器都不能获得总线使用权;

握手模式(Handshake mode):一个单独的DMA请求信号对应一个DMA应答信号,在该模式下,一次DMA操作意味着在DMA操作中的一对或不可分的读和写周期。由nXDREQ产生的DMA请求引起一个字节、半字或一个字被传送出去,在握手模式下,每一个数据的传送都需要DMA请求。

4)DMA传输数据类型

UNIT:每个DMA请求恰好发生一个DMA读/写周期,即一个字的读,然后一个字的写;

Burst 4:4个字突发读,然后4个字突发写。



5)请求/应答协议示例

◆Single service in Demand Mode with Unit Transfer Size



◆Single service in Handshake Mode with Unit Transfer Size



◆Whole service in Handshake Mode with Unit Transfer Size


3.本文在上一篇《FL2440无操作系统应用程序编写测试011——IIS_AUDIO》基础上利用DMA方式传输音频数据,实现在播放音乐的过程中,CPU也可执行其他程序

4.DMA寄存器设置

static void DMA2_Port_Init(void){

//DMA2

rDISRC2 = (U32)WindowsXP_Wav; //Start address



rDISRCC2 = (0<<1)|(0<<0); //Source in AHB,Increment



//Destination address

//#define IISFIFO ((volatile unsigned short *)0x55000010)

rDIDST2 = (U32)IISFIFO;



//Destination in APB,Fixed,Interrupt will occur when TC reaches 0

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



}

5.代码分析 DMA.c

#include "2440addr.h"

#include "2440lib.h"

#include "def.h"

#include "option.h"

extern unsigned char WindowsXP_Wav[]; //243552Bytes

U32 wav_length_result, wav_length_remain;

U8 flag;

#define L3MODE (1<<2) //GPB2

#define L3DATA (1<<3) //GPB3

#define L3CLOCK (1<<4) //GPB4

//UDA131TS L3总线接口写入函数

//address为0地址模式,否则为数据传输模式

//data为传输数据

static void WriteL3(U8 address,U8 data){

int i, j;

if(!address){ //地址模式

//L3CLOCK=High,L3MODE=Low

rGPBDAT = rGPBDAT & ~(L3MODE|L3DATA|L3CLOCK )|L3CLOCK;

}else{ //数据传输模式

//L3CLOCK=High,L3MODE=High

rGPBDAT=rGPBDAT & ~(L3MODE|L3DATA|L3CLOCK)|(L3CLOCK|L3MODE);

}

for(j = 0; j < 5; j++); //delay

//将字节数据按串行格式发送,低位在前,高位在后

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

if(data & 0x1){ //Bit[i]=1

rGPBDAT &= ~L3CLOCK; //L3CLOCK=Low

rGPBDAT |= L3DATA; //L3DATA =High

for(j = 0; j < 5; j++);

rGPBDAT |= L3CLOCK; //L3CLOCK=High

rGPBDAT |= L3DATA; //L3DATA =High

for(j = 0; j < 5; j++);

}else{ //Bit[i]=0

rGPBDAT &= ~L3CLOCK; //L3CLOCK=Low

rGPBDAT &= ~L3DATA; //L3DATA =High

for(j = 0; j < 5; j++);

rGPBDAT |= L3CLOCK; //L3CLOCK=High

rGPBDAT &= ~L3DATA; //L3DATA =Low

for(j = 0; j < 5; j++);

}

data >>= 1; //Next bit

}

}

//UDA1341TS L3 controller Initialize

static void UDA1341TS_L3_Init(void){

//Set GPB[4:2] as output and Disable pull-up function

rGPBCON = rGPBCON & ~(0x3f<<4) | (0x15<<4);

rGPBUP = rGPBUP & ~(0x7<<2) | (0x7<<2);

//配置UDA1341TS L3

//状态模式

WriteL3(0,0x14+2);

WriteL3(1,0x40); //0100_0000 Reset

WriteL3(0,0x14+2);

WriteL3(1,0x10); //0001_0000 System Clock 384fs,No DC filter,I2S-bus

WriteL3(0,0x14+2);

WriteL3(1,0xc1); //1100_0001 DAC Output gain 6dB,ADC off,DAT on

}

//IIS Port Initialize

static void IIS_Port_Init(void){

//Set GPE[4:0] as IIS Port and Disable pull-up function

rGPECON = rGPECON & ~(0x3ff) | 0x2aa;

rGPEUP = rGPEUP & ~(0x1f) | 0x1f;

//DMA开启,在接受空闲状态,不产生IISLRCK信号,IIS预分频使能

rIISCON = (1<<5)|(0<<4)|(0<<3)|(1<<2)|(1<<1);

//主设备时钟PCLK,主设备模式,发送模式,IIS总线格式

//串行数据(量化位数)16位,主时钟是384fs,串行位时钟32fs

rIISMOD = (0<<9)|(0<<8)|(2<<6)|(0<<5)|(0<<4)|(1<<3)|(1<<2)|(1<<0);

//fs=22.050Khz,CODECLK=384fs=8.4672Mhz

//预分频N=PCLK/CODECLK-1)=33.8571/8.4672-1=2.9986

//取N=3

rIISPSR = (3<<5)|3;

//DMA方式发送FIFO,发送FIFO使能

rIISFCON = (1<<15)|(1<<13);

}

static void DMA2_Port_Init(void){

//DMA2

rDISRC2 = (U32)WindowsXP_Wav; //Start address

rDISRCC2 = (0<<1)|(0<<0); //Source in AHB,Increment

//Destination address

//#define IISFIFO ((volatile unsigned short *)0x55000010)

rDIDST2 = (U32)IISFIFO;

/Destination in APB,Fixed,Interrupt will occur when TC reaches 0

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

}

//DMA2中断处理程序

static void __irq DMA2_ISR(void){

U32 r;

EnterCritical(&r);

ClearPending(BIT_DMA2); //清除中断信号源

if(flag){

//IIS close

rIISCON = 0x0;

//DMA2 Turn off

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



}else{

wav_length_result--;

rDISRC2 += 0x200000;

if(!wav_length_result){

flag = 1;

rDCON2 = (1<<31)|(0<<30)|(1<<29)|(0<<28)|(0<<27)|(0<<24)|(1<<23)|(1<<22)|(1<<20)|(wav_length_remain<<0);

}

//DMA2 Turned on again

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



}

ExitCritical(&r);

}

//PlayWave

static void PlayWave(U8 buffer[], U32 length){

//获取单次DMA传输的TC值

//TC=length/TSZ/DSZ

wav_length_result = (length>>1)>>20;

wav_length_remain = (length>>1)&0xfffff;

if(!wav_length_result){

flag = 1;

//Handshake Mode,Synchronized to PCLK,

//Enable Interrupt,TSZ:unit,Single service

//DMA request source:I2SSDO,H/W request mode,No auto reload

//DSZ:Half word,TC:length/TSZ/DSZ

rDCON2 = (1<<31)|(0<<30)|(1<<29)|(0<<28)|(0<<27)|(0<<24)|(1<<23)|(1<<22)|(1<<20)|(wav_length_remain<<0);

}else{

flag = 0;

rDCON2 = (1<<31)|(0<<30)|(1<<29)|(0<<28)|(0<<27)|(0<<24)|(1<<23)|(1<<22)|(1<<20)|(0xfffff<<0);

}

//DMA2 Turn on

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

//IIS start

rIISCON |= 0x1;

}

void DMA2_IIS_PlayMusic_Test(void){

U32 Save_rMPLLCON = rMPLLCON; //PCLK=50Mhz

UDA1341TS_L3_Init(); //UDA1341TS L3 controller Initialize

IIS_Port_Init(); //IIS Port Initialize

DMA2_Port_Init(); //DMA2 Port Initialize

pISR_DMA2 = (U32)DMA2_ISR; //Set up ISR for DMA2

EnableIrq(BIT_DMA2); //Enable Interrupt of DMA2

rMPLLCON = (150<<12)|(5<<4)|(1<<0); //PCLK= 33.8571Mhz

PlayWave(WindowsXP_Wav, 243552);

rMPLLCON= Save_rMPLLCON; //PCLK=50Mhz

DisableIrq(BIT_DMA2); //Disable Interrupt of DMA2

}

6.测试程序及结果

#include "UART.h"

#include "DMA.h"

int Main(void)

{

UART0_Port_Init(115200); //UART端口初始化

UART0_Printf("Play Music...\n");

DMA2_IIS_PlayMusic_Test(); //播放音频文件

UART0_Printf("End\n");

while(1){

;

}

return 0;

}



注:播放声音的效果与上一篇一样,但输出“End”字符串是与放音同时进行的,上一篇必须结束放音时才输出。

因此用DMA方式传输大量数据,可显著提高CPU的效率。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: