FPGA驱动AD芯片_实现与芯片通信

FPGA驱动AD芯片_实现与芯片通信

概述: 利用FPGA实现AD芯片的时序,进一步实现与AD芯片数据的交互,主要熟悉FPGA对时序图的实现,掌握时序图转换Verilog硬件描述语言技巧后与其它芯片进行数据的交互也是类似的。

说明: FPGA芯片采用了altera的Cyclon IV E系列的“EP4CE10F17C8”,软件环境-Quartus-Ⅱ,采用的AD芯片为—AD-TLC549。

通过FPGA实现以下时序设计:
FPGA驱动AD芯片_实现与芯片通信_第1张图片

文章目录

    • 1.AD-TLC549简介
    • 2.AD-TLC549时序图解析
    • 3.时序图转化为Verilog代码
    • 4. 仿真结果


1.AD-TLC549简介

位数:8位。
最大转换时间:17us(36个内部时钟周期)。
转换速率:每秒40000次。
TOP VIEW
FPGA驱动AD芯片_实现与芯片通信_第2张图片
电路连接图
FPGA驱动AD芯片_实现与芯片通信_第3张图片


2.AD-TLC549时序图解析

From datasheet:

FPGA驱动AD芯片_实现与芯片通信_第4张图片

2.1时序图说明:

(1) 当CS为高时,转换结果数据串行输出端DATA OUT处于高阻态,此时I/O CLOCK也不起作用。
(2) 当CS为低时,AD前一次转换的数据A的最高位A7立即出现在数据线DATA OUT上,其余的7位数据在I/O CLOCK的下降沿依次由时钟同步输出(方便我们在上升沿采集数据,细品)。

注意:

当CS变为低电平到I/O CLOCK的第一个时钟到来至少需要1.4us。

在这里插入图片描述
I/O CLOCK不能超过1.1M,Verilog代码中采用了1M的时钟。
FPGA驱动AD芯片_实现与芯片通信_第5张图片
(3) 读完8位数据后,AD开始转换下一帧 数据B,以便下次读取,转换时片选信号CS必须置高电平,每次转换的时间不超过17us,转换开始于CS变低后的I/O CLOCK的第8个下降沿,没有转换完成的标志信号;也没有启动控制端,只要读取前一次数据后马上就可以开始新的AD转换,转换完后就进入保持状态。
在这里插入图片描述


3.时序图转化为Verilog代码

在时序图转化为Verilog代码过程中,要注意的是时间 t su { {\text{t}}_{ {\text{su}}}} tsu=1.4us、 t conv { {\text{t}}_{ {\text{conv}}}} tconv=17us、I/O CLOCK=1MHz,AD转换的时候I/O CLOCK是没有的
FPGA驱动AD芯片_实现与芯片通信_第6张图片
在这里插入图片描述
在这里插入图片描述

(1)代码TOP VIEW:

FPGA驱动AD芯片_实现与芯片通信_第7张图片
(2)代码按以下状态机编写:

FPGA驱动AD芯片_实现与芯片通信_第8张图片
状态1:CS拉低至CLK第一个上升沿。
状态2:在I/O CLOCK8个上升沿读取数据。
状态3:等待AD转换完成。
状态4:AD转换完完成。

(3)依据时序图完成以下代码:

//系统时钟为50M,周期为20ns; AD时钟为1M,周期为1us

`define Tsu_time 			10'd70			//70*20	=1.4us,Tsu延时的计数终值
`define Cov_time 			10'd850			//850*20=17us, Cov延时的计数终值
`define CLK_time 			10'd50			//20*50	=1us,  实现1M AD时钟得计数终值
`define CLKHALF_time 		10'd25			//20*25	=0.5us,实现1M AD时钟得计数中值		

module AD_TLC549
(
	//输入
	input			CLK_50M,				//系统时钟
	input 			RST_N,					//复位
	input 			AD_DATA,				//8bit AD原始数据
	//输出
	output reg 		AD_CS,					//片选
	output reg 		AD_CLK					//AD时钟	1M
);

//状态机,四个状态;状态1:CS拉低至CLK第一个上升沿,状态2:读取数据,状态3等待转换,状态4:转换完成
reg [2:0]	SM_NOW/*synthesis preserve*/; //现在的状态
reg [2:0]	SM_NEXT/*synthesis preserve*/;//下一状态
parameter 	SM_Tsu		= 3'd0,			 //CS拉低至CLK第一个上升沿		1.4us
			SM_Data 	= 3'd1,			 //读取AD数据					8个AD_CLK
			SM_Cov		= 3'd2,			 //等待转换						17us
			SM_End		= 3'd3;			 //转换完成

