Write ADC driver TODO write testbench for ADC driver
This commit is contained in:
parent
ad27f2a94c
commit
5f2364b5cf
|
@ -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
|
Loading…
Reference in New Issue