Skip to content

Commit

Permalink
Add test bitstream to verify the ADC.
Browse files Browse the repository at this point in the history
  • Loading branch information
oskirby committed Jul 19, 2020
1 parent 051b864 commit b8254bc
Show file tree
Hide file tree
Showing 5 changed files with 315 additions and 2 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*.json
*.asc
*.rpt
*.svf
*.bit
*.dfu
32 changes: 32 additions & 0 deletions verilog/adc/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
PROJ=adc
DEVICE=--um5g-45k
SOURCES=top.v adc.v

all: $(PROJ).bit $(PROJ).svf $(PROJ).dfu

$(PROJ).json: $(SOURCES)
yosys -p "synth_ecp5 -top top -json $@" $^

%_out.config: %.json
nextpnr-ecp5 --json $< --textcfg $@ $(DEVICE) --package CABGA381 --lpf ../logicbone-rev0.lpf

%.bit: %_out.config
ecppack --spimode qspi $< $@

%.svf: %_out.config
ecppack --svf $@ $<

%.dfu: %.bit
dfu-tool -d 1d50:615d convert dfu $^ $@

prog: ${PROJ}.svf
openocd -f ../logicbone-jlink.cfg -c "transport select jtag; init; svf $<; exit"

dfu: ${PROJ}.dfu
dfu-util -d 1d50:615d -a0 -D $<

clean:
rm -f *.svf *.bit *.dfu *.config *.json

.PHONY: prog clean

220 changes: 220 additions & 0 deletions verilog/adc/adc.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
module adc #(
parameter CHANNEL_MASK = 8'b01111111,
) (
input clk,
input reset,

// SPI Bus Pins
output reg csel,
output reg sclk,
output reg mosi,
input miso,

// ADC measurement data.
output reg [11:0] adc_data,
output reg [3:0] adc_channel,
output reg adc_valid
);

localparam ADC_STATE_INIT = 4'h0;
localparam ADC_STATE_RESET = 4'h1;
localparam ADC_STATE_READ_STATUS = 4'h2;
localparam ADC_STATE_POLL_STATUS = 4'h3;
localparam ADC_STATE_START_CAL = 4'h4;
localparam ADC_STATE_READ_CAL = 4'h5;
localparam ADC_STATE_POLL_CAL = 4'h6;
localparam ADC_STATE_CFG_DATA = 4'h7;
localparam ADC_STATE_CFG_CHAN = 4'h8;
localparam ADC_STATE_CFG_SEQ = 4'h9;
localparam ADC_STATE_READOUT = 4'hA;

localparam ADC_OPCODE_NOP = 8'b00000000;
localparam ADC_OPCODE_READ = 8'b00010000;
localparam ADC_OPCODE_WRITE = 8'b00001000;
localparam ADC_OPCODE_SETBIT = 8'b00011000;
localparam ADC_OPCODE_CLRBIT = 8'b00100000;

localparam ADC_REG_SYSTEM_STATUS = 8'h00;
localparam ADC_REG_GENERAL_CFG = 8'h01;
localparam ADC_REG_DATA_CFG = 8'h02;
localparam ADC_REG_SEQUENCE_CFG = 8'h10;
localparam ADC_REG_AUTO_SEQ_CH_SEL = 8'h12;

reg adc_reset_done = 1'b0;
reg adc_cal_done = 1'b0;

reg [3:0] adc_state = ADC_STATE_INIT;
reg [3:0] next_adc_state = ADC_STATE_INIT;
reg [23:0] next_adc_outdata = 0;
reg [4:0] next_adc_bitcount = 0;
always @(*) begin
next_adc_state <= adc_state;
next_adc_bitcount <= 0;
next_adc_outdata <= 0;

