天天看點

TLC549ADC驅動的FPGA實作

1.引言與相關資料

TLC549是一款8位串行ADC,其采樣速率不高,精度也隻有8位,但不需要對其進行任何控制就可以自動的進行ADC的工作,需要做的隻是在适當的時機按串行方式讀出8位AD值就可以。 理論上這款ADC性能其實不咋地,局限性也很大,不過是我購買的FPGA開發闆上自帶的一款ADC,後續有個設計需要用到它進行AD采樣。

TLC549ADC驅動的FPGA實作

相關資料百度上可以找到一篇關于TLC549中文資料。以下是連結: TLC中文資料

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的采樣值