I2S DAC的Verilog实现

本文档介绍了如何使用FPGA控制具备I2S接口的DAC器件进行数字音频数据传输。详细阐述了I2S总线标准中的关键信号,包括SCLK、LRCK和SDAT,并通过Verilog代码展示了如何生成相应的时钟信号和数据输出。在代码中,通过时钟分频产生MCLK、SCLK和LRCK,并根据输入的左右声道数据生成串行数据SDAT。仿真实验验证了24位音频数据的正确传输。
摘要由CSDN通过智能技术生成

I2S总线是Inter-IC Sound 总线的缩写,其最初是由飞利浦公司为数字音频设备之间的音频数据传输而制定的一种总线标准。

在飞利浦公司的I2S标准中,既规定了硬件接口规范,也规定了数字音频数据的格式。

硬件方面,主要有三个信号,分别是:

1、串行时钟SCLK(有时也叫位时钟BCLK),即对应数字音频的每一个数据,SCLK都有一个脉冲信号。

2、帧时钟LRCK,用于切换左右声道的数据。一般LRCK为1表示正在传输右声道,为0表示正在传输左声道。

3、串行数据SDAT,用二进制补码形式表示的音频数据。

有时为了使系统间能够更好地同步,还需要另外一个时钟MCLK,称为主时钟,或系统时钟,其跟采样频率之间存在一定的比例关系。

软件方面:

I2S格式的信号无论有多少位有效数据,数据的最高位总是出现在LRCK变化(也就是一帧开始)后的第2个SCLK脉冲处。这就使得接收端与发送端的有效位数可以不同。如果接收端能处理的有效位数少于发送端,可以放弃数据帧中多余的低位数据;如果接收端能处理的有效位数多于发送端,可以自行补足剩余的位。这种同步机制使得数字音频设备的互连更加方便,而且不会造成数据错位。

/****************************************************************************************************/

以上内容摘抄自百科

/***************************************************************************************************/

实际项目中,采用了一片具备I2S格式的DAC器件,并用FPGA器件作为控制器件来控制DAC工作,就具体的DAC器件而言,需要控制的信号有

MCLK/SCLK/LRCK/SDAT/RST/MODE等信号。其与FPGA之间的连接不过多叙述,下面直接给出该部分实现的verilog代码,请有兴趣的自行参考。

module dac(
    input clk_i,        //clk in
    input rst_i,        //rst
     
     input [2:0] da_ctrl, //dac sample rate control
     
    output sclk_o,    //sclk
    output mclk_o,    //mclk
    output lrck_o,    //lrck
    output sdout_o,    //sdin
     
    output [1:0] mode_o,//mode
    output reg da_rst,    //rst
     output da_done,    
     
     input [23:0] l_data_i,    //left channel data in    
     input [23:0] r_data_i    //right channel data in
    );

/******************************************************/
reg da_sclk_r,da_mclk_r,da_lrck_r;
reg [1:0] da_mode_r;

reg [9:0] clk_div;
always@(posedge clk_i or negedge rst_i) begin
    if(!rst_i) begin
        clk_div <= 10'd0;
    end
    else
        clk_div <= clk_div + 1'b1;
end

//这里采用时钟分频的方式来获得各时钟信号

always@(posedge clk_i or negedge rst_i) begin
    if(!rst_i) begin
        da_sclk_r <= 1'b1;
        da_mclk_r <= 1'b1;
        da_lrck_r <= 1'b1;
        da_mode_r <= 2'b00;
    end
    else begin
        case(da_ctrl[2:0])
            3'b000: begin
                da_mclk_r <= clk_div[0];
                da_sclk_r <= clk_div[1];
                da_lrck_r <= clk_div[7];
                da_mode_r <= 2'b11;
            end
            3'b001: begin
                da_mclk_r <= clk_div[1];
                da_sclk_r <= clk_div[2];
                da_lrck_r <= clk_div[8];
                da_mode_r <= 2'b10;
            end

            ......
            default: begin
                da_mclk_r <= clk_div[1];
                da_sclk_r <= clk_div[3];
                da_lrck_r <= clk_div[9];
                da_mode_r <= 2'b10;
            end
        endcase
    end
end
assign sclk_o = da_sclk_r;
assign mclk_o = da_mclk_r;
assign lrck_o = da_lrck_r;
assign mode_o = da_mode_r;

/******************************************************/
reg [ 4:0] L_count,R_count;    //left and right count
reg send_done;                        //finish
always@(posedge da_sclk_r or negedge da_rst) begin
    if(da_rst == 1'b0) begin
        L_count <= 5'd0;
        R_count <= 5'd0;
        send_done <= 1'b0;
    end
    else if(da_lrck_r == 1'b0) begin
        R_count <= 5'd0;
        send_done <= 1'b0;
        if(L_count < 5'd25) begin
            L_count <= L_count + 1'b1;
        end
    end
    else begin
        L_count <= 5'd0;
        if(R_count < 5'd25) begin
            R_count <= R_count + 1'b1;
        end
        if(R_count == 5'd25)
            send_done <= 1'b1;
    end
end
assign da_done = send_done;

/*****************************************************/

reg [23:0] da_data_o;    //output data

always@(negedge da_sclk_r) begin
    if(L_count == 5'd1)
        da_data_o <= l_data_i;
    else if(R_count == 5'd1)
        da_data_o <= r_data_i;
    else
        da_data_o <= {da_data_o[22:0],1'b1};
end
assign sdout_o = da_rst ? da_data_o[23] : 1'b0;
endmodule

构建仿真模块,进行verilog仿真,结果如下

 从结果中,可以看出,预输出的24位数据为:left,0x555555;right,0x0ff00f。比对时序可以看出,输出正确。

I2S的控制时序如下图所示(摘抄自器件的datasheet)

在编写这份文档的过程 中,也有参考部分CSDN上的网友们给出的思路、代码等。相关内容可以在CSDN上一并搜索查看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值