// this module configures the DRV8353, // leaving the PWM for a different module // if the fault pin is triggered // it will read the fault status registers // and assert the appropriate output wire // it also allows disabling/enabling // the MOSFETs using the coast/brake pins // in the driver control register module drv8353r_driver( input clk, input rst, input en, input drv_fault_n, output drv_en, output drv_cs_n, output drv_sck, output drv_sdi, input drv_sdo, // assert stop with the coast_nbrake // bit to disable the gate drivers input stop, input coast_nbrake, input clear_fault, output rdy, output fault_a, output fault_b, output fault_c ); parameter WAIT_TIME = 98; wire [15:0] driver_control; wire [15:0] hs_control; wire [15:0] ls_control; wire [15:0] ocp_control; wire [15:0] csa_control; assign driver_control = { 4'b0010, // address = 0x02 1'b1, // write 1'b0, // OCP_ACT, shutdown affected half bridge on fault 1'b0, // DIS_GDUV, undervoltage enabled 1'b0, // DIS_GDF, gate drive fault enabled 1'b0, // OTW_REP, overtemp not reported 2'b01, // PWM_MODE, 3x PWM mode 1'b0, // 1PWM_COM, 1x PWM uses synchronous rectifier 1'b0, // 1PWM_DIR, default 1'b0, // COAST, disabled 1'b0, // BRAKE, disabled 1'b0 // CLR_FLT, no clear }; // TODO actually calculate HS/LS gate drive // requirements assign hs_control = { 4'b0011, // address = 0x03 1'b1, // write 3'b000, // LOCK, don't lock or unlock 4'b0100, // IDRIVEP_HS, 300 mA 4'b0010 // IDRIVEN_HS, 200 mA }; assign ls_control = { 4'b0100, // address = 0x04 1'b1, // write 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 }; assign ocp_control = { 4'b0101, // address = 0x05 1'b1, // write 1'b0, // TRETRY, VDS_OCP/SEN_OCP retry time is 8ms 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 }; assign csa_control = { 4'b0110, // address = 0x06 1'b1, // write 1'b0, // CSA_FET = SPx 1'b0, // VREF_DIV, unidirectional 1'b0, // LS_REF, VDS_OCP is measured from SHx to SNx 2'b10, // CSA_GAIN, 20V/V 1'b0, // DIS_SEN overcurrent fault enabled 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 }; 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]; assign config_bits[2] = ls_control[cur_bit]; 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; reg fault_a_ff = 0; reg fault_b_ff = 0; reg fault_c_ff = 0; assign fault_a = fault_a_ff; assign fault_b = fault_b_ff; assign fault_c = fault_c_ff; 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; // 8x downsample 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