作者:李西銳??校對:陸輝
大俠好,歡迎來到FPGA技術(shù)江湖。本系列將帶來FPGA的系統(tǒng)性學(xué)習(xí),從最基本的數(shù)字電路基礎(chǔ)開始,最詳細(xì)操作步驟,最直白的言語描述,手把手的“傻瓜式”講解,讓電子、信息、通信類專業(yè)學(xué)生、初入職場小白及打算進(jìn)階提升的職業(yè)開發(fā)者都可以有系統(tǒng)性學(xué)習(xí)的機(jī)會。
系統(tǒng)性的掌握技術(shù)開發(fā)以及相關(guān)要求,對個人就業(yè)以及職業(yè)發(fā)展都有著潛在的幫助,希望對大家有所幫助。本次帶來Vivado系列,TLC549驅(qū)動設(shè)計。話不多說,上貨。
TCL549驅(qū)動設(shè)計
在生活中,數(shù)模轉(zhuǎn)換的例子到處可見。但是在我們做FPGA設(shè)計時,需要對數(shù)字信號進(jìn)行處理,但是,不是所有的信號都是以數(shù)字信號的形式體現(xiàn)的,比如光信號、聲信號、電信號等等。那么此時就需要我們先進(jìn)行一下模數(shù)轉(zhuǎn)換之后再進(jìn)行處理。在此,我們將介紹一款模數(shù)轉(zhuǎn)換芯片TLC549。
TLC549是一款串行總線控制的8bit模數(shù)轉(zhuǎn)換芯片,封裝如下圖:
管腳說明:
芯片特征:
1、8bit A/D轉(zhuǎn)換器。
2、最大轉(zhuǎn)換時間為17us。
3、供電3V~6V之間。
4、低功耗最大功率為15mW。
在官方手冊中,對此芯片有這樣的一段描述:
在這段描述中,大致說出了這個芯片的一些控制。比如:TLC548和TLC549都是8bit的模數(shù)轉(zhuǎn)換器。這個芯片使用I/O CLOCK和CS_N來控制數(shù)據(jù)。TLC548的I/O CLOCK最大頻率為2.048MHz,TLC549的I/O CLOCK最大頻率為1.1MHz。
在這段描述中可以看出,AD芯片的數(shù)據(jù)輸出,需要在I/O CLOCK和CS_N的控制下才能進(jìn)行。
芯片示意圖:
從圖中可以看出,參考電壓是模數(shù)轉(zhuǎn)換的一個標(biāo)準(zhǔn),CS_N和I/O CLOCK給到邏輯控制和輸出計數(shù)。數(shù)據(jù)通過一個輸出寄存器給到一個并串轉(zhuǎn)換的模塊。DATA_OUT數(shù)據(jù)是給到我們的FPGA的,所以,對于我們來說需要做的就是輸出CS_N和I/O CLOCK的波形,同時,將給進(jìn)來的數(shù)據(jù)采到。
上圖為驅(qū)動的時序圖,可以看到,當(dāng)數(shù)據(jù)輸出的時候,CS_N為低電平,總共輸出8bit,輸出完之后,CS_N拉高。我們在做驅(qū)動時??梢詫⒁淮无D(zhuǎn)換過程看成一個周期,后續(xù)也是重復(fù)過程。那么,我們就需要搞清楚每段時間的要求,有助于我們寫驅(qū)動。
在上圖中,我們可以知道:
1、CS_N從拉低到第一bit數(shù)據(jù)出現(xiàn)在數(shù)據(jù)線上的時間最大為1.4us。
2、CS_N從拉低到第一個時鐘上升沿出現(xiàn),時間最小為1.4us。
3、I/O CLOCK頻率最大為1.1MHz。為了方便計算,我們采取1MHz。
4、Tconv轉(zhuǎn)換時間最大為17us。
5、CS_N拉高時間最小為17us。
在知道了以上信息后,我們開始寫驅(qū)動,首先新建一下工程。
選擇好之后點(diǎn)擊完成,新建文件寫代碼。
代碼如下:
1 module TLC549_driver(
2
3 input wire clk,
4 input wire rst_n,
5
6 output reg ad_clk,
7 output reg ad_cs_n,
8 input wire ad_data,
9
10 output reg [7:0] data
11 );
12
13 parameter t = 1300;
14
15 reg [10:0] cnt;
16 reg [7:0] data_temp;
17
18 always @ (posedge clk, negedge rst_n)
19 begin
20 if(rst_n == 1'b0)
21 cnt <= 11'd0;
22 else if(cnt == t - 1)
23 cnt <= 11'd0;
24 else
25 cnt <= cnt + 1'b1;
26 end
27
28 always @ (posedge clk, negedge rst_n)
29 begin
30 if(rst_n == 1'b0)
31 begin
32 ad_clk <= 1'b0;
33 ad_cs_n <= 1'b1;
34 data_temp <= 8'd0;
35 data <= 8'd0;
36 end
37 else
38 case(cnt)
39 0 : begin ad_cs_n <= 1'b0; ad_clk <= 1'b0; end
40 74 : begin ad_clk <= 1'b1; data_temp[7] <= ad_data; end
41 99 : begin ad_clk <= 1'b0; end
42 124 : begin ad_clk <= 1'b1; data_temp[6] <= ad_data; end
43 149 : begin ad_clk <= 1'b0; end
44 174 : begin ad_clk <= 1'b1; data_temp[5] <= ad_data; end
45 199 : begin ad_clk <= 1'b0; end
46 224 : begin ad_clk <= 1'b1; data_temp[4] <= ad_data; end
47 249 : begin ad_clk <= 1'b0; end
48 274 : begin ad_clk <= 1'b1; data_temp[3] <= ad_data; end
49 299 : begin ad_clk <= 1'b0; end
50 324 : begin ad_clk <= 1'b1; data_temp[2] <= ad_data; end
51 349 : begin ad_clk <= 1'b0; end
52 374 : begin ad_clk <= 1'b1; data_temp[1] <= ad_data; end
53 399 : begin ad_clk <= 1'b0; end
54 424 : begin ad_clk <= 1'b1; data_temp[0] <= ad_data; end
55 449 : begin ad_clk <= 1'b0; ad_cs_n <= 1'b1; end
56 1299: begin data <= data_temp; end
57 default : ;
58 endcase
59 end
60
61 endmodule
代碼寫好之后,我們做一下仿真看一下數(shù)據(jù)能否被正確采集,代碼如下:
1 `timescale 1ns / 1ps
2
3 module TLC549_driver_tb;
4
5 reg clk;
6 reg rst_n;
7
8 wire ad_clk;
9 wire ad_cs_n;
10 reg ad_data;
11
12 wire [7:0] data;
13
14 initial begin
15 clk = 0;
16 rst_n = 0;
17 ad_data = 0;
18 #100;
19 rst_n = 1;
20 #1000;
21 ad_data = 1; //10100110
22 #1000;
23 ad_data = 0;
24 #1000;
25 ad_data = 1;
26 #1000;
27 ad_data = 0;
28 #1000;
29 ad_data = 0;
30 #1000;
31 ad_data = 1;
32 #1000;
33 ad_data = 1;
34 #1000;
35 ad_data = 0;
36 #20000;
37 $stop;
38 end
39
40 always #10 clk = ~clk;
41
42 TLC549_driver TLC549_driver_inst(
43
44 .clk (clk),
45 .rst_n (rst_n),
46
47 .ad_clk (ad_clk),
48 .ad_cs_n (ad_cs_n),
49 .ad_data (ad_data),
50
51 .data (data)
52 );
53
54 endmodule
編譯無誤,打開波形觀察。
仿真中給出的數(shù)據(jù)位8’b10100110,換算成16進(jìn)制為8’ha6。與波形中顯示一致,仿真正確。