新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > Cortex-M3 (NXP LPC1788)之IIS應用--UDA1380進行音頻數據播放

        Cortex-M3 (NXP LPC1788)之IIS應用--UDA1380進行音頻數據播放

        作者: 時間:2016-11-19 來源:網絡 收藏
        LPC1788發送到I2S總線上的音頻數據要通過音頻解碼芯片才能輸出模擬音頻信號。開發板上使用的是UDA1380,對它的寄存器的配置可以通過L3總線或者I2C總線進行,這里使用I2C總線進行控制,對于I2C總線的操作可以參考之前I2C的介紹。UDA1380的寄存器主要分成3類,系統控制、插值濾波(interpolation filter)、抽取濾波(decimator filter)。插值濾波和DAC轉換有關,用于控制控制聲音的輸出參數。抽取濾波和ADC有關,用于控制對音頻的采樣。寄存器的地址和功能如圖1所示。

        本文引用地址:http://www.104case.com/article/201611/318458.htm

        圖1:UDA1380寄存器地址和功能

        根據圖1的紅色標記中的內容,可以知道兩個濾波器的正常使用需要一個128fs的clock,這個時鐘可以通過SYSCLK引腳或者WSI的信號獲得。在硬件連接上,通過將LPC1788的MCLK輸出的時鐘,連接到UDA1380的SYSCLK引腳。因此,我們需要配置I2S的發送模式控制寄存器I2STXMODE,使能TX_REF在MCLK輸出,使UDA1380內部產生一個濾波器需要的時鐘。

        程序中我們通過I2S發送一段音頻數據,該數據是我從WAV格式的文件中去掉WAV頭格式后得到的一個純音頻數據數組。該WAV音頻為16位雙通道 采樣頻率為44.1KHZ。LPC1788將該數組發送到I2S總線,UDA1380讀取該數據進行聲音的輸出。程序如下

        1. #include"i2c.h"
        2. #include"audio.h"
        3. #definerI2SDAO(*(volatileunsigned*)(0x400A8000))
        4. #definerI2STXFIFO(*(volatileunsigned*)(0x400A8008))
        5. #definerI2STXRATE(*(volatileunsigned*)(0x400A8020))
        6. #definerI2STXBITRATE(*(volatileunsigned*)(0x400A8028))
        7. #definerI2STXMODE(*(volatileunsigned*)(0x400A8030))
        8. #definerI2SDMA1(*(volatileunsigned*)(0x400A8014))
        9. #definerI2SDMA2(*(volatileunsigned*)(0x400A8018))
        10. #definerI2SSTATE(*(volatileunsigned*)(0x400A8010))
        11. #definerI2SIRQ(*(volatileunsigned*)(0x400A801C))
        12. #definerI2SDAI(*(volatileunsigned*)(0x400A8004))
        13. #definerI2SRXFIFO(*(volatileunsigned*)(0x400A800C))
        14. #definerI2SRXRATE(*(volatileunsigned*)(0x400A8024))
        15. #definerI2SRXBITRATE(*(volatileunsigned*)(0x400A802C))
        16. #definerI2SRXMODE(*(volatileunsigned*)(0x400A8034))
        17. #definerIOCON_P0_07(*(volatileunsigned*)(0x4002C01C))
        18. #definerIOCON_P0_08(*(volatileunsigned*)(0x4002C020))
        19. #definerIOCON_P0_09(*(volatileunsigned*)(0x4002C024))
        20. #definerIOCON_P1_16(*(volatileunsigned*)(0x4002C0C0))
        21. #defineUDA1380_ADDRESS0x1A
        22. voidUda1380_WriteData(unsignedcharreg,unsignedshortintdata)
        23. {
        24. unsignedcharconfig[3];
        25. config[0]=reg;
        26. config[1]=(data>>8)&0xFF;//MS
        27. config[2]=data&0xFF;//LS
        28. I2C0_MasterTransfer(UDA1380_ADDRESS,config,sizeof(config),0,0);
        29. I2C0_MasterTransfer(UDA1380_ADDRESS,config,1,&config[1],2);//校驗寫入的數據是否正確
        30. if((config[1]<<8|config[2])!=data)
        31. {
        32. while(1);//寫入和讀出的數據不一致
        33. }
        34. }
        35. voidUda1380_config()
        36. {
        37. I2C0_Init();
        38. Uda1380_WriteData(0x7F,0x0);//restoreL3-defaultvalues
        39. Uda1380_WriteData(0x01,0x0);//數據格式為標準的I2S格式
        40. Uda1380_WriteData(0x13,0x0);//配置音頻的輸出
        41. Uda1380_WriteData(0x14,0x0);
        42. Uda1380_WriteData(0x00,0x2|0x1<<8|0x1<<9);//使能DAC的時鐘,選擇使用SYSCLK產生128fs的時鐘
        43. Uda1380_WriteData(0x02,0x1<<15|0x1<<13|0x1<<10|0x1<<8);//使能DAC電源
        44. }
        45. intmain(void)
        46. {
        47. unsignedintcount=0,i;
        48. unsignedcharflag=1;
        49. rIOCON_P0_07=(rIOCON_P0_07&(~0x3))|0x1;//I2S_TX_SCK
        50. rIOCON_P0_08=(rIOCON_P0_08&(~0x3))|0x1;//I2S_TX_WS
        51. rIOCON_P0_09=(rIOCON_P0_09&(~0x3))|0x1;//I2S_TX_SDA
        52. rIOCON_P1_16=(rIOCON_P1_16&(~0x3))|0x2;//I2SMCLK
        53. rPCONP|=0x1<<27;
        54. rI2SDAO=(16-1)<<6|0x1<<4|0x1<<3|0x1;//16位,立體音,禁止發送
        55. rI2STXMODE|=0x1<<3;//使能MCLK輸出,使TX_REF輸出到UDA1380的SYSCLK引腳
        56. rI2STXRATE=0x1<<8|0x1;//配置分數速率寄存器得到TX_REF=CCLK/(1/1)/2
        57. rI2STXBITRATE=CCLK/2/(44100*2*16)-1;//44.1KHZ采樣16位
        58. for(i=0;i<0x1000000;i++);//延時等待UDA1380內部通過SYSCLK產生穩定的128fs提供插值濾波和抽取濾波使用
        59. Uda1380_config();
        60. rI2SDAO&=~(1<<4);
        61. rI2SDAO&=~(1<<3);
        62. rI2SDAO&=~(1<<15);//啟動I2S數據傳輸
        63. while(flag)
        64. {
        65. if(((rI2SSTATE>>16)&0xFF)<=4)//如果發送FIFO中的數據小于或等于4個字
        66. {
        67. for(i=0;i<8-(((rI2SSTATE>>16)&0xFF));i++)//將FIFO填充到8個字
        68. {
        69. rI2STXFIFO=*(unsignedint*)(audio+count);//轉換成int類型的指針,從指針指向的位置讀取32位數據
        70. count+=4;//讀取一個字,相當于讀取char類型數組中的4個元素
        71. if(count>=sizeof(audio))//數組中的數據發送完
        72. {
        73. flag=0;
        74. break;
        75. }
        76. }
        77. }
        78. }
        79. rI2SDAO|=0x1<<3|0x1<<4;//停止I2S傳輸
        80. return0;
        81. }
        下面對程序需要注意的做下說明:

        1,i2c.h中是上一篇介紹I2C總線中所用的函數,aduio.h中存放的是音頻數據的數組,const unsigned char audio[]={0,0,0,0,0,......................

        2,I2C總線每次發送的數據為1個字節,而UDA1380的寄存器為16為,因此我們先發送高字節然后再發送低字節,具體的時序可以參考UDA1380的數據手冊。

        3,程序中配置發送控制寄存器I2STXMODE使能了MCLK輸出TX_REF的時鐘到UDA1380的SYSCLK引腳,而UDA1380中配置成使用該時鐘產生內部濾波器需要的128fs的時鐘。在圖1中標志中說明run at ....因此在程序中配置UDA1380之前,使用了一個for延時,用于等待UDA1380內部產生穩定的128fs時鐘。只有這樣才能正確的配置0x10之后的濾波器相關寄存器。否則對0x10之后的濾波器相關寄存器操作會失敗。這點沒有驗證,但是在debug調試的時候可以正常的有聲音輸出,但是下載到板子上運行,則沒有效果。如果去掉for循環延時效果也不正常發音。如果不使能MCLK輸出,則寫0x13寄存器的值不會成功,讀取該寄存器的值永遠都是其默認值。因此推測和UDA1380的SYSCLK產生內部濾波器使用的128fs時鐘有關。

        參考了linux內核里面的uda1380的驅動,其中也提到了配置0x10以后的濾波器相關寄存器要滿足條件


        1. 107/*theinterpolator&decimatorregsmustonlybewrittenwhenthe
        2. 108*codecDAIisactive.
        3. 109*/

        誰有這方面的經驗,希望多指教!




        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 拜城县| 珲春市| 宁晋县| 甘肃省| 张北县| 内丘县| 建始县| 安新县| 吉隆县| 芮城县| 蒙自县| 通化县| 临朐县| 咸宁市| 钟山县| 韩城市| 湾仔区| 青田县| 商城县| 什邡市| 红河县| 通海县| 成武县| 罗山县| 于都县| 台安县| 新平| 台东县| 都匀市| 平阳县| 班玛县| 招远市| 沧州市| 西宁市| 胶州市| 蓬溪县| 新竹市| 固安县| 绍兴县| 德阳市| 陆良县|