问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 91 人浏览分享

开启左侧

HDMI-IP项目-主讲I2S音频原理-连载五

[复制链接]
91 0
本帖最后由 UT发布 于 2025-5-12 11:11 编辑

1音频传输概念

I2SInter-IC Sound)是由飞利浦公司(现NXP)制定的数字音频传输标准,主要用于集成电路间的PCM音频数据传输。该协议规范了数据格式、时钟同步和电气接口三大要素。

音频采集(RX方向):
麦克风→前置放大→抗混叠滤波→ADC采样(16/24bit位深)→I2S传输至处理器。此模式下,ADC通常作为时钟主设备(Master)。

音频播放(TX方向):
处理器解码音频I2S传输至DAC→模拟信号重建→功率放大→扬声器输出。此时处理器常作为时钟主设备。

接口结构:

SCK(位时钟):频率 = 2×采样率×位宽

LRCK(帧同步):频率 = 采样率

SD(数据线):双向传输通道

技术优势:

支持44.1kHz/48kHz/96kHz采样率

时钟抖动容限<1ns

兼容TDM扩展协议(多声道传输)

工作模式:
image.jpg
典型应用:
640?wx_fmt=png&from=appmsg
2 I2S协议
2.1 I2S基本信号

I2S协议基本时序关系

640?wx_fmt=png&from=appmsg

如上图所示,I2S接口通过三类关键信号线实现数字音频同步传输:

如上图所示,I2S接口通过三类关键信号线实现数字音频同步传输:

1. 时钟线(Continuous Serial Clock, SCK/BCLK

该信号提供全系统同步基准时钟,其频率计算公式为:SCK频率 = 2 × 音频采样率 × 数据位宽。例如在48kHz采样率、24bit位宽配置下,SCK时钟频率达到2.304MHz。系统支持主从两种工作模式:当主控芯片(如DSP)作为时钟源时处于Master模式,由外部设备(如ADC/DAC)提供时钟时则切换为Slave模式。协议规定标准模式下数据在SCK下降沿被锁存,上升沿完成电平切换。

2. 帧同步线(Left-Right Clock, LRCK/WS

该信号频率直接等同于音频采样率,例如48kHz采样率对应LRCK输出48kHz方波。电平状态明确指示声道归属:低电平周期表示左声道数据传输窗口,其有效数据段从LRCK上升沿前1SCK周期开始;高电平周期对应右声道,数据窗口持续至LRCK下降沿后1SCK周期结束。

3. 数据线(Serial Data, SD

支持16/24/32位数据位宽配置,其中16/24bit应用场景采用高位补零方式填充至32bit帧长,专业音频设备则直接使用全32bit有效数据。数据传输方向分为:发送通道(TX)由主设备通过SDOUT引脚输出至DAC等设备,接收通道(RX)通过SDIN引脚采集来自ADC的音频数据。所有传输均遵循MSB(最高有效位)优先机制。

2.2 I2S协议中常见的参数
1. 位宽(Word Length

定义单个采样点的数据精度,典型配置包含:

16位:CD音质标准,动态范围96dB,适用于消费类电子产品

24位:专业音频标准,提供144dB理论动态范围

32位:用于DSP内部高精度运算缓冲,实际传输时高位补零

2. 时钟极性(Clock Polarity

控制数据传输的基准时钟边沿:

CPOL=0:时钟空闲低电平,数据在上升沿锁存(多数ADC器件默认设置)

CPOL=1:时钟空闲高电平,数据在下降沿采样(常见于DAC器件)

3. 帧同步极性(Frame Sync

定义声道切换信号的激活电平:

低电平有效:左声道数据在LRCK下降沿后开始传输

高电平有效:右声道数据在LRCK上升沿后开始传输
注:需与SCK相位配合,标准I2S协议默认低电平标识左声道

4. 传输格式(Data Format

包含数据封装与时序规范:

标准I2SLRCK变化后延迟1SCK周期开始传输MSB

左对齐:MSB对齐LRCK边沿,减少传输延迟

右对齐:LSB对齐LRCK边沿,兼容早期DSP架构

声道顺序:标准协议默认左声道优先,可配置为右声道前置

3主从工作模式

I2S工作模式可以是主模式(Master Mode)或从模式(Slave Mode)。两者唯一的区别是:Master Mode提供时钟信号(SCK)和帧同步信号(LRCK)。如下图所示,一共存在三种工作模式,分别是:

1.发射器(transmitter)为Master,接收器(receiver)为Slave,此时由发射器提供SCKLRCK

2.接收器(receiver)为Master,发射器(transmitter)为Slave,此时由接收器提供SCKLRCK

3.发射器(transmitter)和接收器(receiver)均为Slave,由系统中其他模块提供SCKLRCK

640?wx_fmt=png&from=appmsg
4数据传输模式

I2S接口标准中,存在三种数据传输模式,分别是:飞利浦标准模式I2S mode),左对齐(Left Justified)和右对齐(Right Justified)三种传输模式。

4.1飞利浦标准(I2S)模式
image.jpg
                                                 I2S标准模式接口时序
其主要特点如下:

1LRCK(左右声道选择信号):LRCK信号用于指示当前数据帧是左声道数据还是右声道数据。飞利浦格式中,当LRCK为低时,表示当前传输的数据是左声道数据;当LRCK为高时,表示当前传输的数据为右声道数据

2SCK(位时钟):数据传输的时钟信号。在SCK下降沿发送数据,在SCK上升沿采样数据

3Data Delay:发送的有效数据相对于LRCK的跳变沿(从01或从10)延迟一个时钟周期

4)数据发送从MSB开始;数据MSBLRCK delay 1SCK的边沿对齐

4.2左对齐(Left Justified)模式
640?wx_fmt=png&from=appmsg
                                                    左对齐模式接口时序
其主要特点如下

1)在左对齐格式中,LRCK为高时,表示当前传输的数据为左声道数据;当LRCK为低时,表示当前传输的数据为右声道数据

2)在SCK下降沿发送数据,在SCK上升沿接收数据

3)无data delay:发送的有效数据相当于LRCK跳变沿(从01或从10)不延迟

4)数据发送从MSB开始;数据MSBLRCK跳变沿对齐

4.3右对齐(Right Justified)模式
640?wx_fmt=png&from=appmsg
                                                 右对齐模式接口时序
其主要特点如下

1)右对齐格式中,LRCK为高电平时,表示当前传输的数据为右声道数据;当LRCK为低电平时,表示当前传输的数据为左声道数据

