Compare commits

...

2 Commits

Author SHA1 Message Date
Kelvin Ly 5f85a3b99e Work on DRV8353 SPI driver 2020-01-22 07:42:50 -05:00
Kelvin Ly bd108603e3 Reorganize testbench a bit 2020-01-17 07:40:07 -05:00
5 changed files with 300 additions and 54 deletions

View File

@ -17,7 +17,7 @@ module drv8353r_driver(
output drv_cs_n,
output drv_sck,
output drv_sdi,
output drv_sdo,
input drv_sdo,
// assert stop with the coast_nbrake
// bit to disable the gate drivers
@ -28,9 +28,11 @@ module drv8353r_driver(
output rdy,
output fault_a,
output fault_b,
output fault_c,
output fault_c
);
parameter WAIT_TIME = 98;
wire [15:0] driver_control;
wire [15:0] hs_control;
wire [15:0] ls_control;
@ -49,8 +51,9 @@ assign driver_control = {
1'b0, // 1PWM_DIR, default
1'b0, // COAST, disabled
1'b0, // BRAKE, disabled
1'b0, // CLR_FLT, no clear
1'b0 // CLR_FLT, no clear
};
// TODO actually calculate HS/LS gate drive
// requirements
assign hs_control = {
@ -58,7 +61,7 @@ assign hs_control = {
1'b1, // write
3'b000, // LOCK, don't lock or unlock
4'b0100, // IDRIVEP_HS, 300 mA
4'b0010, // IDRIVEN_HS, 200 mA
4'b0010 // IDRIVEN_HS, 200 mA
};
assign ls_control = {
4'b0100, // address = 0x04
@ -66,7 +69,7 @@ assign ls_control = {
1'b1, // CBC, OCP conditions reset when PWM is provided
2'b11, // TDRIVE = 4000 ns gate-current drive time
4'b0100, // IDRIVEP_LS, 300 mA
4'b0010, // IDRIVEN_LS, 200 mA
4'b0010 // IDRIVEN_LS, 200 mA
};
assign ocp_control = {
4'b0101, // address = 0x05
@ -75,7 +78,7 @@ assign ocp_control = {
2'b01, // DEAD_TIME, 100 ns deadtime
2'b01, // OCP_MODE, overcurrent causes automatic retry
2'b10, // OCP_DEG, 4us overcurrent deglitch
4'b1101, // VDS_LVL, 1V
4'b1101 // VDS_LVL, 1V
};
assign csa_control = {
4'b0110, // address = 0x06
@ -88,12 +91,11 @@ assign csa_control = {
1'b0, // CSA_CAL_A, normal operation
1'b0, // CSA_CAL_B, normal operation
1'b0, // CSA_CAL_C, normal operation
2'b11, // SEN_LVL, OCP 1 V
2'b11 // SEN_LVL, OCP 1 V
};
reg [3:0] cur_bit;
wire [4:0] config_bits;
wire config_bit;
wire [3:0] cur_bit;
wire [7:0] config_bits;
assign config_bits[0] = driver_control[cur_bit];
assign config_bits[1] = hs_control[cur_bit];
@ -102,5 +104,141 @@ assign config_bits[3] =
ocp_control[cur_bit];
assign config_bits[4] =
csa_control[cur_bit];
assign config_bits[7:5] = 3'b000;
localparam IDLE = 0,
INIT = 1,
CONFIG = 2,
READY = 3;
reg [2:0] state = IDLE;
reg [2:0] state_next;
assign rdy = (state == READY);
reg drv_en_ff = 0;
reg drv_cs_n_ff = 1;
reg drv_sck_ff = 1;
reg drv_sdi_ff = 0;
reg drv_en_next, drv_cs_n_next;
reg drv_sck_next, drv_sdi_next;
assign drv_en = drv_en_ff;
assign drv_cs_n = drv_cs_n_ff;
assign drv_sck = drv_sck_ff;
assign drv_sdi = drv_sdi_ff;
reg [7:0] count = 0;
reg [7:0] count_next;
reg [7:0] msb_count = 0;
reg [7:0] msb_count_next;
assign cur_bit = 15 - count[6:3];
reg [2:0] cur_reg = 0;
reg [2:0] cur_reg_next;
always @* begin
state_next = state;
drv_en_next = 0;
drv_cs_n_next = 1;
drv_sck_next = 0;
drv_sdi_next = 0;
cur_reg_next = 0;
count_next = count;
msb_count_next = msb_count;
case (state)
IDLE: begin
if (en) begin
state_next = INIT;
drv_en_next = 1;
count_next = 0;
end
end
INIT: begin
drv_en_next = 1;
// wait 1 ms before trying to configure
count_next = count + 1;
if (&count_next) begin
msb_count_next = msb_count;
end
if (msb_count == WAIT_TIME) begin
cur_reg_next = 0;
state_next = CONFIG;
count_next = 0;
end
end
CONFIG: begin
// write all the configuration bits
// to the DRV8353
drv_en_next = 1;
drv_cs_n_next = drv_cs_n_ff;
drv_sck_next = drv_sck_ff;
drv_sdi_next = drv_sdi_ff;
cur_reg_next = cur_reg;
count_next = count + 1;
if (&count[1:0]) begin
if (count[7:2] == 0) begin
drv_cs_n_next = 0;
end
drv_sck_next = count[2];
if (count[7:2] == 33) begin
drv_cs_n_next = 1;
count_next = 0;
cur_reg_next = cur_reg + 1;
drv_sck_next = 0;
if (cur_reg == 4) begin
state_next = READY;
end
end
// write the next bit on high transitions
if (count[2]) begin
drv_sdi_next = config_bits[cur_reg];
end
end
end
READY: begin
drv_en_next = 1;
// TODO if there are faults read
// the status register to output
// the appropriate info
// TODO if a stop is commanded
// write to the register
// to stop the motor driver
// TODO if a stop is deasserted
// write to the register to
// reenable the motor driver
end
endcase
if (rst) begin
state_next = IDLE;
drv_en_next = 0;
drv_cs_n_next = 1;
drv_sck_next = 1;
drv_sdi_next = 0;
end
end
always @(posedge clk) begin
state <= state_next;
drv_en_ff <= drv_en_next;
drv_cs_n_ff <= drv_cs_n_next;
drv_sck_ff <= drv_sck_next;
drv_sdi_ff <= drv_sdi_next;
count <= count_next;
msb_count <= msb_count_next;
cur_reg <= cur_reg_next;
end
endmodule

View File

@ -1,9 +1,17 @@
tests: test_adc
tests: test_adc test_drv8353
test_adc: adc_driver_tb.vcd
test_adc: vcd/adc_driver_tb.vcd
adc_driver_tb.vcd: ./adc_driver_tb
./adc_driver_tb
vcd/adc_driver_tb.vcd: bin/adc_driver_tb
./bin/adc_driver_tb
adc_driver_tb: adc_driver_tb.v ../library/adc_driver.v
iverilog adc_driver_tb.v ../library/adc_driver.v -o adc_driver_tb
bin/adc_driver_tb: adc_driver_tb.v ../library/adc_driver.v
iverilog adc_driver_tb.v ../library/adc_driver.v -o bin/adc_driver_tb
test_drv8353: vcd/drv8353_spi_tb.vcd
vcd/drv8353_spi_tb.vcd: bin/drv8353_spi_tb
./bin/drv8353_spi_tb
bin/drv8353_spi_tb: drv8353_spi_tb.v ../library/drv8353r_driver.v
iverilog $^ -o bin/drv8353_spi_tb

View File

@ -45,7 +45,7 @@ initial begin
configured = 0;
out = 0;
$dumpfile("adc_driver_tb.vcd");
$dumpfile("vcd/adc_driver_tb.vcd");
$dumpvars;
end

View File

@ -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;
}

137
rtl/tb/drv8353_spi_tb.v Normal file
View File

@ -0,0 +1,137 @@
`timescale 10ns/10ns
module drv8353_spi_tb();
reg clk = 0;
reg rst = 1;
reg en = 0;
reg drv_fault_n = 1;
wire drv_en;
wire drv_cs_n;
wire drv_sck;
wire drv_sdi;
reg drv_sdo = 0;
// assert stop with the coast_nbrake
// bit to disable the gate drivers
reg stop = 0;
reg coast_nbrake = 0;
reg clear_fault = 0;
wire rdy;
wire fault_a;
wire fault_b;
wire fault_c;
drv8353r_driver #(0) dut(
.clk(clk),
.rst(rst),
.en(en),
.drv_fault_n(drv_fault_n),
.drv_en(drv_en),
.drv_cs_n(drv_cs_n),
.drv_sck(drv_sck),
.drv_sdi(drv_sdi),
.drv_sdo(drv_sdo),
.stop(stop),
.coast_nbrake(coast_nbrake),
.clear_fault(clear_fault),
.rdy(rdy),
.fault_a(fault_a),
.fault_b(fault_b),
.fault_c(fault_c)
);
integer cfg_num = -1;
integer cfg[5:0];
integer i = 0;
integer bit_count = 0;
reg spi_active = 0;
wire [15:0] cfg0;
wire [15:0] cfg1;
wire [15:0] cfg2;
wire [15:0] cfg3;
wire [15:0] cfg4;
assign cfg0 = cfg[0];
assign cfg1 = cfg[1];
assign cfg2 = cfg[2];
assign cfg3 = cfg[3];
assign cfg4 = cfg[4];
always @(negedge drv_cs_n) begin
spi_active <= 1;
cfg_num <= cfg_num + 1;
if (drv_sck) begin
$display("sck not low on falling edge, clock %d", i);
end
end
always @(posedge drv_cs_n) begin
spi_active <= 0;
bit_count <= 0;
if (drv_sck) begin
$display("sck not low on rising edge, clock %d", i);
end
end
always @(negedge drv_sck) begin
if (spi_active) begin
cfg[cfg_num] <= cfg[cfg_num] << 1 | drv_sdi;
bit_count <= bit_count + 1;
end
end
integer j = 0;
integer expected = 0;
always @*
case (j)
0: expected = 16'b0010100000100000;
1: expected = 16'b0011100001000010;
2: expected = 16'b0100111101000010;
3: expected = 16'b0101100101101101;
4: expected = 16'b0110100010000011;
endcase
always @(rdy) begin
if (rdy) begin
for (j = 0; j < 5; j += 1)
#1
if (cfg[j] != expected)
$display("cfg %d bad, %x != %x", j, cfg[j], expected);
$finish;
end
end
initial begin
$dumpfile("vcd/drv8353_spi_tb.vcd");
$dumpvars;
for (i = 0; i < 5; i += 1) cfg[i] = 0;
// TODO cycle the module long enough to get all the configuration bits
// written out, and check to see if it worked correctly
i = 0;
#2 clk = 0;
#2 clk = 1;
i = i + 1;
rst = 0;
en = 1;
for (i = 0; i < 3000; i+= 1) begin
#2 clk = 0;
#2 clk = 1;
i = i + 1;
end
end
endmodule