草庐IT

基于FPGA的I2S 转TDM8 设计

xiao小怪兽爱上凹凸曼 2023-10-14 原文

文章目录

一、概述

在音频应用领域,I2S和TDM的应用是最基础的应用,不管模拟转数字ADC的采样还是数字转模拟DAC的输出,都经常使用这两种协议,所以跨入音频领域,这些基础的必须先掌握;在本文章主要讲设计思想,针对I2S和TDM的时序只做简单的介绍,然后通过I2S和TDM之间编解码的仿真来熟悉这两种协议的设计思路。

二、I2S简介

I2S(Inter—IC Sound)总线, 又称集成电路内置音频总线,是飞利浦公司为数字音频设备之间的音频数据传输而制定的一种总线标准。在我们本设计中采用是I2S的标准协议。(下图是ADC的时序图)

主时钟 MCLK: 它是 LRCK和SCLK的参考时钟,一个系统应该使用同一的MCLK以保证时钟同步要求。常见频率256fs或512fs。这里的fs就是采样率LRCK的频率。本设计中MCLK为24.576MHz。

采样率 LRCK(也称WS): 用于切换左右声道的数据。对于I2S标准协议来说,LRCK为1表示传输右声道数据,为0则是左声道。在设计中,LRCK的下降沿是我们一个帧的起点,对于I2S来说,左右声道可以搭载两路数据,每2路数据为1帧。本设计中LRCK为48KHz。

串行时钟SCLK: 也叫位时钟BCLK,对应数字音频的每一位数据,该时钟都有一个脉冲。本设计中SCLK为3.072MHz。这里需要注意,不管我们实际音频数据的有效位是16bit、24bit或32bit,我们的串行SCLK都是LRCK的64倍,并且LRCK的下降沿一定是要和BCK的下降沿对齐的。

输入数据DIN: 对于I2s标准协议来说,我们数据是在LRCK下降沿到来后,第二个bck的时钟上升沿开始才是采样到有效数据。正常设计中,音频数据有效位都是24bit,因为32bit没有必要,本设计中也是24bit。

三、TDM简介

TDM即时分复用,它是强化版本的I2s。由于在我们实际应用中发现1组I2s只能传输2路数据,这不能满足我们的需求,所以TDM协议可以满足我们的需求。I2s说白了其实就是TDM2。我们比较常用的是格式是TDM8和TDM16。下图是我们DAC的时序图,是TDM8格式,LRCK的上升沿是一帧的起点,一个帧是8个通道。
主时钟 MCLK: 系统主时钟这里仍然是24.576MHz。
采样率LRCK: 这里LRCK的脉宽大小各个芯片的定义是有点差异的,我们这款DAC,LRCK的脉宽最小可以是1个BCK时钟周期,最大可以是255个时钟周期。本设计TDM的LRCK同样是48KHz。
TDM8移位时钟BCK是采样率LRCK的256倍。
位时钟BCK: 同样的这里移位时钟bck的下降沿一定是要和LRCK边沿是对齐的。本设计BDCK为12.288MHz。注意TDM的一帧的通道数越多,我们BCK频率会越高,对时序的要求就越高,因为一个通道占用32个bck,采样率是固定的。
输入数据DIN: 这里数据的对齐方式采用的I2s的标准格式,也就是在LRCK上升沿后,每32bck的第二个bck的开始才是有效数据。


关于I2S和TDM协议的详细介绍可以参考:I2S/PCM协议及TDM模式详解,这里面有左对齐、右对齐等等相关。

四、设计框图

如图所示,为了能够符合边沿对齐的规则(LRCK的上下沿对齐BCK的下降沿),我们需要使用24.576MHz的时钟下降沿去做分频处理。我们一共是8路数据,4路I2S进行采样(每个AD 2路I2S)。然后进行TDM8编码,输出到DAC。

五、仿真验证

1.时钟分频

如下仿真图图所示,clk是24.576MHz,clkout0是采样时钟LRCK为48KHz,clkout1是I2S的位时钟BCK为3.072MHz,clkout2是TDM8的位时钟BCK为12.288MHz。(采样率LRCK的上下沿是和BCK的下降沿对齐的)

