(重慶郵電大學 通信與信息工程學院,重慶 400065)
ThreadX是Express Logic公司專為嵌入式應用而設計的一款高性能的實時操作系統,支持大量的處理器和SoC,也因此廣泛應用于消費電子、汽車電子、工業自動化、軍事及航空航天等領域。其中隨著信息化、智能化的發展,數字音頻技術音頻系統是嵌入式系統應用中的一個重要組成部分。
I2S總線是工業和嵌入式領域常采用的一種音頻總線,其驅動程序的實現主要依賴于音頻總線接口、相應硬件的工作原理以及驅動的體系結構。基于具體的項目需求背景下,本文主要闡述了音頻接口I2S驅動程序設計方法與流程,為I2S總線在ThreadX下的應用提供了一定的研究方法和技術參考。
ThreadX是Express Logic公司專為嵌入式應用而設計的一種高性能實時內核,具有體積小、速度快、高可靠性和實時性等特點,同時擁有高穩定性和低成本。ThreadX占用空間小,適合先進的終端系統級芯片的設計,且憑借其多任務的特性,ThreadX可以滿足應用系統實時性的要求,有助于提高整個系統的穩定性和可靠性。
ThreadX包含了實時操作系統應該具備的所有服務和組件,包括線程、消息隊列、計數信號量、互斥量、事件標志、內存塊池、內存字節池、應用定時器、時鐘計數器和中斷控制。其中,通過圖1介紹了ThreadX的幾個功能模塊:線程管理和調度、同步與通信、內存管理、時鐘和定時器以及中斷處理。

圖1 ThreadX總體架構圖
當系統通電之后,首先是進行系統復位以及開發工具初始化,當初始化完成之后,控制轉移到用戶提供的main主函數上,在主函數中調用tx_kernel_enter進入ThreadX系統內核。入口函數tx_kernel_enter負責調用處理器指定的低級初始化和C語言的高級初始化,配合ThreadX內部不同數據結構的初始化。

圖2 ThreadX啟動流程
當tx_kernel_enter返回時,控制轉移到線程調度循環,同時也標志著初始化的完成。緊接著在入口函數中調用程序定義函數tx_application_define。tx_application_define函數定義了所有初始的應用線程、隊列、消息、事件標志、存儲池和定時器,同時可以在正常的應用程序執行過程中創建或者刪除系統資源,最后會進入調度循環開始線程調度。ThreadX的啟動過程如圖2所示。
基于上文所述,ThreadX啟動并經過初始化之后開始進入tx_application_define(),并根據具體的應用做一些特定的操作。對于音頻系統,在程序定義函數tx_application_define()中首先為codec線程分配堆棧,并通過動態地調用tx_thread_create(&thread_codec,"thread_codec",thread_codec_entry,NULL,pointer,STACK_SIZE*2,6,6,TX_NO_TIME_SLICE, TX_AUTO_START)函數創建codec線程,然后再通過調用入口函數thread_codec_entry()進入I2S音頻系統的操作。
在應用I2S音頻系統初時需先將I2S總線復位到原始狀態,再調用arm_i2s()配置I2S音頻系統。
void thread_codec_entry(ULONG thread_input) {
i2s_reset();
arm_i2s(main_mes);
}
I2S音頻系統的功能是通過I2S總線接口與音頻編解碼芯片進行交互來實現,其中I2S接口負責傳輸音頻數據,音頻編解碼芯片在I2C總線的控制下完成功能配置后負責接收音頻數據并進行編解碼,其具體功能調用實現圖如3所示。由于在實際項目中,ThreadX提供的驅動源代碼中已經包含了I2C接口驅動模塊與CODEC驅動模塊,故本次驅動開發只需對I2S接口驅動模塊進行配置,測試驗證后方可移植到ThreadX系統中。

圖3 ThreadX下的I2S調用模塊
I2S(Inter-IC Sound)總線是一種總線標準,即飛利浦公司為數字音頻設備之間的音頻數據傳輸而制定的。且I2S總線與音頻設備之間進行數據傳輸,廣泛應用于各種多媒體系統。
I2S有3個主要信號:串行時鐘SCLK(continuous serial clock)、幀時鐘 LRCK(word select )、串行數據 SDATA(serial data)。在I2S音頻系統中,產生SCLK和LRCK信號的一方可稱為主設備,I2S總線控制器與音頻芯片均可作為發送端與接收端,且發送端和接收端需要同步時鐘信號來控制數據的傳輸,傳輸模式之一如圖4所示。如果有多個接收端和發送端,就需要一個控制端作為主導裝置來產生SCLK和LRCK的信號。

