微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > s3c2440的DMA应用

s3c2440的DMA应用

时间:11-19 来源:互联网 点击:
DMA(Direct Memory Access,直接内存访问)是一种不经过CPU而直接从内存存取数据的数据交换模式。在需要进行大量数据交换的场合,用好DMA,可以大大提高系统的性能,因为DMA操作几乎不占用CPU资源。


s3c2440提供了4个通道的DMA,它们不仅可以实现内存之间的数据交换,还可以实现内存与外设,以及外设与外设之间的数据交换。要用好s3c2440的DMA,关键是配置好它的源、目的寄存器,和必要的控制寄存器。寄存器DISRCn是初始DMA源寄存器,它是用于设置DMA数据传输的源基址,而寄存器DIDSTn是初始DMA目的寄存器,它是用于设置DMA数据传输的目的基址。初始DMA源控制寄存器DISRCCn的第1位用于选择源的总线(系统总线AHB还是外设总线APB),第0位用于设置源基址在数据传输过程中是递增还是固定不变。初始DMA目的控制寄存器DIDSTCn的低两位与寄存器DISRCCn相识,但它是用来设置目的基址,而第2位用于设置是在传输完数据之后中断还是在自动重载后中断。DMA控制寄存器DCONn用于控制数据的DMA传输,第31位用于设置传输协议是需求模式还是握手模式,第30位用于选择同步时钟是PCLK还是HCLK,第29位用于设置DMA中断是否发生,第28位用于选择传输大小是单元传输还是突发传输,第27位用于选择服务模式是单步模式还是完全模式,第24位到第26位用于设置DMA的请求源,第23位用于设置DMA的源是软件还是硬件,第22位用于设置是否需要重载传输的目的和源基址,第20位和第21位用于设置数据传输的数据大小(字节、半字还是字),低20位用于初始化传输数据的个数。而通过读取DMA状态寄存器DSTATn的低20位可以获知当前的传输的计数。DMA掩码触发寄存器DMASKTRIGn的第2位可以终止当前DMA操作,第1位可以用于开启DMA通道,第0位则表示在软件请求模式下触发DMA通道。

下面我们就用DMA的方式来实现音频的播放。由于是用DMA的方式,因此在播放的过程中不占用系统资源,我们可以很容易的实现声音的各种操作而丝毫不影响播放的效果,如音量的提高和降低、静音、暂停等。在这里,还需要强调一点,利用DMA传输数据,一次最多可以传输的字节大小为:DSZ×TSZ×TC,DSZ表示的是数据大小(字节、半字还是字,即是1、2还是4),TSZ表示的是传输大小(单元传输还是突发传输,即1还是4),TC表示传输计数值(即寄存器DCONn的低20位存放的数据),因此如果需要传输的字节大小超出了这三个参数乘积的大小,则还要进一步处理,在我们给出的程序中,我们就考虑了这方面的问题。下面就是具体的程序,其中我们是利用UART来实现音频信号的播出、停止、暂停、静音、音量的提高和降低的。

…………
//一段纯音频数据数组
unsigned char music[] = {
0xF9, 0xFF, 0xF5, 0xFF, 0xF8, 0xFF, 0xF8, 0xFF, 0xF6, 0xFF, 0xFF, 0xFF, 0xF5, 0xFF, 0xF9, 0xFF,
0xF6, 0xFF, 0xF6, 0xFF, 0xFA, 0xFF, 0xFD, 0xFF, 0xFA, 0xFF, 0xFA, 0xFF, 0xF7, 0xFF, 0xF6, 0xFF,
…………
};

int result;
int remainder;
char flag;
char cmd;
char play_state;

void __irq uartISR(void)
{
char ch;
rSUBSRCPND |= 0x1;
rSRCPND |= 0x1<28;
rINTPND |= 0x1<28;
ch=rURXH0;

switch(ch)
{
case 0x55://播放
cmd = 1;
break;
case 0x1://静音
cmd = 0x11;
break;
case 0x2://音量提高
cmd = 0x12;
break;
case 0x3://音量降低
cmd = 0x13;
break;
case 0x66://停止
cmd = 0x2;
break;
case 0x77://暂停
cmd = 0x3;
break;
}
rUTXH0=ch;
}