下面展示的是最简单分频处理方法的代码(干货)

module clk_div(
input clk,//24.576MHz
input rst,
output  clkout0,//48KHz
output  clkout1,//3.072MHz
output  clkout2//12.288MHz
    );

reg[9:0]cnt=0;


assign clkout0=cnt[8];
assign clkout1=cnt[2];
assign clkout2=cnt[0];

always@(negedge clk)
begin
if(rst)
cnt<=0;
else
cnt<=cnt+1;
end

endmodule

仿真激励代码:

module vtf_clk_div;

	// Inputs
	reg clk;
	reg rst;

	// Outputs
	wire clkout0;
	wire clkout1;
	wire clkout2;

	// Instantiate the Unit Under Test (UUT)
	clk_div uut (
		.clk(clk), 
		.rst(rst), 
		.clkout0(clkout0), 
		.clkout1(clkout1), 
		.clkout2(clkout2)
	);

	initial begin
		// Initialize Inputs
		clk = 0;
		rst = 1;

		// Wait 100 ns for global reset to finish
		#100;
       	rst = 0; 
		// Add stimulus here

	end
  always # 20.345   clk = ~clk;
endmodule

仿真时序图:

2.I2S 转TDM8功能模块

关于4路I2S转1路TDM8源代码这里就不放了,想要看的可以点击如下链接获取:I2S转TDM8代码
在激励文件中,定义的data_vld1~data_vld8这8个通道数据对应4路I2s的8个声道,具体可以看仿真时序图。
仿真激励代码:


module vtf_i2s_to_tdm8;

	// Inputs
	reg reset;
	wire MCLK;//TDM8的BCK
	wire LRCK;
	wire SCLK;//I2S的BCK
	reg DATA1;//第一路I2s数据输入
	reg DATA2;//第二路I2s数据输入
	reg DATA3;//第三路I2s数据输入
	reg DATA4;//第四路I2s数据输入

	// Outputs
	wire flag;
	wire DATA_OUT;
/
   
    reg clk;
	reg LRCK_dly1;
	reg LRCK_dly2;
	reg [63:0] TMPA;
	reg [63:0] TMPB;
	reg [63:0] TMPC;
	reg [63:0] TMPD;
	wire clk_48k_negedge;
/定义的8个数据通过4路I2S发送出去(ch1/ch2第一路、ch3/ch4第二路、
    ch5/ch6第二路、ch7/ch8第二路)

localparam data_vld1=32'hf111_1F00;//ch1
localparam data_vld2=32'hf333_3F00;//ch2
localparam data_vld3=32'hf555_5F00;//ch3
localparam data_vld4=32'hf777_7F00;//ch4
localparam data_vld5=32'hf999_9F00;//ch5
localparam data_vld6=32'hfBBB_BF00;//ch6
localparam data_vld7=32'hfCCC_CF00;//ch7
localparam data_vld8=32'hfDDD_DF00;//ch8
	// Instantiate the Unit Under Test (UUT)
	i2s_to_tdm8 uut (
		.reset(reset), 
		.MCLK(MCLK), 
		.LRCK(LRCK), 
		.SCLK(SCLK), 
		.DATA1(DATA1), 
		.DATA2(DATA2), 
		.DATA3(DATA3), 
		.DATA4(DATA4), 
		.flag(flag), 
		.DATA_OUT(DATA_OUT)
	);
