Cortex-M3 (NXP LPC1788)之IIS應(yīng)用--UDA1380進(jìn)行音頻數(shù)據(jù)播放
圖1:UDA1380寄存器地址和功能
根據(jù)圖1的紅色標(biāo)記中的內(nèi)容,可以知道兩個濾波器的正常使用需要一個128fs的clock,這個時鐘可以通過SYSCLK引腳或者WSI的信號獲得。在硬件連接上,通過將LPC1788的MCLK輸出的時鐘,連接到UDA1380的SYSCLK引腳。因此,我們需要配置I2S的發(fā)送模式控制寄存器I2STXMODE,使能TX_REF在MCLK輸出,使UDA1380內(nèi)部產(chǎn)生一個濾波器需要的時鐘。
程序中我們通過I2S發(fā)送一段音頻數(shù)據(jù),該數(shù)據(jù)是我從WAV格式的文件中去掉WAV頭格式后得到的一個純音頻數(shù)據(jù)數(shù)組。該WAV音頻為16位雙通道 采樣頻率為44.1KHZ。LPC1788將該數(shù)組發(fā)送到I2S總線,UDA1380讀取該數(shù)據(jù)進(jìn)行聲音的輸出。程序如下
- #include"i2c.h"
- #include"audio.h"
- #definerI2SDAO(*(volatileunsigned*)(0x400A8000))
- #definerI2STXFIFO(*(volatileunsigned*)(0x400A8008))
- #definerI2STXRATE(*(volatileunsigned*)(0x400A8020))
- #definerI2STXBITRATE(*(volatileunsigned*)(0x400A8028))
- #definerI2STXMODE(*(volatileunsigned*)(0x400A8030))
- #definerI2SDMA1(*(volatileunsigned*)(0x400A8014))
- #definerI2SDMA2(*(volatileunsigned*)(0x400A8018))
- #definerI2SSTATE(*(volatileunsigned*)(0x400A8010))
- #definerI2SIRQ(*(volatileunsigned*)(0x400A801C))
- #definerI2SDAI(*(volatileunsigned*)(0x400A8004))
- #definerI2SRXFIFO(*(volatileunsigned*)(0x400A800C))
- #definerI2SRXRATE(*(volatileunsigned*)(0x400A8024))
- #definerI2SRXBITRATE(*(volatileunsigned*)(0x400A802C))
- #definerI2SRXMODE(*(volatileunsigned*)(0x400A8034))
- #definerIOCON_P0_07(*(volatileunsigned*)(0x4002C01C))
- #definerIOCON_P0_08(*(volatileunsigned*)(0x4002C020))
- #definerIOCON_P0_09(*(volatileunsigned*)(0x4002C024))
- #definerIOCON_P1_16(*(volatileunsigned*)(0x4002C0C0))
- #defineUDA1380_ADDRESS0x1A
- voidUda1380_WriteData(unsignedcharreg,unsignedshortintdata)
- {
- unsignedcharconfig[3];
- config[0]=reg;
- config[1]=(data>>8)&0xFF;//MS
- config[2]=data&0xFF;//LS
- I2C0_MasterTransfer(UDA1380_ADDRESS,config,sizeof(config),0,0);
- I2C0_MasterTransfer(UDA1380_ADDRESS,config,1,&config[1],2);//校驗寫入的數(shù)據(jù)是否正確
- if((config[1]<<8|config[2])!=data)
- {
- while(1);//寫入和讀出的數(shù)據(jù)不一致
- }
- }
- voidUda1380_config()
- {
- I2C0_Init();
- Uda1380_WriteData(0x7F,0x0);//restoreL3-defaultvalues
- Uda1380_WriteData(0x01,0x0);//數(shù)據(jù)格式為標(biāo)準(zhǔn)的I2S格式
- Uda1380_WriteData(0x13,0x0);//配置音頻的輸出
- Uda1380_WriteData(0x14,0x0);
- Uda1380_WriteData(0x00,0x2|0x1<<8|0x1<<9);//使能DAC的時鐘,選擇使用SYSCLK產(chǎn)生128fs的時鐘
- Uda1380_WriteData(0x02,0x1<<15|0x1<<13|0x1<<10|0x1<<8);//使能DAC電源
- }
- intmain(void)
- {
- unsignedintcount=0,i;
- unsignedcharflag=1;
- rIOCON_P0_07=(rIOCON_P0_07&(~0x3))|0x1;//I2S_TX_SCK
- rIOCON_P0_08=(rIOCON_P0_08&(~0x3))|0x1;//I2S_TX_WS
- rIOCON_P0_09=(rIOCON_P0_09&(~0x3))|0x1;//I2S_TX_SDA
- rIOCON_P1_16=(rIOCON_P1_16&(~0x3))|0x2;//I2SMCLK
- rPCONP|=0x1<<27;
- rI2SDAO=(16-1)<<6|0x1<<4|0x1<<3|0x1;//16位,立體音,禁止發(fā)送
- rI2STXMODE|=0x1<<3;//使能MCLK輸出,使TX_REF輸出到UDA1380的SYSCLK引腳
- rI2STXRATE=0x1<<8|0x1;//配置分?jǐn)?shù)速率寄存器得到TX_REF=CCLK/(1/1)/2
- rI2STXBITRATE=CCLK/2/(44100*2*16)-1;//44.1KHZ采樣16位
- for(i=0;i<0x1000000;i++);//延時等待UDA1380內(nèi)部通過SYSCLK產(chǎn)生穩(wěn)定的128fs提供插值濾波和抽取濾波使用
- Uda1380_config();
- rI2SDAO&=~(1<<4);
- rI2SDAO&=~(1<<3);
- rI2SDAO&=~(1<<15);//啟動I2S數(shù)據(jù)傳輸
- while(flag)
- {
- if(((rI2SSTATE>>16)&0xFF)<=4)//如果發(fā)送FIFO中的數(shù)據(jù)小于或等于4個字
- {
- for(i=0;i<8-(((rI2SSTATE>>16)&0xFF));i++)//將FIFO填充到8個字
- {
- rI2STXFIFO=*(unsignedint*)(audio+count);//轉(zhuǎn)換成int類型的指針,從指針指向的位置讀取32位數(shù)據(jù)
- count+=4;//讀取一個字,相當(dāng)于讀取char類型數(shù)組中的4個元素
- if(count>=sizeof(audio))//數(shù)組中的數(shù)據(jù)發(fā)送完
- {
- flag=0;
- break;
- }
- }
- }
- }
- rI2SDAO|=0x1<<3|0x1<<4;//停止I2S傳輸
- return0;
- }
1,i2c.h中是上一篇介紹I2C總線中所用的函數(shù),aduio.h中存放的是音頻數(shù)據(jù)的數(shù)組,const unsigned char audio[]={0,0,0,0,0,......................
2,I2C總線每次發(fā)送的數(shù)據(jù)為1個字節(jié),而UDA1380的寄存器為16為,因此我們先發(fā)送高字節(jié)然后再發(fā)送低字節(jié),具體的時序可以參考UDA1380的數(shù)據(jù)手冊。
3,程序中配置發(fā)送控制寄存器I2STXMODE使能了MCLK輸出TX_REF的時鐘到UDA1380的SYSCLK引腳,而UDA1380中配置成使用該時鐘產(chǎn)生內(nèi)部濾波器需要的128fs的時鐘。在圖1中標(biāo)志中說明run at ....因此在程序中配置UDA1380之前,使用了一個for延時,用于等待UDA1380內(nèi)部產(chǎn)生穩(wěn)定的128fs時鐘。只有這樣才能正確的配置0x10之后的濾波器相關(guān)寄存器。否則對0x10之后的濾波器相關(guān)寄存器操作會失敗。這點沒有驗證,但是在debug調(diào)試的時候可以正常的有聲音輸出,但是下載到板子上運行,則沒有效果。如果去掉for循環(huán)延時效果也不正常發(fā)音。如果不使能MCLK輸出,則寫0x13寄存器的值不會成功,讀取該寄存器的值永遠(yuǎn)都是其默認(rèn)值。因此推測和UDA1380的SYSCLK產(chǎn)生內(nèi)部濾波器使用的128fs時鐘有關(guān)。
參考了linux內(nèi)核里面的uda1380的驅(qū)動,其中也提到了配置0x10以后的濾波器相關(guān)寄存器要滿足條件
- 107/*theinterpolator&decimatorregsmustonlybewrittenwhenthe
- 108*codecDAIisactive.
- 109*/
誰有這方面的經(jīng)驗,希望多指教!
評論