case (adc_state)
ADC_STATE_INIT : begin
// After init, start by resetting the ADC.
next_adc_outdata <= {ADC_OPCODE_WRITE, ADC_REG_GENERAL_CFG, 8'h01};
next_adc_bitcount <= 24;
next_adc_state <= ADC_STATE_RESET;
end

ADC_STATE_RESET: begin
// After reset, check the status register for the BOR bit to be set.
next_adc_outdata <= {ADC_OPCODE_READ, ADC_REG_SYSTEM_STATUS, 8'h00};
next_adc_bitcount <= 24;
next_adc_state <= ADC_STATE_READ_STATUS;
end

ADC_STATE_READ_STATUS: begin
// Issue a read command to get the BOR status bit.
next_adc_outdata <= {ADC_OPCODE_READ, ADC_REG_SYSTEM_STATUS, 8'h00};
next_adc_bitcount <= 24;
next_adc_state <= ADC_STATE_POLL_STATUS;
end

ADC_STATE_POLL_STATUS: begin
// Keep sending reads until the BOR status bit is set.
if (~adc_reset_done) begin
next_adc_outdata <= {ADC_OPCODE_READ, ADC_REG_SYSTEM_STATUS, 8'h00};
next_adc_bitcount <= 24;
next_adc_state <= ADC_STATE_POLL_STATUS;

// Start ADC offset calibration once the reset has finished.
end else begin
next_adc_outdata <= {ADC_OPCODE_WRITE, ADC_REG_GENERAL_CFG, 8'h02};
next_adc_bitcount <= 24;
next_adc_state <= ADC_STATE_START_CAL;
end
end

ADC_STATE_START_CAL: begin
// Issue a read command to get the CAL status bit.
next_adc_outdata <= {ADC_OPCODE_READ, ADC_REG_GENERAL_CFG, 8'h00};
next_adc_bitcount <= 24;
next_adc_state <= ADC_STATE_READ_CAL;
end

ADC_STATE_READ_CAL: begin
next_adc_outdata <= {ADC_OPCODE_READ, ADC_REG_GENERAL_CFG, 8'h00};
next_adc_bitcount <= 24;
next_adc_state <= ADC_STATE_POLL_CAL;
end

ADC_STATE_POLL_CAL: begin
// Keep sending reads until the CAL bit is clear.
if (~adc_cal_done) begin
next_adc_outdata <= {ADC_OPCODE_READ, ADC_REG_GENERAL_CFG, 8'h00};
next_adc_bitcount <= 24;
next_adc_state <= ADC_STATE_READ_CAL;

// Configure the data channel after calibration is complete.
end else begin
next_adc_outdata <= {ADC_OPCODE_WRITE, ADC_REG_DATA_CFG, 8'h10};
next_adc_bitcount <= 24;
next_adc_state <= ADC_STATE_CFG_DATA;
end
end

ADC_STATE_CFG_DATA: begin
// After data configuration, select the channels to readout.
next_adc_outdata <= {ADC_OPCODE_WRITE, ADC_REG_AUTO_SEQ_CH_SEL, CHANNEL_MASK};
next_adc_bitcount <= 24;
next_adc_state <= ADC_STATE_CFG_CHAN;
end

ADC_STATE_CFG_CHAN: begin
// After data configuration, enable auto-sequence mode.
next_adc_outdata <= {ADC_OPCODE_WRITE, ADC_REG_SEQUENCE_CFG, 8'h11};
next_adc_bitcount <= 24;
next_adc_state <= ADC_STATE_CFG_SEQ;
end

ADC_STATE_CFG_SEQ: begin
// After the auto-sequence mode has been enable, start ADC readout.
next_adc_outdata <= {ADC_OPCODE_NOP, 8'h00};
next_adc_bitcount <= 16;
next_adc_state <= ADC_STATE_READOUT;
end

ADC_STATE_READOUT: begin
// Continue reading ADC data.
next_adc_outdata <= {ADC_OPCODE_NOP, 8'h00};
next_adc_bitcount <= 16;
next_adc_state <= ADC_STATE_READOUT;
end
endcase
end

// SPI shift registers.
reg [4:0] spi_bitcount = 0;
reg [3:0] spi_cseldelay = 0;
reg [23:0] spi_shiftreg_out = 0;
reg [23:0] spi_shiftreg_in = 0;

always @(posedge clk) begin
adc_valid <= 0;

if (reset) begin
csel <= 1'b1;
sclk <= 1'b0;
msoi <= 1'b0;

adc_reset_done <= 1'b0;
adc_cal_done <= 1'b0;
end

// Clock bits in and out of the SPI interface.
else if (spi_bitcount) begin
csel <= 1'b0;
if (sclk) begin
sclk <= 1'b0;
mosi <= spi_shiftreg_out[spi_bitcount-1];
end else begin
sclk <= 1'b1;
spi_shiftreg_in <= {spi_shiftreg_in[22:0], miso};
spi_bitcount <= spi_bitcount - 1;
end
end

// Deactivate the chipselect and latch the output.
else if (spi_cseldelay) begin
if (adc_state == ADC_STATE_POLL_STATUS) begin
adc_reset_done <= spi_shiftreg_in[16];
end
if (adc_state == ADC_STATE_POLL_CAL) begin
adc_cal_done <= ~spi_shiftreg_in[17];
end
if (adc_state == ADC_STATE_READOUT) begin
adc_data <= spi_shiftreg_in[15:4];
adc_channel <= spi_shiftreg_in[3:0];
adc_valid <= 1;
end

if (sclk) begin
csel <= 1'b0;
sclk <= 1'b0;
msoi <= 1'b0;
end else begin
csel <= 1'b1;
sclk <= 1'b0;
spi_cseldelay <= spi_cseldelay - 1;
end
end

// Start the next command.
else if (next_adc_bitcount) begin
adc_state <= next_adc_state;

spi_bitcount <= next_adc_bitcount;
spi_cseldelay <= 4;
spi_shiftreg_out <= next_adc_outdata;

// Activate the chipselect and start the next word.
sclk <= 1'b0;
csel <= 1'b0;
mosi <= next_adc_outdata[next_adc_bitcount-1];
end
end
endmodule
42 changes: 42 additions & 0 deletions verilog/adc/top.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
module top(input refclk,
input pwr_button,
output [3:0] led,

output adc_csel,
output adc_sclk,
output adc_mosi,
input adc_miso,

output [3:0] debug
);

reg [7:0] por_delay = 8'hff;
always @(posedge refclk) if (por_delay) por_delay <= por_delay - 1;

reg [3:0] led_data = 3'b0;
always @(posedge refclk) begin
if (adc_valid && (adc_channel == 0)) led_data <= adc_data[11:8];
end
assign led = ~led_data;

wire [11:0] adc_data;
wire [3:0] adc_channel;
wire adc_valid;

adc adc_instance(
.clk(refclk),
.reset(por_delay != 0),

.csel(adc_csel),
.sclk(adc_sclk),
.mosi(adc_mosi),
.miso(adc_miso),

.adc_data(adc_data),
.adc_channel(adc_channel),
.adc_valid(adc_valid)
);

assign debug = {adc_miso, adc_mosi, adc_sclk, adc_csel};

endmodule
17 changes: 15 additions & 2 deletions verilog/logicbone-rev0.lpf
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
LOCATE COMP "clk" SITE "M19";
IOBUF PORT "clk" IO_TYPE=LVCMOS18;
LOCATE COMP "refclk" SITE "M19";
IOBUF PORT "refclk" IO_TYPE=LVCMOS18;

#======================================
# Bank 2: Expansion Header P8 - DEBUG
#======================================
LOCATE COMP "debug[0]" SITE "C20";
LOCATE COMP "debug[1]" SITE "D20";
LOCATE COMP "debug[2]" SITE "E20";
LOCATE COMP "debug[3]" SITE "F20";

IOBUF PORT "debug[0]" IO_TYPE=LVCMOS33;
IOBUF PORT "debug[1]" IO_TYPE=LVCMOS33;
IOBUF PORT "debug[2]" IO_TYPE=LVCMOS33;
IOBUF PORT "debug[3]" IO_TYPE=LVCMOS33;

#======================================
# Bank 0: Expansion Header P9 and ADC
Expand Down

0 comments on commit b8254bc

Please sign in to comment.