圖4 I2S數據傳輸模式
(1)幀時鐘LRCK
音頻數據由左右聲道組成,使用幀時鐘選擇可以區分左右聲道,即LRCK為低電平時表示正在傳輸的是左聲道的數據,為高電平時表示正在傳輸的是右聲道的數據。LRCK可以在串行時鐘的上升沿或者下降沿發生改變,且總是在最高位傳輸前的一個時鐘周期發生改變,這樣可以從設備得到與被傳輸的串行數據同步的時間。
(2)串行時鐘SCLK
串行時鐘,即表示每一個時鐘信號傳送一位音頻數據,因此,I2S串行時鐘的頻率計算公式如下:
I2S SCLK的頻率=聲道數×采樣頻率(fs)×采樣位數
其中聲道數通道數為2,即左、右聲道。采樣頻率可為系統主時鐘,并且I2S LRCK的頻率值可等值于采樣頻率。采樣位數可根據寄存器配置數據寬度決定。
由于I2S總線只負責音頻數據的傳輸,而要真正實現音頻數據的錄入和播放,還需要同外接的音頻芯片同步采樣時鐘與采樣位數來處理音頻數據。在I2S總線中,I2S接口端和音頻芯片(CODEC)端分別可以作為主設備,其中只要當某一端作為產生時鐘信號LRCK和SCLK的器件,則就能作為主設備。
(3)串行數據SDATA
串行數據,其用二進制補碼表示音頻數據,在串行時鐘SCLK脈沖下,數據一位一位地傳輸在SDATA線上。當音頻數據被音頻芯片模數轉化器處理成二進制數據流后,將數據分成8位或16位傳輸,且每個字節的數據傳輸從左邊的二進制位MSB(MostSignificantBit)開始。當發送方和接收方的數據寬度不一樣時,發送方不考慮接收方的數據寬度,如果發送方的數據寬度小于系統字段寬度,可以在低位補0;反之超過LSB(Least Significant Bit)的部分被截斷。
基于實際項目,I2S接口模塊集成在芯片中,其目的是為了適應移動音頻設備越來越高的要求,且內置的I2S總線接口也可以方便和其他音頻編解碼芯片配合使用。而實際項目中采用的音頻編解碼芯片為TLV320AIC3106芯片。
TLV320AIC3106是TI公司生產的具有立體聲耳機放大器的低功耗立體聲音頻編解碼器,記錄路徑包含集成的麥克風偏置、數字控制的立體聲麥克風前置放大器和自動增益控制(AGC),內部A/D轉換器和D/A轉換器可用于實現模擬音頻信號的采集和數字音頻信號的模擬輸出。
雖僅支持I2S硬件接口和I2S總線數據格式,但字節長度最高可達到32位,且其還包括高度可編程的PLL,用于靈活的時鐘生成,并支持來自各種可用MCLK(從512 kHz~50 MHz)的所有標準音頻速率,能有效降低使用功耗,可在多種需要進行聲音錄入或輸出的嵌入式媒體設備中進行實際應用。
從實際項目出發,處理器需要通過I2S總線才能完成和音頻芯片之間的數據傳輸。圖5為I2S音頻系統邏輯框圖。
一般而言,處理器與外部芯片進行數據傳輸的方式有兩種:傳統的中斷方式和直接存儲器存取DMA方式。音頻數據的傳輸可以通過設置寄存器先入先出FIFO隊列來完成。若處理器采用中斷的方式往FIFO隊列錄入數據,其不僅很難保證音頻播放的連續性,而且還會因處理器頻繁的響應中斷而導致系統執行效率和性能的降低。為了避免錄入與播放的斷續,且FIFO空間有限,需要將錄入的音頻數據存儲到其他內存緩沖區內,錄入數據與播放數據可存放在不同的內存緩沖中,但需要快速切換使用的緩存空間,所以根據實際項目的需求,在為音頻系統開發I2S總線接口驅動過程中,設計采用DMA方式進行音頻數據傳輸。
音頻系統最終是為了實現錄音與播音的異時或同時處理效果。項目的系統DMA支持8個通道,為了實現音頻數據全雙工傳輸,開發過程中采用兩個DMA通道,通過設置使能I2S接口控制器中的寄存器I2S_TX_DMA_DISABLE和I2S_RX_DMA_DISABLE來使I2S接口與處理器之間音頻數據傳輸工作在DMA模式下。
此模式下使用I2S接口的FIFO寄存器組I2S_TX_DMA_FIFO_INPUT_DATA、I2S_TX_DMA_FIFO_STATUS、I2S_RX_DMA_OUTPUT_DATA和I2S_RX_FIFO_STATUS來存放音頻數據,設置FIFO的狀態來觸發DMA控制器,將數據與內存區域之間進行傳輸,最終以實現錄音和播音。

