IIS總線設計

I2S是數字音頻的接口,這裏不用多說,請讀者自己查閱相關資料。

本文中要設計的是FPGA與數字音頻芯片的I2S接口時序。簡單點說,就是通過FPGA向音頻芯片寫數據,通過的是I2S總線,因爲這個總線比較麻煩,我在這裏做成接口模塊,其它模塊直接拿來用就可以了。

 

提示,I2S總線的接口信號如下:

1、LRCLK:左右聲道控制,高電平時,SDATA上爲左聲道數據,低電平時,SDATA上爲右聲道數據。(也有相反的情況,請參考不同的音頻芯片的手冊)

2、BCLK:跟SDATA上數據對應的時鐘,上升沿採數據,也可能在下降沿採數據,請注意對應音頻芯片手冊上的說明。

3、SDATA:串行數據,一個BCLK對應一個。

 

時序圖如下,WS就是LRCLK,BCLK就是SCK。

image

 

一、設計思路,數據流向,如下:

 

image

 

 

二、分析

左聲道和右聲道的數據,分別設計成兩個FIFO即可。重點在於如何將兩路數據拼裝到一起,再轉換成串行的數據。

 

三、設計

 

1、LRCLK和BCLK的產生

提示,如果數字音頻的數據是16位的,那麼BCLK就是LRCLK的16倍。即在一個LRCLK中,有32個BCLK,16個左聲道數據,16個右聲道數據。同樣,如果數據是12位的,那麼BCLK就是LRCLK的24倍。

verilog代碼如下:

// LRCLK & BCLK Generate

reg [7:0] lrclk_cnt = 0; 
reg [2:0] bclk_cnt = 0;

always@(posedge clk) begin

    lrclk_cnt <= lrclk_cnt + 1; 
    if (lrclk_cnt == 127)    audio_lrclk <= 1'b1; 
    if (lrclk_cnt == 255)    audio_lrclk <= 1'b0;

end

always@(posedge clk) begin

    bclk_cnt <= bclk_cnt + 1; 
    if (bclk_cnt == 3)    audio_bclk <= 1'b1; 
    if (bclk_cnt == 7)    audio_bclk <= 1'b0;

end

 

說明,如果音頻數據的採樣率是48KHz,那麼,一般情況下,clk應該是採樣率的256、384或者512倍。比較常見的是256倍,那麼,這裏的clk=44.8KHz*256=12.288MHz。

 

之所以用這種計數器的方式產生LRCLK和BCLK,是爲下面的裝入數據做準備的。

 

2、SDATA數據的載入

// DAC Data Assembling

reg [15:0] lbuf = 16'd0; 
reg [15:0] rbuf = 16'd0;

always@(negedge clk) begin

    case(lrclk_cnt) 
    // Left 
    0:   audio_sdata <= lbuf[15]; 
    8:   audio_sdata <= lbuf[14]; 
    16:  audio_sdata <= lbuf[13]; 
    24:  audio_sdata <= lbuf[12]; 
    32:  audio_sdata <= lbuf[11]; 
    40:  audio_sdata <= lbuf[10]; 
    48:  audio_sdata <= lbuf[9]; 
    56:  audio_sdata <= lbuf[8]; 
    64:  audio_sdata <= lbuf[7]; 
    72:  audio_sdata <= lbuf[6]; 
    80:  audio_sdata <= lbuf[5]; 
    88:  audio_sdata <= lbuf[4]; 
    96:  audio_sdata <= lbuf[3]; 
    104: audio_sdata <= lbuf[2]; 
    112: audio_sdata <= lbuf[1]; 
    120: audio_sdata <= lbuf[0]; 
    // Right 
    128: audio_sdata <= rbuf[15]; 
    136: audio_sdata <= rbuf[14]; 
    144: audio_sdata <= rbuf[13]; 
    152: audio_sdata <= rbuf[12]; 
    160: audio_sdata <= rbuf[11]; 
    168: audio_sdata <= rbuf[10]; 
    176: audio_sdata <= rbuf[9]; 
    184: audio_sdata <= rbuf[8]; 
    192: audio_sdata <= rbuf[7]; 
    200: audio_sdata <= rbuf[6]; 
    208: audio_sdata <= rbuf[5]; 
    216: audio_sdata <= rbuf[4]; 
    224: audio_sdata <= rbuf[3]; 
    232: audio_sdata <= rbuf[2]; 
    240: audio_sdata <= rbuf[1]; 
    248: audio_sdata <= rbuf[0]; 
    endcase

end

 

說明,至於在計數器的哪個值上將數據賦值,以上的代碼都是經過仿真和實測的,讀者可以自己仿真觀察一下就知道了。

 

3、FIFO數據的讀取

第2節代碼中可以看到,sdata的數據是從lbuf和rbuf中取的,那麼下面的模塊就是如何將數據從FIFO中取出,並放到lbur和rbuf中了。

// Fetch Audio Data From FIFO

assign lfifo_rd_clk = clk; 
assign rfifo_rd_clk = clk;

always@(negedge clk) begin

    case(lrclk_cnt) 
    125: 
        begin 
            if(!rfifo_empty) rfifo_rd_en <= 1; 
        end 
    126: 
        begin 
            rfifo_rd_en <= 0; 
            rbuf <= rfifo_dout; 
        end 
    253: 
        begin 
            if(!lfifo_empty) lfifo_rd_en <= 1; 
        end 
    254: 
        begin 
            lfifo_rd_en <= 0; 
            lbuf <= lfifo_dout; 
        end 
    endcase

end

 

說明,上面取數據對應的計數器值也是經過仿真和實測的,沒有問題,讀者可以自己仿真觀察下。

 

最後,上面的代碼都是經過作者實測的。

測試情況:

1、找一個mp3或者其它音頻文件,48KHz的採樣率以上,如果採樣率不是48KHz的,通過Adobe Audition(原Cool Edit)軟件調整採樣率(升採樣率會出現雜音,你懂的)。

2、用Matlab打開,可以看到在計算機上的音頻文件的數據是經過歸一化的。將他們轉化成16位的二進制數(unsigned int類型的也一樣),然後另存爲二進制文件。

3、通過USB接口(見EZ-USB與FPGA的通信接口設計),自己編寫的軟件,將這個二進制文件發送下去。FPGA端連續不斷的將數據輸出即可聽到聲音。(軟件通過USB發送數據下去的時候,最好將文件切成1K的段發下去,因爲FPGA的FIFO緩衝區沒那麼大,USB發送數據的延時等待也要設置成200ms以上,不然數據流會斷掉)

轉載:https://www.cnblogs.com/lifan3a/articles/4874798.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章