我是靠谱客的博主 曾经水池,最近开发中收集的这篇文章主要介绍FPGA实现DAC驱动设计(以TLV5618为例),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

 

目录

step1:查询器件手册,了解TLV5618基本信息。

step2:引脚功能及输出电压范围

 step3 16位控制字数据格式

  step4 接口时序

   step5 系统框图

 step6 verilog代码

step7 testbench

step8 仿真结果


DAC(Digital to Analog Conver),即数模转换器D/A,简称ADC,是指将数字信号转变为模拟信号的电子元件。

step1:查询器件手册,了解TLV5618基本信息。

TLV5618是一个基于电压输出型的双通道 的12 位单电源数模转换器,其由串行接口、一个速度和电源控制器、 电阻网络、2 倍增益的输出缓冲器组成。

 TLV5618 使用 CMOS 电平兼容的三线制SPI串行总线与各种处理器进行连接接收控制器发送的 16 位的控制字,这 16 位的控制字被分为 2 个部分,包括 4 位的编程位,12 位的数据位。

step2:引脚功能及输出电压范围

 TLV5618 的参考电压由 LM4040-2.0 提供,LM4040-2.0 是一个专用于12 位精度场合的精密参考源,输出电压为 2.048V。

 TLV5618芯片实际输出电压范围为0~2*VREF。在AC620开发板上,对应为0~4.096V。当芯片上电时,DAC 的值全部被复位到0。每个 DAC 通道的输出可由下列公式计算得出:

 其中,REF 是基准电压,本电路中为 2.048V;CODE 是数字电压输入值,范围 0 到2^12 - 1。

 step3 16位控制字数据格式

 

  step4 接口时序

   step5 系统框图

 step6 verilog代码

module tlv5618(

	input sys_clk_i,//50M
	input ext_Rst_n,
	input start_en,//模块使能信号
	input [15:0]DAC_DATA,//控制器控制字
	output reg DAC_DIN,//TLV5618的DAC_DIN接口
	output reg DAC_SCLK,//TLV5618的DAC_SCLK接口,不高于20M设置12.5M
	output reg DAC_CS_N,//TLV5618的DAC_CS_N接口
	output reg set_done,//更新DAC完成标志,1表示完成
	output  DAC_state//模块状态表示,1表示空闲,0表示忙碌

);

assign DAC_state = DAC_CS_N;//开始工作DAC_CS_N为0
reg [1:0]div_cnt;//25M分频计数器
parameter cnt_max = 2;
reg en;
wire trans_done; //转换序列完成标志信号

always@(posedge sys_clk_i or negedge ext_Rst_n)
	
	if(!ext_Rst_n)
	
		en <= 1'b0;
		
	else if(start_en)
	
	   en <= 1'b1;
		
	else if(trans_done)
		
		en <= 1'b0;
		
	else en <= en;

