欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

TLC549ADC驱动的FPGA实现

程序员文章站 2022-04-01 18:42:28
...

1.引言与相关资料

TLC549是一款8位串行ADC,其采样速率不高,精度也只有8位,但不需要对其进行任何控制就可以自动的进行ADC的工作,需要做的只是在适当的时机按串行方式读出8位AD值就可以。
理论上这款ADC性能其实不咋地,局限性也很大,不过是我购买的FPGA开发板上自带的一款ADC,后续有个设计需要用到它进行AD采样。
TLC549ADC驱动的FPGA实现
相关资料百度上可以找到一篇关于TLC549中文资料。以下是链接:

2.TLC549驱动时序与采样过程

TLC549区别与其他ADC的主要特征就在于:器件内部存在时钟,与外部时钟独立,这个时钟控制ADC进行电平值的转换。也就是说其接口上的Clk管脚实际上只控制读ADC的值,而不直接控制采样频率。具体的采样时序如下:
TLC549ADC驱动的FPGA实现
上述具体过程如下:
1.初始时CS拉高,此时芯片不向外输出AD值。
2.当CS拉低后,芯片通过两个内部时钟来确认这一变化,同时D0端向外输出上一次采样结果AD值的最高位:D7
3.此后CS持续拉低,CLK上来时钟脉冲后,在CLK时钟脉冲的前四个下降沿依次输出D6,D5,D4,D3。
4.同时在第四个下降沿时开始对AD的模拟端进行采样。
5.在之后的3个脉冲依次输出D2,D1以及D0。此时CLK已经经过7个脉冲
6.在第8个脉冲的下降沿,ADC把模拟端的电压保存下来,准备开始转换。
7.同时CS需要拉高,CLK需要持续拉低,ADC开始转换模拟电压,经过36个ADC的内部时钟后,电压值转换完毕。可以进行下一次读取。
从上述过程中,可以获取两个信息:
1.ADC转换过程与I/O管脚CLK无关,但转换期间不能被CLK和CS打扰。属于ADC的等待状态
2.读取信息时下降沿输出数据,从MSB-LSB的顺序输出,属于ADC的读取数据状态

3.TLC549驱动的硬件编写

FPGA的实现比较简单,通过计数器完成CLK时钟的生成和等待时间的定时,利用有限状态机控制CS和CLK信号完成ADC的两种状态之间的切换。以下例子中CLK的频率为500KHz,而等待时间则为40个内部时钟周期。
编写模块实例图如下:
TLC549ADC驱动的FPGA实现

模块信号说明:
I_Adc_Data_In-------------------------------------------ADC输入的串行AD数据
O_CS_n----------------------------------------------------CS控制信号
O_Adc_Clk------------------------------------------------CLK控制时钟
O_Adc_Data_Vaild--------------------------------------标志Data_out端数据是否有效的指示端,有效时会输出一个高电平
O_Adc_Data_Out[7:0]----------------------------------AD采样的8位数据,当Vaild端输出一个高电平脉冲后才表示有效

具体的FPGA程序如下:
module ADC_TLC549(
		I_Clk,
		I_Rst_n,
		I_Adc_Data_In,
		O_CS_n,
		O_Adc_Clk,
		O_Adc_Data_Out,
		O_Adc_Data_Vaild
    );


//I/O
input			I_Clk;
input			I_Rst_n;
input			I_Adc_Data_In;

output		O_CS_n;
output		O_Adc_Clk;
output [7:0]	O_Adc_Data_Out;
output		O_Adc_Data_Vaild;


/*************I/O时钟计数器********************/
parameter   IO_Clk_Freq=7'd99;  //系统时钟50MHz,500k=50/100->99;
parameter   IO_Clk_Freq_div=7'd49;//采样时钟频率的两倍,对应与采样时钟上升沿
parameter   IO_Clk_Width=3'd7;

reg	[IO_Clk_Width-1:0] R_IO_Clk_Count;
reg			   R_Clk_En;
always @ (posedge I_Clk)
begin
	if (~I_Rst_n)
	 begin
	  R_IO_Clk_Count<=7'b0;
	 end
	else
	 begin
	  if (R_Clk_En)
	   begin
	       if (R_IO_Clk_Count==IO_Clk_Freq)
		  R_IO_Clk_Count<=7'b0;
		 else
		  R_IO_Clk_Count<=R_IO_Clk_Count+7'd1;
	   end
	  else
	   R_IO_Clk_Count<=7'b0;
	 end