///调用上面的分频模块	
		clk_div clk_div_inst (
		.clk(clk), 
		.rst(reset), 
		.clkout0(LRCK), //48KHz
		.clkout1(SCLK), //3.072MHz
		.clkout2(MCLK)//12.288MHz
	);



	initial begin
		// Initialize Inputs
		reset = 1;
		clk = 0;
		DATA1 = 0;
		DATA2 = 0;
		DATA3 = 0;
		DATA4 = 0;
      LRCK_dly1=0;
		LRCK_dly2=0;
		TMPA=0;
		TMPB=0;
		TMPC=0;
		TMPD=0;
		// Wait 100 ns for global reset to finish
		#100;
       reset =0; 
		// Add stimulus here

	end
    always # 20.345   clk = ~clk;   
	 always @(posedge SCLK)
	 begin
	LRCK_dly1 <=LRCK;
	LRCK_dly2 <=LRCK_dly1;
	 end
	assign clk_48k_negedge =~LRCK_dly1&LRCK_dly2;
	 
	always @(negedge SCLK) 
	 begin
	 if(clk_48k_negedge)begin
	   DATA1<=data_vld1[31];
		TMPA<={data_vld1[30:0],data_vld2,1'b0};
		end
		else begin
	   TMPA<=TMPA<<1;
		DATA1<=TMPA[63];
      end		
	 end
	 
	always @(negedge SCLK) 
	 begin
	 if(clk_48k_negedge)begin
	   DATA2<=data_vld3[31];
		TMPB<={data_vld3[30:0],data_vld4,1'b0};
		end
		else begin
	   TMPB<={TMPB[62:0],1'b1};	 
		DATA2<=TMPB[63];
		end
	 end
	 
	always @(negedge SCLK) 
	 begin
	 if(clk_48k_negedge)begin
	   DATA3<=data_vld5[31];
		TMPC<={data_vld5[30:0],data_vld6,1'b0};
		end
		else begin
	   TMPC<={TMPC[62:0],1'b1};	 
		DATA3<=TMPC[63];
		end 
	 end
	 
	always @(negedge SCLK) 
	 begin
	 if(clk_48k_negedge)begin
	   DATA4<=data_vld7[31];
		TMPD<={data_vld7[30:0],data_vld8,1'b0};
		end
		else begin
	   TMPD<={TMPD[62:0],1'b1};	 
		DATA4<=TMPD[63];
		end	 
	 end	 
endmodule

时序仿真图:
对于I2S时序来说LRCK的下降沿是一帧的开始,DATA1~DATA4是4路I2S的输入数据,通道对应如图所示;对于TDM8时序来说LRCK的上升沿是一帧的开始,DATA_OUT是TDM8的输出数据,这里通道对应如图所示。

广大博友,关于I2S转1路TDM8的应用这里就介绍完了,可以拓展应用,比如:8路I2S转1路TDM16、8路I2S转2路TDM8等等,只要时序搞明白了,用起来就简单了,大家可以自己研究研究,如有问题欢迎探讨。

有关基于FPGA的I2S 转TDM8 设计的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  3. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  4. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  5. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  6. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  7. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  8. ruby-on-rails - 设计注册确认 - 2

    我在我的项目中有一个用户和一个管理员角色。我使用Devise创建了身份验证。在我的管理员角色中,我没有任何确认。在我的用户模型中,我有以下内容:devise:database_authenticatable,:confirmable,:recoverable,:rememberable,:trackable,:validatable,:timeoutable,:registerable#Setupaccessible(orprotected)attributesforyourmodelattr_accessible:email,:username,:prename,:surname,:

  9. ruby-on-rails - 设计通过 reset_password_token 获取用户 - 2

    我正在尝试创建密码规则来设计可恢复的密码更改。我通过passwords_controller.rb做了一个父类(superclass),但我需要在应用规则之前检查用户角色,但我所拥有的只是reset_password_token。 最佳答案 假设您的模型是用户:User.with_reset_password_token(your_token_here)Source 关于ruby-on-rails-设计通过reset_password_token获取用户,我们在StackOverflow

  10. ruby-on-rails - Rails 5,公寓和设计 : sign in with subdomains are not working - 2

    我已经使用Apartment设置了一个Rails5应用程序(1.2.0)和Devise(4.2.0)。由于某些DDNS问题,应用只能在app.myapp.com下访问(请注意子域app)。myapp.com重定向到app.myapp.com。我的用例是每个注册该应用的用户(租户)都应该通过他们的子域(例如tenant.myapp.com)访问他们的特定数据。用户不应限定在其子域内。基本上应该可以从任何子域登录。重定向到租户的正确子域由ApplicationController处理。根据Devise标准,登录页面位于app.myapp.com/users/sign_in。这就是问题开始的

随机推荐