前记:师夷长技以自强
p272
1.基本概念
DAC: Digital to Analog Conver,将数字信号转变为模拟信号的电子元件。由两个分组成,第一部分是电阻阵列,第二部分是n个电流开关(或者电压开关)。实验中使用的型号为TLV5618。
线性序列机:使用一个计数器不断计数,每个计数值根据芯片的时序对信号操作。
2.TLV5618简介
2.1.电气特性:
TLV5618是12位数字端输入2通道输出的DAC,实际控制只有3个管脚,兼容SPI接口。编程控制字有16位,其中4位控制为,12位数据位。
Terminal Functions
|
TERMINAL NAME | I/O/P | DESCTRIPTION |
| AGND | P | Group |
| \CS | I | Chip select.Digital input active low,used to enable/disable inputs. |
| DIN | I | Digital serial data input |
| OUTA | O | DAC A analog voltage output |
| OUTB | O | DAC B analog voltage output |
| REF | I | Analog reference voltage input |
| SCLK | I | Digital serial clock input |
| VDD | P | Positive power supply |
2.2电路设计
TLV5618与FPGA采用三线制SPI通信,REF端有LM4040-2.0提供,是一个专用于12位精度场合的精密参考电源。

2.3输出电压计算原理
电阻网络型DAC的输出电压范围应该是0V~Vref,另外在每个DAC通道的电阻网络电压输出后级,连接了一个2倍增益放大器,则最终输出电压的范围是0V~4.096V。
2.4接口时序
接口时序有三个问题:什么时候开始传数据?每个数据什么时候移入芯片内部寄存器?什么时候所有数据位全部移完?什么时候真正开始转换而输出模拟电压?
应该什么时候给DAC传数据呢?当然是工作的时候,而什么时候工作呢?那就是\CS未低的时候。每个数据是在SCLK的下降沿被存入芯片内部寄存器的,因此应该是最后一个SCLK下降沿的上升沿后所有数据位全部移完。当\CS变为高电平时,SCLK不再影响数据芯片内部寄存器的数据,此时真正开始转换而输出模拟电压。

那个输入数据的格式应该是怎么样的呢?
| D15 | D14 | D13 | D12 | D11 | D10 | D9 | D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
| R1 | SPD | PWR | R0 | 12位数据 | |||||||||||
SPD:1-快速模式,0-低速模式
PWR:1-掉电模式,0-正常模式
芯片内部除了有DAC A和DAC B两个锁存器外,还有一个缓冲区用来辅助两个通道的同时控制。其中R1和R2就是用来控制数据输出到哪里的。
|
R1 | R0 | 描述 |
| 0 | 0 | 写数据到DAC B和Buf |
| 0 | 1 | 写数据到Buf |
| 1 | 0 | 写数据到DAC A同时把缓冲区内容更新到DAC B |
| 1 | 1 | resever |
3.基于线性序列机的DAC驱动设计
3.1 线性序列机思想
在逻辑中使用一个计数器来计数,然后每个计数值就相当于在相应的时间点,在这个时间点上,各个信号需要进行什么操作直接赋值即可。这里有一个问题,DAC的工作频率如何选?通过查看芯片手册可以知道,SCLK的最大频率为20MHz,而FPGA的工作频率是50MHz,可选DAC的工作频率为12.5MHz,设置一个两倍于SCLK的采样时钟SCLK2X,使用50M系统时钟二分频即可得到SCLK2X。下面根据DAC的时序图列出芯片的线性序列机的操作表:

时间点对应的信号操作表为:
| 计数值 | 对应信号状态 |
| 0 | CS_N = 0;SCLK = 1;DIN = DATA[15]; |
| 1 | SCLK = 0; |
| 2 | SCLK =1;DIN = DATA[14]; |
| 3 | SCLK = 0; |
| 4 | SCLK =1;DIN = DATA[13]; |
| 5 | SCLK = 0; |
| 6 | SCLK =1;DIN = DATA[12]; |
| 7 | SCLK = 0; |
| 8 | SCLK =1;DIN = DATA[11]; |
| 9 | SCLK = 0; |
| 10 | SCLK =1;DIN = DATA[10]; |
| 11 | SCLK = 0; |
| 12 | SCLK =1;DIN = DATA[9]; |
|
13 | SCLK = 0; |
| 14 | SCLK =1;DIN = DATA[8]; |
| 15 | SCLK = 0; |
| 16 | SCLK =1;DIN = DATA[7]; |
| 17 | SCLK = 0; |
| 18 | SCLK =1;DIN = DATA[6]; |
| 19 | SCLK = 0; |
| 20 | SCLK =1;DIN = DATA[5]; |
| 21 | SCLK = 0; |
| 22 | SCLK =1;DIN = DATA[4]; |
|
23 | SCLK = 0; |
| 24 | SCLK =1;DIN = DATA[3]; |
| 25 | SCLK = 0; |
| 26 | SCLK =1;DIN = DATA[2]; |
| 27 | SCLK = 0; |
| 28 | SCLK =1;DIN = DATA[1]; |
| 29 | SCLK = 0; |
| 30 | SCLK =1;DIN = DATA[0]; |
| 31 | SCLK = 0; |
| 32 | SCLK = 1; |
| 33 | CS_N = 1; |
3.2 DAC模块的接口设计

