forked from OlmerAod/ADC_Interface
-
Notifications
You must be signed in to change notification settings - Fork 0
/
adc_interface.v
114 lines (103 loc) · 3.54 KB
/
adc_interface.v
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
// ADC_Interface
// Simple SPI interface for AD7908/AD7918/AD7928 written in verilog HDL
// Transferes control register from external bus to the ADC and conversion
// results from ADC to the bus.
// Also enerates CS and SCLK singals for ADC.
module adc_interface
#(parameter division_by = 6) // clk scaler parameter. Can be EVEN NUMBER ONLY! Possible values: [2:2:32].
// The upper limit can be extended by editing clk_div_counter bitness.
(input clk, // external clock
input reset, // asynchronous reset of the interface on posedge of "reset". Active level - "1"
input transfer_req, // Transfer request from external device. Active level - "1"
input [15:0] data_bus_in, // Transfer data bus (control register) from ext. device. Active level - "1"
// transfer_req and data_bus_in signals should stay active untill negedge of ready!
input ADC_Dout, // Serial output (conversion results) from ADC. Active level - "1"
output reg CS = 1, // Chip select signal for SPI connection between interface and ADC. Active level - "0"
output ADC_Din, // Serial input to ADC (serialized data_bus_in)
output SCLK, // Serial clock for SPI connection between interface and ADC. f(SCLK) = f(clk)/((div_param+1)*2).
// Changes only when CS is active, otherwise it is "1".
output ready, // "Ready for next transfer" rises when the ADC is ready for next transfer\conversion process. Active level - "1"
output [15:0] data_bus_out // Transfer data bus (conversion results) from ADC (parallelized ADC_Dout). Active level - "1"
);
reg [3:0] clk_div_counter = 0;
reg clk_divided = 0;
reg [15:0] data_bus_in_reg = 0;
reg ready_reg = 0;
reg [15:0] data_bus_out_reg = 0;
reg [3:0] counter = 4'b0000;
reg transfer_req_temp = 0;
wire SCLK_clone; // SCLK_clone signal is a workaround for a Quartus 13 bug (my main IDE at this moment)
assign SCLK_clone = clk_divided||CS; // See https://www.altera.com/support/support-resources/knowledge-base/solutions/rd06192013_268.html
assign SCLK = SCLK_clone;
assign ADC_Din = data_bus_in_reg[15];
assign ready = ready_reg&&CS;
assign data_bus_out = {1'b0, data_bus_out_reg[15:1]};
parameter div_param = (division_by-2)/2;
// Master to ADC transfer + counter logics
always@(posedge clk_divided or posedge reset)
begin
if (reset)
begin
CS <= 1;
counter <= 4'b0000;
ready_reg <= 0;
end
else
begin
if(transfer_req_temp)
CS <= 0;
if (~CS)
begin
counter <= counter + 4'd1;
ready_reg <= 0;
end
else
ready_reg <= 1;
if (counter == 4'b1111)
CS <= 1'b1;
end
end
always@(posedge clk or posedge reset)
begin
if(reset)
begin
clk_div_counter <= 0;
clk_divided <= 0;
transfer_req_temp <= 0;
data_bus_in_reg <= 0;
end
else
begin
if(~CS)
begin
transfer_req_temp <= 0;
end
else
if(transfer_req)
begin
transfer_req_temp <= 1;
data_bus_in_reg <= data_bus_in;
end
if (clk_div_counter == div_param[3:0]) // div_param[3:0] is used to prevent synth of 32bit comparator instead of 4 bit.
begin
clk_div_counter <= 0;
clk_divided <= ~clk_divided;
end
else
clk_div_counter <= clk_div_counter + 4'd1;
if (~CS && (clk_div_counter == div_param[3:0]) && ~clk_divided) // equal to @(posedge SCLK)
data_bus_in_reg <= data_bus_in_reg << 1;
end
end
// ADC to Master transfer logics
always@(posedge SCLK or posedge reset)
begin
if (reset)
data_bus_out_reg <= 0;
else
begin
if (~CS)
data_bus_out_reg <= {data_bus_out_reg[14:0], ADC_Dout};
end
end
endmodule