FPGA设计中DAC7512控制的Verilog实现

合集下载
相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

FPGA设计中DAC7512控制的Verilog实现

一,概述

DAC7512是一个12-BIT,串行接口的DAC。低功耗,RAIL-TO-RAIL输出,SOT23-6封装。3线串行端口最高工作频率可以达到30MHZ,并兼容SPI,QSPI,MICROWIRE等总线。

DAC7512没有专用的基准电压输入,直接把VDD和GND作为基准电压,12BIT的分辨率,其输出电压为VOUT = VDD * D/4096。其中D是12BIT电压数值。

SOT23-6封装的DAC7512的引脚图如下。

DAC7512具有3线串行端口,其信号定义如下所示:

对DAC7512来讲,在总线上只会接收控制器发出的16BIT的数字信号(2BIT 无效数据,2bit控制数据和12bit(信号幅值数据)。所以对于控制器来讲,在总线操作上,只需要串行写这一种操作。

总线串行写操作在SYNC的下降沿开始。16 bit的数据在SCLK的下降沿被依次送入到DAC7512内部的移位寄存器中。从功耗的角度上讲,如果SYNC在空闲状态保持低电平,则有利于功耗的降低,但从总线操作的角度上讲,需要SYNC的下降沿来启动一次传输。

下面的图和表是总线操作的时序要求:

二,总线控制器的设计

根据总线控制器的特性,采用状态机来实现总线控制器的设计。从上面DAC7512的操作时序上来看,用一个三状态的状态机实现总线控制器是比较好的选择。在系统初始化或者没有数据传输时,系统处于空闲状态(DAC_IDLE),为了降低功耗,在这个状态下,SYNC信号为低电平;当有数据需要传输时,先进入DAC_PRE状态,在这个状态下,使SYNC信号为高电平,DAC_PRE状态保持的时间最短为SYNC需要保持为高电平的时间,即上图的T8,在VDD为3.6V~5.5V的时候,为33ns;当DAC_PRE状态结束时,进入DAC_DATA状态,在这个状态下,依次把16bit数据送到总线上去。

下图是状态机状态转换图。系统初始化或者数据传输结束时,进入

DAC_IDLE状态。当有数据需要传输时,进入DAC_PRE状态。在DAC_PRE状态保持的时间,根据SYNC保持高电平的时间来决定,采用一个计数器来实现保持时间。系统进入DAC_DATA时,开始传输数据,当16bit数据全部传输完毕后,系统回归到IDLE状态。

DAC_DATA状态下,送往总线的数据由计数器来控制,DAC_DATA状态保持的时间也由计数器控制。由于总线上,数据在SCLK的下降沿被DAC7512锁存,所以控制器需要在SCLK的下降沿之前把数据送到总线上,并且要保证数据SETUP TIME的要求。为了便于控制,我们采用一个比SCLK的频率高一倍,且相位相同的时钟(CLK_IN)来控制总线上数据的转换。DAC_DATA状态计数器也工作在这个时钟频率下。

下面是状态机部分的verilog实现:

reg DA_SCLK; //串口时钟,由CLK_IN二分频得到,本例中CLK_IN为50MHz 时钟,DA_SCLK为25MHz

always @(posedge CLK_IN or negedge RESET)

begin

if(~RESET)

DA_SCLK <= 1'b0;

else

DA_SCLK <= ~DA_SCLK;

end

parameter DAC_IDLE = 3'b001, //系统空闲

DAC_PRE = 3'b010, //系统数据预传输状态

DAC_DATA = 3'b100; //系统数据传输状态

reg [2:0] DACSM, DACSMNXT;

wire PHASE_DAC_IDLE = DACSM[0];

wire PHASE_DAC_PRE = DACSM[1];

wire PHASE_DAC_DATA = DACSM[2];

wire PHASENXT_DAC_IDLE = DACSMNXT[0];

wire PHASENXT_DAC_PRE = DACSMNXT[1];

wire PHASENXT_DAC_DATA = DACSMNXT[2];

reg [2:0] DAC_PRE_CNT; //系统预传输保持时间计数器,工作在CLK_IN时钟频率下,生成的DAC_PRE_END信号作为状态机跳转信号。

always @(posedge CLK_IN or negedge RESET)

begin

if(~RESET)

DAC_PRE_CNT <= 3'b0;

else if(PHASE_DAC_PRE)

DAC_PRE_CNT <= DAC_PRE_CNT + 3'b1;

else

DAC_PRE_CNT <= 3'b0;

end

wire DAC_PRE_END = (DAC_PRE_CNT >= 3'b110);

reg [7:0] DAC_DATA_CNT; //DAC_DATA状态计数器,工作在CLK_IN时钟频率下,是总线上数据传输频率的两倍,所以在需要传输16bit数据的时候,该时钟需要计数到32。

always @(posedge CLK_IN or negedge RESET)

begin

if(~RESET)

DAC_DATA_CNT <= 8'b0;

else if(DAC_DATA_CNT == 8'd32)

DAC_DATA_CNT <= 8'd0;

else if(PHASENXT_DAC_DATA | PHASE_DAC_DATA)

DAC_DATA_CNT <= DAC_DATA_CNT + 8'b1;

else

DAC_DATA_CNT <= 8'b0;

end

wire DAC_DATA_END; //数据传输结束信号

assign DAC_DATA_END = (DAC_DATA_CNT >= 8'd31);

always @(posedge DA_SCLK or negedge RESET)

begin

if(~RESET)

DACSM <= DAC_IDLE;

else

DACSM <= DACSMNXT;

end

always @(DACSM or DA_DATA_EN or DAC_PRE_END or DAC_DATA_END) begin

DACSMNXT = DACSM;

case(DACSM)

DAC_IDLE:

if(DA_DATA_EN)

DACSMNXT = DAC_PRE;

else

DACSMNXT = DAC_IDLE;

DAC_PRE:

if(DAC_PRE_END)

DACSMNXT = DAC_DATA;

else

DACSMNXT = DAC_PRE;

DAC_DATA:

相关文档
最新文档