圖5 I2S音頻系統邏輯框圖
如圖5所示,在音頻數據傳輸過程中使用了兩個DMA通道以實現全雙工工作方式。當錄制聲音時則先由音頻芯片采集音頻數據,然后由音頻數據傳輸專用總線將數據發送到I2S總線控制器的rx_fifo中,最后由內部總線將采集到的音頻數據通過DMA使用其中1個DMA通道搬送,寫入到內存緩沖區中。
當播放聲音時,首先將音頻數據通過另一個DMA通道經由DMA控制器將音頻數據寫入I2S總線控制器的tx_fifo中,最后由音頻數據傳輸專用總線傳送到音頻芯片中進行播放。

圖6 全雙工模式(TX+RX)
音頻系統中I2S接口需經過正確的配置方可實現錄音和播音等功能。本文主要是根據實際項目的需求來設計一組固定的I2S音頻接口驅動程序,控制音頻數據在硬件中流動,以實現音頻數據的正確接收和發送。設計的音頻系統采樣規格是系統主時鐘為44.1 kHz,采樣位數為16位。
基于實際項目需求來實現音頻系統的全雙工模式,主要是對I2S總線的寄存器進行設置。其工作流程如圖6所示。
而具體開發I2S音頻接口驅動程序完成的工作有:
(1)配置音頻錄入RX_ONLY模式與音頻播放TX_ONLY模式
音頻數據的錄入和播放都必須先配置好I2S_tx與I2S_rx的相關參數,如音頻數據的采樣率與采樣位數等。若要實現音頻數據的播放,則調用開發函數I2S_tx_master()將I2S總線初始化為發送模式;若要實現音頻數據的錄入,則調用開發函數I2S_rx_master()將I2S總線初始化為發送模式。根據實際項目需求,將I2S接口的數據發送和接收模式分別通過寄存器I2S_TX_WORK_MODE和I2S_RX_SLAVE_EN設置為Master模式,并對發送和接收Master模式下的高低占空比、串行位時鐘占空比進行配置,然后再依次分別對I2S接口與音頻芯片之間的數據接收與發送進行配置,如采樣寬度、音頻芯片接口模式以及音量調節等參數。部分代碼如下:
voidI2S_tx_master(){
REG32(I2S_TX_WORK_MODE) = 0;//設置I2S傳輸方式:主設備
REG32(I2S_TX_SRC_INFO) = ((0x0<<5) |(0x10<<0));//傳輸數據格式與寬度:立體聲,16位
REG32(I2S_SRC_SR_CYCLE) = 0x177;//外部編解碼器采樣時鐘占空比: 32KFS
REG32(I2S_TX_BCLK_DUTY_CYCLE) = 0x5;
//傳輸串行位時鐘占空比:32KFS
REG32(I2S_TX_BAL) = ((1<<4) |(1<<0));
//平衡音量控制
REG32(I2S_TX_VLD_DW) = 0x10;
//傳輸到編解碼器的有效數據寬度:16位
REG32(I2S_TX_TYPE) = ((1<<5)|(0<<4) |(0<<0));//傳輸類型為I2S標準模式
REG32(I2S_TX_CLK_PHASE) = ((0<<4) |(0<<0));//傳輸LRCK相位設置和傳輸位串行相位設置
REG32(I2S_TX_ANTI_POP_LENTH) = 0x8;
REG32(I2S_TX_VOL) = 0x1;//主音量控制
觀察組患者的LVEDD為(56.34±4.78)mm,LVESD為(41.01±6.67)mm,LVEF為(52.43±5.32)%,血清BNP(309.77±104.44)pg/mL,6MWT為(389.32±70.32)m;對照組的LVEDD為(58.54±3.98)mm,LVESD為(46.32±4.01)mm,LVEF為(45.78±4.78)%,血清BNP(695.33±321.34)pg/mL,6MWT為(312.45±72.12)m,組間比較,差異有統計學意義(P<0.05)。
}
(2)全雙工模式配置模塊
通過調用開發函數I2S_loop_back_set()來設置I2S_LOOP_BACK_ENABLE的第0位為0,即以REG32(I2S_LOOP_BACK_ENABLE) &= ~0x1,將I2S總線初始化為全雙工模式。寄存器I2S_LOOP_BACK_ENABLE具體信息如下所示:

