协议篇-I2S协议

        I2S常用于音频数据通信,协议内容比较简单,主要由三根线信号线如下:

        LRCLK:左右声道数据传输通道,低电平代表左声道数据,高电平代表右声道数据;

        BCLK:数据时钟信号,上升沿采样;

        SDATA:音频数据。

        名词解析:

        左右声道指的是在电子设备中模拟人类左右耳的听觉范围产生的声音输出。‌它们是相互独立的音频信号,‌用于在不同空间位置采集或回放声音,‌以确保声音的高还原性。‌左声道通常模拟人类左耳的听觉范围,‌而右声道模拟右耳的听觉范围。‌在录制音乐时,‌使用两个话筒按照左右声道进行录制,‌以确保播放时的立体声效果。

        协议比较简单,有点类似与SPI协议,以DAC芯片AD1955为例讲解I2S协议,如下图所示为AD1955在I2S协议下数据图:

                                                图1 音频数据时序图

        图中第一个时序图是标准的I2S协议,DAC可以输出16位或者24位DAC数据,这里以16个DAC数据为例讲解。LRCLK和BCLK在代码编写时可以是同步信号,LRCLK可以是BCLK的1/64频率,工作流程如下:

        1、LRCLK和BCLK同时低电平,在BCLK的第二个下降沿发送数据,数据在第二个上升沿到来之前保证数据稳定;

        2、BCLK之后的每一个下降沿可以改变数据,上升沿采样直到16位/24位DAC数据发送完毕;

        3、在第个时钟周期17个时钟周期结束时左声道数据发送完毕,此时LRCLK低电平还有15个时钟周期,这段时间数据无效。

        4、BCLK第33个时钟周期下降沿和LRCLK的上升沿对齐,

        5、第34时钟周期下降沿发送音频数据最高位MSB,接收端通过上升沿采样;

        6、BCLK第49个时钟周期发送完右声道最小bit位;

        7、BCLK继续发送完64个时钟周期,到这里左右声道一个采集单位输出完毕。

        I2S协议不是很严谨,BCLK发送数据位宽没有限制,这里左右声道各32个时钟周期,实际上只用到17个时钟周期。设计中可以随意变更,只要时钟周期大于等于17个即可,如果发送24位DAC,时钟周期大于25位就可以。

        另外AD1955可以选用RIGHT-JUSTIFIED/LEFT-JUSTIFIED MODE协议模式,这些协议模式和I2S协议基本一致,也可以驱动DAC左右声道模拟信息输出。

        基于之前原则的是LEFT-JUSTIFIED驱动该DAC芯片,仿真波形图如下:

                                                图2 AD1955 LEFT-JUSTIFIED模式

        左声道发送0x1234,右声道发送0x5678;

        由于该芯片我使用的是External Filter Mode模式,根据芯片手册写的该模式下左声道数据通过DA_SDATA接口输入,右声道通过EF_RDATA接口输入,所以左右声道数据经过FPGA两个接口输出。

        芯片该处说明如下图所示:

                                                        图3 AD1955External Filter Mode模式数据接收

如下为FPGA仿真代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/07/17 16:02:09
// Design Name: 
// Module Name: DAC_TB
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module DAC_TB(

    );
	
	
reg sys_clk;	
reg sys_rst_n;
reg[15:0] DATA_L_IN;
reg[15:0] DATA_R_IN;
reg DATA_EN; 	
	

always #4.88 sys_clk = ~sys_clk;	102.4MHz

	
initial begin
	sys_clk = 'd0;
	sys_rst_n = 'd0;
	DATA_EN = 'd0;
	DATA_L_IN = 'd0;
	DATA_R_IN = 'd0;
	#30_000
	sys_rst_n = 'd1;
	#500
	repeat(1)@(posedge sys_clk);
	DATA_EN = 'd1;
	DATA_L_IN = 16'h1234;
	DATA_R_IN = 16'h5678;
	repeat(1)@(posedge sys_clk);
	DATA_EN = 'd0;	
end		



JUSTIFED_MODE_DRV	JUSTIFED_MODE_DRV(
	.sys_clk(sys_clk),
	.sys_rst_n(sys_rst_n),	
	.DATA_L_IN(DATA_L_IN),
	.DATA_R_IN(DATA_R_IN),
	.DATA_EN(DATA_EN),
	//dac out
	.DA_MCLK_out(DA_MCLK),
	.DA_RDATA(DA_RDATA),
	.DA_SDATA(DA_SDATA),
	.DA_BCLK(DA_BCLK),
	.DA_LRCLK(DA_LRCLK)
);

	
	
	
endmodule





        FPGA LEFT-JUSTIFIED驱动代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/01/10 17:00:02
// Design Name: 
// Module Name: JUSTIFED_MODE_DRV
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module JUSTIFED_MODE_DRV(
	input sys_clk,
	input sys_rst_n,
	voice dds
	input[15:0] DATA_L_IN,
	input[15:0] DATA_R_IN,	
	input DATA_EN,
	DAC IO
	//dac out
	output DA_MCLK_out,	clk io FS 256   256/32*2 = 4锛?
	output reg DA_RDATA,RIGHT DATA
	output reg DA_SDATA,LEFT DATA
	//output  DA_SDATA,LEFT DATA
	output reg DA_BCLK,
	output reg DA_LRCLK
    );
	