//产生计数
reg[9:0] 	Time_cnt;						//在状态机的每个状态开始都会被清零,可以运用至每个状态的计数
reg[3:0] 	CLK_posedge;					//AD_CLK 的8个时钟上升沿

//读取的8bit数据
reg[7:0]	DATA;							//数据现态
reg[7:0]    DATA_N/*synthesis preserve*/;	//数据的下一个状态


//时钟
reg 			AD_CLK_N;					//AD_CLK的下一个状态


//时序产生,Tsu计时、Cov计时、AD_CLK计时
always@(posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		Time_cnt <= 10'd0;
	else if(SM_NOW != SM_NEXT)
		Time_cnt <= 10'd0;
	else if(SM_NOW == SM_Tsu)//产生tus延时
	begin
		if(Time_cnt == `Tsu_time)
			Time_cnt <= 10'd0;
		else
			Time_cnt <= Time_cnt + 10'd1;
	end
	else if(SM_NOW == SM_Cov)//产生Cov延时
	begin
		if(Time_cnt == `Cov_time)
			Time_cnt <= 10'd0;
		else
			Time_cnt <= Time_cnt + 10'd1;
	end
	else if(SM_NOW == SM_Data)//产生CLK
	begin
		if(Time_cnt == `CLK_time)	
			Time_cnt <= 10'd0;
		else
			Time_cnt <= Time_cnt + 10'd1;
	end
	else
		Time_cnt <= Time_cnt;
end

//产生AD_CLK
always@(posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		AD_CLK <= 0;
	else
		AD_CLK <= AD_CLK_N;
end
always@(*)
begin
	if(SM_NOW != SM_Data)
		AD_CLK_N = 0;	
	else if(Time_cnt == `CLKHALF_time)				//半周期			
	begin
		AD_CLK_N = 1;								//CLK_H	
	end
	else if(Time_cnt == `CLK_time)					//满周期
		AD_CLK_N = 0;								//CLK_L
	else
		AD_CLK_N = AD_CLK;
end

//记录AD_CLK的8个上升沿
always@(posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		CLK_posedge <= 4'd0;
	else if(SM_NOW != SM_Data)
		CLK_posedge <= 4'd0;
	else if(Time_cnt == `CLKHALF_time)	
		CLK_posedge <= CLK_posedge + 4'd1;
	else
		CLK_posedge <= CLK_posedge;
end

//CS信号产生
always@(posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		AD_CS <= 1'b1;
	else
	begin
		if(SM_NOW == SM_Tsu)
			AD_CS <= 1'b0;
		else if(SM_NOW == SM_Cov)
			AD_CS <= 1'b1;
		else
			AD_CS <= AD_CS;
	end
end


//状态机,产生AD时序
always@(posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		SM_NOW <= 3'd0;
	else
		SM_NOW <= SM_NEXT;
end
always@(*)
begin
	case(SM_NOW)
		SM_Tsu:												//状态1:CS拉低至CLK第一个上升沿。
			if(Time_cnt == `Tsu_time)
				SM_NEXT = SM_Data;
			else
				SM_NEXT = SM_Tsu;
		SM_Data:											//状态2:在I/O CLOCK8个上升沿读取数据。
			if(CLK_posedge == 4'd8 && Time_cnt == `CLK_time)
				SM_NEXT = SM_Cov;
			else
				SM_NEXT = SM_Data;
		SM_Cov: 											//状态3:等待AD转换完成。
			if(Time_cnt == `Cov_time)
				SM_NEXT = SM_End;
			else
				SM_NEXT = SM_Cov;
		SM_End:												//状态4:AD转换完完成。
				 SM_NEXT <= SM_Tsu;			
		default:SM_NEXT <= SM_Tsu;		
	endcase
end



//提取数据
always@(posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		DATA <= 8'b0;
	else
		DATA <= DATA_N;
end

always@(*)
begin
	if((SM_NOW == SM_Data)&&(!AD_CLK)&&(AD_CLK_N))//上升沿
		DATA_N = {
     DATA[6:0],AD_DATA};
	else
		DATA_N = DATA;
end

endmodule

4. 仿真结果

通过SignalTapⅡ仿真得到以下波形:
FPGA驱动AD芯片_实现与芯片通信_第9张图片
波形解析:

(1) t su { {\text{t}}_{ {\text{su}}}} tsu
用计数器实现了1.9us延时,大于了1.4us。
FPGA驱动AD芯片_实现与芯片通信_第10张图片

(2) t conv { {\text{t}}_{ {\text{conv}}}} tconv
用计数器实现17us延时
FPGA驱动AD芯片_实现与芯片通信_第11张图片
(3) 8bit数据及其时钟:
FPGA驱动AD芯片_实现与芯片通信_第12张图片

你可能感兴趣的:(FPGA学习笔记,verilog,fpga)