ADC芯片TLC549的Verilog HDL

1.TLC549简介

TLC549是美国德州仪器公司生产的8位串行A/D转换器芯片,可与通用微处理器、控制器通过CLK、CS、DATAOUT三条口线进行串行接口。具有4MHz片内系统时钟和软、硬件控制电路,转换时间最长17μs, TLC549为40000次/s。总失调误差最大为±0.5LSB,典型功耗值为6mW。采用差分参考电压高阻输入,抗干扰,可按比例量程校准转换范围,VREF-接地,VREF+-VREF-≥1V,可用于较小信号的采样。

ADC芯片TLC549的Verilog HDL_第1张图片
芯片顶视图.png

REF+:正基准信号输入端

ANALOG IN:模拟信号输入端

REF-:负基准电压输入端

GND:接地端

#CS:片选信号,低电平有效

DATA OUT:转换结果串行输出端

I/O CLOCK:外接时钟输入端

VCC:电源输入端

其他信息可参照TLC549的datasheet。

2.AD通信协议

ADC芯片TLC549的Verilog HDL_第2张图片
TLC549时序图.png

TLC549均有片内系统时钟,该时钟与I/O CLOCK是独立工作的,无须特殊的速度或相位匹配。其工作时序如图2所示。当CS为高时,数据输出(DATA OUT)端处于高阻状态,此时I/O CLOCK不起作用。

当CS为低时,AD前一次转换的数据A的最高位A7立马出现在数据线DATA OUT上,其余七位在I/O CLOCK的下降沿依次由时钟同步输出,,因此可在I/O CLOCK的上升沿读取数据,其中值得注意的是:1.图中他tsu(cs)至少要1.4us;2.I/O CLOCK不能超过1.1MHz。

读完8位数据后,AD开始转换这一次转换的采样数据B,以便下一次读取转换时,片选信号CS置高,每次转换不超过17us,开始于CS拉低后的第八个I/O CLOCK的下降沿,没有转换完成标志,没有启动控制端,只要读取前一次数据后就马上可以开始新的AD转换,转换完成进入保持状态。

3.代码

*File name:ad.v

*Author: ***

*Description:The AD module

***************************************************************/

`define AD_CLK_TIME 10'd45

`define AD_CLK_TIME_HALF 10'd22

module AD

(

input   sys_clk_50m,

input   rst_n,

output reg  poc_ad_cs,  //TLC549的片选

output reg  poc_ad_clk, //TLC549的I/O CLOCK

input pid_ad_data,  //TLC549的数据串行输出端,相对于FPGA为输入

output reg [3:0]    o_vol_int,  //转换后输出电压的整数部分

output reg [3:0]    o_vol_dec   //转换后输出电压的小数部分

);

reg n_ad_cs;    //AD_CS的下一个状态

reg n_ad_clk;   //AD_CLK的下一个状态

reg [ 2:0]  ad_fsm_cs;  //状态机的当前状态

reg [ 2:0]  ad_fsm_ns;  //状态机的下一个状态

wire    [ 3:0]  n_o_vol_int;    //o_vol_int的下一个状态

wire    [ 3:0]  n_o_vol_dec;    //o_vol_dec的下一个状态

reg [ 5:0]  time_cnt;   //用于记录一个时钟所用时间的定时器

reg [ 5:0]  n_time_cnt; //time_cnt的下一个状态

reg [ 5:0]  bit_cnt;    //用来记录时钟周期个数的计数器

reg [ 5:0]  n_bit_cnt;  //bit_cnt的下一个状态

reg [ 7:0]  data_out;   //用来保存稳定的AD数据

reg [ 7:0]  n_data_out; //data_out的下一个状态

reg [ 7:0]  ad_data_reg;    //用于保存数据的移位寄存器

reg [ 7:0]  n_ad_data_reg;  //ad_data_reg_n的下一个状态

wire    [11:0]  mid1;   //数据转换电压的整数部分

wire    [11:0]  mid2;   //数据转换电压的小数部分

parameter   FSM_IDLE    = 3'h0; //状态机的初始状态;

parameter   FSM_READY   = 3'h1; //满足CS有效时的第一个1.4us的延时状态

parameter   FSM_DATA    = 3'h2; //读取8个数据状态

parameter   FSM_WAIT_CONV   = 3'h3; //等待转换状态,等待17us;

parameter   FSM_END = 3'h4; //结束的状态

/********************************************

状态机转换

********************************************/

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

ad_fsm_cs <= FSM_IDLE;

else

ad_fsm_cs <= ad_fsm_ns;

always @ (*)

begin

case(ad_fsm_cs)

FSM_IDLE:

