I2S匯流排介面設計(Verilog)

2021-09-07 03:03:29 字數 3863 閱讀 3474

i2s是數字音訊的介面,這裡不用多說,請讀者自己查閱相關資料。

本文中要設計的是fpga與數字音訊晶元的i2s介面時序。簡單點說,就是通過fpga向音訊晶元寫資料,通過的是i2s匯流排,因為這個匯流排比較麻煩,我在這裡做成介面模組,其它模組直接拿來用就可以了。

提示,i2s匯流排的介面訊號如下:

2、bclk:跟sdata上資料對應的時鐘,上公升沿採資料,也可能在下降沿採資料,請注意對應音訊晶元手冊上的說明。

3、sdata:序列資料,乙個bclk對應乙個。

時序圖如下,ws就是lrclk,bclk就是sck。

一、設計思路,資料流向,如下:

二、分析

左聲道和右聲道的資料,分別設計成兩個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;

endalways@(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、找乙個***或者其它音訊檔案,48khz的取樣率以上,如果取樣率不是48khz的,通過adobe audition(原cool edit)軟體調整取樣率(公升取樣率會出現雜音,***)。

2、用matlab開啟,可以看到在計算機上的音訊檔案的資料是經過歸一化的。將他們轉化成16位的二進位制數(unsigned int型別的也一樣),然後另存為二進位制檔案。

3、通過usb介面(見ez-usb與fpga的通訊介面設計),自己編寫的軟體,將這個二進位制檔案傳送下去。fpga端連續不斷的將資料輸出即可聽到聲音。(軟體通過usb傳送資料下去的時候,最好將檔案切成1k的段發下去,因為fpga的fifo緩衝區沒那麼大,usb傳送資料的延時等待也要設定成200ms以上,不然資料流會斷掉)

I2S匯流排介面設計(Verilog)

i2s是數字音訊的介面,這裡不用多說,請讀者自己查閱相關資料。本文中要設計的是fpga與數字音訊晶元的i2s介面時序。簡單點說,就是通過fpga向音訊晶元寫資料,通過的是i2s匯流排,因為這個匯流排比較麻煩,我在這裡做成介面模組,其它模組直接拿來用就可以了。提示,i2s匯流排的介面訊號如下 2 bc...

I2S音訊匯流排學習(四)I2S介面設計

圖1 傳送端 隨著ws訊號的改變,匯出乙個wsp脈衝訊號,進入並行移位暫存器裝入data left或data right,從而輸出資料被啟用。序列資料在時鐘下降沿移出。序列資料的預設輸入是0,因此所有位於最低位 lsb 後的資料將被設定為0。圖2 接收端 隨著第乙個ws訊號的改變,wsp在sck訊號...

I2S音訊匯流排學習(四)I2S介面設計

圖1 傳送端 隨著ws訊號的改變,匯出乙個wsp脈衝訊號,進入並行移位暫存器裝入data left或data right,從而輸出資料被啟用。序列資料在時鐘下降沿移出。序列資料的預設輸入是0,因此所有位於最低位 lsb 後的資料將被設定為0。圖2 接收端 隨著第乙個ws訊號的改變,wsp在sck訊號...