1. 程式人生 > >基礎篇-verilog-單路序列ADC-TLC549

基礎篇-verilog-單路序列ADC-TLC549

註明:雖然此實驗來自於諸多入門教程,其中包括gao石的,但我個人覺得他的時序寫的不好,沒有完全遵循晶片的時序,它直接用AD——CLK的上升沿讀取AD_DATA, 但是,事實上,晶片時序,並不是在8位全在上升沿讀取。
8位序列模數轉換器
8位開關電容逐次逼近的方法實現A/D
內部具有4MHz的系統時鐘,轉換速度小於17us
允許的最大轉換速率是40000次/s(一個週期,取樣下來,再讀取。)
電源3V到6V
方便採用3線序列介面方式與各種微處理器進行連線

1

2
4
在這裡插入圖片描述

最高有效位(A7)在CS降低後自動置於資料輸出總線上。剩下的7位(a6 - a0)在前7個I / O時鐘的邊緣上被鎖定了。B7-B0遵循同樣的方式。
根據NOTEs的意思,也就是DA_DATA遵循某種時序序列吐出data,那麼,在何時才吐出的是DATA的哪一位呢?
這就要遵循一定的時序關係。
這種關係便是:
在第一個CLK的上升沿讀取A7,第一個CLK到第六個CLK的下降沿讀取A6——A0。


思路:狀態機:3個狀態
1:轉換狀態(也可視作初始狀態)
2:1.4us(CS由高變低狀態)
3:DA_CLK(取樣狀態)
//-----------------------------------------------------------------------------2018.11.6 23:00
//------------------------------------------------------------------------------- 明日再來寫
7
系統時鐘是4M,並非是取樣時鐘,注意取樣在SAMPLE階段,也就是後4個時鐘週期進行的。外接時鐘速率1.1M並不是指的取樣速率,那是介面讀取速率。序列晶片,我門需要注意的是一個週期,取樣時間+轉換時間=1/40_000 而在並行晶片中,往往是給的CLOCK即取樣時鐘。
下圖是AD904晶片時序,在DATA_change階段進行取樣,並進行完成相關的量化。

下面的程式碼,序列TLC549,取樣後,儲存在8位暫存器當中

module AD_TLC549
#(
	parameter T_conv=12'd850,//轉換時間50M*17us=850
	parameter T_su=8'd70,//準備時間50M*1.4us=70us
	parameter AD_CLK_nop=4'd8,//定義8個AD_CLK
	parameter AD_CLK_circle_time=6'd46,//0.92us
	parameter AD_CLK_circle_time_half=6'd23  //23*50=0.46us
)
(
input sys_clk,
input RST_N,
input AD_DATA,
//-------------------
output AD_CLK,
output CS_N,

output reg [AD_CLK_nop-1:0] AD_out_DATA //序列的AD_DATA轉並行的8位暫存器




);

wire AD_CLK_edg;
reg AD_out_reg_finish;//序列轉並行完成標誌
reg [11:0] T_conv_cnt=0;//轉換時間的計數器
reg [7:0] T_su_cnt=0;//準備時間的計數器
reg [3:0] AD_CLK_cnt=0;//AD_CLK個數計數器
reg [5:0]    AD_CLK_circle_time_cnt=0;//一個AD_CLK的高/低電平時間計數器
reg AD_CLK_reg_reg;//用於快取一拍AD_CLK,實現下降沿檢測



//設定輸出暫存器
reg AD_CLK_reg=0;
reg CS_N_reg;

reg [AD_CLK_nop-1:0] AD_out_reg;





//採用三段式狀態機
/*有限狀態機,三段式建模風格*/
/*三個過程*/
//狀態編碼
localparam  transition_state = 3'b001,//資料轉換狀態
				ready_1_4_state  = 3'b010,//準備取樣狀態
				Acess_sample_state     = 3'b100;//取樣狀態
//這裡可以把資料轉換狀態視作初始狀態,1沒有時鐘,2 CS_N為高,也無效。
reg  [2:0]  now_state=transition_state;
reg  [2:0]	next_state=transition_state;

//1.實現狀態轉換:實現當前狀態now_state到next_state的轉換
always @ (posedge sys_clk)
begin
	if(!RST_N)
		now_state<=transition_state;
	else
	   now_state<=next_state;
