python 开发板 i2s_[Craftor原创] I2S总线接口设计(Verilog)
本文有Craftor原創(chuàng),轉(zhuǎn)載請保留出處。
I2S是數(shù)字音頻的接口,這里不用多說,請讀者自己查閱相關(guān)資料。
本文中要設(shè)計的是FPGA與數(shù)字音頻芯片的I2S接口時序。簡單點說,就是通過FPGA向音頻芯片寫數(shù)據(jù),通過的是I2S總線,因為這個總線比較麻煩,我在這里做成接口模塊,其它模塊直接拿來用就可以了。
提示,I2S總線的接口信號如下:
1、LRCLK:左右聲道控制,高電平時,SDATA上為左聲道數(shù)據(jù),低電平時,SDATA上為右聲道數(shù)據(jù)。(也有相反的情況,請參考不同的音頻芯片的手冊)
2、BCLK:跟SDATA上數(shù)據(jù)對應(yīng)的時鐘,上升沿采數(shù)據(jù),也可能在下降沿采數(shù)據(jù),請注意對應(yīng)音頻芯片手冊上的說明。
3、SDATA:串行數(shù)據(jù),一個BCLK對應(yīng)一個。
時序圖如下,WS就是LRCLK,BCLK就是SCK。
一、設(shè)計思路,數(shù)據(jù)流向,如下:
二、分析
左聲道和右聲道的數(shù)據(jù),分別設(shè)計成兩個FIFO即可。重點在于如何將兩路數(shù)據(jù)拼裝到一起,再轉(zhuǎn)換成串行的數(shù)據(jù)。
三、設(shè)計
1、LRCLK和BCLK的產(chǎn)生
提示,如果數(shù)字音頻的數(shù)據(jù)是16位的,那么BCLK就是LRCLK的16倍。即在一個LRCLK中,有32個BCLK,16個左聲道數(shù)據(jù),16個右聲道數(shù)據(jù)。同樣,如果數(shù)據(jù)是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
說明,如果音頻數(shù)據(jù)的采樣率是48KHz,那么,一般情況下,clk應(yīng)該是采樣率的256、384或者512倍。比較常見的是256倍,那么,這里的clk=44.8KHz*256=12.288MHz。
之所以用這種計數(shù)器的方式產(chǎn)生LRCLK和BCLK,是為下面的裝入數(shù)據(jù)做準(zhǔn)備的。
2、SDATA數(shù)據(jù)的載入
// 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
說明,至于在計數(shù)器的哪個值上將數(shù)據(jù)賦值,以上的代碼都是經(jīng)過仿真和實測的,讀者可以自己仿真觀察一下就知道了。
3、FIFO數(shù)據(jù)的讀取
第2節(jié)代碼中可以看到,sdata的數(shù)據(jù)是從lbuf和rbuf中取的,那么下面的模塊就是如何將數(shù)據(jù)從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
說明,上面取數(shù)據(jù)對應(yīng)的計數(shù)器值也是經(jīng)過仿真和實測的,沒有問題,讀者可以自己仿真觀察下。
最后,上面的代碼都是經(jīng)過作者實測的。
測試情況:
1、找一個mp3或者其它音頻文件,48KHz的采樣率以上,如果采樣率不是48KHz的,通過Adobe Audition(原Cool Edit)軟件調(diào)整采樣率(升采樣率會出現(xiàn)雜音,你懂的)。
2、用Matlab打開,可以看到在計算機上的音頻文件的數(shù)據(jù)是經(jīng)過歸一化的。將他們轉(zhuǎn)化成16位的二進制數(shù)(unsigned int類型的也一樣),然后另存為二進制文件。
3、通過USB接口(見EZ-USB與FPGA的通信接口設(shè)計),自己編寫的軟件,將這個二進制文件發(fā)送下去。FPGA端連續(xù)不斷的將數(shù)據(jù)輸出即可聽到聲音。(軟件通過USB發(fā)送數(shù)據(jù)下去的時候,最好將文件切成1K的段發(fā)下去,因為FPGA的FIFO緩沖區(qū)沒那么大,USB發(fā)送數(shù)據(jù)的延時等待也要設(shè)置成200ms以上,不然數(shù)據(jù)流會斷掉)
文中完整的代碼:
總結(jié)
以上是生活随笔為你收集整理的python 开发板 i2s_[Craftor原创] I2S总线接口设计(Verilog)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 领诵员冯琳最新消息!保研复旦、主持卫视跨
- 下一篇: python图像几何变换_Python