2)在SCK下降沿发送数据,在SCK上升沿接收数据

3)无Data delay:发送的有效数据相当于LRCK跳变沿(从01或从10)不延迟

4)数据发送从MSB开始;数据LSBLRCK跳变沿对齐

5数据位宽与位深

1)位宽:根据SCKLRCK的关系:

采样频率位宽位宽

640?wx_fmt=png&from=appmsg

位宽一般为16位或32

2)位深:表示音频数据量化后的精度

需要注意的是,I2S中位宽和位深都是由Master决定的。因此在使用时需要先确定本模块在系统中的工作模式(Master or Slave)。下面以32位位宽,32/24/20/16位位深为例,说明位宽与位深的区别(以下例子的数据格式均为I2S格式)

32位位宽,32位位深

640?wx_fmt=png&from=appmsg

32位位宽,24位位深

640?wx_fmt=png&from=appmsg

32位位宽,20位位深

640?wx_fmt=png&from=appmsg

32位位宽,16位位深

640?wx_fmt=png&from=appmsg
6 I2S/发模块代码
6.1 I2S_driver模块

I2S_driver模块是一个基于Verilog实现的I2S协议发送控制器,主要用于驱动音频数据传输。该模块通过系统时钟生成符合I2S标准的位时钟(BCLK)和声道时钟(LRCK),支持可配置的音频位深(16/24/32位)和采样率(44.1kHz/48kHz等)。