模块端口功能描述如下
| 端口名称 | I/O | 描述 |
| Clk | I | 系统时钟,50MHz |
| Rst_n | I | 系统复位信号,低电平有效 |
| Start | I | 模块使能控制 |
| Dac_data[15:0] | I | 控制字 |
| Set_Done | O | 每次更新完成产生一个宽度为1个时钟周期的高电平脉冲 |
| CS_N | O | TLV5618的片选信号 |
| DIN | O | TLV5618的DIN信号 |
| SCLK | O | TLV5618的SCLK信号 |
| DAC_STATE | O | 0-忙碌,1-空闲 |
3.3 代码编写
为了辅助生成模块的输出信号,需要的内部信号有:
reg [15:0]Dac_data_r;//暂存输入的数据
reg en;//转换使能信号,标识ADC是否在工作
reg [7:0]DIV_CNT;//分频计数器
reg SCLK2X;//根据DIV_CNT生成的时钟信号
reg [5:0]SCL2X_CNT;//SCLK2X的计数器
wire Trans_done;//转换完成信号
需要注意的一点是,一次转换结束的标志是(SCL2X_CNT == 33 && SCLK2X)
module TLV5618(
input Clk,
input Rst_n,
input Start,
input [15:0]Dac_data,
output reg Set_Done,
output reg CS_N,
output reg DIN,
output reg SCLK,
output DAC_STATE
);
localparam DIV_PARAM = 2;//div system clock
reg en;
reg [15:0]Dac_data_r;
reg [7:0]DIV_CNT;
reg SCLK2X;
reg [5:0]SCLK2X_CNT;
wire Trans_done;
always@(posedge Clk,negedge Rst_n)//en
if(!Rst_n)
en <= 0;
else if(Start)
en <= 1;
else if(Set_Done)
en <= 0;
else
en <= en;
always@(posedge Clk,negedge Rst_n)//DIV_CNT
if(!Rst_n)
DIV_CNT <= 0;
else if(en)
if(DIV_CNT == DIV_PARAM - 1)
DIV_CNT <= 0;
else
DIV_CNT <= DIV_CNT + 8'b1;
else
DIV_CNT <= 0;
always@(posedge Clk,negedge Rst_n)//SCLK2X
if(!Rst_n)
SCLK2X <= 0;
else if(en&&(DIV_CNT == (DIV_PARAM - 1)))
SCLK2X <= 1;
else
SCLK2X <= 0;
always@(posedge Clk,negedge Rst_n)//SCLK2X_CNT
if(!Rst_n)
SCLK2X_CNT <= 0;
else if(en&&SCLK2X)
if(SCLK2X_CNT == 6'd33)
SCLK2X_CNT <= 0;
else
SCLK2X_CNT <= SCLK2X_CNT + 6'b1;
else
SCLK2X_CNT <= SCLK2X_CNT;
always@(posedge Clk,negedge Rst_n)
if(!Rst_n)begin
SCLK <= 1;
DIN <= 1;
CS_N <= 1;
Dac_data_r <= 0;
end
else if(!Set_Done&&SCLK2X)begin
case(SCLK2X_CNT)
0:
begin
SCLK <= 1;
DIN <= Dac_data_r[15];
Dac_data_r <= Dac_data_r << 1;
CS_N <= 0;
end
1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31:
begin
SCLK <= 0;
end
2,4,6,8,10,12,14,16,18,20,22,24,26,28,30:
begin
SCLK <= 1;
DIN <= Dac_data_r[15];
Dac_data_r <= Dac_data_r << 1;
end
32:SCLK <= 1;
33:CS_N <= 1;
default:;
endcase
end
else if(Start)
Dac_data_r <= Dac_data;
assign Trans_done = (SCLK2X_CNT == 33)&&SCLK2X;
always@(posedge Clk,negedge Rst_n)
if(!Rst_n)
Set_Done <= 0;
else if(Trans_done)
Set_Done <= 1;
else
Set_Done <= 0;
assign DAC_STATE = !en;
endmodule
3.4仿真测试
`timescale 1ns/1ns
`define period 20
module TLV5618_tb;
reg Clk;
reg Rst_n;
reg Start;
reg [15:0]Dac_data;
wire set_Done;
wire CS_N;
wire DIN;
wire SCLK;
wire DAC_STATE;
TLV5618 TLV5618_1(
.Clk(Clk),
.Rst_n(Rst_n),
.Start(Start),
.Dac_data(Dac_data),
.Set_Done(set_Done),
.CS_N(CS_N),
.DIN(DIN),
.SCLK(SCLK),
.DAC_STATE(DAC_STATE)
);
initial Clk <= 0;
always #10 Clk <= ~ Clk;
initial begin
Rst_n = 0;
Start = 0;
Dac_data = 0;
#`period;
Rst_n = 1;
#`period;
Dac_data = 16'hC_AAA;
Start = 1;
#`period;
Start = 0;
#200
wait(set_Done);
#20000;
Dac_data = 16'h4_555;
Start = 1;
#`period;
Start = 0;
#200;
wait(set_Done);
$stop;
end
endmodule
全局图

局部图

本文详细介绍了DAC(数字模拟转换器)的基本概念,重点解析了TLV5618芯片的电气特性、电路设计及输出电压计算原理。通过基于线性序列机的驱动设计,阐述了DAC与FPGA的三线制SPI通信过程,包括数据传输时序、控制字格式与模块接口设计。
1487

被折叠的 条评论
为什么被折叠?



