177 lines
3.9 KiB
Verilog
177 lines
3.9 KiB
Verilog
// driver for the MAX1141 ADC used in the board
|
|
// it has 4 analog inputs, and is configured to automatically
|
|
// scan them sequentially while being driven by SCK
|
|
// it divides the input clock by 16 to produce the SPI clock
|
|
|
|
// it writes one configuration word to the ADC and then constantly
|
|
// polls it for new data
|
|
module adc_driver(
|
|
input clk,
|
|
input rst,
|
|
|
|
input so,
|
|
output si,
|
|
output ss,
|
|
output sck,
|
|
|
|
output [1:0] channel,
|
|
output [11:0] val,
|
|
output vld,
|
|
input ack
|
|
);
|
|
|
|
reg [1:0] channel_ff = 0;
|
|
reg [11:0] adc_val_ff = 0;
|
|
reg new = 0;
|
|
|
|
assign channel = channel_ff;
|
|
assign val = adc_val_ff;
|
|
assign vld = new & ~ack;
|
|
|
|
reg sck_strobe = 0;
|
|
wire strobe = sck_strobe;
|
|
wire strobe2 = ~sck_strobe;
|
|
|
|
always @(posedge clk) begin
|
|
if (~rst)
|
|
sck_strobe <= sck_strobe + 1;
|
|
else
|
|
sck_strobe <= 0;
|
|
end
|
|
|
|
localparam INIT = 0, CONFIG = 1, ADC = 2;
|
|
reg [1:0] state = INIT;
|
|
reg [1:0] state_next;
|
|
|
|
reg [4:0] bit_pos = 0;
|
|
reg [4:0] bit_pos_next;
|
|
|
|
reg [15:0] so_ff = 0;
|
|
reg [15:0] so_ff_next;
|
|
|
|
reg write_out;
|
|
reg sck_next;
|
|
reg ss_next;
|
|
reg si_next;
|
|
|
|
reg si_ff = 1;
|
|
reg ss_ff = 1;
|
|
reg sck_ff = 1;
|
|
assign si = si_ff;
|
|
assign ss = ss_ff;
|
|
assign sck = sck_ff;
|
|
|
|
wire [15:0] config_word;
|
|
wire config_bit;
|
|
assign config_word = {
|
|
1'b0, // ADC Mode Control
|
|
4'b0100, // Standard_Ext
|
|
4'b0011, // Up to AIN3
|
|
2'b01, // reset FIFO
|
|
2'b00, // normal PM mode
|
|
1'b1, // include channel number in output
|
|
1'b0, // SWCNV enable, not used in external clock mode
|
|
1'b0 // reserved
|
|
};
|
|
assign config_bit = config_word[15-bit_pos[4:1]];
|
|
|
|
always @* begin
|
|
state_next = state;
|
|
bit_pos_next = bit_pos;
|
|
write_out = 0;
|
|
so_ff_next = so_ff;
|
|
|
|
sck_next = 1;
|
|
ss_next = 1;
|
|
si_next = 0;
|
|
|
|
if (~rst) begin
|
|
// latch sck and ss state until the strobe happens
|
|
si_next = si;
|
|
ss_next = ss;
|
|
sck_next = sck;
|
|
|
|
if (strobe2) begin
|
|
if (state == CONFIG || state == ADC) begin
|
|
// deassert slave select so it can be triggered on the next frame
|
|
if (bit_pos == 31 & ~ss_next & ~sck) begin
|
|
ss_next = 1;
|
|
//bit_pos_next = 0; // don't need this because it's going to
|
|
// overflow
|
|
end else begin
|
|
ss_next = 0;
|
|
end
|
|
end
|
|
end
|
|
if (strobe) begin
|
|
case (state)
|
|
INIT: begin
|
|
ss_next = 0;
|
|
state_next = CONFIG;
|
|
bit_pos_next = 0;
|
|
end
|
|
CONFIG: begin
|
|
sck_next = bit_pos[0];
|
|
bit_pos_next = bit_pos + 1;
|
|
|
|
// update on the falling edge
|
|
if (sck) begin
|
|
si_next = config_bit;
|
|
end
|
|
// switch state on the rising edge after the overflow
|
|
// and reassert ss to start the next frame
|
|
if (~sck & (bit_pos == 31)) begin
|
|
//ss_next = 0;
|
|
state_next = ADC;
|
|
end
|
|
end
|
|
ADC: begin
|
|
//ss_next = 0;
|
|
si_next = 0;
|
|
sck_next = bit_pos[0];
|
|
bit_pos_next = bit_pos + 1;
|
|
|
|
// update bit pos state on the rising edge
|
|
// shift in data as well
|
|
if (~sck) begin
|
|
so_ff_next = {so_ff[14:0], so};
|
|
|
|
// after reading the last bit
|
|
// deassert ss so it can be reasserted on the next rising edge
|
|
if (bit_pos == 31) begin
|
|
//ss_next = 1;
|
|
write_out = 1;
|
|
end
|
|
end
|
|
end
|
|
endcase
|
|
end
|
|
end else begin
|
|
state_next = INIT;
|
|
bit_pos_next = 0;
|
|
sck_next = 1;
|
|
ss_next = 1;
|
|
end
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
state <= state_next;
|
|
bit_pos <= bit_pos_next;
|
|
|
|
sck_ff <= sck_next;
|
|
ss_ff <= ss_next;
|
|
si_ff <= si_next;
|
|
so_ff <= so_ff_next;
|
|
|
|
// write the data out when write_out is asserted
|
|
if (write_out) begin
|
|
{channel_ff, adc_val_ff} <= so_ff_next[13:0];
|
|
new <= 1;
|
|
end
|
|
// deassert vld when the data is acknowledged
|
|
if (ack)
|
|
new <= 0;
|
|
end
|
|
|
|
endmodule
|