//放音子程序
void playsound(unsigned char *buffer,int length)
{
//用于计算音频数据的长度是否超过DMA所能传输的字节数范围
//这里音频数据的通道位数为16位,因此需要length除以2
remainder = (length>>1) & 0xfffff;//余数
result = (length>>1) / 0x100000;//商

play_state = 1;//置播放标志

rGPBDAT = rGPBDAT & ~(L3M|L3C|L3D) |(L3M|L3C);

//配置1341,详细讲解请看上一篇文章
WriteL3(0x14 + 2,1);
WriteL3(0x60,0);

WriteL3(0x14 + 2,1);
WriteL3(0x10,0);

WriteL3(0x14 + 2,1);
WriteL3(0xc1,0);

//配置IIS
rIISPSR= 3<5|3;
rIISCON= (1<5)|(0<4)|(0<3)|(1<2)|(1<1);//发送IIS的DMA使能
rIISMOD= (0<9)|(0<8)|(2<6)|(0<5)|(0<4)|(1<3)|(1<2)|(1<0);
rIISFCON = (1<15)|(1<13); //发送FIFO为DMA

//配置DMA
rDISRC2 = (U32)buffer;//DMA的源基址为音频数据数组的首地址
rDISRCC2 = (0<1)|(0<0);//AHB,源地址递增
rDIDST2 = (U32)IISFIFO;//DMA的目的基址为IIS的FIFO
rDIDSTC2 = (0<2)| (1<1)|(1<0);//当传输计数值为0时中断,APB,目的地址不变
if (result == 0)//所传输的字节数没有超出DMA的最大传输范围
{
flag = 0;//清标志,表示没有超出范围,进入DMA中断后结束DMA操作
//握手模式,PCLK同步,传输计数中断,单元传输,单步服务模式,IISSDO,
//硬件请求模式,非自动重载,半字,
rDCON2 = (1<31) | (0<30) | (1<29) | (0<28) | (0<27) | (0<24) | (1<23) | (1<22) | (1<20) | (remainder);

}
else//所传输的字节数超出了DMA的最大传输范围
{
flag = 1;//置标志,表示超出范围
rDCON2 = (1<31) | (0<30) | (1<29) | (0<28) | (0<27) | (0<24) | (1<23) | (1<22) | (1<20) | (0xfffff);
}
rDMASKTRIG2=(0<2)|(1<1)|0;//不停止DMA,DMA通道开启,非软件触发

//启动IIS
rIISCON |= 0x1;
}

void __irq DMA_end(void)
{
rSRCPND |= 0x1<19;
rINTPND |= 0x1<19;

if (flag == 0)//DMA传输完毕
{
rIISCON = 0x0;//关闭IIS
rIISFCON = 0x0;//清IIS的FIFO
rDMASKTRIG2=1<2;//停止DMA
play_state = 0;//清播放标志
}
else//DMA没有传输完毕,继续传输
{
result --;//商递减
rDISRC2 += 0x200000;//DMA源基址递增。因为传输的数据是半字,所以这里递增0x200000
if (result == 0 )//只剩下余数部分需要传输
{
rDCON2=(rDCON2&(~0xfffff))|(remainder);//需要重新设置传输计数值
flag=0;//清标志
}
rDMASKTRIG2=(0<2)|(1<1)|0;//需要重新设置DMA通道的开启
}
}

void Main(void)
{

char mute;
char volume;

…………

rSRCPND = (0x1<19)|(0x1<28);
rSUBSRCPND = 0x1;
rINTPND = (0x1<19)|(0x1<28);
rINTSUBMSK = ~(0x1);
rINTMSK = ~((0x1<19)|(0x1<28));//开启DMA2中断屏蔽
pISR_UART0 = (U32)uartISR;
pISR_DMA2=(U32)DMA_end;

result=0;
remainder=0;
flag=0;
cmd=0;
play_state =0;

while(1)
{
switch(cmd)
{
case 0x1://播放
if (play_state==0)
{
volume = 0;//音量清零
mute=0xa0;//初始化静音
playsound(music,sizeof(music));
}
else
{
while(!(rUTRSTAT0 & 0x2))
;
rUTXH0=0xff;
}
cmd = 0;
break;
case 0x2://停止
if (play_state==1)
{
rIISCON = 0x0;//停止IIS
rIISFCON = 0x0;//清IIS的FIFO
rDMASKTRIG2=1<2;//终止DMA2
flag = 0;
play_state = 0;
}
else
{
while(!(rUTRSTAT0 & 0x2))
;
rUTXH0=0xff;
}
cmd = 0;
break;
case 0x3://暂停,
if(play_state == 1)
{
rIISCON ^= 0x1;//

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top