目录
一、前言
最近在学习利用FPGA结合DAC芯片实现数模转换,在实验中选择的LTC1446这款芯片。接下来自己将结合芯片手册进行分析,并编写Verilog代码并进行仿真验证。
二、结合LTC1446芯片手册分析
- 首先从上述第一处可以看出该款芯片为双通道输入,最多可将24位的数字信号进行转换。
- 对于第二处,所谓的三线通信其实在这里就是Spi通信的“变种”,因为版权的原因,很多公司这样进行描述,这里是clk,cs,mosi三线;另外,其提高更新频率为500KHZ,则我们在将数字信号输入的频率是不能超过500KHZ的,不然该芯片不能正确工作。
- 第三处,展示的是芯片和一般微处理器的连接方式,从而印证了第二处所说的是spi的主设备数据输出,从设备数据输入模式。
- 第四处,可以看到当$\overline{CS}$/LD为低电平时,数据是被锁存的,不能输出;当$\overline{CS}$/LD为高电平时,数字信号转化为模拟信号输出,这在写代码的时候也是需要注意的。
- 第五处,$D_{OUT}$需要在clk上升沿的时候才可以获取其输出,不过在这个实验仿真中不需要用到,所以需要额外关注。
- 第六处的时序转换是最需要我们关注的
- 首先看clk信号,初始状态为高电平,则在仿真过程中编写testbench时需要注意,另外可以看到对于时钟信号的周期是有标注时间的,需要我们看一下有无限制。
可以看到最小时钟周期为120ns,1/(120*$10^{-9}$)=8.3MHZ,一般我们使用的FPGA的时钟信号为50MHZ.所以需要进行分频得到芯片的输入时钟信号。
- 再看$D_{IN}$信号,传输数据是时候是先对应A通道的12位,从高到底;然后再是对应A通道的12位,从高到底。
- 再看$\overline{CS}$/LD信号,其开始为低电平,在clk为高电平时,$\overline{CS}$/LD由低电平转为高电平;在clk为低电平时,$\overline{CS}$/LD由高电平转为低电平
- $D_{OUT}$可以看出输出的滞后一个24位数据帧的。
- 再看第七处
- 在时钟上升沿数据被加载进入转换寄存器
- 先A通道的12bit,再B通道的12bit,且从分别从高位到低位,和时序图中描述的一样
- $\overline{CS}$/LD被拉高的时候,数据加载到DAC寄存器
- 时钟内部被禁用当$\overline{CS}$/LD被拉高的时候
- 在clk为低电平时,$\overline{CS}$/LD由高电平转为低电平,和时序图中的描述一致
三、Verilog代码与仿真
先画出输入输出的模块框图如下:
输入:
clk:FPGA时钟信号
n_rst:复位信号
data_in:24位数字信号
set:使能信号
输出:
spi_clk:生成的输入到芯片的时钟
spi_cs:生成的输入到芯片的cs信号
spi_din:生成的输入到芯片符合时序的数字信号
工程代码:
`timescale 1ns/1ns
module LTC1446_DA
(
input clk, //50MHZ时钟输入
input n_rst,
input [23:0] data_in, //输入的电压数值(高12位:通道A输出 ;低12位:通道B输出)
input set,
output reg spi_clk,
output reg spi_cs,
output spi_din
);
//0-15计数,用于16分频使用
reg [3:0] cnt;
always@(posedge clk or negedge n_rst)
begin
if(n_rst==1'b0)
cnt<=4'h0;
else if(set==1'b1)
cnt<=4'h0;
else
cnt<=cnt+1'b1;
end
reg [5:0] len_cnt;//发送为数据计数
always@(posedge clk or negedge n_rst)
begin
if(n_rst==1'b0)
len_cnt<=6'h0;
else if(set==1'b1)
len_cnt<=6'd25; //一帧数据数为25
else if((cnt==4'd15)&&(len_cnt>1'b0)) //cnt==15时,发送一位数据,即spi_clk时钟下降沿时,使得其上升沿可读取稳定数值
len_cnt<=len_cnt-6'd1;
else
len_cnt<=len_cnt;
end
reg [23:0] data_reg;//输出SPI_DIN数据
always@(posedge clk or negedge n_rst)
begin
if(n_rst==1'b0)
data_reg<=23'h0;
else if(set==1'b1)
data_reg<={data_in};
else if((cnt==4'd15)&&(len_cnt>1'b0))
data_reg<={data_reg[22:0],1'b0};//在spi_clk的下降沿,将数据最高位发送到spi_din
else
data_reg<=data_reg;
end
assign spi_din=data_reg[23];
//生成spi_clk时钟信号(clk/16分频)
always@(posedge clk or negedge n_rst)
begin
if(n_rst==1'b0)
spi_clk<=1'b1;
else if(set==1'b1)
spi_clk<=1'b1;
else if(len_cnt>1'b0)
spi_clk<=cnt[3]; //对clk/16分频
else
spi_clk<=1'b1;
end
always@(posedge clk or negedge n_rst)
begin
if(n_rst==1'b0)
spi_cs<=1'b0;
else if(set==1'b1)
spi_cs<=1'b0;
else if((len_cnt==6'd2)&&(cnt>4'd11))//已完成24位数据发送&当spi_clk下降沿之前
spi_cs<=1'b1; //cnt=[12-15]期间为高电平,其余为低电平
else
spi_cs<=1'b0;
end
endmodule
仿真代码:
`timescale 1ns/1ns
module tb_LTC1446_DA();
reg clk;
reg n_rst;
reg [23:0] data_in;
reg set;
wire spi_clk;
wire spi_cs;
wire spi_din;
always #10 clk=~clk;
initial
begin
clk=0;
n_rst<=1;
data_in<=0;
set<=0;
#10
n_rst<=0;
#20
n_rst<=1;
#20
data_in<=24'b1110_1010_1100_0101_1100_1010;
set<=1;
#20
set<=0;
end
LTC1446_DA LTC1446_DA_inst
(
.clk (clk ) ,
.n_rst (n_rst ) ,
.data_in (data_in) ,
.set (set ) ,
.spi_clk (spi_clk) ,
.spi_cs (spi_cs ) ,
.spi_din (spi_din)
);
endmodule
仿真结果:
分析的时候对应每个信号判断时候符合要求即可。
四、总结
对于这类工程,我觉得最重要的就是厘清芯片手册的中不同信号对应的时序,各种限制如时间周期等才能写出能正常驱动芯片的代码。当然自己的水平是非常有限的,对于不同的芯片手册自己学习中经常会有看的不知所云,无法把握重点的情况,但是我坚信自己一定不是第一个使用该手册的人,前人一定会有相关描述或工程可以借鉴,通过检索不断学习,一定会找到解决问题的办法。加油,努力成为一名优秀的工程师!
标签:LTC1446,LD,FPGA,clk,芯片,DAC,低电平,spi,CS From: https://www.cnblogs.com/lgziyan/p/17933433.html