DMA(Direct Memory Access,直接内存访问)是一种不经过CPU而直接从内存存取数据的数据交换模式。在需要进行大量数据交换的场合,用好DMA,可以大大提高系统的性能,因为DMA操作几乎不占用CPU资源。
由于是用DMA的方式,因此在播放的过程中不占用系统资源,我们可以很容易的实现声音的各种操作而丝毫不影响播放的效果,如音量的提高和降低、静音、暂停等。
定义变量:
static int remainder; static char mute; static char volume;
中断函数,当DMA传送完成时打印Success。
static void __irq PlayDMA2Done(void) { ClearPending(BIT_DMA2);
Uart_Printf("Success"); }
放音:
void playsound(unsigned char *buffer, int length) { //用于计算音频数据的长度是否超过DMA所能传输的字节数范围 //这里音频数据的通道位数为16位,因此需要length除以2 remainder = (length>>1) & 0xfffff; rGPBDAT = rGPBDAT & ~(L3M|L3C|L3D) |(L3M|L3C); //L3开始传输:L3M=H, L3C=H //配置UDA1341 WriteL3(0x14 + 2,1); //状态模式(000101xx+10) WriteL3(0x60,0); //0,1,10, 000,0 : 状态0,复位 WriteL3(0x14 + 2,1); //状态模式 (000101xx+10) WriteL3(0x10,0); //0,0,01, 000,0 : 状态0, 384fs,IIS,no DC-filtering WriteL3(0x14 + 2,1); //状态模式 (000101xx+10) WriteL3(0xc1,0); //1,0,0,0, 0,0,01:状态1, //Gain of DAC 6 dB,Gain of ADC 0dB,ADC non-inverting, //DAC non-inverting,Single speed playback,ADC-Off DAC-On //配置s3c2440的IIS寄存器
//fs=22.05kHz,CODECLK=384fs=8.4672MHz //预分频器为3,所以CDCLK=PCLK/(3+1)
rIISPSR = 3<<5|3; //发送DMA使能,输入空闲,预分频器有效 rIISCON = (1<<5)|(0<<4)|(0<<3)|(1<<2)|(1<<1); //PCLK为时钟源,输出模式,IIS模式,每个声道16位,CODECLK=384fs,SCLK=32fs rIISMOD =(0<<9)|(0<<8)|(2<<6)|(0<<5)|(0<<4)|(1<<3)|(1<<2)|(1<<0); rIISFCON = (1<<15)|(1<<13); //输出FIFODMA模式,输出FIFO使能 //配置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,目的地址不变 //握手模式,PCLK同步,传输计数中断,单元传输,单步服务模式,IISSDO, //硬件请求模式,自动重载,半字, rDCON2 = (1<<31)|(0<<30)|(1<<29)|(0<<28)|(0<<27)|(0<<24)|(1<<23)|(0<<22)|(1<<20)|(remainder); rDMASKTRIG2=(0<<2)|(1<<1)|0; //不停止DMA,DMA通道开启,非软件触发 pISR_DMA2 = (U32)PlayDMA2Done; EnableIrq(BIT_DMA2); //启动IIS rIISCON |= 0x1; }
开始播放:
void PlayMusicTest(void) { //配置MPLL //fs=22.05 rMPLLCON = (150<<12) | (5<<4) | 1; //配置L3接口总线,GPB2:L3MODE, GPB3:L3DATA, GPB4:L3CLOCK rGPBCON = 0x015550; //输出 rGPBUP = 0x7ff; //上拉无效 rGPBDAT = 0x1e4; //配置IIS接口 rGPEUP = rGPEUP & ~(0x1f) | 0x1f; //上拉无效,GPE[4:0] 1 1111 rGPECON = rGPECON & ~(0x3ff) | 0x2aa; rSRCPND = (0x1<<19); rSUBSRCPND = 0x1; rINTPND = (0x1<<19); rINTSUBMSK = ~(0x1); rINTMSK = ~(0x1<<19);//开启DMA2中断屏蔽 Uart_Init(33857000,115200);//根据PCLK设置波特率 Uart_Printf("nNOW PLAY THE WindowsXP"); Uart_Printf("nsample=%d",*(U32 *)(WindowsXP_Wav+0x18));//输出采样频率 playsound(WindowsXP_Wav+44,sizeof(WindowsXP_Wav)-44);//在数据开始处开始播放 while(1) { U8 key = Uart_Getch(); if(key == ESC_KEY) break; if(key == 'p') //暂停
{ rIISCON ^= 0x1; } if(key == 'm') { mute ^= 0x4;
mute |= 0x80; WriteL3(0x14 + 0,1); //DATA0 (000101xx+00) WriteL3(mute,0); //10,1,00,x,00:x,静音 } if(key == '+') { if(volume>0) { volume --; WriteL3(0x14 + 0,1); //DATA0 (000101xx+00) WriteL3(volume,0); //音量提高 } } if(key == '-') { if(volume<61) { volume++; WriteL3(0x14 + 0,1); //DATA0 (000101xx+00) WriteL3(volume,0); //音量降低 } } } rIISCON = 0x0; //停止IIS rIISFCON = 0x0; //清IIS的FIFO rDMASKTRIG2=1<<2; //终止DMA2 }