FPGA进阶篇--SPI控制双通道16bit串行DAC8532(代码)

FPGA进阶篇--SPI控制双通道16bit串行DAC8532

ciscomonkey 2019-02-22 12:36:11  2142  收藏 27

分类专栏: FPGA进阶_quartus系列

版权

文章目录

一、芯片手册关键点笔记

1、时序

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、寄存器

看完了,时序部分,我们来看看寄存器部分,通过配置寄存器,可以控制我们的输出,所以寄存器也非常重要。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里就说了,如果SYNC(取反)信号的突然上升,在数据还没有传完的时候就上升,这种中断的方式,数据缓冲器内容,DAC寄存器内容的更新或操作模式的更改都不会发生,已经写入的这一段数据都会被丢弃,移位寄存器会重新置位。
在这里插入图片描述
上图为这几种模式的介绍,我们一般来说用正常模式就行,其余模式,可以根据实际需求更改。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
上图是三种powerdown模式,但是我们一般就设置为00,正常模式即可,不需要用到powerdown模式
下面,还给出了操作的例子
在这里插入图片描述
在这里插入图片描述
例子1是在等待两个24sclk序列加载完毕后,此时,A B 的寄存器都加载了数据后,再同时进行数模转换。
例子2是24个SCLK加载完数据到A后,立马就开始输出,第二个SCLK加载完数据到B后,B开始输出。
在这里插入图片描述
在这里插入图片描述

二、FPGA控制DAC8532驱动

时隔3天,终于调好了程序,非常适合几乎所有的SPI控制的ADC和DAC芯片。
只需要改动参数parameter即可。
这也是我写程序的一个良好习惯,尽量参数化,尽量让写过的程序以后复用,而不要今天用SPI写一次,隔天换了个DA的时序,也是SPI控制的,又用SPI再写一次,这样效率相当低下,尽量一次就写好,写工整。

软件:quartus 13.1
modelsim 10.1 c

代码:

顶层模块

DAC8532_drive_project

//功能描述:驱动双通道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


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103

DAC8532_DATA_Ctrl模块:

//功能描述:驱动双通道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




  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110

spi_data_transfer模块:

//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


	

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192

仿真:

// 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





  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

约束:

create_clock -name {clk} -period 10.000 -waveform {0.000 5.000} [get_ports {clk}]


derive_pll_clocks
derive_clock_uncertainty
  • 1
  • 2
  • 3
  • 4
  • 5

仿真结果:

两个通道,同时输出一个电压,有两种电压选择(根据switch 0 or 1)
第一个给了一个start,
先给一个start,然后隔了一段时间,再给一个start。
每start一次,就传输一次。
下图,两个通道均输出16‘b1010101010101010的电压
在这里插入图片描述
在这里插入图片描述

门级仿真:

门级仿真有点问题,明天再调调。

signaltap在线调试

在这里插入图片描述
注意:
//wire start=1;如果要使用signal_tap在线调试没有外部触发,就把这个start一直置位为1即可

经过测试:即使主频时钟设置为跑到200M,也不会出现时序违规
在这里插入图片描述
在这里插入图片描述

三、福利:工程链接

https://download.csdn.net/download/ciscomonkey/10981766

猜你喜欢

转载自blog.csdn.net/qq_25814297/article/details/108603196
今日推荐