DMA(Direct Memory Access,直接内存拜访)是一种不经过CPU而直接从内存存取数据的数据交换形式。在需求进行很多数据交换的场合,用好DMA,能够大大进步体系的功能,由于DMA操作几乎不占用CPU资源。
下面咱们就用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;//异或,
}
else
{
while(!(rUTRSTAT0 & 0x2))
;
rUTXH0=0xff;
}
cmd = 0;
break;
case 0x11://静音
if (play_state==1)
{
mute ^= 0x4;
WriteL3(0x14 + 0,1);//DATA0 (000101xx+00)
WriteL3(mute,0);//10,1,00,x,00:x,静音
}
else
{
while(!(rUTRSTAT0 & 0x2))
;
rUTXH0=0xff;
}
cmd = 0;
break;
case 0x12://音量递加
if (play_state==1)
{
if(volume>0)
{
volume –;
WriteL3(0x14 + 0,1);//DATA0 (000101xx+00)
WriteL3(volume,0);//音量进步
}
}
else
{
while(!(rUTRSTAT0 & 0x2))
;
rUTXH0=0xff;
}
cmd = 0;
break;
case 0x13://音量递减
if (play_state==1)
{
if(volume<61)
{
volume++;
WriteL3(0x14 + 0,1);//DATA0 (000101xx+00)
WriteL3(volume,0);//音量下降
}
}
else
{
while(!(rUTRSTAT0 & 0x2))
;
rUTXH0=0xff;
}
cmd = 0;
break;
}
}
}