Compare commits
No commits in common. "0e67bfc6dc668ad95f26c66f8ec5e9b88ff938cd" and "ad27f2a94c8ea34d79f96cf1b4b576584a22e336" have entirely different histories.
0e67bfc6dc
...
ad27f2a94c
|
@ -1,168 +0,0 @@
|
||||||
module adc_driver(
|
|
||||||
input clk,
|
|
||||||
input rstn,
|
|
||||||
|
|
||||||
input adc_so,
|
|
||||||
output adc_si,
|
|
||||||
output adc_ss,
|
|
||||||
output adc_sck,
|
|
||||||
|
|
||||||
output [1:0] channel,
|
|
||||||
output [11:0] adc_val,
|
|
||||||
output vld,
|
|
||||||
input ack
|
|
||||||
);
|
|
||||||
|
|
||||||
reg [1:0] channel_ff = 0;
|
|
||||||
reg [11:0] adc_val_ff = 0;
|
|
||||||
reg vld_ff = 0;
|
|
||||||
|
|
||||||
assign channel = channel_ff;
|
|
||||||
assign adc_val = adc_val_ff;
|
|
||||||
assign vld = vld_ff;
|
|
||||||
|
|
||||||
reg [2:0] sck_strobe = 0;
|
|
||||||
wire strobe = &sck_strobe;
|
|
||||||
wire strobe2 = &(sck_strobe^3'b100);
|
|
||||||
|
|
||||||
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 [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 adc_si_ff = 1;
|
|
||||||
reg adc_ss_ff = 1;
|
|
||||||
reg adc_sck_ff = 1;
|
|
||||||
assign adc_si = adc_si_ff;
|
|
||||||
assign adc_ss = adc_ss_ff;
|
|
||||||
assign adc_sck = adc_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;
|
|
||||||
|
|
||||||
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 (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 & ~adc_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 (adc_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 (~adc_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 (~adc_sck) begin
|
|
||||||
so_ff_next = {so_ff[14:0], adc_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;
|
|
||||||
|
|
||||||
adc_sck_ff <= sck_next;
|
|
||||||
adc_ss_ff <= ss_next;
|
|
||||||
adc_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];
|
|
||||||
vld_ff <= 1;
|
|
||||||
end
|
|
||||||
// deassert vld when the data is acknowledged
|
|
||||||
if (ack)
|
|
||||||
vld_ff <= 0;
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -1,2 +0,0 @@
|
||||||
a.out
|
|
||||||
*.vcd
|
|
|
@ -1,165 +0,0 @@
|
||||||
`timescale 10ns/10ns
|
|
||||||
|
|
||||||
module top();
|
|
||||||
|
|
||||||
reg clk = 0;
|
|
||||||
reg rstn = 1;
|
|
||||||
reg adc_so = 1;
|
|
||||||
wire adc_si;
|
|
||||||
wire adc_sck;
|
|
||||||
wire adc_ss;
|
|
||||||
|
|
||||||
reg sck_old = 1;
|
|
||||||
reg ss_old = 1;
|
|
||||||
|
|
||||||
wire [1:0] channel;
|
|
||||||
wire [11:0] adc_val;
|
|
||||||
wire vld;
|
|
||||||
|
|
||||||
reg ack = 0;
|
|
||||||
|
|
||||||
adc_driver dut(
|
|
||||||
.clk(clk),
|
|
||||||
.rstn(rstn),
|
|
||||||
.adc_so(adc_so),
|
|
||||||
.adc_si(adc_si),
|
|
||||||
.adc_ss(adc_ss),
|
|
||||||
.adc_sck(adc_sck),
|
|
||||||
|
|
||||||
.channel(channel),
|
|
||||||
.adc_val(adc_val),
|
|
||||||
.vld(vld),
|
|
||||||
.ack(ack)
|
|
||||||
);
|
|
||||||
|
|
||||||
reg configured;
|
|
||||||
|
|
||||||
reg [15:0] out;
|
|
||||||
|
|
||||||
initial begin
|
|
||||||
clk = 0;
|
|
||||||
rstn = 1;
|
|
||||||
adc_so = 1;
|
|
||||||
sck_old = 1;
|
|
||||||
|
|
||||||
configured = 0;
|
|
||||||
out = 0;
|
|
||||||
|
|
||||||
$dumpfile("adc_driver_tb.vcd");
|
|
||||||
$dumpvars;
|
|
||||||
end
|
|
||||||
|
|
||||||
always
|
|
||||||
#2 clk = !clk;
|
|
||||||
|
|
||||||
reg enabled;
|
|
||||||
integer bit_pos;
|
|
||||||
integer channel_num;
|
|
||||||
integer tosend;
|
|
||||||
integer configdata;
|
|
||||||
integer adc_pos;
|
|
||||||
|
|
||||||
integer adc_out[3:0];
|
|
||||||
integer expected[3:0];
|
|
||||||
|
|
||||||
integer i;
|
|
||||||
initial begin
|
|
||||||
bit_pos = 0;
|
|
||||||
channel_num = 0;
|
|
||||||
tosend = 0;
|
|
||||||
enabled = 0;
|
|
||||||
configdata = 0;
|
|
||||||
adc_pos = 0;
|
|
||||||
adc_so = 1;
|
|
||||||
|
|
||||||
for (i = 0; i < 4; i++) begin
|
|
||||||
#1 adc_pos = i;
|
|
||||||
#1 expected[i] = out;
|
|
||||||
end
|
|
||||||
adc_pos = 0;
|
|
||||||
for (i = 0; i < 4; i++)
|
|
||||||
adc_out[i] = 0;
|
|
||||||
end
|
|
||||||
|
|
||||||
always @* begin
|
|
||||||
case (adc_pos[1:0])
|
|
||||||
2'b00: out = 16'h01ff;
|
|
||||||
2'b01: out = 16'h1fff;
|
|
||||||
2'b10: out = 16'h2dea;
|
|
||||||
2'b11: out = 16'h3caf;
|
|
||||||
endcase
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
always @(posedge clk) begin
|
|
||||||
if (~adc_ss & ss_old) begin
|
|
||||||
enabled <= 1;
|
|
||||||
//bit_pos <= 0;
|
|
||||||
end
|
|
||||||
if (enabled) begin
|
|
||||||
if (!configured) begin
|
|
||||||
// load into configdata if it hasn't
|
|
||||||
// been configured yet
|
|
||||||
if (~sck_old & adc_sck) begin
|
|
||||||
configdata <= (configdata << 1) | adc_si;
|
|
||||||
if (bit_pos >= 15) begin
|
|
||||||
configured <= 1;
|
|
||||||
bit_pos <= 0;
|
|
||||||
end else
|
|
||||||
bit_pos <= bit_pos + 1;
|
|
||||||
end
|
|
||||||
end else begin
|
|
||||||
if (~sck_old & adc_sck) begin
|
|
||||||
// TODO make sure the input is zero
|
|
||||||
end
|
|
||||||
if (sck_old & ~adc_sck) begin
|
|
||||||
// otherwise start loading in adc data
|
|
||||||
if (bit_pos >= 15) begin
|
|
||||||
bit_pos <= 0;
|
|
||||||
end else
|
|
||||||
bit_pos <= bit_pos + 1;
|
|
||||||
|
|
||||||
adc_so <= out[15-bit_pos];
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if (vld & configured & ~ack) begin
|
|
||||||
adc_pos <= adc_pos + 1;
|
|
||||||
adc_out[channel] = adc_val;
|
|
||||||
ack <= 1;
|
|
||||||
if (channel == 3) begin
|
|
||||||
// TODO check configdata
|
|
||||||
i = {
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
if (configdata != i)
|
|
||||||
$display("config %d != %d", configdata, i);
|
|
||||||
for (i = 0; i < 4; i++) begin
|
|
||||||
if (adc_out[i] != (12'hfff & expected[i]) )
|
|
||||||
$display("adc %x %x != %x", i, adc_out[i], expected[i]);
|
|
||||||
end
|
|
||||||
$finish;
|
|
||||||
end
|
|
||||||
end else
|
|
||||||
ack <= 0;
|
|
||||||
|
|
||||||
ss_old <= adc_ss;
|
|
||||||
sck_old <= adc_sck;
|
|
||||||
end
|
|
||||||
|
|
||||||
initial begin
|
|
||||||
#50000
|
|
||||||
$finish;
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -1,37 +0,0 @@
|
||||||
#include "Vadc_driver.h"
|
|
||||||
#include "verilated.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
int main(int argc, char** argv, char** env) {
|
|
||||||
Verilated::commandArgs(argc, argv);
|
|
||||||
auto driver = std::unique_ptr<Vadc_driver>();
|
|
||||||
uint64_t tick = 0;
|
|
||||||
bool done = false;
|
|
||||||
|
|
||||||
driver->clk = 0;
|
|
||||||
driver->rstn = 1;
|
|
||||||
driver->adc_so = 0;
|
|
||||||
driver->ack = 0;
|
|
||||||
|
|
||||||
int sck_old = driver->sck;
|
|
||||||
|
|
||||||
while (!done) {
|
|
||||||
if (tick > 5) {
|
|
||||||
driver->rstn = 0;
|
|
||||||
}
|
|
||||||
if ((tick % 10) == 0) {
|
|
||||||
driver->clk = 1;
|
|
||||||
}
|
|
||||||
if ((tick % 10) == 5) {
|
|
||||||
driver->clk = 0;
|
|
||||||
}
|
|
||||||
driver->eval();
|
|
||||||
if (driver->sck & !sck_old) {
|
|
||||||
}
|
|
||||||
sck_old = driver->sck;
|
|
||||||
if (driver->vld) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
Loading…
Reference in New Issue