always@(posedge sys_clk_i or negedge ext_Rst_n)
	
	if(!ext_Rst_n)
	
		div_cnt <= 2'd0;
		
	else if(en) begin
	
		if(div_cnt< 1'b1)
		
			div_cnt <= div_cnt +1'b1;
			
		else
		
			div_cnt <= 2'd0;end
	else 
	
		div_cnt <= 2'd0;

reg SCLK2x;//25M时钟信号

always@(posedge sys_clk_i or negedge ext_Rst_n)
	
	if(!ext_Rst_n)
		
		SCLK2x <= 1'b0;

		
	else if(en && (div_cnt == 2'd1))
		
		SCLK2x <= 1'b1;
		
	else
		SCLK2x <= 1'b0;
		
/*25M信号的第二种写法
always@(posedge sys_clk_i or negedge ext_Rst_n)
if(!ext_Rst_n)
	div_cnt <= 2'd0;
else if(start_en) begin
	if(div_cnt<= 2'd0)
	div_cnt <= 2'd0;
	else
	div_cnt <= 2'd0;end
else 
	div_cnt <= 2'd0;

reg SCLK2x;//25M时钟信号

always@(posedge sys_clk_i or negedge ext_Rst_n)
if(!ext_Rst_n)
	SCLK2x <= 1'b0;
else if(div_cnt == 2'd0)
	SCLK2x <= ~SCLK2x;
else
	SCLK2x <= SCLK2x;

*/	
/*12.5M信号的写法
always@(posedge sys_clk_i or negedge ext_Rst_n)
if(!ext_Rst_n)
	div_cnt <= 2'd0;
else if(start_en) begin
	if(div_cnt< 2'd1)
	div_cnt <= div_cnt +1'b1;
	else
	div_cnt <= 2'd0;end
else 
	div_cnt <= 2'd0;

reg SCLK2x;//25M时钟信号

always@(posedge sys_clk_i or negedge ext_Rst_n)
if(!ext_Rst_n)
	SCLK2x <= 1'b0;
else if(div_cnt == 2'd1)
	SCLK2x <= ~SCLK2x;
else
	SCLK2x <= SCLK2x;

*/	
		
reg [5:0]SCLK2x_num;

always@(posedge sys_clk_i or negedge ext_Rst_n)
	
	if(!ext_Rst_n)
	
		SCLK2x_num <= 6'd0;
		
	else if(en&&SCLK2x) begin
	
		if(SCLK2x_num <= 6'd32)
			
			SCLK2x_num <= SCLK2x_num +1'b1;
			
		else 	SCLK2x_num <= 6'd0;end
	else
	
		SCLK2x_num <= SCLK2x_num;
		
		/*计数至33,33自加一清0(此时en和sclk的有效信号最后一次被采集),
		此后,en无效,div_cnt不计数,sclk2x保持为0*/
		
reg [15:0]r_DAC_DATA;
always@(posedge sys_clk_i or negedge ext_Rst_n)
	
	if(!ext_Rst_n)
	
		r_DAC_DATA <= 16'd0;
		
	else if(start_en)
	
		r_DAC_DATA <= DAC_DATA;//收到开始发送命令时,寄存DAC_DATA值	
		
	else 
	
		r_DAC_DATA <= r_DAC_DATA;
		
always@(posedge sys_clk_i or negedge ext_Rst_n)
	
	if(!ext_Rst_n)begin

	DAC_DIN <= 1'b1;//空闲拉高
	DAC_SCLK <= 1'b0;
	DAC_CS_N <= 1'b1;//空闲拉高
	end
	 
	else if(!set_done&&SCLK2x)begin
	case(SCLK2x_num)
	0:begin 	
	       DAC_DIN <=r_DAC_DATA[15];
	       DAC_SCLK <=1'b1;
	       DAC_CS_N <=1'b0;//空闲拉高
	  end
	1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31: DAC_SCLK <=1'b0;
	2:begin   DAC_DIN <=r_DAC_DATA[14];DAC_SCLK <= 1'b1;end   
	4:begin   DAC_DIN <=r_DAC_DATA[13];DAC_SCLK <= 1'b1;end
	6:begin   DAC_DIN <=r_DAC_DATA[12];DAC_SCLK <= 1'b1;end
	8:begin   DAC_DIN <=r_DAC_DATA[11];DAC_SCLK <= 1'b1;end
	10:begin  DAC_DIN <=r_DAC_DATA[10];DAC_SCLK <= 1'b1;end
	12:begin  DAC_DIN <=r_DAC_DATA[9];DAC_SCLK <= 1'b1;end
	14:begin  DAC_DIN <=r_DAC_DATA[8];DAC_SCLK <= 1'b1;end
	16:begin  DAC_DIN <=r_DAC_DATA[7];DAC_SCLK <= 1'b1;end
	18:begin  DAC_DIN <=r_DAC_DATA[6];DAC_SCLK <= 1'b1;end
	20:begin  DAC_DIN <=r_DAC_DATA[5];DAC_SCLK <= 1'b1;end
	22:begin  DAC_DIN <=r_DAC_DATA[4];DAC_SCLK <= 1'b1;end
	24:begin  DAC_DIN <=r_DAC_DATA[3];DAC_SCLK <= 1'b1;end
	26:begin  DAC_DIN <=r_DAC_DATA[2];DAC_SCLK <= 1'b1;end
	28:begin  DAC_DIN <=r_DAC_DATA[1];DAC_SCLK <= 1'b1;end
	30:begin  DAC_DIN <=r_DAC_DATA[0];DAC_SCLK <= 1'b1;end
	32: DAC_SCLK <= 1'b1;
	33: DAC_CS_N <=1'b1; 
	endcase	
end
	
assign trans_done = (SCLK2x_num==6'd33)&&SCLK2x;//assign 和clk对齐的信号,立即有效操作
always@(posedge sys_clk_i or negedge ext_Rst_n)
	
	if(!ext_Rst_n)	
	
		set_done <= 1'b0;
	
   else if(trans_done)
	
		set_done <= 1'b1;//和clk对齐的信号,需要等待下一个clk到来时,进行有效操作
		
	else 
	
		set_done <= 1'b0;
endmodule 

step7 testbench

`timescale 1ns/1ns
`define clk_period 20

module tlv5618_tb;

	reg sys_clk_i;//50M
	reg ext_Rst_n;
	reg start_en;//模块使能信号
	reg [15:0]DAC_DATA;//控制器控制字
	wire  DAC_DIN;//TLV5618的DAC_DIN接口
	wire  DAC_SCLK;//TLV5618的DAC_SCLK接口,不高于20M设置12.5M
	wire  DAC_CS_N;//TLV5618的DAC_CS_N接口
	wire  set_done;//更新DAC完成标志,1表示完成
	wire  DAC_state;//模块状态表示,1表示空闲,0表示忙碌
	
tlv5618 tlv5618(

.sys_clk_i(sys_clk_i),
.ext_Rst_n(ext_Rst_n),
.start_en(start_en),
.DAC_DATA(DAC_DATA),
.DAC_DIN(DAC_DIN),
.DAC_SCLK(DAC_SCLK),
.DAC_CS_N(DAC_CS_N),
.set_done(set_done),
.DAC_state(DAC_state)

);


initial sys_clk_i =  0;
always#(`clk_period/2) sys_clk_i = ~sys_clk_i;
initial begin
ext_Rst_n = 0;
start_en = 0;
DAC_DATA = 0;
#201;
ext_Rst_n = 1;
#200;
DAC_DATA = 16'hC_AAA;
start_en = 1;
#20;
start_en = 0;
wait(set_done);
#20000;
DAC_DATA = 16'h4_555;
start_en = 1;
#20;
start_en = 0;
wait(set_done);
#20000;
DAC_DATA = 16'h1_555;
start_en = 1;
#20;
start_en = 0;
wait(set_done);
#20000;
DAC_DATA = 16'hF_555;
start_en = 1;
#20;
start_en = 0;
wait(set_done);
$stop;
end 
endmodule 

step8 仿真结果

 

最后

以上就是曾经水池为你收集整理的FPGA实现DAC驱动设计(以TLV5618为例)的全部内容,希望文章能够帮你解决FPGA实现DAC驱动设计(以TLV5618为例)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(40)

评论列表共有 0 条评论

立即
投稿
返回
顶部