Write ADC driver TODO write testbench for ADC driver

This commit is contained in:
Kelvin Ly 2020-01-06 08:04:00 -05:00
parent ad27f2a94c
commit 5f2364b5cf
1 changed files with 152 additions and 0 deletions

152
rtl/library/adc_driver.v Normal file
View File

@ -0,0 +1,152 @@
module adc_driver(
input clk,
input rstn,
input adc_so,
output reg adc_si,
output reg adc_ss,
reg adc_sck,
output reg [1:0] channel,
output reg [11:0] adc_val,
output reg vld,
input ack
);
reg [2:0] sck_strobe = 0;
wire strobe = &sck_strobe;
always @(posedge clk) begin
if (rstn)
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 [3:0] bit_pos = 0;
reg [3: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 adc_sck_ff = 1;
assign adc_sck = adc_sck_ff;
wire config_bit;
assign config_bit = {
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
}[15-bit_pos];
always @* begin
state_next = state;
bit_pos_next = bit_pos;
write_out = 0;
so_ff_next = so_ff;
sck_next = 1;
ss_next = 1;
if (rstn) begin
// latch sck and ss state until the strobe happens
si_next = adc_si;
ss_next = adc_ss;
sck_next = adc_sck;
if (sck_strobe) begin
case (state)
INIT: begin
ss_next = 0;
state_next = CONFIG;
bit_pos_next = 0;
end
CONFIG: begin
ss_next = 0;
sck_next = ~adc_sck;
// update on the falling edge
if (adc_sck) begin
bit_pos_next = bit_pos + 1;
si_next = config_bit;
// deassert slave select so it can be triggered on the next frame
if (bit_pos == 15) begin
ss_next = 1;
//bit_pos_next = 0; // don't need this because it's going to
// overflow
end
end
// switch state on the rising edge after the overflow
// and reassert ss to start the next frame
if (~adc_sck & (bit_pos == 0)) begin
ss_next = 0;
state_next = ADC;
end
end
ADC: begin
ss_next = 0;
si_next = 0;
sck_next = ~adc_sck;
// update bit pos state on the falling edge
// shift in data as well
if (adc_sck) begin
bit_pos_next = bit_pos + 1;
so_ff_next = {so_ff[14:0], adc_si};
// after reading the last bit
// deassert ss so it can be reasserted on the next rising edge
if (bit_pos == 15) begin
ss_next = 1;
end
end
// write the data out on the rising edge after the overflow
if (~adc_sck & (bit_pos == 0)) begin
write_out = 1;
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;
adc_sck_ff <= sck_next;
adc_ss <= ss_next;
adc_si <= si_next;
so_ff <= so_ff_next;
// write the data out when write_out is asserted
if (write_out) begin
{adc_channel, adc_val} <= so_ff[13:0];
vld <= 1;
end
// deassert vld when the data is acknowledged
if (ack)
vld <= 0;
end
endmodule