end

assign O_Adc_Clk=(R_IO_Clk_Count>IO_Clk_Freq_div)?1'b1:1'b0;

/***************转换时间计时器*********************************/
parameter		Delay_Time=9'd499;//转换时钟为4MHz,总等待时间需要超过34个周期,这里取40个周期,则为500个系统时钟
parameter		CS_n_Time=9'd449;
parameter		Transfer_Count_Width=4'd9;
reg		[Transfer_Count_Width-1:0] R_Transfer_Count;
reg					   R_Transfer_En;
always @ (posedge I_Clk)
begin
   if (~I_Rst_n)
	 begin
	  R_Transfer_Count<=9'b0;
	 end
   else
	 begin
	  if (R_Transfer_En)
	   begin
              if (R_Transfer_Count==Delay_Time)
		  R_Transfer_Count<=R_Transfer_Count;
	    else
		  R_Transfer_Count<=R_Transfer_Count+9'd1;
	   end
	  else
	   R_Transfer_Count<=9'b0;	 
	 end
end

/**************总采样过程状态机***********************/
reg	[3:0] R_State;
reg	      R_CS_n;
reg	[7:0] R_Data;
reg	      R_Vaild;
always @ (posedge I_Clk)
begin
	if (~I_Rst_n)
	 begin
	  R_State<=4'b0;
	  R_CS_n<=1'b1;
	  R_Data<=8'b0;
	  R_Transfer_En<=1'b0;
	  R_Clk_En<=1'b0;
	  R_Vaild<=1'b0;
	 end
   else
	  case (R_State)
	  4'd0:
	    begin
		  R_Vaild<=1'b0;
		  R_Transfer_En<=1'b1;
		  R_Clk_En<=1'b0;
		  R_CS_n<=1'b1;
		  if (R_Transfer_Count==CS_n_Time)
		   R_State<=R_State+4'd1;
		  else
		   R_State<=R_State;
		 end
		4'd1:
		  begin
		   R_CS_n<=1'b0;
		   if (R_Transfer_Count==Delay_Time)
			 begin
			  R_State<=R_State+4'd1;
			  R_Transfer_En<=1'b0;
			 end
			else
			 begin
			  R_State<=R_State;
			  R_Transfer_En<=1'b1;
			 end
		  end
		 4'd2,4'd3,4'd4,4'd5,4'd6,4'd7,4'd8,4'd9:
		  begin
		   R_Clk_En<=1'b1;
			if (R_IO_Clk_Count==IO_Clk_Freq_div)
			 begin
			  R_State<=R_State+4'd1;
			  R_Data<={R_Data[6:0],I_Adc_Data_In};
			 end
			else
			  R_State<=R_State;
		  end	
		 4'd10:
		  begin
		   if (R_IO_Clk_Count==IO_Clk_Freq)
			 begin
			  R_Clk_En<=1'b0;
			  R_State<=4'd0;
			  R_Vaild<=1'b1;
			  R_CS_n<=1'b1;
			 end
			else
			 begin
			  R_Clk_En<=1'b1;
			  R_State<=R_State;
			  R_Vaild<=1'b0;	
			  R_CS_n<=1'b0;
			 end
		  end
	  default:
	      begin
		    R_State<=4'b0;
	       R_CS_n<=1'b1;
	       R_Data<=8'b0;
	       R_Transfer_En<=1'b0;
	       R_Clk_En<=1'b0;
	       R_Vaild<=1'b0;			 
			end
	  endcase		
end

assign	O_CS_n=R_CS_n;
assign	O_Adc_Data_Out=R_Data;
assign	O_Adc_Data_Vaild=R_Vaild;
endmodule

通过ChipScope对采样到的值进行观察,结果如下:
TLC549ADC驱动的FPGA实现

没过一段时间,Data端会输出一个稳定的8位数值,为AD的采样值





相关标签: ADC驱动