前言
之前做的dds信号发生器,输出的是数字量数据,如果需要实际使用产生的信号,则需要DA转换,就是数字量到模拟量的转换。Digital-Analog-Converter,数字模拟转换器。
正文
一、DAC的设计验证
1.项目需求
对dds信号发生器产生的数据通过DA芯片转换为模拟量(电压)。
之前dds信号发生器完成,幅度调节,相位调节,频率调节。这里使用的DA芯片为TLC5620,其特点为:
4通道8位da转换器
采用串行接口的数据输入
输出电压范围参考电压和地之间1-2倍的范围
命令字节11bit:数据格式2bit通道选择+1bit范围+8bit数据
高位在前(msb)

数据在da clk的下降沿移入到串行接口寄存器(fpga发数据在da clk 的上升沿)
load:高电平时没有数据更新,当ldac为低电平时,拉低load信号输出就会更新
ldac:拉低ldac信号输出就可以更新
两种更新方式:
(1)先拉低load信号,再拉低ldac信号(2)ldac信号一直为低电平,拉低load就可以更新
两种传输方式:
(1)一次性传输11bit数据(2)分两个8时钟周期传输,第一个传输通道选择和范围,第二个传输数据
这里使用的为一次性11bit数据传输:


2.技术介绍
由上传输时序图和对应的时刻对应表可知,clk是1Mhz时钟但在传输完11bit数据的最后一位后一直拉低,直到下次数据传输,传输完11bit数据的最后一位后,先拉低load信号,再拉低ldac信号。
由于需要的clk不连续,所以之前使用的状态机不适用于该工程。
这里提出一种新的写法:序列机(相当于时钟树(可以理解为闹铃,告诉你在什么时刻该干什么)),我们使用的系统时钟为50Mhz,ad_clk为1Mhz = 1000ns = 50个clk周期,共需要11个周期,50*11 = 25*22,传输完数据后拉低250ns的load信号,这里使用20*13 = 260ns,再拉低ldac信号。把时序表列出来:
| rst_n | cnt= 0 | ad_clk = 0,ad_data = 0,ad_load = 1,ad_ldac = 1 |
| 0 | ad_clk = 0,ad_data = 0,ad_load = 1,ad_ldac = 1 | |
| 1 | ad_clk = 1,ad_data = data_in[10] | |
| 1+25*1 | ad_clk = 0 | |
| 1+25*2 | ad_clk = 1,ad_data = data_in[9] | |
| ...... | ||
| 1+25*20 | da_clk=1 da_data=data_in[0] | |
| 1+25*21 | da_clk=0 | |
| 1+25*22 | da_load = 0 | |
| 1+25*22+13 | da_load=1 da_ldac=0 | |
| 1+25*21+13+13 | da_ldac=1 |
3.顶层架构
这里直接使用RTL视图了:

4.端口描述
通过芯片手册,可以看出在该DA芯片中有2级寄存器,LOAD管理前寄存,LDAC管理后寄存,当两个信号拉低时数据才能进入DAC转换模块。在这里简称LOAD为前寄存,LDAC为后寄存。

| clk | 50Mhz |
| data_in[10:0] | 模拟量输入 |
| rst_n | 复位 |
| ad_clk | 1Mhz断续信号 |
| data | 数字量输出 |
| laod | 前寄存 |
| laod | 后寄存 |
二、代码验证
DAC芯片控制模块
module da_ctrl(
input clk ,//50Mhz
input rst_n ,
input [10:0] data_in ,
output reg data ,
output reg laod ,//前锁存
output reg ldac ,//后锁存
output reg ad_clk //1Mhz
);
reg [09:0]time_cnt;//总计时器
reg [10:0]data_pa;//输入寄存器
always@(posedge clk,negedge rst_n)//输入寄存确保数据完整
begin
if(!rst_n)
data_pa <= 0;
else if(time_cnt == 0)
data_pa <= data_in;
else
data_pa <= data_pa;
end
always@(posedge clk,negedge rst_n)//计时器驱动
begin
if(!rst_n)
time_cnt <= 0;
else
time_cnt <= time_cnt + 1;
end
always@(posedge clk,negedge rst_n)
begin
if(!rst_n)
begin
ad_clk<= 0;
data <= 0;
laod <= 1;
ldac <= 1;
end
else
case(time_cnt)
0:
begin
ad_clk<= 0;
data <= 0;
laod <= 1;
ldac <= 1;
end
1:
begin
ad_clk<= 1;
data <= data_pa[10];
end
1+25*1:
ad_clk<= 0;
1+25*2:
begin
ad_clk<= 1;
data <= data_pa[9];
end
1+25*3:
ad_clk<= 0;
1+25*4:
begin
ad_clk<= 1;
data <= data_pa[8];
end
1+25*5:
ad_clk<= 0;
1+25*6:
begin
ad_clk<= 1;
data <= data_pa[7];
end
1+25*7:
ad_clk<= 0;
1+25*8:
begin
ad_clk<= 1;
data <= data_pa[6];
end
1+25*9:
ad_clk<= 0;
1+25*10:
begin
ad_clk<= 1;
data <= data_pa[5];
end
1+25*11:
ad_clk<= 0;
1+25*12:
begin
ad_clk<= 1;
data <= data_pa[4];
end
1+25*13:
ad_clk<= 0;
1+25*14:
begin
ad_clk<= 1;
data <= data_pa[3];
end
1+25*15:
ad_clk<= 0;
1+25*16:
begin
ad_clk<= 1;
data <= data_pa[2];
end
1+25*17:
ad_clk<= 0;
1+25*18:
begin
ad_clk<= 1;
data <= data_pa[1];
end
1+25*19:
ad_clk<= 0;
1+25*20:
begin
ad_clk<= 1;
data <= data_pa[0];
end
1+25*21:
ad_clk<= 0;
1+25*22:
laod<= 0;
1+25*22+13:
begin
laod<= 1;
ldac<= 0;
end
1+25*22+13+13:
ldac<= 1;
endcase
end
endmodule
仿真模块
`timescale 1ns/1ps
module da_ctrl_tp;
reg clk ;//50Mhz
reg rst_n ;
reg[10:0]data_in ;
wire data ;
wire laod ;//前锁存
wire ldac ;//后锁存
wire ad_clk ;//1Mhz
da_ctrl da_ctrl(
.clk (clk ),//50Mhz
.rst_n (rst_n ),
.data_in (data_in ),
.data (data ),
.laod (laod ),//前锁存
.ldac (ldac ),//后锁存
.ad_clk (ad_clk ) //1Mhz
);
always #10 clk = ~clk;
initial begin
clk = 1;
rst_n = 0;
#30;
rst_n = 1;
data_in = 11'b110_0101_1001;
#100000;
$stop;
end
endmodule
三、仿真验证
1Mhz的ad_clk生成正确:

260ns的laod,ldac产生正确

后续需要将dds与该模块连接,通过示波器观察da芯片的对应输出通道,验证功能是否完全
参考资料
TLC5620芯片手册(本地文件,如有需要,私信即可)


1980

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



