1. 程式人生 > >FPGA設計標準I2S協議音訊編解碼器

FPGA設計標準I2S協議音訊編解碼器

FPGA設計標準I2S協議音訊編解碼器

–I2S基本介紹

I2S(Inter-IC Sound)是飛利浦公司針對數字音訊裝置(如CD播放器、數碼音效處理器、數字電視音響系統)之間的音訊資料傳輸而制定的一種匯流排標準。它採用了獨立的導線傳輸時鐘與資料訊號的設計,通過將資料和時鐘訊號分離,避免了因時差誘發的失真,為使用者節省了購買抵抗音訊抖動的專業裝置的費用。

–I2S取樣和處理過程

模擬訊號–>音訊codec晶片–>I2S數字訊號(音訊ADC轉換過程)
I2S數字訊號–>音訊codec晶片–>模擬訊號(音訊DAC轉換過程)
在這裡插入圖片描述

備註:音訊codec晶片需要進行相關暫存器配置才能工作。相關配置資料可以檢視晶片手冊。

–I2S協議規範

I2S有3個主要訊號

  • 1.序列時鐘SCLK,也叫位時鐘(BCLK),即對應數字音訊的每一位資料,SCLK都有1個脈衝。SCLK的頻率=2×取樣頻率×取樣位數。
  • 2.幀時鐘LRCK,(也稱WS),用於切換左右聲道的資料。LRCK為“1”表示正在傳輸的是右聲道的資料,為“0”則表示正在傳輸的是左聲道的資料。LRCK的頻率等於取樣頻率。
  • 3.序列資料SDATA,由於音訊資料有正負之分,故而用二進位制補碼錶示的音訊資料。

有時為了使系統間能夠更好地同步,還需要另外傳輸一個訊號MCLK,稱為主時鐘,也叫系統時鐘(Sys Clock),是取樣頻率的256倍或384倍。

隨著技術的發展,在統一的 I2S介面下,出現了多種不同的資料格式。根據SDATA資料相對於LRCK和SCLK的位置不同,分為左對齊(較少使用)、I2S格式(即飛利浦規定的格式)和右對齊(也叫日本格式、普通格式)。
在這裡插入圖片描述在這裡插入圖片描述

–FPGA設計標準I2S音訊編解碼器

程式碼已經在Cyclone ® IV EP4CE6 Device硬體平臺測試OK.
音訊解碼器程式碼如下,歡迎各位學友共同探討

在這裡插入程式碼片
 module i2s_decoder_slave#(
parameter DATA_WIDTH = 32
)
(
input sys_clk_i,
input audio_clk_i,
input rstn_i,
//
output reg [DATA_WIDTH-1:0] audio_data_o, //hi:left lw:right
output reg audio_den_o,
//
input i2s_din_i,
output reg i2s_mclk_o,
input i2s_lrclk_i,
input i2s_bclk_i
);
////////////////////////////////////////////////////////////////////////////////////////
//ʱ��ʱ 49.152M������ʱ��Ϊ fs=48khz��mclk=256fs=12.288M,bclk=mclk/4,ʱ��Ϊ mclk �� 4�����ʴ˴�Ϊ 16
localparam BCLK_PER_NUM = 16;
localparam LRCLK_BCLK_RATE = 64;
localparam I2S_EMPTY_WIDTH = LRCLK_BCLK_RATE/2 - DATA_WIDTH/2;
reg [1:0] mclk_cntr;
reg [3:0] i2s_din_dly;
reg [3:0] i2s_bclk_dly;
reg [4:0] bit_cntr;
reg [LRCLK_BCLK_RATE/2-1:0] rsr;
reg [7:0] i2s_lrclk_dly;
reg sample_en;
reg [DATA_WIDTH/2-1:0] audio_left_data;//left data
reg [DATA_WIDTH/2-1:0] audio_right_data;//right data
////////////////////////////////////////////////////////////////////////////////////////
[email protected]
(posedge audio_clk_i or negedge rstn_i) begin if(rstn_i == 1'b0) mclk_cntr <= 'b0; else mclk_cntr <= mclk_cntr + 2'b1; end [email protected](posedge audio_clk_i or negedge rstn_i) begin if(rstn_i == 1'b0) i2s_mclk_o <= 'b0; else if (mclk_cntr[0]) i2s_mclk_o <= ~i2s_mclk_o; end [email protected](posedge sys_clk_i or negedge rstn_i) begin if(rstn_i == 1'b0) i2s_bclk_dly <= 4'b0; else i2s_bclk_dly <= {i2s_bclk_dly[2:0],i2s_bclk_i}; end wire i2s_bclk_rise = (i2s_bclk_dly[3:2]==2'b01); wire i2s_bclk_fall = (i2s_bclk_dly[3:2]==2'b10); [email protected](posedge sys_clk_i or negedge rstn_i) begin if(rstn_i == 1'b0) bit_cntr <= 5'b0; else if (^i2s_lrclk_dly[3:2]) bit_cntr <= 5'b0; else if(i2s_bclk_fall) bit_cntr <= bit_cntr + 1'b1; end [email protected](posedge sys_clk_i or negedge rstn_i) begin if(rstn_i == 1'b0) i2s_lrclk_dly <= 8'b0; else i2s_lrclk_dly <= {i2s_lrclk_dly[6:0],i2s_lrclk_i}; end [email protected](posedge sys_clk_i or negedge rstn_i) begin if(rstn_i == 1'b0) sample_en <= 1'b0; else if (^i2s_lrclk_dly[3:2]) sample_en <= 1'b0; else if (i2s_bclk_fall) sample_en <= 1'b1; end [email protected](posedge sys_clk_i or negedge rstn_i) begin if(rstn_i == 1'b0) i2s_din_dly <= 4'b0; else i2s_din_dly <= {i2s_din_dly[2:0],i2s_din_i}; end [email protected](posedge sys_clk_i or negedge rstn_i) begin if(rstn_i == 1'b0) rsr <= 32'h0; else if(sample_en && i2s_bclk_rise) rsr <= { rsr[30:0],i2s_din_dly[3] }; end [email protected](posedge sys_clk_i or negedge rstn_i) begin if(rstn_i == 1'b0) begin audio_left_data <= 'h0; audio_right_data <= 'h0; end else if(^i2s_lrclk_dly[3:2]) begin if(~i2s_lrclk_dly[3]) audio_left_data <= rsr[LRCLK_BCLK_RATE/2-2:I2S_EMPTY_WIDTH-1]; if(i2s_lrclk_dly[3]) audio_right_data <= rsr[LRCLK_BCLK_RATE/2-2:I2S_EMPTY_WIDTH-1]; end end [email protected](posedge sys_clk_i or negedge rstn_i) begin if(rstn_i == 1'b0) audio_den_o <= 1'b0; else if(i2s_lrclk_dly[5:4]==2'b10 ) audio_den_o <= 1'b1; else audio_den_o <= 1'b0; end [email protected](posedge sys_clk_i or negedge rstn_i) begin if(rstn_i == 1'b0) audio_data_o <= 0; else if(i2s_lrclk_dly[5:4]==2'b10) audio_data_o <= {audio_left_data,audio_right_data}; end //////////////////////////////////////////////////////////////////////////