parameter DATA_EN_NUM = 32;	
	
	
reg fifo_rd_en;
wire[31:0] fifo_data;
reg[31:0] data_l;
reg[31:0] data_r;

reg[7:0] DA_MCLK_cnt;
reg[7:0] DA_BCLK_cnt;
reg data_out_l_en;
reg data_out_r_en;
reg[7:0] i;
reg[7:0] q;
wire DA_MCLK;

// assign data_l = {fifo_data[31:16],16'd0};
// assign data_r = {fifo_data[15:0],16'd0};
// assign data_l = {16'h1234,16'd0};
// assign data_r = {16'h8765,16'd0};


//assign DA_SDATA = DA_RDATA;


always @(posedge DA_MCLK or negedge sys_rst_n)begin
	if(sys_rst_n == 'd0)begin
		DA_MCLK_cnt <= 'd0;	
		DA_BCLK <= 'd1;
	end
	else if(DA_MCLK_cnt >= 'd1)begin
		DA_MCLK_cnt <= 'd0;
		DA_BCLK <= ~DA_BCLK;	
		
	end
	else begin
		DA_MCLK_cnt <= DA_MCLK_cnt + 'd1;			
	end	
end


always @(posedge DA_MCLK or negedge sys_rst_n)begin
	if(sys_rst_n == 'd0)begin
		DA_LRCLK <= 'd0;	
		DA_BCLK_cnt <= 'd0;	
	end
	else if(DA_BCLK == 'd1 && DA_MCLK_cnt >= 'd1)begin
		if(DA_BCLK_cnt == 'd64)begin
			DA_BCLK_cnt <= 'd1;
			DA_LRCLK <= 'd1;		
		end
		else if(DA_BCLK_cnt >= 'd32)begin
			DA_BCLK_cnt <= DA_BCLK_cnt + 'd1;
			DA_LRCLK <= 'd0;
		end
		else begin
			DA_BCLK_cnt <= DA_BCLK_cnt + 'd1;
			DA_LRCLK <= 'd1;
		end
	end
end	
	

always @(posedge DA_MCLK or negedge sys_rst_n)begin
	if(sys_rst_n == 'd0)begin
		data_out_l_en <= 'd0;	
		data_out_r_en <= 'd0;
		DA_SDATA <= 'd0;
		DA_RDATA <= 'd0;
		i <= 'd31;
		q <= 'd31;
	end
	else if(DA_BCLK == 'd1 && DA_MCLK_cnt >= 'd1 && DA_BCLK_cnt == 'd64)begin
		data_out_l_en <= 'd1;
		i <= i - 'd1;
		q <= 'd0;
		//DA_SDATA <= data_l[i];
	end
	else if(DA_BCLK == 'd1 && DA_MCLK_cnt >= 'd1 && DA_BCLK_cnt <= 'd31)begin
		data_out_l_en <= 'd1;
		i <= i - 'd1;
		q <= 'd31;
		DA_SDATA <= data_l[i];
	end
	else if(DA_BCLK == 'd1 && DA_MCLK_cnt >= 'd1)begin
		data_out_r_en <= 'd1;
		q <= q - 'd1;
		i <= 'd31;
		DA_RDATA <= data_r[q];
		//DA_SDATA <= data_l[q];
	end
	
	else begin
		data_out_l_en <= 'd0;	
		data_out_r_en <= 'd0;	
	end
end



always @(posedge DA_MCLK or negedge sys_rst_n)begin
	if(sys_rst_n == 'd0)begin
		fifo_rd_en <= 'd0;	
		data_l <= 'd0;	
		data_r <= 'd0;	
	end
	else if(DA_BCLK == 'd1 && DA_MCLK_cnt >= 'd1 && DA_BCLK_cnt == 'd63)begin
		fifo_rd_en <= 'd1;	
		data_l <= {fifo_data[31:16],16'd0};
		data_r <= {fifo_data[15:0],16'd0};
	end
	else begin
		fifo_rd_en <= 'd0;	
	end
end
	

FIFO_JUSTIFED	FIFO_JUSTIFED_INST(
	.wr_clk(sys_clk),
	.rd_clk(DA_MCLK),
	.rst(~sys_rst_n),
	.din({DATA_L_IN,DATA_R_IN}),
	.wr_en(DATA_EN),
	.rd_en(fifo_rd_en),
	.dout(fifo_data),
	.full(),
	.empty()
  );


PLL_DA_MCLK	PLL_DA_MCLK_INST(
 // Clock out ports
	.clk_out1(DA_MCLK_out),
	.clk_out2(DA_MCLK),
 // Clock in ports
	.clk_in1(sys_clk)

);
  
	
	
endmodule

        LEFT-JUSTIFIED时序和I2S时序非常相似,有兴趣的可以基于改代码做修改。

        总结:

        音频DAC相比较普通DAC是由两路DAC组成,并且满足I2S协议,I2S协议是专门为音频设计的,因为需要两个声音模仿人耳立体声。一般音频DAC的采样率在几百KHz以内,而人耳能识别的声音在44.1KHz以内。

        如有疑问可留言,后面可能会提供FPGA源码,敬请期待

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值