FPGA驱动AD芯片_实现与芯片通信
概述: 利用FPGA实现AD芯片的时序,进一步实现与AD芯片数据的交互,主要熟悉FPGA对时序图的实现,掌握时序图转换Verilog硬件描述语言技巧后与其它芯片进行数据的交互也是类似的。
说明: FPGA芯片采用了altera的Cyclon IV E系列的“EP4CE10F17C8”,软件环境-Quartus-Ⅱ,采用的AD芯片为—AD-TLC549。
通过FPGA实现以下时序设计:
1.AD-TLC549简介
位数:8位。
最大转换时间:17us(36个内部时钟周期)。
转换速率:每秒40000次。
TOP VIEW:
电路连接图:
2.AD-TLC549时序图解析
From datasheet:
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的时钟。
(3) 读完8位数据后,AD开始转换下一帧 数据B,以便下次读取,转换时片选信号CS必须置高电平,每次转换的时间不超过17us,转换开始于CS变低后的I/O CLOCK的第8个下降沿,没有转换完成的标志信号;也没有启动控制端,只要读取前一次数据后马上就可以开始新的AD转换,转换完后就进入保持状态。
3.时序图转化为Verilog代码
在时序图转化为Verilog代码过程中,要注意的是时间
=1.4us、
=17us、I/O CLOCK=1MHz,AD转换的时候I/O CLOCK是没有的。
(1)代码TOP VIEW:
(2)代码按以下状态机编写:
状态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Ⅱ仿真得到以下波形:
波形解析:
(1)
:
用计数器实现了1.9us延时,大于了1.4us。
(2)
:
用计数器实现17us延时
(3) 8bit数据及其时钟: