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
|
//------------------------------
// Module name: spi2adc
// Function: SPI interface for MCP3002 ADC
// Creator: Peter Cheung
// Version: 1.1
// Date: 24 Jan 2014
//------------------------------
module spi2adc (sysclk, start, channel, data_from_adc, data_valid,
sdata_to_adc, adc_cs, adc_sck, sdata_from_adc);
input sysclk; // 50MHz system clock of DE0
input start; // Pulse to start ADC, minimum wide = clock period
input channel; // channel 0 or 1 to be converted
output [9:0] data_from_adc; // 10-bit ADC result
output data_valid; // High indicates that converted data valid
output sdata_to_adc; // Serial commands send to adc chip
output adc_cs; // chip select - low when converting
output adc_sck; // SPI clock - active during conversion
input sdata_from_adc; // Converted serial data from ADC, MSB first
//-------------Input Ports-----------------------------
// All the input ports should be wires
wire sysclk, start, sdata_from_adc;
//-------------Output Ports-----------------------------
// Output port can be a storage element (reg) or a wire
reg [9:0] data_from_adc;
reg adc_cs;
wire sdata_to_adc, adc_sck, data_valid;
//-------------Configuration parameters for ADC --------
parameter SGL=1'b1; // 0:diff i/p, 1:single-ended
parameter MSBF=1'b1; // 0:LSB first, 1:MSB first
// --- Submodule: Generate internal clock at 1 MHz -----
reg clk_1MHz; // 1Mhz clock derived from 50MHz
reg [4:0] ctr; // internal counter
parameter TIME_CONSTANT = 5'd24; // 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; // ... to start. Initialise to make simulation easier
end
always @ (posedge sysclk) //
if (ctr==0) begin
ctr <= TIME_CONSTANT;
clk_1MHz <= ~clk_1MHz; // toggle the output clock for squarewave
end
else
ctr <= ctr - 1'b1;
// ---- end internal clock generator ----------
// ---- Detect start is asserted with a small state machine
// .... FF set on positive edge of start
// .... reset when adc_cs goes high again
reg [1:0] sr_state;
parameter IDLE = 2'b00,WAIT_CSB_FALL = 2'b01, WAIT_CSB_HIGH = 2'b10;
reg adc_start;
initial begin
sr_state = IDLE;
adc_start = 1'b0; // set while sending data to ADC
end
always @ (posedge sysclk)
case (sr_state)
IDLE: if (start==1'b0) sr_state <= IDLE;
else begin
sr_state <= WAIT_CSB_FALL;
adc_start <= 1'b1;
end
WAIT_CSB_FALL: if (adc_cs==1'b1) sr_state <= WAIT_CSB_FALL;
else sr_state <= WAIT_CSB_HIGH;
WAIT_CSB_HIGH: if (adc_cs==1'b0) sr_state <= WAIT_CSB_HIGH;
else begin
sr_state <= IDLE;
adc_start <= 1'b0;
end
default: sr_state <= IDLE;
endcase
//------- End circuit to detect start and end of conversion
// spi controller designed as a state machine
// .... with 16 states (idle, and S1-S15 indicated by state value
reg [4:0] state;
reg adc_done, adc_din, shift_ena;
initial begin
state = 5'b0; adc_cs = 1'b1; adc_done = 1'b0;
adc_din = 1'b0; shift_ena <= 1'b0;
end
always @(posedge clk_1MHz) begin
// default outputs and state transition
adc_cs <= 1'b0; adc_done <= 1'b0; adc_din <= 1'b0; shift_ena <= 1'b0;
state <= state + 1'b1;
case (state)
5'd0: begin
if (adc_start==1'b0) begin
state <= 5'd0; // still idle
adc_cs <= 1'b1; // chip select not active
end
else begin
state <= 5'd1; // start converting
adc_din <= 1'b1; // start bit is 1
end
end
5'd1: adc_din <= SGL; // SGL bit
5'd2: adc_din <= channel; // CH bit
5'd3: adc_din <= MSBF; // MSB first bit
5'd4: shift_ena <= 1'b1; // start shifting data from adc
5'd15: begin
shift_ena <= 1'b0;
adc_done <= 1'b1;
end
5'd16: begin
adc_cs <= 1'b1; // last state - disable chip select
state <= 5'd0; // go back to idle state
end
default:
shift_ena <= 1'b1; // unspecified states are covered by default above
endcase
end // ... always
// shift register for output data
reg [9:0] shift_reg;
initial begin
shift_reg = 10'b0;
data_from_adc = 10'b0;
end
always @(negedge clk_1MHz)
if((adc_cs==1'b0)&&(shift_ena==1'b1)) // start shifting data_in
shift_reg <= {shift_reg[8:0],sdata_from_adc};
// Latch converted output data
always @(posedge clk_1MHz)
if(adc_done)
data_from_adc = shift_reg;
// Assign outputs to drive SPI interface to DAC
assign adc_sck = !clk_1MHz & !adc_cs;
assign sdata_to_adc = adc_din;
assign data_valid = adc_cs;
endmodule
|