I2S_LOOP_BACK_ENABLEWidthBitDefaultDescription1[0]0TX-->RXLoopdebugcontrol:0:disable1:enable,internallyconnectTXSDTOtoRXSDTI
(3)DMA配置模塊
為實現音頻數據在CPU與外部芯片之間的存儲與播放,需進行DMA通道DMA_CHn(0≤n≤7)配置,其中DMA_CH0作為將數據從內存緩沖區傳送到I2S接口控制器的tx_fifo中的通道,調用i2s_dma_tx_configure()實現;DMA_CH1作為將音頻設備傳送過來的音頻數據從I2S接口控制器的rx_fifo傳送到內存緩沖去中的通道,調用i2s_dma_rx_configure()實現。DMA功能的實現主要是配置各通道的源地址(DMAC_CHn_BASE + DMAC_SAR)與目的地址(DMAC_CH0_BASE + DMAC_DAR),配置完DMA_CH0與DMA_CH1之后再通過配置寄存器DMAC_DMACFGREG和DMAC_CHENREG使能DMA傳輸功能。部分代碼如下:
//配置DMA_CH0
REG32(DMAMAC_BASE_ADDR+DMAC_CH0_BASE + DMAC_SAR) =0xc0000000;//設置源地址 REG32(DMAMAC_BASE_ADDR+DMAC_CH0_BASE+DMAC_DAR)=I2S_TX_DMA_FIFO_INPUT_DATA ;//設置目的地址
REG32(DMAMAC_BASE_ADDR + DMAC_CH0_BASE + DMAC_DSTATAR) = I2S_TX_DMA_FIFO_STATUS;
REG32(DMAMAC_BASE_ADDR + DMAC_CH0_BASE + DMAC_CTL) = 0x00109125;
REG32(DMAMAC_BASE_ADDR + DMAC_CH0_BASE + DMAC_CTL + 4) = 0x00000380;
……
//使能DMA_CH0
REG32(DMAMAC_BASE_ADDR + DMAC_DMACFGREG) =0x00000001;
REG32(DMAMAC_BASE_ADDR + DMAC_CHENREG) = 0x00000101; REG32(DMAMAC_BASE_ADDR + DMAC_MASKTFR) = 0x0101; REG32(DMAMAC_BASE_ADDR + DMAC_MASKBLOCK) = 0x0101;while(REG32(I2S_TX_DMA_FIFO_STATUS) & 0x4);
綜上所述,完成I2S全雙工模式相關配置后,則需要對驅動程序進行測試。首先將I2S接口驅動程序置于Makefile工程環境中進行編譯,編譯通過,然后再將其進行ASIC仿真測試。全雙工模式下的音頻錄入測試結果與播放測試結果分析如下。
音頻錄入測試:圖7為音頻芯片采樣第一個數據的波形圖,根據ws_in對應的波形圖,來讀取sdi對應的波形圖可得采樣的第一個數據,其左聲道數據為“b510”,其右聲道數據為“bd10”,再觀察圖8中rx_fifo_din對應的紫色光標處得知rx_fifo中存儲的第一個數據為“32’hbd10_b510”,此表明了音頻錄入數據無誤。

圖7 音頻芯片采樣數據波形圖

圖8 I2S總線rx_fifo數據圖
音頻播放測試:同理如上。圖9中tx_fifo_dout對應的數據是通過DMA從內存緩沖區搬到tx_fifo中的數據,其值為“bd1f_b51f”。再觀察圖10中ws_out對應的波形
圖來讀取sdo對應的波形圖的數據,其左聲道數據為“b51f”,其右聲道數據為“bd1f”,繼而表明了音頻播放數據無誤。

圖9 I2S總線tx_fifo數據圖

圖10 音頻芯片采樣數據波形圖
綜上測試結果分析可得,本文設計的I2S接口驅動程序能實現CPU與外部芯片之間音頻數據的正確錄入與播放,可移植到ThreadX系統中并與外接芯片完成音頻數據的格式轉換,最終實現錄音與播音功能。

[1] 潘應進,朱子元. 基于ThreadX實時操作系統的USB設備驅動開發[J]. 工業控制計算機,2016,29(2):30-32.
[2] 宋鑫夢,郭改枝,王秀麗. 基于嵌入式的I2S音頻系統設計與實現[J]. 內蒙古師范大學學報:自然科學漢文版,2015,44(2):245-248.
[3] 霍燃,高麗萍,陳慶奎. 嵌入式Linux系統下基于UDA1341芯片的音頻驅動程序設計[J]. 計算機應用與軟件,2012,29(4):16-19.
[4] 李文正. 基于I2S總線的嵌入式音頻系統的設計[J]. 軟件,2010,31(12):55-60.
[5] 趙鵬. 嵌入式Linux音頻驅動及簡單播放器的設計與實現[D].長春:吉林大學,2009.
[6] 丁德紅,劉亞波. 嵌入式系統中的I2S音頻接口技術[J]. 單片機與嵌入式系統應用,2009(2):25-28.
[7] 房國志,馬傳龍. Linux中I2S總線聲卡驅動的研究[J]. 科技創新導報,2009(2):5-7.
[8] 莊海軍. 基于S3C2410的I2S音頻總線研究及其驅動實現[J]. 淮陰工學院學報,2008,17(5):72-76.
劉伍洋(研究生),主要研究內容為嵌入式底層軟件開發。