色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

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

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

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

          本文引用地址:http://cafeforensic.com/article/201611/318458.htm

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

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

          程序中我們通過I2S發(fā)送一段音頻數據,該數據是我從WAV格式的文件中去掉WAV頭格式后得到的一個純音頻數據數組。該WAV音頻為16位雙通道 采樣頻率為44.1KHZ。LPC1788將該數組發(fā)送到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位,立體音,禁止發(fā)送
          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產生穩(wěn)定的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)//如果發(fā)送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))//數組中的數據發(fā)送完
          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總線每次發(fā)送的數據為1個字節(jié),而UDA1380的寄存器為16為,因此我們先發(fā)送高字節(jié)然后再發(fā)送低字節(jié),具體的時序可以參考UDA1380的數據手冊。

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

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


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

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




          評論


          相關推薦

          技術專區(qū)

          關閉