FPGA驱动DAC芯片输出(以TLV5618为例)_StrangerZhou1的博客-程序员秘密_dac fpga

技术标签: fpga  FPGA学习笔记  

一、任务

使用FPGA芯片控制DAC采集芯片,输出指定的电压值。

二、硬件部分

为了将FPGA输出的数字电压转换成模拟电压,我们使用到了数模转换芯片(简称DAC)TLV5618。进行设计前,我们先到网上检索并查看了该芯片的数据手册。

1.芯片功能图

在这里插入图片描述

2.端口功能表

在这里插入图片描述
从功能图和功能表中我们可以看出,TLV5618有四个输入端口:
片选信号CS、数据串行输入端口DIN、模拟参考电压REF、数字时钟SCLK
两个输出端分别为OUTAOUTB,均为对应的模拟电压输出端。

3.时序图

在这里插入图片描述
时序图中我们可以看到使用该芯片时要注意这几个参数:
tw(L):低电平最小宽度,25ns。
tw(H):高电平最小宽度,25ns。
tsu(D):数据最短建立时间。
th(D):数据最短保持时间。
tsu(CS-CK):片选信号下降沿到第一个时钟下降沿最短时间。
th(CSH):片选信号最短拉高时间。

在我们写FPGA代码时,需要根据严格按照时序图来。

4.输出电压计算

在这里插入图片描述
由手册给出的公式知,输出电压与输入的编码值成正比,同时还要乘以一个系数REF,这个系数从芯片的REF引脚输入。我们打开并查看开发板的原理图:在这里插入图片描述
从图中知,我们用到了芯片LM4040-2.0给DAC供电,这个芯片工作时输出电压为4.028V(即精度为12位),故参数REF为4.028。

5.时钟频率与刷新率计算

在这里插入图片描述
我们查阅手册后知道,使用该芯片时,时钟最大频率为20MHz,刷新率为时钟频率的1/16。而开发板提供的原始时钟为50MHz,因此可以采用四分频后得到12.5MHz的时钟频率。

三、设计方案

在这里插入图片描述
我们考虑用FPGA设计一个DAC驱动,通过CS、sclk、din三根信号线与DAC芯片连接,设计输入端口Data[15:0]。同时为了便于与其他模块共同协作,我们加上了使能端口en转换完成标志位Conv_done,这是FPGA设计时必须考虑的一点,对于复杂的驱动模块,这两个信号是不可或缺的

四、软件部分

这里直接上代码部分,注释里面有解读。