if((bit_cnt == 6'd2 ) && (time_cnt == `AD_CLK_TIME))

ad_fsm_ns = FSM_READY;

else

ad_fsm_ns = ad_fsm_cs;

FSM_READY:

if((bit_cnt == 6'd1 ) && (time_cnt == `AD_CLK_TIME))

ad_fsm_ns = FSM_DATA;

else

ad_fsm_ns = ad_fsm_cs;

FSM_DATA:

if((bit_cnt == 6'd8 ) && (time_cnt == `AD_CLK_TIME))

ad_fsm_ns = FSM_WAIT_CONV;

else

ad_fsm_ns = ad_fsm_cs;

FSM_WAIT_CONV:

if((bit_cnt == 6'd18) && (time_cnt == `AD_CLK_TIME))

ad_fsm_ns = FSM_END;

else

ad_fsm_ns = ad_fsm_cs;

FSM_END:

ad_fsm_ns = FSM_READY;

default:ad_fsm_ns = FSM_IDLE;

endcase

end

/*********************************************************

时钟计数器,用以产生1.1M的时钟

*********************************************************/

always @ (posedge sys_clk_50m or negedge rst_n)

if  (!rst_n)

time_cnt <= 6'd0;

else

time_cnt <= n_time_cnt;

always @ (*)

if (time_cnt == `AD_CLK_TIME)

n_time_cnt = 6'd0;

else

n_time_cnt = time_cnt + 6'd1;

/*********************************************

位计数器

*********************************************/

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

bit_cnt <= 6'd0;

else

bit_cnt <= n_bit_cnt;

always @ (*)

begin

if (ad_fsm_cs != ad_fsm_ns)

n_bit_cnt = 6'h0;

else if ( time_cnt== `AD_CLK_TIME_HALF )

n_bit_cnt = bit_cnt + 6'h1;

else

n_bit_cnt = bit_cnt;

end

/*******************************************************

产生外接时钟输入端的时钟信号,频率为1.1M,占空比约为50%

********************************************************/

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

poc_ad_clk <= 1'b0;

else

poc_ad_clk <= n_ad_clk;

always @(*)

begin

if (ad_fsm_cs != FSM_DATA)

n_ad_clk = 1'b0;

else if ( time_cnt == `AD_CLK_TIME_HALF )

n_ad_clk = 1'b1;

else if (time_cnt == `AD_CLK_TIME)

n_ad_clk = 1'b0;

else

n_ad_clk = poc_ad_clk;

end

/****************************************************

对TLC549的片选信号进行控制

*****************************************************/

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

poc_ad_cs <= 1'b0;

else

poc_ad_cs <= n_ad_cs;

always @ (*)

if ((ad_fsm_cs == FSM_DATA) || (ad_fsm_cs == FSM_READY))

n_ad_cs = 1'b0;

else

n_ad_cs = 1'b1;

/******************************************************

对数据寄存器赋值

******************************************************/

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

ad_data_reg <= 8'd0;

else

ad_data_reg <= n_ad_data_reg;

always @ (*)

begin

if ((ad_fsm_cs == FSM_DATA) && (!poc_ad_clk) && (n_ad_clk))

n_ad_data_reg = {ad_data_reg[6:0],pid_ad_data};

else

n_ad_data_reg = ad_data_reg;

end

/*************************************************************

输出数据处理

*************************************************************/

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

data_out <= 8'd0;

else

data_out <= n_data_out;

always @ (*)

begin

if (ad_fsm_cs == FSM_END)

n_data_out = ad_data_reg;

else

n_data_out = data_out;

end

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

o_vol_int <= 4'd0;

else

o_vol_int <= n_o_vol_int;

always @ (posedge sys_clk_50m or negedge rst_n)

if (!rst_n)

o_vol_dec <= 4'd0;

else

o_vol_dec <= n_o_vol_dec;

assign mid1 = {2'h0,data_out[7:0],2'h0} + {4'h0,data_out[7:0]};

assign mid2 = {1'h0,mid1[7:0],3'h0} + {3'h0,mid1[7:0],1'h0};

assign n_o_vol_int = mid1[11:8];

assign n_o_vol_dec = mid2[11:8];

endmodule

解释一下代码中在的数据转换部分,这里我所用的基准电压为5V,TLC549转换所得数据为8位,即0~255,那么电压计算公式如下:

V = data*5/256

这里不使用取模和求余运算,因为大家知道取模和求余运算会生成一个庞大的电路,运行速度慢,还浪费资源,FPGA所擅长的移位运算,无疑是不错的选择。

整数部分计算如下:

o_vol_int = (data*4+data)/255,转换成移位运算为((data<<2)+data)>>8

小数部分计算如下

o_vol_dec = ((5data&0xff)10)>>8

你可能感兴趣的:(ADC芯片TLC549的Verilog HDL)