lss: Add tBUF setting to I2C master to insert bus idle time before starts and repeated starts

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2026-03-18 12:30:11 -07:00
parent d268e6d27a
commit 4b90b35b4c
3 changed files with 32 additions and 9 deletions

View File

@@ -45,7 +45,8 @@ module taxi_i2c_master (
/* /*
* Configuration * Configuration
*/ */
input wire logic [15:0] prescale, input wire logic [15:0] prescale = 10,
input wire logic [15:0] tbuf_cyc = 10,
input wire logic stop_on_idle input wire logic stop_on_idle
); );
@@ -118,6 +119,10 @@ prescale
set prescale to 1/4 of the minimum clock period in units set prescale to 1/4 of the minimum clock period in units
of input clk cycles (prescale = Fclk / (FI2Cclk * 4)) of input clk cycles (prescale = Fclk / (FI2Cclk * 4))
tbuf_cyc
bus free time (tBUF) before a start or repeated start in
units of bit periods / scl cycles
stop_on_idle stop_on_idle
automatically issue stop when command input is not valid automatically issue stop when command input is not valid
@@ -214,8 +219,10 @@ logic mode_read_reg = 1'b0, mode_read_next;
logic mode_write_multiple_reg = 1'b0, mode_write_multiple_next; logic mode_write_multiple_reg = 1'b0, mode_write_multiple_next;
logic mode_stop_reg = 1'b0, mode_stop_next; logic mode_stop_reg = 1'b0, mode_stop_next;
logic [15:0] delay_count_reg = '0, delay_count_next; logic [15:0] delay_count_qb_reg = '0, delay_count_qb_next;
logic [15+2:0] delay_count_tbuf_reg = '0, delay_count_tbuf_next;
logic delay_run_reg = 1'b0, delay_run_next; logic delay_run_reg = 1'b0, delay_run_next;
logic delay_tbuf_reg = 1'b0, delay_tbuf_next;
logic delay_scl_reg = 1'b0, delay_scl_next; logic delay_scl_reg = 1'b0, delay_scl_next;
logic delay_sda_reg = 1'b0, delay_sda_next; logic delay_sda_reg = 1'b0, delay_sda_next;
@@ -595,8 +602,10 @@ always_comb begin
phy_ready_next = 1'b0; phy_ready_next = 1'b0;
phy_rx_data_next = phy_rx_data_reg; phy_rx_data_next = phy_rx_data_reg;
delay_count_next = delay_count_reg; delay_count_qb_next = delay_count_qb_reg;
delay_count_tbuf_next = delay_count_tbuf_reg;
delay_run_next = delay_run_reg; delay_run_next = delay_run_reg;
delay_tbuf_next = delay_tbuf_reg;
delay_scl_next = delay_scl_reg; delay_scl_next = delay_scl_reg;
delay_sda_next = delay_sda_reg; delay_sda_next = delay_sda_reg;
@@ -613,13 +622,18 @@ always_comb begin
delay_sda_next = sda_o_reg && !sda_i_reg; delay_sda_next = sda_o_reg && !sda_i_reg;
end else if (delay_run_reg) begin end else if (delay_run_reg) begin
// time delay // time delay
if (delay_count_reg != 0) begin if (delay_count_qb_reg != 0) begin
delay_count_next = delay_count_reg - 1; delay_count_qb_next = delay_count_qb_reg - 1;
end else if (delay_tbuf_reg && delay_count_tbuf_reg != 0) begin
delay_count_qb_next = prescale;
delay_count_tbuf_next = delay_count_tbuf_reg - 1;
end else begin end else begin
delay_run_next = 1'b0; delay_run_next = 1'b0;
delay_tbuf_next = 1'b0;
end end
end else begin end else begin
delay_count_next = prescale; delay_count_qb_next = prescale;
delay_count_tbuf_next = {tbuf_cyc, 2'b00};
end end
if (phy_release_bus) begin if (phy_release_bus) begin
@@ -662,6 +676,7 @@ always_comb begin
phy_ready_next = 1'b0; phy_ready_next = 1'b0;
sda_o_next = 1'b1; sda_o_next = 1'b1;
delay_run_next = 1'b1; delay_run_next = 1'b1;
delay_tbuf_next = 1'b1;
phy_state_next = PHY_STATE_REPEATED_START_1; phy_state_next = PHY_STATE_REPEATED_START_1;
end else if (phy_write_bit && phy_ready_reg) begin end else if (phy_write_bit && phy_ready_reg) begin
phy_ready_next = 1'b0; phy_ready_next = 1'b0;
@@ -818,6 +833,7 @@ always_comb begin
sda_o_next = 1'b1; sda_o_next = 1'b1;
delay_run_next = 1'b1; delay_run_next = 1'b1;
delay_tbuf_next = 1'b1;
phy_state_next = PHY_STATE_STOP_3; phy_state_next = PHY_STATE_STOP_3;
end end
PHY_STATE_STOP_3: begin PHY_STATE_STOP_3: begin
@@ -852,8 +868,10 @@ always_ff @(posedge clk) begin
mode_write_multiple_reg <= mode_write_multiple_next; mode_write_multiple_reg <= mode_write_multiple_next;
mode_stop_reg <= mode_stop_next; mode_stop_reg <= mode_stop_next;
delay_count_reg <= delay_count_next; delay_count_qb_reg <= delay_count_qb_next;
delay_count_tbuf_reg <= delay_count_tbuf_next;
delay_run_reg <= delay_run_next; delay_run_reg <= delay_run_next;
delay_tbuf_reg <= delay_tbuf_next;
delay_scl_reg <= delay_scl_next; delay_scl_reg <= delay_scl_next;
delay_sda_reg <= delay_sda_next; delay_sda_reg <= delay_sda_next;
@@ -892,8 +910,10 @@ always_ff @(posedge clk) begin
if (rst) begin if (rst) begin
state_reg <= STATE_IDLE; state_reg <= STATE_IDLE;
phy_state_reg <= PHY_STATE_IDLE; phy_state_reg <= PHY_STATE_IDLE;
delay_count_reg <= '0; delay_count_qb_reg <= '0;
delay_count_tbuf_reg <= '0;
delay_run_reg <= 1'b0; delay_run_reg <= 1'b0;
delay_tbuf_reg <= 1'b0;
delay_scl_reg <= 1'b0; delay_scl_reg <= 1'b0;
delay_sda_reg <= 1'b0; delay_sda_reg <= 1'b0;
s_axis_cmd_ready_reg <= 1'b0; s_axis_cmd_ready_reg <= 1'b0;

View File

@@ -51,7 +51,8 @@ class TB:
self.i2c_mem.append(I2cMemory(sda=dut.sda_o, sda_o=dut.sda_i, self.i2c_mem.append(I2cMemory(sda=dut.sda_o, sda_o=dut.sda_i,
scl=dut.scl_o, scl_o=dut.scl_i, addr=0x51, size=1024)) scl=dut.scl_o, scl_o=dut.scl_i, addr=0x51, size=1024))
dut.prescale.setimmediatevalue(2) dut.prescale.setimmediatevalue(20)
dut.tbuf_cyc.setimmediatevalue(20)
dut.stop_on_idle.setimmediatevalue(0) dut.stop_on_idle.setimmediatevalue(0)
async def reset(self): async def reset(self):

View File

@@ -36,6 +36,7 @@ logic bus_active;
logic missed_ack; logic missed_ack;
logic [15:0] prescale; logic [15:0] prescale;
logic [15:0] tbuf_cyc;
logic stop_on_idle; logic stop_on_idle;
taxi_i2c_master taxi_i2c_master
@@ -70,6 +71,7 @@ uut (
* Configuration * Configuration
*/ */
.prescale(prescale), .prescale(prescale),
.tbuf_cyc(tbuf_cyc),
.stop_on_idle(stop_on_idle) .stop_on_idle(stop_on_idle)
); );