本帖最后由 UT发布 于 2025-5-12 11:11 编辑
1音频传输概念I2S(Inter-IC Sound)是由飞利浦公司(现NXP)制定的数字音频传输标准,主要用于集成电路间的PCM音频数据传输。该协议规范了数据格式、时钟同步和电气接口三大要素。 音频采集(RX方向):
麦克风→前置放大→抗混叠滤波→ADC采样(16/24bit位深)→I2S传输至处理器。此模式下,ADC通常作为时钟主设备(Master)。 音频播放(TX方向):
处理器解码音频→I2S传输至DAC→模拟信号重建→功率放大→扬声器输出。此时处理器常作为时钟主设备。 接口结构: SCK(位时钟):频率 = 2×采样率×位宽 LRCK(帧同步):频率 = 采样率 SD(数据线):双向传输通道 技术优势: 支持44.1kHz/48kHz/96kHz采样率 时钟抖动容限<1ns 兼容TDM扩展协议(多声道传输) 工作模式: 典型应用:
2 I2S协议
2.1 I2S基本信号I2S协议基本时序关系
如上图所示,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上升沿前1个SCK周期开始;高电平周期对应右声道,数据窗口持续至LRCK下降沿后1个SCK周期结束。 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) 包含数据封装与时序规范: 标准I2S:LRCK变化后延迟1个SCK周期开始传输MSB 左对齐:MSB对齐LRCK边沿,减少传输延迟 右对齐:LSB对齐LRCK边沿,兼容早期DSP架构 声道顺序:标准协议默认左声道优先,可配置为右声道前置 3主从工作模式I2S工作模式可以是主模式(Master Mode)或从模式(Slave Mode)。两者唯一的区别是:Master Mode提供时钟信号(SCK)和帧同步信号(LRCK)。如下图所示,一共存在三种工作模式,分别是: 1.发射器(transmitter)为Master,接收器(receiver)为Slave,此时由发射器提供SCK和LRCK 2.接收器(receiver)为Master,发射器(transmitter)为Slave,此时由接收器提供SCK和LRCK 3.发射器(transmitter)和接收器(receiver)均为Slave,由系统中其他模块提供SCK和LRCK
4数据传输模式I2S接口标准中,存在三种数据传输模式,分别是:飞利浦标准模式(I2S mode),左对齐(Left Justified)和右对齐(Right Justified)三种传输模式。 4.1飞利浦标准(I2S)模式
I2S标准模式接口时序
其主要特点如下: (1)LRCK(左右声道选择信号):LRCK信号用于指示当前数据帧是左声道数据还是右声道数据。飞利浦格式中,当LRCK为低时,表示当前传输的数据是左声道数据;当LRCK为高时,表示当前传输的数据为右声道数据 (2)SCK(位时钟):数据传输的时钟信号。在SCK下降沿发送数据,在SCK上升沿采样数据 (3)Data Delay:发送的有效数据相对于LRCK的跳变沿(从0到1或从1到0)延迟一个时钟周期 (4)数据发送从MSB开始;数据MSB与LRCK delay 1个SCK的边沿对齐 4.2左对齐(Left Justified)模式
左对齐模式接口时序 其主要特点如下 (1)在左对齐格式中,LRCK为高时,表示当前传输的数据为左声道数据;当LRCK为低时,表示当前传输的数据为右声道数据 (2)在SCK下降沿发送数据,在SCK上升沿接收数据 (3)无data delay:发送的有效数据相当于LRCK跳变沿(从0到1或从1到0)不延迟 (4)数据发送从MSB开始;数据MSB与LRCK跳变沿对齐 4.3右对齐(Right Justified)模式
右对齐模式接口时序 其主要特点如下 (1)右对齐格式中,LRCK为高电平时,表示当前传输的数据为右声道数据;当LRCK为低电平时,表示当前传输的数据为左声道数据 (2)在SCK下降沿发送数据,在SCK上升沿接收数据 (3)无Data delay:发送的有效数据相当于LRCK跳变沿(从0到1或从1到0)不延迟 (4)数据发送从MSB开始;数据LSB与LRCK跳变沿对齐 5数据位宽与位深(1)位宽:根据SCK与LRCK的关系: 采样频率位宽位宽
位宽一般为16位或32位 (2)位深:表示音频数据量化后的精度 需要注意的是,I2S中位宽和位深都是由Master决定的。因此在使用时需要先确定本模块在系统中的工作模式(Master or Slave)。下面以32位位宽,32/24/20/16位位深为例,说明位宽与位深的区别(以下例子的数据格式均为I2S格式) 32位位宽,32位位深:
32位位宽,24位位深:
32位位宽,20位位深:
32位位宽,16位位深:
6 I2S收/发模块代码
6.1 I2S_driver模块I2S_driver模块是一个基于Verilog实现的I2S协议发送控制器,主要用于驱动音频数据传输。该模块通过系统时钟生成符合I2S标准的位时钟(BCLK)和声道时钟(LRCK),支持可配置的音频位深(16/24/32位)和采样率(44.1kHz/48kHz等)。 其核心功能包括:通过三段式状态机实现智能数据预请求机制,在声道切换前主动触发外部数据供给;采用双时钟域架构处理跨时钟域同步,通过移位寄存器实现并行音频数据的MSB优先串行化输出;同时集成复位安全策略和亚稳态消除电路。
- `timescale 1ns / 1ps
-
- //////////////////////////////////////////////////////////////////////////////////
- // 模块名称:I2S_driver
- // 功能描述:I2S协议音频驱动控制器,支持带流量控制的数据传输
- // 接口说明:
- // I_audio_valid:输入数据有效标志(高电平有效,需保持至O_data_req撤销)
- // O_data_req:数据请求信号(高脉冲宽度=1个系统时钟周期)
- // 时钟特性:
- // O_i2s_BCLK = 主时钟 / (采样率 × 传输位宽 × 4)
- // O_i2s_LRCK = 采样率(每个周期包含AUDIO_WIDTH×2个BCLK周期)
- //////////////////////////////////////////////////////////////////////////////////
-
- module I2S_driver #(
- parameter I_CLK = 50_000_000, // 系统时钟频率(单位Hz)
- parameter AUDIO_BIT_DEPTH = 24, // 有效音频位深度(实际数据位数)
- parameter AUDIO_WIDTH = 32, // 传输位宽(每个声道的时钟数)
- parameter AUDIO_SAMPLE_RATE = 48000 // 音频采样率(单位Hz)
- ) (
- // 系统接口
- input wire I_clk, // 主时钟(50MHz),上升沿有效
- input wire I_reset_n, // 异步低电平复位(0复位,1正常工作)
-
- // 音频数据接口
- input wire I_audio_valid, // 输入数据有效标志(高电平锁存数据)
- input wire [AUDIO_BIT_DEPTH-1:0] I_audio_left_data, // 左声道数据(二进制补码,LSB对齐)
- input wire [AUDIO_BIT_DEPTH-1:0] I_audio_right_data, // 右声道数据(二进制补码,LSB对齐)
- output reg O_data_req, // 数据请求信号(高电平请求新数据)
-
- // I2S物理接口
- output reg O_i2s_BCLK, // 位时钟(每个脉冲传输1bit数据)
- output reg O_i2s_LRCK, // 声道时钟(低电平=左声道,高电平=右声道)
- output reg O_i2s_DOUT // 串行数据输出(MSB优先,BCLK下降沿更新)
- );
-
- //================================ 状态机定义 ================================
- localparam REQ_IDLE = 2'b00; // 空闲状态:等待数据请求时机
- localparam REQ_PENDING = 2'b01; // 请求状态:已发出O_data_req,等待数据到达
- localparam REQ_DONE = 2'b10; // 完成状态:数据已加载,等待传输完成
-
- //================================ 寄存器定义 ================================
- reg [7:0] r_lrck_counter; // LRCK分频计数器(计数范围:0~AUDIO_WIDTH-1)
- reg [15:0] r_bclk_counter; // BCLK分频计数器(计数范围:0~BCLK_DIV-1)
- reg [1:0] r_current_state; // 状态机当前状态
- reg [1:0] r_next_state; // 状态机下一状态(组合逻辑)
-
- reg [AUDIO_BIT_DEPTH-1:0] r_left_data; // 左声道数据寄存器(缓存同步后的输入数据)
- reg [AUDIO_BIT_DEPTH-1:0] r_right_data; // 右声道数据寄存器(缓存同步后的输入数据)
- reg [AUDIO_BIT_DEPTH-1:0] r_shift_data; // 串行移位寄存器(MSB优先输出)
-
- reg r_audio_valid; // 同步后的有效信号(消除亚稳态)
- reg [AUDIO_BIT_DEPTH-1:0] r_audio_left_data; // 同步后的左声道数据(两级触发器同步)
- reg [AUDIO_BIT_DEPTH-1:0] r_audio_right_data; // 同步后的右声道数据(两级触发器同步)
-
- //========================= BCLK分频系数计算(组合逻辑) ========================
- localparam integer BCLK_DIV = I_CLK/(AUDIO_SAMPLE_RATE * AUDIO_WIDTH * 4);
- // 公式说明:实际分频系数 = 系统时钟 / (采样率 × 传输位宽 × 4)
- // 其中×4的原因:每个BCLK周期需要2个时钟边沿(上升/下降沿),且包含左右两个声道
-
- //======================================================================
- // BCLK生成模块(系统时钟域)
- // 功能:通过分频计数器生成I2S位时钟
- // 特征:
- // - 异步复位初始化
- // - 每个分频周期结束时翻转时钟信号
- //======================================================================
- always @(posedge I_clk or negedge I_reset_n) begin
- if (!I_reset_n) // 异步复位初始化
- r_bclk_counter <= 16'h0;
- else if (r_bclk_counter >= (BCLK_DIV - 1)) // 达到分频周期最大值
- r_bclk_counter <= 16'h0; // 计数器归零
- else
- r_bclk_counter <= r_bclk_counter + 16'h1; // 计数器递增
- end
-
- always @(posedge I_clk or negedge I_reset_n) begin
- if (!I_reset_n)
- O_i2s_BCLK <= 1'b0;
- else if (r_bclk_counter >= (BCLK_DIV - 1)) // 分频周期结束
- O_i2s_BCLK <= ~ O_i2s_BCLK; // 翻转时钟信号(生成50%占空比)
- else
- O_i2s_BCLK <= O_i2s_BCLK; // 保持当前电平
- end
-
- //======================================================================
- // LRCK生成模块(BCLK时钟域)
- // 功能:生成声道选择时钟信号
- // 关键逻辑:
- // - 在BCLK下降沿更新计数器(确保数据稳定)
- // - 每个LRCK周期包含AUDIO_WIDTH个BCLK周期
- //======================================================================
- always @(negedge O_i2s_BCLK or negedge I_reset_n) begin
- if (!I_reset_n)
- r_lrck_counter <= 8'h0;
- else if (r_lrck_counter == (AUDIO_WIDTH - 1)) // 完成一个声道周期
- r_lrck_counter <= 8'h0; // 计数器归零
- else
- r_lrck_counter <= r_lrck_counter + 8'h1; // 计数器递增
- end
-
- always @(negedge O_i2s_BCLK or negedge I_reset_n) begin
- if (!I_reset_n)
- O_i2s_LRCK <= 1'b0; // 初始状态为右声道(I2S协议定义)
- else if (r_lrck_counter == (AUDIO_WIDTH - 1)) // 声道周期结束
- O_i2s_LRCK <= ~O_i2s_LRCK; // 切换声道(0=左,1=右)
- else
- O_i2s_LRCK <= O_i2s_LRCK; // 保持当前声道
- end
-
- //======================================================================
- // 状态机控制模块(系统时钟域)
- // 功能:管理数据请求和传输状态
- // 状态转移条件:
- // IDLE→PENDING:在左声道开始前1个BCLK周期发出请求
- // PENDING→DONE :收到有效数据后进入传输状态
- // DONE→IDLE :当前帧传输完成后回归空闲
- //======================================================================
- always @(posedge I_clk or negedge I_reset_n) begin
- if (!I_reset_n)
- r_current_state <= REQ_IDLE; // 复位到初始状态
- else
- r_current_state <= r_next_state; // 更新当前状态
- end
-
- // 状态转移组合逻辑
- always @(*) begin
- case (r_current_state)
- REQ_IDLE: begin
- // 在左声道开始位置(LRCK=0且计数器=0)触发请求
- if (((r_lrck_counter == 0) && !O_i2s_LRCK))
- r_next_state = REQ_PENDING;
- else
- r_next_state = REQ_IDLE;
- end
- REQ_PENDING: begin
- // 收到有效数据后进入传输状态
- if (r_audio_valid)
- r_next_state = REQ_DONE;
- else
- r_next_state = REQ_PENDING;
- end
- REQ_DONE: begin
- // 等待当前帧传输完成(计数器达到最大值)
- if (r_lrck_counter == (AUDIO_WIDTH * 2 - 1))
- r_next_state = REQ_IDLE;
- else
- r_next_state = REQ_DONE;
- end
- default: r_next_state = REQ_IDLE; // 容错处理
- endcase
- end
-
- // 数据请求信号生成
- always @(posedge I_clk or negedge I_reset_n) begin
- if (!I_reset_n)
- O_data_req <= 1'b0;
- else begin
- // 在左声道起始位置生成单周期脉冲
- if ((r_lrck_counter == 0) && !O_i2s_LRCK)
- O_data_req <= 1'b1; // 断言请求信号
- else
- O_data_req <= 1'b0; // 撤销请求信号
- end
- end
-
- //======================================================================
- // 数据通道模块(跨时钟域处理)
- // 包含:
- // 1. 输入数据同步(系统时钟→BCLK时钟域)
- // 2. 并行数据锁存
- // 3. 串行移位输出
- //======================================================================
- // 输入数据同步(两级触发器消除亚稳态)
- always @(posedge I_clk or negedge I_reset_n) begin
- if (!I_reset_n)
- r_audio_valid <= 'b0;
- else
- r_audio_valid <= I_audio_valid; // 第一级同步
- end
-
- always @(posedge I_clk or negedge I_reset_n) begin
- if (!I_reset_n)
- r_audio_left_data <= 'b0;
- else
- r_audio_left_data <= I_audio_left_data; // 左声道数据同步
- end
-
- always @(posedge I_clk or negedge I_reset_n) begin
- if (!I_reset_n)
- r_audio_right_data <= 'b0;
- else
- r_audio_right_data <= I_audio_right_data; // 右声道数据同步
- end
-
- // 有效数据锁存(在r_audio_valid上升沿锁存)
- always @(posedge I_clk or negedge I_reset_n) begin
- if (!I_reset_n)
- r_left_data <= {AUDIO_BIT_DEPTH{1'b0}};
- else if (r_audio_valid)
- r_left_data <= r_audio_left_data; // 锁存左声道数据
- end
-
- always @(posedge I_clk or negedge I_reset_n) begin
- if (!I_reset_n)
- r_right_data <= {AUDIO_BIT_DEPTH{1'b0}};
- else if (r_audio_valid)
- r_right_data <= r_audio_right_data; // 锁存右声道数据
- end
-
- // 串行移位输出逻辑(BCLK时钟域)
- always @(posedge O_i2s_BCLK or negedge I_reset_n) begin
- if (!I_reset_n)
- r_shift_data <= {AUDIO_BIT_DEPTH{1'b0}};
- else begin
- if (r_lrck_counter == 8'h0) // 声道切换时刻
- // 根据LRCK状态加载对应声道数据
- r_shift_data <= O_i2s_LRCK ? r_right_data : r_left_data;
- else
- // 移位输出(丢弃已输出的高位,低位补0)
- r_shift_data <= {r_shift_data[AUDIO_BIT_DEPTH-2:0], 1'b0};
- end
- end
-
- // 数据输出驱动(BCLK下降沿更新)
- always @(negedge O_i2s_BCLK or negedge I_reset_n) begin
- if (!I_reset_n)
- O_i2s_DOUT <= 1'b0;
- else
- O_i2s_DOUT <= r_shift_data[AUDIO_BIT_DEPTH-1]; // 输出当前最高有效位
- end
-
- endmodule
复制代码
6.2 I2S_receiver模块I2S_receiver模块是I2S协议接收端的数字控制器,能够从I2S接口中精确解析音频数据。该模块通过两级同步消除BCLK/LRCK信号的亚稳态,利用边沿检测和位计数器在BCLK上升沿采集串行数据,支持16/24/32位可配置位深,自动跳过I2S协议的首个无效时钟相位。 其核心功能包括左右声道分离、MSB优先的串并转换,以及生成与系统时钟同步的单周期有效信号(O_audio_valid),适用于麦克风阵列、ADC芯片数据采集等嵌入式音频处理系统,具有抗时钟偏移、防数据错位的可靠性设计。 - `timescale 1ns / 1ps
-
- //////////////////////////////////////////////////////////////////////////////////
- // 模块名称:I2S_receiver
- // 功能描述:I2S协议接收控制器,支持标准I2S格式音频数据解析
- // 主要特性:
- // 1. 自动检测BCLK/LRCK时钟边沿
- // 2. 支持可配置音频位深(16/24/32位)
- // 3. 跨时钟域数据同步处理
- // 4. 有效数据标识生成
- // 协议特征:
- // - LRCK低电平表示左声道,高电平表示右声道
- // - 数据在BCLK下降沿变化,上升沿采样
- // - 标准I2S格式跳过第一个BCLK上升沿
- //////////////////////////////////////////////////////////////////////////////////
-
- module I2S_receiver #(
- parameter BITDEEP = 24 // 有效音频位深度(实际采样位数),建议值16/24/32
- ) (
- input wire I_clk, // 系统主时钟(用于同步逻辑)
- input wire I_reset_n, // 异步低电平复位(0复位,1正常工作)
-
- // I2S物理接口
- input wire I_i2s_BCLK, // 位时钟输入(需低于系统时钟频率)
- input wire I_i2s_LRCK, // 声道时钟输入(频率=采样率)
- input wire I_i2s_DOUT, // 串行数据输入(MSB先行)
-
- // 音频数据输出
- output reg O_audio_valid, // 有效数据标志(高脉冲宽度=1个系统时钟周期)
- output reg [BITDEEP-1:0] O_audio_left_data, // 左声道数据(二进制补码,LSB对齐)
- output reg [BITDEEP-1:0] O_audio_right_data // 右声道数据(二进制补码,LSB对齐)
- );
-
- //======================================================================
- // 边沿检测信号
- //======================================================================
- wire w_bclk_peg; // BCLK上升沿检测(用于数据采样)
- wire w_bclk_neg; // BCLK下降沿检测(用于计数器递增)
- wire w_lrck_peg; // LRCK上升沿检测(右声道开始)
- wire w_lrck_neg; // LRCK下降沿检测(左声道开始)
-
- //======================================================================
- // 跨时钟域同步寄存器
- //======================================================================
- reg r_i2s_BCLK; // 第一级同步寄存器(BCLK信号)
- reg r_i2s_LRCK; // 第一级同步寄存器(LRCK信号)
- reg r_i2s_DOUT; // 第一级同步寄存器(DOUT信号)
- reg rr_i2s_BCLK; // 第二级同步寄存器(消除亚稳态)
- reg rr_i2s_LRCK; // 第二级同步寄存器(消除亚稳态)
- reg rr_i2s_DOUT; // 第二级同步寄存器(消除亚稳态)
-
- //======================================================================
- // 数据采集控制寄存器
- //======================================================================
- reg [5:0] r_DOUT_cunt; // 数据位计数器(范围0-63,支持最大32位位深)
- reg r_audio_valid; // 有效信号中间寄存器
- reg [BITDEEP-1:0] r_audio_left_data; // 左声道数据缓存
- reg [BITDEEP-1:0] r_audio_right_data; // 右声道数据缓存
-
- //======================================================================
- // 边沿检测组合逻辑
- //======================================================================
- assign w_bclk_peg = r_i2s_BCLK && ~rr_i2s_BCLK; // BCLK上升沿:前拍低且当前拍高
- assign w_bclk_neg = ~r_i2s_BCLK && rr_i2s_BCLK; // BCLK下降沿:前拍高且当前拍低
- assign w_lrck_peg = r_i2s_LRCK && ~rr_i2s_LRCK; // LRCK上升沿(右声道开始)
- assign w_lrck_neg = ~r_i2s_LRCK && rr_i2s_LRCK; // LRCK下降沿(左声道开始)
-
- //======================================================================
- // 输入信号同步模块(防止亚稳态)
- // 功能:将异步I2S信号同步到系统时钟域
- // 策略:两级触发器串联,间隔至少1个系统时钟周期
- //======================================================================
- always @(posedge I_clk or negedge I_reset_n) begin
- if (~I_reset_n) begin // 异步复位初始化
- {r_i2s_BCLK, rr_i2s_BCLK} <= 2'b00;
- {r_i2s_LRCK, rr_i2s_LRCK} <= 2'b00;
- {r_i2s_DOUT, rr_i2s_DOUT} <= 2'b00;
- end
- else begin // 时钟沿同步
- // 第一级同步
- r_i2s_BCLK <= I_i2s_BCLK; // BCLK输入同步
- r_i2s_LRCK <= I_i2s_LRCK; // LRCK输入同步
- r_i2s_DOUT <= I_i2s_DOUT; // DOUT输入同步
-
- // 第二级同步
- rr_i2s_BCLK <= r_i2s_BCLK; // 消除亚稳态
- rr_i2s_LRCK <= r_i2s_LRCK; // 消除亚稳态
- rr_i2s_DOUT <= r_i2s_DOUT; // 消除亚稳态
- end
- end
-
- //======================================================================
- // 数据位计数器模块
- // 功能:统计每个声道周期内的有效数据位数
- // 特征:
- // - LRCK边沿复位计数器
- // - BCLK下降沿递增计数
- //======================================================================
- always @(posedge I_clk or negedge I_reset_n) begin
- if (~I_reset_n)
- r_DOUT_cunt <= 'b0; // 复位清零
- else if (w_bclk_neg & (~w_lrck_neg && ~w_lrck_peg)) // BCLK下降沿且无LRCK跳变
- r_DOUT_cunt <= r_DOUT_cunt + 1; // 计数器递增
- else if (w_lrck_neg | w_lrck_peg) // LRCK边沿(声道切换)
- r_DOUT_cunt <= 'b0; // 计数器复位
- else
- r_DOUT_cunt <= r_DOUT_cunt; // 保持当前值
- end
-
- //======================================================================
- // 左声道数据采集模块
- // 采集时机:BCLK上升沿 + 左声道周期(LRCK=0) + 有效数据位区间
- // 数据格式:MSB先行,持续移位存储
- //======================================================================
- always @(posedge I_clk or negedge I_reset_n) begin
- if (~I_reset_n)
- r_audio_left_data <= 'b0; // 复位清零
- // 左声道有效数据位(跳过第一个BCLK上升沿)
- else if (w_bclk_peg & ~rr_i2s_LRCK & r_DOUT_cunt >= 6'd1 & r_DOUT_cunt <= BITDEEP)
- r_audio_left_data <= {r_audio_left_data[BITDEEP-2:0], rr_i2s_DOUT}; // 左移位存储
- else
- r_audio_left_data <= r_audio_left_data; // 保持当前值
- end
-
- //======================================================================
- // 右声道数据采集模块
- // 采集时机:BCLK上升沿 + 右声道周期(LRCK=1) + 有效数据位区间
- //======================================================================
- always @(posedge I_clk or negedge I_reset_n) begin
- if (~I_reset_n)
- r_audio_right_data <= 'b0; // 复位清零
- // 右声道有效数据位(跳过第一个BCLK上升沿)
- else if (w_bclk_peg & rr_i2s_LRCK & r_DOUT_cunt >= 6'd1 & r_DOUT_cunt <= BITDEEP)
- r_audio_right_data <= {r_audio_right_data[BITDEEP-2:0], rr_i2s_DOUT}; // 左移位存储
- else
- r_audio_right_data <= r_audio_right_data; // 保持当前值
- end
-
- //======================================================================
- // 有效信号生成模块
- // 生成逻辑:当完成BITDEEP位数据采集后,生成单周期有效脉冲
- // 同步策略:在系统时钟域生成,保证输出信号稳定性
- //======================================================================
- always @(posedge I_clk or negedge I_reset_n) begin
- if (~I_reset_n)
- r_audio_valid <= 'b0; // 复位清零
- // 右声道数据采集完成时生成有效信号(BITDEEP+1对应最后一位)
- else if (w_bclk_peg & rr_i2s_LRCK & r_DOUT_cunt == BITDEEP + 1)
- r_audio_valid <= 'b1; // 断言有效信号
- else
- r_audio_valid <= 'b0; // 撤销有效信号
- end
-
- //======================================================================
- // 输出数据锁存模块
- // 功能:在有效信号上升沿锁存数据,保证输出稳定性
- // 时序:与系统时钟同步,消除亚稳态风险
- //======================================================================
- // 左声道数据输出锁存
- always @(posedge I_clk or negedge I_reset_n) begin
- if (~I_reset_n)
- O_audio_left_data <= 'b0; // 复位清零
- else if (r_audio_valid)
- O_audio_left_data <= r_audio_left_data; // 锁存有效数据
- else
- O_audio_left_data <= 'b0; // 非有效期输出清零
- end
-
- // 右声道数据输出锁存
- always @(posedge I_clk or negedge I_reset_n) begin
- if (~I_reset_n)
- O_audio_right_data <= 'b0; // 复位清零
- else if (r_audio_valid)
- O_audio_right_data <= r_audio_right_data; // 锁存有效数据
- else
- O_audio_right_data <= 'b0; // 非有效期输出清零
- end
-
- // 有效信号输出锁存
- always @(posedge I_clk or negedge I_reset_n) begin
- if (~I_reset_n)
- O_audio_valid <= 'b0; // 复位清零
- else
- O_audio_valid <= r_audio_valid; // 直接传递有效信号
- end
-
- 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_BCLK、O_i2s_LRCK、O_i2s_DOUT发送出去。
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。
通过仿真可以看出,I2S_driver接收到的模拟的音频信号是24’h7FFFF0,经过I2S_receiver 模块解析,得到的有效数据展开看也是24’h7FFFF0。两个模块的功能无误。
|