// 驱动部分
module tlv5618(
	Clk,
	Rst_n,
	
	DAC_DATA,	//并行数据输入端
	Start,		//开始标志位
	Set_Done,	//完成标志位
	
	DAC_CS_N,	//片选
	DAC_DIN,	//串行数据送给ADC芯片
	DAC_SCLK,	//工作时钟SCLK
	DAC_State	//工作状态
);
	
	parameter fCLK = 50;		//时钟参数
	parameter DIV_PARAM = 2;	//分频参数

	input Clk;
	input Rst_n;
	input [15:0] DAC_DATA;
	input Start;
	output reg Set_Done;
	
	output reg DAC_CS_N;
	output reg DAC_DIN;
	output reg DAC_SCLK;
	output DAC_State;
	
	assign DAC_State = DAC_CS_N;	//工作状态标志与片选信号相同
	
	reg [15:0] r_DAC_DATA;
	
	reg [3:0] DIV_CNT;		//分频计数器
	reg SCLK2X;				//2倍SCLK的采样时钟
	
	reg [5:0] SCLK_GEN_CNT;	//SCLK生成暨序列机计数器
	
	reg en;					//转换使能信号
	
	wire trans_done; 		//转换序列完成标志信号
	
	[email protected](posedge Clk or negedge Rst_n)
	if(!Rst_n)
		en <= 1'b0;
	else if(Start)
		en <= 1'b1;
	else if(trans_done)
		en <= 1'b0;	//转换完成后将使能关闭
	else
		en <= en;		

	//分频计数器
	[email protected](posedge Clk or negedge Rst_n)
	if(!Rst_n)
		DIV_CNT <= 4'd0;
	else if(en)begin
		if(DIV_CNT == (DIV_PARAM - 1'b1))	//前面设置了分频系数为2,这里计数器能够容纳2拍时钟脉冲
			DIV_CNT <= 4'd0;
		else 
			DIV_CNT <= DIV_CNT + 1'b1;
		end
	else
		DIV_CNT <= 4'd0;

	//二分频
	[email protected](posedge Clk or negedge Rst_n)
	if(!Rst_n)
		SCLK2X <= 1'b0;
	else if(en && (DIV_CNT == (DIV_PARAM - 1'b1)))
		SCLK2X <= 1'b1;
	else
		SCLK2X <= 1'b0;
		
	//生成序列计数器,对SCLK脉冲进行计数
	[email protected](posedge Clk or negedge Rst_n)
	if(!Rst_n)
		SCLK_GEN_CNT <= 6'd0;
	else if(SCLK2X && en)begin	//在高脉冲期间,累计拍数
		if(SCLK_GEN_CNT == 6'd33)
			SCLK_GEN_CNT <= 6'd0;
		else
			SCLK_GEN_CNT <= SCLK_GEN_CNT + 1'd1;
		end
	else
		SCLK_GEN_CNT <= SCLK_GEN_CNT;

	[email protected](posedge Clk or negedge Rst_n)
	if(!Rst_n)
		r_DAC_DATA <= 16'd0;
	else if(Start)	//收到开始发送命令时,寄存DAC_DATA值
		r_DAC_DATA <= DAC_DATA;
	else
		r_DAC_DATA <= r_DAC_DATA;
				
	//依次将数据移出到DAC芯片
	[email protected](posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		DAC_DIN <= 1'b1;
		DAC_SCLK <= 1'b0;
		DAC_CS_N <= 1'b1;
		end
	else if(!Set_Done && SCLK2X) begin
		case(SCLK_GEN_CNT)
			0:
				begin	//高脉冲期间内,计数为0时了,打开片选使能,给予时钟上升沿,将最高位数据送给ADC芯片
					DAC_CS_N <= 1'b0;
					DAC_DIN <= r_DAC_DATA[15];
					DAC_SCLK <= 1'b1;
				end
		
			1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31:
				begin
					DAC_SCLK <= 1'b0;	//时钟低电平
				end
			
			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;	//关闭片选
			default:;
		endcase
	end
	
	assign trans_done = (SCLK_GEN_CNT == 33) && SCLK2X;
	
	[email protected](posedge Clk or negedge Rst_n)
	if(!Rst_n)
		Set_Done <= 1'b0;
	else if(trans_done)
		Set_Done <= 1'b1;
	else
		Set_Done <= 1'b0;
	
endmodule

//顶层模块
module DAC_test(
			Clk,   //模块时钟50M
			Rst_n, //模块复位
			
			DAC_CS_N,  //TLV5618的CS_N接口
			DAC_DIN,   //TLV5618的DIN接口
			DAC_SCLK   //TLV5618的SCLK接口
		);
	input Clk;
	input Rst_n;
	
	output DAC_CS_N;
	output DAC_DIN;
	output DAC_SCLK;
	
	reg Start;
	reg [15:0]r_DAC_DATA;
	wire DAC_State;
	wire [15:0]DAC_DATA;
	wire Set_Done;
	
	tlv5618 tlv5618(
		.Clk(Clk),
		.Rst_n(Rst_n),
		
		.DAC_DATA(DAC_DATA),
		.Start(Start),
		.Set_Done(Set_Done),
		
		.DAC_CS_N(DAC_CS_N),
		.DAC_DIN(DAC_DIN),
		.DAC_SCLK(DAC_SCLK),
		.DAC_State(DAC_State)
	);

	[email protected](posedge Clk or negedge Rst_n)
	if(!Rst_n)
		r_DAC_DATA <= 16'd0;
	else if(DAC_State)
		r_DAC_DATA <= DAC_DATA;
		
	[email protected](posedge Clk or negedge Rst_n)
	if(!Rst_n)
		Start <= 1'd0;
	else if(r_DAC_DATA != DAC_DATA) 
		Start <= 1'b1;
	else
		Start <= 1'd0;

endmodule

五、仿真

在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_51261356/article/details/113197323

智能推荐

github.com使用方法_weixin_30919571的博客-程序员秘密

github.com作为一个开源的代码托管平台,非常适合创建自己的代码库,也适合从别人已有项目fork自己的私有库;如果想私有托管,需要缴费使用。 创建自己代码库 在个人主页面,点击右上角+号,选择New repository: 在新页面输入Repository name,添加Description,选择Public/Private,或者添加一个README说明文件,设置好之后点击Create ...

一加手机如何拷贝公交卡_一加6T有NFC吗?一加手机6T支持NFC刷公交卡怎么设置?[多图]..._粗细愁倚阑的博客-程序员秘密

一加6T有NFC吗?一加手机6T支持NFC刷公交卡怎么设置?前日一加6T国行版在国内正式公布了,一加6T和一加6相比,虽然差别不是特别大,升级的地方也不是满多,但是各方面表现都还算出色。不过今天就百度网友问到小编,一加6T有没有NFC功能的问题,大家都知道,现在NFC应用场景越来越多了,因此网友们关注NFC功能也在情理之中,今天新机汇就来跟大家详细解答一下,一起来看看。一加6T有NFC功能吗?可以...

return和throw到底怎么搞?_知道越多,知道越少的博客-程序员秘密_return throw

当存在返回值的时候(不为void的时候),我们尽量可以抛出一个异常来代替return如下: public int pop() { if (isEmpty()) { //throw相当于已经停止了代码,所以不用return //当存在返回值的时候(不为void)的时候,我们尽量可以抛出一个异常来代替return throw new RuntimeException("栈空,无法取出数据~"); }

caffe配置文件 网络lenet-train-test.prototxt注释及说明_轻风1976的博客-程序员秘密

name: "LeNet"layer {  name: "mnist"  type: "Data"  top: "data"                                         #this layer produces two blobs, one is the data blob, and one is the label blob.  top:

ASP.net 将Excel转换成图片 并裁剪指定大小_一只毛驴成长记的博客-程序员秘密

一、将当前Excel文件装换为图片1.需要引用Spire.Xls dll,可以去网上下载;2.对应方法public class XLS { /// &amp;lt;summary&amp;gt; /// Excel转图片 /// &amp;lt;/summary&amp;gt; /// &amp;lt;param name=&quot;filePath&quot;&amp;gt;文件路径&amp;lt...

git rebase 变基命令——移花接木_BenBenF19的博客-程序员秘密_停止变基

git rebase 变基命令——移花接木语法描述git rebase &lt;since&gt; [&lt;till&gt;]​git rebase --onto &lt;newbase&gt; &lt;since&gt; &lt;till&gt;冲突解决--onto &lt;newbase&gt; 选项——指定新提交起点--continue 选项——继续变基--abort 选项——终止变基--skip 选项——跳过冲突提交语法git rebase [&lt;选项&gt; …​] [--onto

随便推点

Python数组基本操作_狗头实习生的博客-程序员秘密_python 数组操作

项目一:基础编程1.创建两个数组完成sqrt,abs,函数的调用,以及两个数组做加法输出格式如下:import numpy as npfrom numpy import arangeprint()print('第一题')a1 = np.array([10, 20, 30, 40])print(a1)a2 = np.array([8, -67, -34, 69])print(a2)print(np.sqrt(a1))print(np.abs(a2))print(a2+a1)

软件开发成本估算_weixin_30612769的博客-程序员秘密

项目开发注意开发历程2011-07-18 18:01376人阅读评论(0)收藏举报 首先我们需要明确的是为什么要做软件项目预算.首先软件项目是不同于一般工程项目的项目类型.受用户需求,开发方式的影响很大.没有明确的预算,会导致软件开支的不可控制,随着项目的进行,开发放要承担的风险也会增加.另外如果没有预算,更不可能与客户达成开发协议.没有人会傻到委托别人做一个自己都不知道要花多...

40 个免费的面向编程初学者的视频教程_普通网友的博客-程序员秘密

来源 |https://javascript.plainenglish.io/top-40-free-programming-courses-for-beginners-bc39253e784c今天,我将跟大家分享40个免费的编程视频教程,大家可以根据自己的情况,进行合理安排学习。现在,我们就一起来看看这些教程吧。01、JavaScript 基础地址:https://w...

主成分分析(PCA)的数学原理与应用_danielxxxxx的博客-程序员秘密

PCA(主成分分析)主要用于数据降维。问题:样本 x i ∈R m  x_i \in \mathbb R^{m} 以列向量表示,现将 n n 个样本构成的样本集 X∈R m×n  X\in \mathbb R^{m\times n} 降维到 X ^ ∈R k×n  \hat{X} \in \mathbb R^{k\times n}(k≤m k \leq m),以达到数据压缩的目的。不难发现,上述问题

SQL Server聚合函数总结_marvel_java的博客-程序员秘密

当走在嘈杂的城市中时,什么能让我们变得冷静呢?心声向我述说了一些,“简单”不一定就真的简单,它是相对的,当我们长大了,想要保持儿时的单纯,我想只能在梦中由心所发了,因为现实让我们都变了,要想重新找回曾经的东西,可能真的很难。

中国氢能行业发展现状与投资规划深度研究报告2022-2027年版_普通网友的博客-程序员秘密

中国氢能行业发展现状与投资规划深度研究报告2022-2027年版+氢能是通过氢气和氧气反应所产生的能量。氢能是氢的化学能,氢在地球上主要以化合态的形式出现,是宇宙中分布广泛的物质,它构成了宇宙质量的75%,属于二次能源。工业上生产氢的方式很多,常见的有水电解制氢、煤炭气化制氢、重油及天然气水蒸气催化转化制氢等,但这些反应消耗的能量都大于其产生的能量。经过十余年的长足发展,我国氢气年产量已逾千万吨规模,位居世界第一大产氢国;同时,我国金属储氢材料产销量已超过日本,成为世界大储氢材料产销国。氢气产量和..

推荐文章

热门文章

相关标签