看完了,时序部分,我们来看看寄存器部分,通过配置寄存器,可以控制我们的输出,所以寄存器也非常重要。
这里就说了,如果SYNC(取反)信号的突然上升,在数据还没有传完的时候就上升,这种中断的方式,数据缓冲器内容,DAC寄存器内容的更新或操作模式的更改都不会发生,已经写入的这一段数据都会被丢弃,移位寄存器会重新置位。
上图为这几种模式的介绍,我们一般来说用正常模式就行,其余模式,可以根据实际需求更改。
上图是三种powerdown模式,但是我们一般就设置为00,正常模式即可,不需要用到powerdown模式
下面,还给出了操作的例子
例子1是在等待两个24sclk序列加载完毕后,此时,A B 的寄存器都加载了数据后,再同时进行数模转换。
例子2是24个SCLK加载完数据到A后,立马就开始输出,第二个SCLK加载完数据到B后,B开始输出。
时隔3天,终于调好了程序,非常适合几乎所有的SPI控制的ADC和DAC芯片。
只需要改动参数parameter即可。
这也是我写程序的一个良好习惯,尽量参数化,尽量让写过的程序以后复用,而不要今天用SPI写一次,隔天换了个DA的时序,也是SPI控制的,又用SPI再写一次,这样效率相当低下,尽量一次就写好,写工整。
软件:quartus 13.1
modelsim 10.1 c
代码:
顶层模块
//功能描述:驱动双通道16bit的DAC同时产生正弦波形,或者三角波形
//author: ciscomonkey
//思路分析:组合控制+数据,组合完毕,发出传输指令,SPI模块开始传输,传输完毕信号给控制模块,控制模块接收到传输完毕信号,
//进入等待DA芯片的转换时间,等待结束,再次进入组合状态。
`timescale 1 ns/ 1 ns
module DAC8532_drive_project
#
(
parameter data_width=24,//控制+DAC_data数据长度
parameter DAC_data_width=16,//DAC_data数据长度
parameter wait_conversion_time=10,//转换时间,100M(10ns),100ns
parameter SPI_RATE=10_000_000,
parameter CLOCK_RATE=100_000_000
)
(
input clk,
input rst,
input start, //触发启动程序
input switch, //波形选择,1为电平1,2为电平2
output sclk, //输出时钟信号
output SYNC_n, //输出同步信号
output Din //输出数据
);
//
//
//
//
reg [DAC_data_width-1:0] voltage_1_reg=16'b1010_1010_1010_1010;
reg [DAC_data_width-1:0] voltage_2_reg=16'b0101_0101_0101_0101;
wire [DAC_data_width-1:0] voltage_1;
wire [DAC_data_width-1:0] voltage_2;
assign voltage_1=voltage_1_reg;
assign voltage_2=voltage_2_reg;
wire [DAC_data_width-1:0] DAC_a_data = switch ? voltage_1 : voltage_2;
wire [DAC_data_width-1:0] DAC_b_data = switch ? voltage_1 : voltage_2;
wire spi_data_done;
wire mosi;
wire start_spi;
wire [data_width-1:0] miso_data_reg;
wire [data_width-1:0] data_reg;
wire write_busy;
wire data_DAC_ab_finish;
//-------------------------------------------------------------
DAC8532_DATA_Ctrl
# (
.data_width(data_width),//控制+DAC_data数据长度
.DAC_data_width(DAC_data_width),//DAC_data数据长度
.wait_conversion_time(wait_conversion_time)
)DAC8532_DATA_Ctrl_inst
(
.clk(clk),
.rst(rst),
.DAC_a_data(DAC_a_data),
.DAC_b_data(DAC_b_data),
.start(start), //启动DAC8532
.spi_data_done(spi_data_done), //24位宽的数据传输完的标志
.data_reg(data_reg), //串行输出一帧数据(控制+数据)
.start_spi(start_spi), //组合好一帧数据后开始传输命令
.data_DAC_ab_finish(data_DAC_ab_finish)
);
//----------------------------------------------------------------------
spi_data_transfer
# (
.data_width(data_width) , // SPI一次写入数据长度
.SPI_RATE(SPI_RATE) , // SPI时钟速率
.CLOCK_RATE(CLOCK_RATE) // 系统时钟速率
)spi_data_transfer_inst
(
.clk(clk),
.rst(rst),
.data_reg(data_reg), //输入数据,用于mosi
.start_spi(start_spi),//开启传输指令
.miso_data_reg(miso_data_reg), //miso,主机(FPGA)接收的数据,从机发送
.miso(0),
.sclk(sclk), //时钟
.write_busy(write_busy), //写入繁忙
.spi_data_done(spi_data_done), //数据传输完的标志
.mosi(mosi), //主发从收,主机(FPGA)发送,从机接收
.SYNC_n(SYNC_n)
);
assign Din=mosi;
endmodule
//功能描述:驱动双通道16bit的DAC同时产生正弦波形,或者三角波形
//author: ciscomonkey
//思路分析:组合控制+数据,组合完毕,发出传输指令,SPI模块开始传输,传输完毕信号给控制模块,控制模块接收到传输完毕信号,
//进入等待DA芯片的转换时间,等待结束,再次进入组合状态。
`timescale 1 ns/ 1 ns
module DAC8532_drive_project
#
(
parameter data_width=24,//控制+DAC_data数据长度
parameter DAC_data_width=16,//DAC_data数据长度
parameter wait_conversion_time=15,//转换时间,100M(10ns),100ns
parameter SPI_RATE=10_000_000,
parameter CLOCK_RATE=100_000_000
)
(
input clk,
input rst,
input start, //触发启动程序
input switch, //波形选择,1为电平1,2为电平2
output sclk, //输出时钟信号
output SYNC_n, //输出同步信号
//
output [5:0] next_state_test, //状态机测试信号
output [5:0] now_state_test,
output Din //输出数据
);
//
//
//
//
reg [DAC_data_width-1:0] voltage_1_reg=16'b1010_1010_1010_1010;
reg [DAC_data_width-1:0] voltage_2_reg=16'b0101_0101_0101_0101;
wire [DAC_data_width-1:0] voltage_1;
wire [DAC_data_width-1:0] voltage_2;
assign voltage_1=voltage_1_reg;
assign voltage_2=voltage_2_reg;
wire [DAC_data_width-1:0] DAC_a_data = switch ? voltage_1 : voltage_2;
wire [DAC_data_width-1:0] DAC_b_data = switch ? voltage_1 : voltage_2;
wire spi_data_done;
wire mosi;
wire start_spi;
wire [data_width-1:0] miso_data_reg;
wire [data_width-1:0] data;
wire write_busy;
wire data_DAC_ab_finish;
//-------------------------------------------------------------
DAC8532_DATA_Ctrl
# (
.data_width(data_width),//控制+DAC_data数据长度
.DAC_data_width(DAC_data_width),//DAC_data数据长度
.wait_conversion_time(wait_conversion_time)
)DAC8532_DATA_Ctrl_inst
(
.clk(clk),
.rst(rst),
.DAC_a_data(DAC_a_data),
.DAC_b_data(DAC_b_data),
.start(start), //启动DAC8532
.spi_data_done(spi_data_done), //24位宽的数据传输完的标志
.now_state_test(now_state_test),
.next_state_test(next_state_test),
.data(data), //串行输出一帧数据(控制+数据)
.start_spi(start_spi), //组合好一帧数据后开始传输命令
.data_DAC_ab_finish(data_DAC_ab_finish)
);
//----------------------------------------------------------------------
spi_data_transfer
# (
.data_width(data_width) , // SPI一次写入数据长度
.SPI_RATE(SPI_RATE) , // SPI时钟速率
.CLOCK_RATE(CLOCK_RATE) // 系统时钟速率
)spi_data_transfer_inst
(
.clk(clk),
.rst(rst),
.data_reg(data), //输入数据,用于mosi
.start_spi(start_spi),//开启传输指令
.miso_data_reg(miso_data_reg), //miso,主机(FPGA)接收的数据,从机发送
.miso(0),
.sclk(sclk), //时钟
.write_busy(write_busy), //写入繁忙
.spi_data_done(spi_data_done), //数据传输完的标志
.mosi(mosi), //主发从收,主机(FPGA)发送,从机接收
.SYNC_n(SYNC_n)
);
assign Din=mosi;
endmodule
//module:DAC8532_DATA_Ctrl
//author:Ciscomonkey
//functional description:提供mosi的数据,用于传输,发出传输指令则可以开启传输,并控制好时序,在传输完毕后,等待转换时间
`timescale 1 ns/ 1 ns
module DAC8532_DATA_Ctrl
# (
parameter data_width=24,//控制+DAC_data数据长度
parameter DAC_data_width=16,//DAC_data数据长度
parameter wait_conversion_time=15//A通道传输后,转换时间至少100ns(100M(10ns)),实际测试:+1
)
(
input clk,
input rst,
input [DAC_data_width-1:0] DAC_a_data,
input [DAC_data_width-1:0] DAC_b_data,
input start,//启动DAC8532
input spi_data_done, //24位宽的数据传输完的标志
output [data_width-1:0] data, //串行输出一帧数据(控制+数据)
output start_spi, //组合好一帧数据后开始传输命令
output [5:0] now_state_test,
output [5:0] next_state_test,
output data_DAC_ab_finish //conversion转换结束标志
);
reg start_spi_reg;
reg [data_width-1:0] data_reg;
reg data_DAC_ab_finish_reg;
//状态机 三段式
localparam IDLE_state=6'b000_000;
localparam combine_DAC_a_data_state=6'b000_001; //控制+DAC_a_data
localparam spi_DAC_A_trans_state=6'b000_010; //A通道SPI的传输
localparam conversion_DAC_a_data_state=6'b00_100; //DAC_a_data的转换等待时间
localparam combine_DAC_b_data_state=6'b001_000; //控制+DAC_b_data
localparam spi_DAC_B_trans_state=6'b010_000; //B通道SPI的传输
localparam conversion_DAC_b_data_state=6'b100_000; //DAC_b_data的转换等待时间
reg [5:0] now_state=IDLE_state;
reg [5:0] next_state=IDLE_state;
//----------
assign now_state_test=now_state;
assign next_state_test=next_state;
reg [DAC_data_width-1:0] conversion_time_cnt='d0;
//1、实现状态转换
always @ (posedge clk or negedge rst)
begin
if(!rst) //低电平复位
now_state<=IDLE_state;
else
now_state<=next_state;
end
//2、根据条件产生下一个状态
always@(*)
begin
case(now_state)
IDLE_state:
begin
if(start)
begin
next_state=combine_DAC_a_data_state;
end
else
begin
next_state=IDLE_state;
end
end
combine_DAC_a_data_state:
begin
next_state=spi_DAC_A_trans_state;
end
spi_DAC_A_trans_state:
begin
if(spi_data_done)//如果传输完毕,则进入转换状态
next_state=conversion_DAC_a_data_state;
else
next_state=spi_DAC_A_trans_state;
end
conversion_DAC_a_data_state:
begin
if(conversion_time_cnt==wait_conversion_time-1)
begin
next_state=combine_DAC_b_data_state;
end
else
begin
next_state=conversion_DAC_a_data_state;
end
end
combine_DAC_b_data_state:
begin
next_state=spi_DAC_B_trans_state;
end
spi_DAC_B_trans_state:
begin
if(spi_data_done)//如果传输完毕
next_state=conversion_DAC_b_data_state;
else
next_state=spi_DAC_B_trans_state;
end
conversion_DAC_b_data_state:
begin
if(conversion_time_cnt==wait_conversion_time-1)
begin
next_state=IDLE_state; //如果需要传输多个数据,比如正弦,那么就next_state回到combine_DAC_a_data_state
end
else
begin
next_state=conversion_DAC_b_data_state;
end
end
endcase
end
//3、状态条件输出
always @ (posedge clk)
begin
case(next_state)
IDLE_state:
begin
conversion_time_cnt<='d0;
data_reg<='d0;//用于组合数据(控制+数据)
start_spi_reg<=0;
end
combine_DAC_a_data_state:
begin
data_reg<={2'b00, 2'b00, 1'b0, 1'b0, 2'b0, DAC_a_data};
start_spi_reg<=1;//发出传输数据指令
end
spi_DAC_A_trans_state:
begin
start_spi_reg<=0;
end
conversion_DAC_a_data_state:
begin
conversion_time_cnt<=conversion_time_cnt+1'd1;
end
combine_DAC_b_data_state:
begin
conversion_time_cnt<=0;
data_reg<={2'b00, 2'b11, 1'b0, 1'b1, 2'b0, DAC_b_data};
start_spi_reg<=1;//发出传输数据指令
end
spi_DAC_B_trans_state:
begin
start_spi_reg<=0;
end
conversion_DAC_b_data_state:
begin
conversion_time_cnt<=conversion_time_cnt+1'd1;
end
endcase
end
//4、每个状态输出的值
always @ (posedge clk)//data_DAC_ab_finish转换完毕的标志
begin
if(conversion_time_cnt==wait_conversion_time-1)
data_DAC_ab_finish_reg<=1;
else
data_DAC_ab_finish_reg<=0;
end
//
assign start_spi=start_spi_reg;
assign data=data_reg;
assign data_DAC_ab_finish=data_DAC_ab_finish_reg;
endmodule
// Copyright (C) 1991-2013 Altera Corporation
// Your use of Altera Corporation's design tools, logic functions
// and other software and tools, and its AMPP partner logic
// functions, and any output files from any of the foregoing
// (including device programming or simulation files), and any
// associated documentation or information are expressly subject
// to the terms and conditions of the Altera Program License
// Subscription Agreement, Altera MegaCore Function License
// Agreement, or other applicable license agreement, including,
// without limitation, that your use is for the sole purpose of
// programming logic devices manufactured by Altera and sold by
// Altera or its authorized distributors. Please refer to the
// applicable agreement for further details.
// *****************************************************************************
// This file contains a Verilog test bench template that is freely editable to
// suit user's needs .Comments are provided in each section to help the user
// fill out necessary details.
// *****************************************************************************
// Generated on "02/28/2019 16:07:31"
// Verilog Test Bench template for design : DAC8532_drive_project
//
// Simulation tool : ModelSim (Verilog)
//
`timescale 1 ns/ 1 ns
module DAC8532_drive_project_vlg_tst();
// constants
// general purpose registers
reg eachvec;
// test vector input registers
reg clk;
reg rst;
reg start;
reg switch;
// wires
wire Din;
wire SYNC_n;
wire [5:0] next_state_test;
wire [5:0] now_state_test;
wire sclk;
// assign statements (if any)
DAC8532_drive_project i1 (
// port map - connection between master ports and signals/registers
.Din(Din),
.SYNC_n(SYNC_n),
.clk(clk),
.next_state_test(next_state_test),
.now_state_test(now_state_test),
.rst(rst),
.sclk(sclk),
.start(start),
.switch(switch)
);
initial
begin
#0 clk=0;
#0 rst=0;
#0 start=0;
#10 switch=1;
#60 rst=1;
#100 start=1;
#110 start=0;
end
always #5
begin
clk<=~clk;
end
endmodule
create_clock -name {clk} -period 10.000 -waveform {0.000 5.000} [get_ports {clk}]
derive_pll_clocks
derive_clock_uncertainty
两个通道,同时输出一个电压,有两种电压选择(根据switch 0 or 1)
第一个给了一个start,
先给一个start,然后隔了一段时间,再给一个start。
每start一次,就传输一次。
下图,两个通道均输出16‘b1010101010101010的电压
注意:
//wire start=1;如果要使用signal_tap在线调试没有外部触发,就把这个start一直置位为1即可
经过测试:即使主频时钟设置为跑到200M,也不会出现时序违规
https://download.csdn.net/download/ciscomonkey/10981766