新聞中心

s3c2440的DMA應(yīng)用

作者: 時(shí)間:2016-11-19 來源:網(wǎng)絡(luò) 收藏
DMA(Direct Memory Access,直接內(nèi)存訪問)是一種不經(jīng)過CPU而直接從內(nèi)存存取數(shù)據(jù)的數(shù)據(jù)交換模式。在需要進(jìn)行大量數(shù)據(jù)交換的場合,用好DMA,可以大大提高系統(tǒng)的性能,因?yàn)镈MA操作幾乎不占用CPU資源。

s3c2440提供了4個(gè)通道的DMA,它們不僅可以實(shí)現(xiàn)內(nèi)存之間的數(shù)據(jù)交換,還可以實(shí)現(xiàn)內(nèi)存與外設(shè),以及外設(shè)與外設(shè)之間的數(shù)據(jù)交換。要用好s3c2440的DMA,關(guān)鍵是配置好它的源、目的寄存器,和必要的控制寄存器。寄存器DISRCn是初始DMA源寄存器,它是用于設(shè)置DMA數(shù)據(jù)傳輸?shù)脑椿?,而寄存器DIDSTn是初始DMA目的寄存器,它是用于設(shè)置DMA數(shù)據(jù)傳輸?shù)哪康幕?。初始DMA源控制寄存器DISRCCn的第1位用于選擇源的總線(系統(tǒng)總線AHB還是外設(shè)總線APB),第0位用于設(shè)置源基址在數(shù)據(jù)傳輸過程中是遞增還是固定不變。初始DMA目的控制寄存器DIDSTCn的低兩位與寄存器DISRCCn相識,但它是用來設(shè)置目的基址,而第2位用于設(shè)置是在傳輸完數(shù)據(jù)之后中斷還是在自動重載后中斷。DMA控制寄存器DCONn用于控制數(shù)據(jù)的DMA傳輸,第31位用于設(shè)置傳輸協(xié)議是需求模式還是握手模式,第30位用于選擇同步時(shí)鐘是PCLK還是HCLK,第29位用于設(shè)置DMA中斷是否發(fā)生,第28位用于選擇傳輸大小是單元傳輸還是突發(fā)傳輸,第27位用于選擇服務(wù)模式是單步模式還是完全模式,第24位到第26位用于設(shè)置DMA的請求源,第23位用于設(shè)置DMA的源是軟件還是硬件,第22位用于設(shè)置是否需要重載傳輸?shù)哪康暮驮椿?,?0位和第21位用于設(shè)置數(shù)據(jù)傳輸?shù)臄?shù)據(jù)大?。ㄗ止?jié)、半字還是字),低20位用于初始化傳輸數(shù)據(jù)的個(gè)數(shù)。而通過讀取DMA狀態(tài)寄存器DSTATn的低20位可以獲知當(dāng)前的傳輸?shù)挠?jì)數(shù)。DMA掩碼觸發(fā)寄存器DMASKTRIGn的第2位可以終止當(dāng)前DMA操作,第1位可以用于開啟DMA通道,第0位則表示在軟件請求模式下觸發(fā)DMA通道。

下面我們就用DMA的方式來實(shí)現(xiàn)音頻的播放。由于是用DMA的方式,因此在播放的過程中不占用系統(tǒng)資源,我們可以很容易的實(shí)現(xiàn)聲音的各種操作而絲毫不影響播放的效果,如音量的提高和降低、靜音、暫停等。在這里,還需要強(qiáng)調(diào)一點(diǎn),利用DMA傳輸數(shù)據(jù),一次最多可以傳輸?shù)淖止?jié)大小為:DSZ×TSZ×TC,DSZ表示的是數(shù)據(jù)大?。ㄗ止?jié)、半字還是字,即是1、2還是4),TSZ表示的是傳輸大小(單元傳輸還是突發(fā)傳輸,即1還是4),TC表示傳輸計(jì)數(shù)值(即寄存器DCONn的低20位存放的數(shù)據(jù)),因此如果需要傳輸?shù)淖止?jié)大小超出了這三個(gè)參數(shù)乘積的大小,則還要進(jìn)一步處理,在我們給出的程序中,我們就考慮了這方面的問題。下面就是具體的程序,其中我們是利用UART來實(shí)現(xiàn)音頻信號的播出、停止、暫停、靜音、音量的提高和降低的。


…………
//一段純音頻數(shù)據(jù)數(shù)組
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)
{
//用于計(jì)算音頻數(shù)據(jù)的長度是否超過DMA所能傳輸?shù)淖止?jié)數(shù)范圍
//這里音頻數(shù)據(jù)的通道位數(shù)為16位,因此需要length除以2
remainder = (length>>1) & 0xfffff;//余數(shù)
result = (length>>1) / 0x100000;//商

play_state = 1;//置播放標(biāo)志

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

//配置1341,詳細(xì)講解請看上一篇文章
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);//發(fā)送IIS的DMA使能
rIISMOD= (0<<9)|(0<<8)|(2<<6)|(0<<5)|(0<<4)|(1<<3)|(1<<2)|(1<<0);
rIISFCON = (1<<15)|(1<<13); //發(fā)送FIFO為DMA

//配置DMA
rDISRC2 = (U32)buffer;//DMA的源基址為音頻數(shù)據(jù)數(shù)組的首地址
rDISRCC2 = (0<<1)|(0<<0);//AHB,源地址遞增
rDIDST2 = (U32)IISFIFO;//DMA的目的基址為IIS的FIFO
rDIDSTC2 = (0<<2)| (1<<1)|(1<<0);//當(dāng)傳輸計(jì)數(shù)值為0時(shí)中斷,APB,目的地址不變
if (result == 0)//所傳輸?shù)淖止?jié)數(shù)沒有超出DMA的最大傳輸范圍
{
flag = 0;//清標(biāo)志,表示沒有超出范圍,進(jìn)入DMA中斷后結(jié)束DMA操作
//握手模式,PCLK同步,傳輸計(jì)數(shù)中斷,單元傳輸,單步服務(wù)模式,IISSDO,
//硬件請求模式,非自動重載,半字,
rDCON2 = (1<<31) | (0<<30) | (1<<29) | (0<<28) | (0<<27) | (0<<24) | (1<<23) | (1<<22) | (1<<20) | (remainder);

}
else//所傳輸?shù)淖止?jié)數(shù)超出了DMA的最大傳輸范圍
{
flag = 1;//置標(biāo)志,表示超出范圍
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通道開啟,非軟件觸發(fā)

//啟動IIS
rIISCON |= 0x1;
}


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

if (flag == 0)//DMA傳輸完畢
{
rIISCON = 0x0;//關(guān)閉IIS
rIISFCON = 0x0;//清IIS的FIFO
rDMASKTRIG2=1<<2;//停止DMA
play_state = 0;//清播放標(biāo)志
}
else//DMA沒有傳輸完畢,繼續(xù)傳輸
{
result --;//商遞減
rDISRC2 += 0x200000;//DMA源基址遞增。因?yàn)閭鬏數(shù)臄?shù)據(jù)是半字,所以這里遞增0x200000
if (result == 0 )//只剩下余數(shù)部分需要傳輸
{
rDCON2=(rDCON2&(~0xfffff))|(remainder);//需要重新設(shè)置傳輸計(jì)數(shù)值
flag=0;//清標(biāo)志
}
rDMASKTRIG2=(0<<2)|(1<<1)|0;//需要重新設(shè)置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;
}
}
}


關(guān)鍵詞: s3c2440DMA應(yīng)

評論


技術(shù)專區(qū)

關(guān)閉