summaryrefslogtreecommitdiff
path: root/part_4/mylib/spi2dac.v
blob: 6b8bbbd5d03ab2e1439e6c5fa2f1fc6d89ec63e5 (plain)
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
//------------------------------
// Module name: spi2dac
// Function: SPI interface for MPC4911 DAC
// Creator:  Peter Cheung
// Version:  3.0
// Date:     8 Dec 2016
//------------------------------

module spi2dac (sysclk, data_in, load, dac_sdi, dac_cs, dac_sck, dac_ld);

	input	sysclk;			// 50MHz system clock of DE1
	input	[9:0]	data_in;	// input data to DAC
	input	load;				// Pulse to load data to dac
	output dac_sdi;		// SPI serial data out
	output dac_cs;			// chip select - low when sending data to dac
	output dac_sck;		// SPI clock, 16 cycles at half sysclk freq
	output dac_ld;

//-------------Input Ports-----------------------------
// All the input ports should be wires
	wire			sysclk, load;
	wire [9:0]	data_in;
	
//-------------Output Ports-----------------------------
// Output port can be a storage element (reg) or a wire
	reg			dac_cs, dac_ld;
	wire			dac_sck, dac_sdi;
	
	parameter	BUF=1'b1;		// 0:no buffer, 1:Vref buffered
	parameter	GA_N=1'b1;		// 0:gain = 2x, 1:gain = 1x
	parameter	SHDN_N=1'b1;	// 0:power down, 1:dac active
	
	wire [3:0] cmd = {1'b0,BUF,GA_N,SHDN_N};  // wire to VDD or GND
	
	// --- internal 1MHz symmetical clock generator -----
	reg			clk_1MHz;	// 1Mhz clock derived from 50MHz
	reg [4:0]	ctr;			// internal counter
	reg			tick;			// 1MHz clock tick (1 cycle of 20ns every 1 usec)
	
	parameter	TC = 5'd24;  // Terminal count - change this for diff clk freq
	initial begin
		clk_1MHz = 0;			// don't need to reset - don't care if it is 1 or 0 to start
		ctr = 5'b0;				//  ... Initialise when FPGA is configured
		tick = 1'b0;
	end
		
	always @ (posedge sysclk)    
	  if (ctr==0) begin
		  ctr <= TC;
		  if (clk_1MHz==1'b0) 
				tick <= 1'b1;
		  clk_1MHz <= ~clk_1MHz; // toggle the output clock for squarewave
		end
	  else begin
		  ctr <= ctr - 1'b1;
		  tick <= 1'b0;
		end
	// ---- end internal 1MHz symmetical clock generator ----------

	// ---- FSM to detect rising edge of load and falling edge of dac_cs
	// .... sr_state set on posedge of load
	// .... sr_state reset when dac_cs goes high at the end of DAC output cycle
	reg [1:0] 	sr_state;
	parameter	IDLE  = 2'b00,WAIT_CSB_FALL = 2'b01, WAIT_CSB_HIGH = 2'b10;
	reg			dac_start;		 // set if a DAC write is detected
	
	initial begin
		sr_state = IDLE;
		dac_start = 1'b0;	// set while sending data to DAC
		end
	
	always @ (posedge sysclk)  // state transition
		case (sr_state)
			IDLE:	if (load==1'b1) sr_state <= WAIT_CSB_FALL;
			WAIT_CSB_FALL: if (dac_cs==1'b0) sr_state <= WAIT_CSB_HIGH;
			WAIT_CSB_HIGH: if (dac_cs==1'b1) sr_state <= IDLE;
			default: sr_state <= IDLE;
		endcase
	
	always @ (*)
		case (sr_state)
			IDLE: dac_start = 1'b0;
			WAIT_CSB_FALL: dac_start = 1'b1;
			WAIT_CSB_HIGH: dac_start = 1'b0;
			default: dac_start = 1'b0;
		endcase
		
	//------- End circuit to detect start and end of conversion	state machine

	//------- spi controller FSM
	// .... with 17 states (idle, and S1-S16 
	// .... for the 16 cycles each sending 1-bit to dac)
	reg [4:0] 	state;
	
	initial	begin	
		state = 5'b0; dac_ld = 1'b0; dac_cs = 1'b1; 
		end
		
	always @(posedge sysclk)  // FSM state transition
		if (tick==1'b1)
		case (state)
			5'd0:	if (dac_start == 1'b1)    // waiting to start
						state <= state + 1'b1; 
					else 
						state <= 5'b0; 
			5'd17: 	state <= 5'd0;  // go back to idle state
			default: state <= state + 1'b1;	// default go to next state
		endcase
	
	always @ (*)	begin			// FSM output
		dac_cs = 1'b0;  dac_ld = 1'b1;
		case (state)
			5'd0: 	dac_cs = 1'b1;
			5'd17: 	begin dac_cs = 1'b1; dac_ld = 1'b0; end
			default: begin dac_cs = 1'b0;	dac_ld = 1'b1;	end
			endcase
		end //always
	// --------- END of spi controller FSM
	
	// shift register for output data
	reg [15:0] shift_reg;
	initial	begin	
		shift_reg = 16'b0; 
		end

	always @(posedge sysclk)
		if((dac_start==1'b1)&&(dac_cs==1'b1)&&(tick==1'b1))		// parallel load data to shift reg
			shift_reg <= {cmd,data_in,2'b00};
		else if (tick==1'b1)													// .. else start shifting
			shift_reg <= {shift_reg[14:0],1'b0};
	
	// Assign outputs to drive SPI interface to DAC
			assign dac_sck = !clk_1MHz&!dac_cs;
			assign dac_sdi = shift_reg[15];
endmodule