end
//2.設定狀態切換條件,產生下一個狀態
[email protected]
(*) begin case(now_state) transition_state: if(T_conv_cnt==T_conv) //如果轉換時間36 next_state=ready_1_4_state; else next_state=transition_state; ready_1_4_state: if(T_su_cnt==T_su) next_state=Acess_sample_state; else next_state=ready_1_4_state; Acess_sample_state: if(AD_CLK_cnt<AD_CLK_nop) next_state=Acess_sample_state; else next_state=transition_state; default:; endcase end //3.產生每個狀態機的條件輸出值 always @ (posedge sys_clk) begin case(next_state) transition_state: begin T_conv_cnt<=T_conv_cnt+1; T_su_cnt<=0; AD_CLK_cnt<=0; end ready_1_4_state: begin T_su_cnt<=T_su_cnt+1; T_conv_cnt<=0; end Acess_sample_state: begin if (AD_CLK_edg) AD_CLK_cnt <= AD_CLK_cnt + 1'b1; else AD_CLK_cnt <= AD_CLK_cnt; end endcase end //4.設定每個輸出值 //1.CS_N的輸出值 [email protected](posedge sys_clk) begin if(!RST_N) begin CS_N_reg<=1; // end else if(now_state==transition_state) begin CS_N_reg<=1; // end else begin CS_N_reg<=0; //CS_N低電平有效 end end assign CS_N=CS_N_reg; //2.AD_CLK的輸出值 [email protected](posedge sys_clk) begin if(!RST_N) AD_CLK_circle_time_cnt<=0; else if(now_state==Acess_sample_state) AD_CLK_circle_time_cnt<=(AD_CLK_circle_time_cnt<AD_CLK_circle_time-1)?(AD_CLK_circle_time_cnt+1'b1):0; else AD_CLK_circle_time_cnt<=0; end [email protected] (posedge sys_clk) begin if(!RST_N) AD_CLK_reg<=0; else if(now_state==Acess_sample_state) AD_CLK_reg <= (AD_CLK_circle_time_cnt <=AD_CLK_circle_time_half-1) ? 1'b1 : 1'b0; else AD_CLK_reg<=0; end //3.AD_CLK_nop_edg控制 always @ (posedge sys_clk) begin AD_CLK_reg_reg<=AD_CLK_reg; //寄存一拍 end assign AD_CLK_edg = AD_CLK_reg_reg&(~AD_CLK_reg);//判斷下降沿 assign AD_CLK=AD_CLK_reg; //4.AD_DATA_reg控制讀取........控制在什麼時候,把序列AD_DATA的資料寫入多位的暫存器AD_DATA_reg之中,時機不對,自然寫入的數肯定就不對 always @ (posedge sys_clk) begin if((now_state==ready_1_4_state)&(next_state==Acess_sample_state)) AD_out_reg[AD_CLK_nop-1]<=AD_DATA; else if(AD_CLK_edg&(AD_CLK_cnt<=AD_CLK_nop-1)) AD_out_reg[AD_CLK_nop-1-1:0]<={AD_out_reg[AD_CLK_nop-1-1-1:0],AD_DATA};//移位迴圈實現序列轉並行 else if(AD_CLK_cnt==AD_CLK_nop)//在第8個時鐘下降沿的時候,代表了AD_DATA_reg已經移位完成,之所以沒有剛好設定第7個下降沿,是擔心第7個下降沿還在讀取。 AD_out_reg_finish<=1; else begin AD_out_reg<=AD_out_reg; AD_out_reg_finish<=0; end end always @ (posedge sys_clk) begin if(AD_out_reg_finish==1) //只有在讀取8位完畢後,再將這8位數更新 AD_out_DATA<=AD_out_reg; else AD_out_DATA<=AD_out_DATA; end endmodule
// Copyright (C) 1991-2013 Altera Corporation
// Your use of Altera Corporation's design tools, logic functions 
// and other software and tools, and its AMPP partner logic 
// functions, and any output files from any of the foregoing 
// (including device programming or simulation files), and any 
// associated documentation or information are expressly subject 
// to the terms and conditions of the Altera Program License 
// Subscription Agreement, Altera MegaCore Function License 
// Agreement, or other applicable license agreement, including, 
// without limitation, that your use is for the sole purpose of 
// programming logic devices manufactured by Altera and sold by 
// Altera or its authorized distributors.  Please refer to the 
// applicable agreement for further details.

// *****************************************************************************
// This file contains a Verilog test bench template that is freely editable to  
// suit user's needs .Comments are provided in each section to help the user    
// fill out necessary details.                                                  
// *****************************************************************************
// Generated on "11/08/2018 16:19:41"
                                                                                
// Verilog Test Bench template for design : AD_TLC549
// 
// Simulation tool : ModelSim (Verilog)
// 

`timescale 1 ns/ 1 ps
module AD_TLC549_vlg_tst();
// constants                                           
// general purpose registers
reg eachvec;
// test vector input registers
reg AD_DATA;
reg RST_N;
reg sys_clk;
// wires                                               
wire AD_CLK;
wire [7:0]  AD_out_DATA;
wire CS_N;

// assign statements (if any)                          
AD_TLC549 i1 (
// port map - connection between master ports and signals/registers   
	.AD_CLK(AD_CLK),
	.AD_DATA(AD_DATA),
	.AD_out_DATA(AD_out_DATA),
	.CS_N(CS_N),
	.RST_N(RST_N),
	.sys_clk(sys_clk)
);
initial                                                
begin                                                                                           
$display("Running testbench");  
#0 sys_clk=0;
#0 RST_N=0;
#40 RST_N=1;
#0 AD_DATA=1;

                       
end 
//------------------------------------------                                                   
always                                                                
begin                                                  
 #10 sys_clk=~sys_clk; 


 
end                                                    
endmodule





5
在第8個AD_clk過後才更新AD_out_DATA


整體效果:
在這裡插入圖片描述

符合AD_CLK 一個週期0.92us,半個週期長度也符合,檢查了

符合1.4us

在這裡插入圖片描述
6
以下是工程連線:
https://download.csdn.net/download/ciscomonkey/10773104