其核心功能包括:通过三段式状态机实现智能数据预请求机制,在声道切换前主动触发外部数据供给;采用双时钟域架构处理跨时钟域同步,通过移位寄存器实现并行音频数据的MSB优先串行化输出;同时集成复位安全策略和亚稳态消除电路。

  1. `timescale 1ns / 1ps  
  2. //////////////////////////////////////////////////////////////////////////////////  
  3. // 模块名称:I2S_driver  
  4. // 功能描述:I2S协议音频驱动控制器,支持带流量控制的数据传输  
  5. // 接口说明:  
  6. //   I_audio_valid:输入数据有效标志(高电平有效,需保持至O_data_req撤销)  
  7. //   O_data_req:数据请求信号(高脉冲宽度=1个系统时钟周期)  
  8. // 时钟特性:  
  9. //   O_i2s_BCLK = 主时钟 / (采样率 × 传输位宽 × 4)  
  10. //   O_i2s_LRCK = 采样率(每个周期包含AUDIO_WIDTH×2个BCLK周期)  
  11. //////////////////////////////////////////////////////////////////////////////////  
  12. module I2S_driver #(  
  13.     parameter I_CLK             = 50_000_000,   // 系统时钟频率(单位Hz)  
  14.     parameter AUDIO_BIT_DEPTH   = 24,           // 有效音频位深度(实际数据位数)  
  15.     parameter AUDIO_WIDTH       = 32,           // 传输位宽(每个声道的时钟数)  
  16.     parameter AUDIO_SAMPLE_RATE = 48000         // 音频采样率(单位Hz)   
  17. ) (  
  18.     // 系统接口  
  19.     input  wire                  I_clk,        // 主时钟(50MHz),上升沿有效  
  20.     input  wire                  I_reset_n,    // 异步低电平复位(0复位,1正常工作)  
  21.    
  22.     // 音频数据接口  
  23.     input  wire                        I_audio_valid,       // 输入数据有效标志(高电平锁存数据)  
  24.     input  wire [AUDIO_BIT_DEPTH-1:0]  I_audio_left_data,   // 左声道数据(二进制补码,LSB对齐)  
  25.     input  wire [AUDIO_BIT_DEPTH-1:0]  I_audio_right_data,  // 右声道数据(二进制补码,LSB对齐)  
  26.     output reg                         O_data_req,          // 数据请求信号(高电平请求新数据)  
  27.    
  28.     // I2S物理接口  
  29.     output reg                   O_i2s_BCLK,   // 位时钟(每个脉冲传输1bit数据)  
  30.     output reg                   O_i2s_LRCK,   // 声道时钟(低电平=左声道,高电平=右声道)  
  31.     output reg                   O_i2s_DOUT     // 串行数据输出(MSB优先,BCLK下降沿更新)  
  32. );   
  33. //================================ 状态机定义 ================================  
  34. localparam REQ_IDLE    = 2'b00; // 空闲状态:等待数据请求时机  
  35. localparam REQ_PENDING = 2'b01; // 请求状态:已发出O_data_req,等待数据到达  
  36. localparam REQ_DONE    = 2'b10; // 完成状态:数据已加载,等待传输完成  
  37. //================================ 寄存器定义 ================================  
  38. reg [7:0]    r_lrck_counter;     // LRCK分频计数器(计数范围:0~AUDIO_WIDTH-1)  
  39. reg [15:0]   r_bclk_counter;     // BCLK分频计数器(计数范围:0~BCLK_DIV-1)  
  40. reg [1:0]    r_current_state;    // 状态机当前状态  
  41. reg [1:0]    r_next_state;       // 状态机下一状态(组合逻辑)  
  42. reg [AUDIO_BIT_DEPTH-1:0] r_left_data;  // 左声道数据寄存器(缓存同步后的输入数据)  
  43. reg [AUDIO_BIT_DEPTH-1:0] r_right_data; // 右声道数据寄存器(缓存同步后的输入数据)  
  44. reg [AUDIO_BIT_DEPTH-1:0] r_shift_data; // 串行移位寄存器(MSB优先输出)  
  45. reg                 r_audio_valid;       // 同步后的有效信号(消除亚稳态)  
  46. reg [AUDIO_BIT_DEPTH-1:0] r_audio_left_data;   // 同步后的左声道数据(两级触发器同步)  
  47. reg [AUDIO_BIT_DEPTH-1:0] r_audio_right_data;  // 同步后的右声道数据(两级触发器同步)  
  48. //========================= BCLK分频系数计算(组合逻辑) ========================  
  49. localparam integer BCLK_DIV = I_CLK/(AUDIO_SAMPLE_RATE * AUDIO_WIDTH * 4);  
  50. // 公式说明:实际分频系数 = 系统时钟 / (采样率 × 传输位宽 × 4)   
  51. // 其中×4的原因:每个BCLK周期需要2个时钟边沿(上升/下降沿),且包含左右两个声道  
  52. //======================================================================  
  53. // BCLK生成模块(系统时钟域)  
  54. // 功能:通过分频计数器生成I2S位时钟  
  55. // 特征:  
  56. //   - 异步复位初始化  
  57. //   - 每个分频周期结束时翻转时钟信号  
  58. //======================================================================  
  59. always @(posedge I_clk or negedge I_reset_n) begin  
  60.     if (!I_reset_n)   // 异步复位初始化  
  61.         r_bclk_counter <= 16'h0;  
  62.     else if (r_bclk_counter >= (BCLK_DIV - 1))  // 达到分频周期最大值  
  63.         r_bclk_counter <= 16'h0;       // 计数器归零  
  64.     else   
  65.         r_bclk_counter <= r_bclk_counter + 16'h1;  // 计数器递增  
  66. end  
  67. always @(posedge I_clk or negedge I_reset_n) begin  
  68.     if (!I_reset_n)   
  69.         O_i2s_BCLK  <= 1'b0;  
  70.     else if (r_bclk_counter >= (BCLK_DIV - 1))  // 分频周期结束  
  71.         O_i2s_BCLK <= ~ O_i2s_BCLK;  // 翻转时钟信号(生成50%占空比)  
  72.     else   
  73.         O_i2s_BCLK <= O_i2s_BCLK;  // 保持当前电平  
  74. end  
  75. //======================================================================  
  76. // LRCK生成模块(BCLK时钟域)  
  77. // 功能:生成声道选择时钟信号  
  78. // 关键逻辑:  
  79. //   - 在BCLK下降沿更新计数器(确保数据稳定)  
  80. //   - 每个LRCK周期包含AUDIO_WIDTH个BCLK周期  
  81. //======================================================================  
  82. always @(negedge O_i2s_BCLK or negedge I_reset_n) begin  
  83.     if (!I_reset_n)   
  84.         r_lrck_counter <= 8'h0;  
  85.     else if (r_lrck_counter == (AUDIO_WIDTH - 1))  // 完成一个声道周期  
  86.         r_lrck_counter <= 8'h0;        // 计数器归零  
  87.     else   
  88.         r_lrck_counter <= r_lrck_counter + 8'h1;  // 计数器递增  
  89. end  
  90. always @(negedge O_i2s_BCLK or negedge I_reset_n) begin  
  91.     if (!I_reset_n)   
  92.         O_i2s_LRCK  <= 1'b0;       // 初始状态为右声道(I2S协议定义)  
  93.     else if (r_lrck_counter == (AUDIO_WIDTH - 1))  // 声道周期结束  
  94.         O_i2s_LRCK <= ~O_i2s_LRCK;  // 切换声道(0=左,1=右)  
  95.     else   
  96.         O_i2s_LRCK <= O_i2s_LRCK;  // 保持当前声道  
  97. end  
  98. //======================================================================  
  99. // 状态机控制模块(系统时钟域)  
  100. // 功能:管理数据请求和传输状态  
  101. // 状态转移条件:  
  102. //   IDLE→PENDING:在左声道开始前1个BCLK周期发出请求  
  103. //   PENDING→DONE :收到有效数据后进入传输状态  
  104. //   DONE→IDLE    :当前帧传输完成后回归空闲  
  105. //======================================================================  
  106. always @(posedge I_clk or negedge I_reset_n) begin  
  107.     if (!I_reset_n)   
  108.         r_current_state <= REQ_IDLE;  // 复位到初始状态  
  109.     else   
  110.         r_current_state <= r_next_state;  // 更新当前状态  
  111. end   
  112. // 状态转移组合逻辑  
  113. always @(*) begin  
  114.     case (r_current_state)  
  115.         REQ_IDLE: begin  
  116.             // 在左声道开始位置(LRCK=0且计数器=0)触发请求  
  117.             if (((r_lrck_counter == 0) && !O_i2s_LRCK))   
  118.                 r_next_state = REQ_PENDING;  
  119.             else   
  120.                 r_next_state = REQ_IDLE;  
  121.         end  
  122.         REQ_PENDING: begin  
  123.             // 收到有效数据后进入传输状态  
  124.             if (r_audio_valid)   
  125.                 r_next_state = REQ_DONE;  
  126.             else   
  127.                 r_next_state = REQ_PENDING;  
  128.         end  
  129.         REQ_DONE: begin  
  130.             // 等待当前帧传输完成(计数器达到最大值)  
  131.             if (r_lrck_counter == (AUDIO_WIDTH * 2 - 1))   
  132.                 r_next_state = REQ_IDLE;   
  133.             else   
  134.                 r_next_state = REQ_DONE;  
  135.         end  
  136.         default: r_next_state = REQ_IDLE; // 容错处理  
  137.     endcase  
  138. end  
  139. // 数据请求信号生成  
  140. always @(posedge I_clk or negedge I_reset_n) begin  
  141.      if (!I_reset_n)   
  142.         O_data_req <= 1'b0;  
  143.     else begin  
  144.         // 在左声道起始位置生成单周期脉冲  
  145.         if ((r_lrck_counter == 0) && !O_i2s_LRCK)   
  146.             O_data_req <= 1'b1;    // 断言请求信号  
  147.         else   
  148.             O_data_req <= 1'b0;    // 撤销请求信号  
  149.     end  
  150. end  
  151. //======================================================================  
  152. // 数据通道模块(跨时钟域处理)  
  153. // 包含:  
  154. //   1. 输入数据同步(系统时钟→BCLK时钟域)  
  155. //   2. 并行数据锁存  
  156. //   3. 串行移位输出  
  157. //======================================================================  
  158. // 输入数据同步(两级触发器消除亚稳态)  
  159. always @(posedge I_clk or negedge I_reset_n) begin  
  160.     if (!I_reset_n)   
  161.         r_audio_valid  <= 'b0;   
  162.     else   
  163.         r_audio_valid  <= I_audio_valid;     // 第一级同步  
  164. end   
  165. always @(posedge I_clk or negedge I_reset_n) begin  
  166.     if (!I_reset_n)   
  167.         r_audio_left_data  <= 'b0;   
  168.     else   
  169.         r_audio_left_data  <= I_audio_left_data;     // 左声道数据同步  
  170. end   
  171. always @(posedge I_clk or negedge I_reset_n) begin  
  172.     if (!I_reset_n)   
  173.         r_audio_right_data  <= 'b0;   
  174.     else   
  175.         r_audio_right_data  <= I_audio_right_data;  // 右声道数据同步  
  176. end   
  177. // 有效数据锁存(在r_audio_valid上升沿锁存)  
  178. always @(posedge I_clk or negedge I_reset_n) begin  
  179.     if (!I_reset_n)   
  180.         r_left_data  <= {AUDIO_BIT_DEPTH{1'b0}};   
  181.     else if (r_audio_valid)   
  182.         r_left_data  <= r_audio_left_data;     // 锁存左声道数据  
  183. end  
  184. always @(posedge I_clk or negedge I_reset_n) begin  
  185.     if (!I_reset_n)   
  186.         r_right_data <= {AUDIO_BIT_DEPTH{1'b0}};   
  187.     else if (r_audio_valid)   
  188.         r_right_data <= r_audio_right_data;    // 锁存右声道数据  
  189. end   
  190. // 串行移位输出逻辑(BCLK时钟域)  
  191. always @(posedge O_i2s_BCLK or negedge I_reset_n) begin  
  192.     if (!I_reset_n)   
  193.         r_shift_data  <= {AUDIO_BIT_DEPTH{1'b0}};   
  194.     else begin  
  195.         if (r_lrck_counter == 8'h0)   // 声道切换时刻  
  196.             // 根据LRCK状态加载对应声道数据  
  197.             r_shift_data <= O_i2s_LRCK ? r_right_data : r_left_data;  
  198.         else   
  199.             // 移位输出(丢弃已输出的高位,低位补0)  
  200.             r_shift_data <= {r_shift_data[AUDIO_BIT_DEPTH-2:0], 1'b0};   
  201.     end  
  202. end  
  203. // 数据输出驱动(BCLK下降沿更新)  
  204. always @(negedge O_i2s_BCLK or negedge I_reset_n) begin  
  205.     if (!I_reset_n)   
  206.         O_i2s_DOUT <= 1'b0;  
  207.     else   
  208.         O_i2s_DOUT <= r_shift_data[AUDIO_BIT_DEPTH-1]; // 输出当前最高有效位  
  209. end  
  210. endmodule
复制代码
6.2 I2S_receiver模块

I2S_receiver模块是I2S协议接收端的数字控制器,能够从I2S接口中精确解析音频数据。该模块通过两级同步消除BCLK/LRCK信号的亚稳态,利用边沿检测和位计数器在BCLK上升沿采集串行数据,支持16/24/32位可配置位深,自动跳过I2S协议的首个无效时钟相位。

其核心功能包括左右声道分离、MSB优先的串并转换,以及生成与系统时钟同步的单周期有效信号(O_audio_valid),适用于麦克风阵列、ADC芯片数据采集等嵌入式音频处理系统,具有抗时钟偏移、防数据错位的可靠性设计。

  1. `timescale 1ns / 1ps  
  2. //////////////////////////////////////////////////////////////////////////////////  
  3. // 模块名称:I2S_receiver  
  4. // 功能描述:I2S协议接收控制器,支持标准I2S格式音频数据解析  
  5. // 主要特性:  
  6. //   1. 自动检测BCLK/LRCK时钟边沿  
  7. //   2. 支持可配置音频位深(16/24/32位)  
  8. //   3. 跨时钟域数据同步处理  
  9. //   4. 有效数据标识生成  
  10. // 协议特征:  
  11. //   - LRCK低电平表示左声道,高电平表示右声道  
  12. //   - 数据在BCLK下降沿变化,上升沿采样  
  13. //   - 标准I2S格式跳过第一个BCLK上升沿  
  14. //////////////////////////////////////////////////////////////////////////////////  
  15. module I2S_receiver #(  
  16.     parameter BITDEEP = 24  // 有效音频位深度(实际采样位数),建议值16/24/32  
  17. ) (  
  18.     input wire I_clk,       // 系统主时钟(用于同步逻辑)  
  19.     input wire I_reset_n,   // 异步低电平复位(0复位,1正常工作)  
  20.     // I2S物理接口  
  21.     input wire I_i2s_BCLK,  // 位时钟输入(需低于系统时钟频率)  
  22.     input wire I_i2s_LRCK,  // 声道时钟输入(频率=采样率)  
  23.     input wire I_i2s_DOUT,  // 串行数据输入(MSB先行)  
  24.    
  25.     // 音频数据输出  
  26.     output reg               O_audio_valid,       // 有效数据标志(高脉冲宽度=1个系统时钟周期)  
  27.     output reg [BITDEEP-1:0] O_audio_left_data,  // 左声道数据(二进制补码,LSB对齐)  
  28.     output reg [BITDEEP-1:0] O_audio_right_data  // 右声道数据(二进制补码,LSB对齐)  
  29. );  
  30. //======================================================================  
  31. // 边沿检测信号  
  32. //======================================================================  
  33. wire w_bclk_peg;  // BCLK上升沿检测(用于数据采样)  
  34. wire w_bclk_neg;  // BCLK下降沿检测(用于计数器递增)  
  35. wire w_lrck_peg;  // LRCK上升沿检测(右声道开始)  
  36. wire w_lrck_neg;  // LRCK下降沿检测(左声道开始)  
  37. //======================================================================  
  38. // 跨时钟域同步寄存器  
  39. //======================================================================  
  40. reg r_i2s_BCLK;   // 第一级同步寄存器(BCLK信号)  
  41. reg r_i2s_LRCK;   // 第一级同步寄存器(LRCK信号)  
  42. reg r_i2s_DOUT;   // 第一级同步寄存器(DOUT信号)  
  43. reg rr_i2s_BCLK;  // 第二级同步寄存器(消除亚稳态)  
  44. reg rr_i2s_LRCK;  // 第二级同步寄存器(消除亚稳态)  
  45. reg rr_i2s_DOUT;  // 第二级同步寄存器(消除亚稳态)  
  46. //======================================================================  
  47. // 数据采集控制寄存器  
  48. //======================================================================  
  49. reg [5:0] r_DOUT_cunt;        // 数据位计数器(范围0-63,支持最大32位位深)  
  50. reg        r_audio_valid;     // 有效信号中间寄存器  
  51. reg [BITDEEP-1:0] r_audio_left_data;   // 左声道数据缓存  
  52. reg [BITDEEP-1:0] r_audio_right_data;  // 右声道数据缓存  
  53. //======================================================================  
  54. // 边沿检测组合逻辑  
  55. //======================================================================  
  56. assign w_bclk_peg = r_i2s_BCLK && ~rr_i2s_BCLK;  // BCLK上升沿:前拍低且当前拍高  
  57. assign w_bclk_neg = ~r_i2s_BCLK && rr_i2s_BCLK;  // BCLK下降沿:前拍高且当前拍低  
  58. assign w_lrck_peg = r_i2s_LRCK && ~rr_i2s_LRCK;  // LRCK上升沿(右声道开始)  
  59. assign w_lrck_neg = ~r_i2s_LRCK && rr_i2s_LRCK;  // LRCK下降沿(左声道开始)  
  60. //======================================================================  
  61. // 输入信号同步模块(防止亚稳态)  
  62. // 功能:将异步I2S信号同步到系统时钟域  
  63. // 策略:两级触发器串联,间隔至少1个系统时钟周期  
  64. //======================================================================  
  65. always @(posedge I_clk or negedge I_reset_n) begin  
  66.     if (~I_reset_n) begin  // 异步复位初始化  
  67.         {r_i2s_BCLK, rr_i2s_BCLK} <= 2'b00;  
  68.         {r_i2s_LRCK, rr_i2s_LRCK} <= 2'b00;  
  69.         {r_i2s_DOUT, rr_i2s_DOUT} <= 2'b00;  
  70.     end   
  71.     else begin  // 时钟沿同步  
  72.         // 第一级同步  
  73.         r_i2s_BCLK  <= I_i2s_BCLK;  // BCLK输入同步  
  74.         r_i2s_LRCK  <= I_i2s_LRCK;  // LRCK输入同步  
  75.         r_i2s_DOUT  <= I_i2s_DOUT;  // DOUT输入同步  
  76.         
  77.         // 第二级同步  
  78.         rr_i2s_BCLK <= r_i2s_BCLK;  // 消除亚稳态  
  79.         rr_i2s_LRCK <= r_i2s_LRCK;  // 消除亚稳态  
  80.         rr_i2s_DOUT <= r_i2s_DOUT;  // 消除亚稳态  
  81.     end  
  82. end  
  83. //======================================================================  
  84. // 数据位计数器模块  
  85. // 功能:统计每个声道周期内的有效数据位数  
  86. // 特征:  
  87. //   - LRCK边沿复位计数器  
  88. //   - BCLK下降沿递增计数  
  89. //======================================================================  
  90. always @(posedge I_clk or negedge I_reset_n) begin  
  91.     if (~I_reset_n)   
  92.         r_DOUT_cunt <= 'b0;  // 复位清零  
  93.     else if (w_bclk_neg & (~w_lrck_neg && ~w_lrck_peg))  // BCLK下降沿且无LRCK跳变  
  94.         r_DOUT_cunt <= r_DOUT_cunt + 1;  // 计数器递增  
  95.     else if (w_lrck_neg | w_lrck_peg)  // LRCK边沿(声道切换)  
  96.         r_DOUT_cunt <= 'b0;  // 计数器复位  
  97.     else   
  98.         r_DOUT_cunt <= r_DOUT_cunt;  // 保持当前值  
  99. end  
  100. //======================================================================  
  101. // 左声道数据采集模块  
  102. // 采集时机:BCLK上升沿 + 左声道周期(LRCK=0) + 有效数据位区间  
  103. // 数据格式:MSB先行,持续移位存储  
  104. //======================================================================  
  105. always @(posedge I_clk or negedge I_reset_n) begin  
  106.     if (~I_reset_n)   
  107.         r_audio_left_data <= 'b0;  // 复位清零  
  108.     // 左声道有效数据位(跳过第一个BCLK上升沿)  
  109.     else if (w_bclk_peg & ~rr_i2s_LRCK & r_DOUT_cunt >= 6'd1 & r_DOUT_cunt <= BITDEEP)   
  110.         r_audio_left_data <= {r_audio_left_data[BITDEEP-2:0], rr_i2s_DOUT};  // 左移位存储  
  111.     else   
  112.         r_audio_left_data <= r_audio_left_data;  // 保持当前值  
  113. end  
  114. //======================================================================  
  115. // 右声道数据采集模块  
  116. // 采集时机:BCLK上升沿 + 右声道周期(LRCK=1) + 有效数据位区间  
  117. //======================================================================  
  118. always @(posedge I_clk or negedge I_reset_n) begin  
  119.     if (~I_reset_n)   
  120.         r_audio_right_data <= 'b0;  // 复位清零  
  121.     // 右声道有效数据位(跳过第一个BCLK上升沿)  
  122.     else if (w_bclk_peg & rr_i2s_LRCK & r_DOUT_cunt >= 6'd1 & r_DOUT_cunt <= BITDEEP)   
  123.         r_audio_right_data <= {r_audio_right_data[BITDEEP-2:0], rr_i2s_DOUT};  // 左移位存储  
  124.     else   
  125.         r_audio_right_data <= r_audio_right_data;  // 保持当前值  
  126. end  
  127. //======================================================================  
  128. // 有效信号生成模块  
  129. // 生成逻辑:当完成BITDEEP位数据采集后,生成单周期有效脉冲  
  130. // 同步策略:在系统时钟域生成,保证输出信号稳定性  
  131. //======================================================================  
  132. always @(posedge I_clk or negedge I_reset_n) begin  
  133.     if (~I_reset_n)   
  134.         r_audio_valid <= 'b0;  // 复位清零  
  135.     // 右声道数据采集完成时生成有效信号(BITDEEP+1对应最后一位)  
  136.     else if (w_bclk_peg & rr_i2s_LRCK & r_DOUT_cunt == BITDEEP + 1)   
  137.         r_audio_valid <= 'b1;  // 断言有效信号  
  138.     else   
  139.         r_audio_valid <= 'b0;  // 撤销有效信号  
  140. end  
  141. //======================================================================  
  142. // 输出数据锁存模块  
  143. // 功能:在有效信号上升沿锁存数据,保证输出稳定性  
  144. // 时序:与系统时钟同步,消除亚稳态风险  
  145. //======================================================================  
  146. // 左声道数据输出锁存  
  147. always @(posedge I_clk or negedge I_reset_n) begin  
  148.     if (~I_reset_n)   
  149.         O_audio_left_data <= 'b0;  // 复位清零  
  150.     else if (r_audio_valid)   
  151.         O_audio_left_data <= r_audio_left_data;  // 锁存有效数据  
  152.     else   
  153.         O_audio_left_data <= 'b0;  // 非有效期输出清零  
  154. end  
  155. // 右声道数据输出锁存  
  156. always @(posedge I_clk or negedge I_reset_n) begin  
  157.     if (~I_reset_n)   
  158.         O_audio_right_data <= 'b0;  // 复位清零  
  159.     else if (r_audio_valid)   
  160.         O_audio_right_data <= r_audio_right_data;  // 锁存有效数据  
  161.     else   
  162.         O_audio_right_data <= 'b0;  // 非有效期输出清零  
  163. end  
  164. // 有效信号输出锁存  
  165. always @(posedge I_clk or negedge I_reset_n) begin  
  166.     if (~I_reset_n)   
  167.         O_audio_valid <= 'b0;  // 复位清零  
  168.     else   
  169.         O_audio_valid <= r_audio_valid;  // 直接传递有效信号  
  170. end  
  171. endmodule
复制代码
7 I2S/发模块仿真7.1 I2S_driver仿真

I2S_driver仿真结果:通过O_data_req获取I_audio_left_data[23:0]I_audio_right_data[23:0]数据,然后经过I2S协议转换通过O_i2s_BCLKO_i2s_LRCKO_i2s_DOUT发送出去。

640?wx_fmt=png&from=appmsg
7.2 I2S_receiver仿真

I2S_receiver 仿真结果:I2S_receiver模块的作用是接收I2S_driver发送过来的I2S协议数据,然后转换成O_audio_left_data[23:0]O_audio_right_data[23:0]左右声道信号,并且产生1时钟周期的vaild信号O_audio_valid

640?wx_fmt=png&from=appmsg

通过仿真可以看出,I2S_driver接收到的模拟的音频信号是24h7FFFF0,经过I2S_receiver 模块解析,得到的有效数据展开看也是24h7FFFF0。两个模块的功能无误。

640?wx_fmt=png&from=appmsg


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

0

关注

0

粉丝

303

主题
精彩推荐
热门资讯
网友晒图
图文推荐

  • 微信公众平台

  • 扫描访问手机版