[Craftor原创] I2S总线接口设计(Verilog)

URL: http://www.cnblogs.com/craftor/archive/2011/11/06/2237947.html

I2S是数字音频的接口,这里不用多说,请读者自己查阅相关资料。

本文中要设计的是FPGA与数字音频芯片的I2S接口时序。简单点说,就是通过FPGA向音频芯片写数据,通过的是I2S总线,因为这个总线比较麻烦,我在这里做成接口模块,其它模块直接拿来用就可以了。

 

提示,I2S总线的接口信号如下:

1、LRCLK:左右声道控制,高电平时,SDATA上为左声道数据,低电平时,SDATA上为右声道数据。(也有相反的情况,请参考不同的音频芯片的手册)

2、BCLK:跟SDATA上数据对应的时钟,上升沿采数据,也可能在下降沿采数据,请注意对应音频芯片手册上的说明。

3、SDATA:串行数据,一个BCLK对应一个。

 

时序图如下,WS就是LRCLK,BCLK就是SCK。

image

 

一、设计思路,数据流向,如下:

 

image

 

 

二、分析

左声道和右声道的数据,分别设计成两个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;

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

 

说明,如果音频数据的采样率是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、找一个mp3或者其它音频文件,48KHz的采样率以上,如果采样率不是48KHz的,通过Adobe Audition(原Cool Edit)软件调整采样率(升采样率会出现杂音,你懂的)。

2、用Matlab打开,可以看到在计算机上的音频文件的数据是经过归一化的。将他们转化成16位的二进制数(unsigned int类型的也一样),然后另存为二进制文件。

3、通过USB接口(见EZ-USB与FPGA的通信接口设计),自己编写的软件,将这个二进制文件发送下去。FPGA端连续不断的将数据输出即可听到声音。(软件通过USB发送数据下去的时候,最好将文件切成1K的段发下去,因为FPGA的FIFO缓冲区没那么大,USB发送数据的延时等待也要设置成200ms以上,不然数据流会断掉)

原作者文中完整的代码:http://dl.dbank.com/c0tbq371og#

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
I2S总线接口设计可以使用Verilog语言来实现。在设计中,需要考虑到FPGA与数字音频芯片之间的信号连接和时序。引用提到了设计一个FPGA与数字音频芯片的I2S接口时序,这意味着需要设计和实现与I2S总线相关的时钟信号(MCLK,BCLK)和数据信号(LRCK,SDATA)的生成和处理。 在Verilog代码中,可以定义输入和输出端口来连接FPGA和音频芯片。引用提到了常见的信号,如MCLK(主时钟),SCLK(数据时钟),LRCK(左右声道选择),SDAT(音频数据),RST(复位信号)和MODE(工作模式选择)。可以根据具体需求在代码中定义这些信号。 接下来,需要根据I2S总线的时序要求来生成时钟和数据信号。例如,可以使用计数器来生成BCLK(位时钟)信号,根据BCLK的边沿来采样和传输音频数据。还可以根据LRCK的边沿来选择左右声道。 随后,需要根据数据要求来处理音频数据。可以使用移位寄存器来将音频数据从SDAT输入并移位到输出端口。在代码中还可以实现复位功能,以及根据MODE信号来选择不同的工作模式。 在设计I2S总线接口时,还需要考虑时序同步和时钟域的问题,以确保数据的准确传输。可以使用FPGA的时钟域划分和时钟同步技术,以及适当的寄存器和状态机来实现。 总的来说,设计I2S总线接口Verilog代码需要考虑与FPGA和音频芯片之间的信号连接和时序要求,并且根据具体的应用需求来生成和处理时钟和数据信号。可以参考引用中提到的时序设计和引用中给出的Verilog代码作为参考。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [[Craftor] I2S总线接口设计Verilog)](https://blog.csdn.net/weixin_30527143/article/details/96956435)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [I2S DAC的Verilog实现](https://blog.csdn.net/snutqq/article/details/120347969)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值