1.引言與相關資料
TLC549是一款8位串行ADC,其采樣速率不高,精度也隻有8位,但不需要對其進行任何控制就可以自動的進行ADC的工作,需要做的隻是在适當的時機按串行方式讀出8位AD值就可以。 理論上這款ADC性能其實不咋地,局限性也很大,不過是我購買的FPGA開發闆上自帶的一款ADC,後續有個設計需要用到它進行AD采樣。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0NXYFhGd192UvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2Lc1TVzIWN5wmYshmMjZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39TO5cTM0UDMyIDNyEDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
相關資料百度上可以找到一篇關于TLC549中文資料。以下是連結: TLC中文資料
2.TLC549驅動時序與采樣過程
TLC549差別與其他ADC的主要特征就在于:器件内部存在時鐘,與外部時鐘獨立,這個時鐘控制ADC進行電平值的轉換。也就是說其接口上的Clk管腳實際上隻控制讀ADC的值,而不直接控制采樣頻率。具體的采樣時序如下:
上述具體過程如下: 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個内部時鐘周期。 編寫子產品執行個體圖如下:
子產品信号說明: 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對采樣到的值進行觀察,結果如下:
沒過一段時間,Data端會輸出一個穩定的8位數值,為AD的采樣值