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
*/
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
);
@@ -118,6 +119,10 @@ prescale
set prescale to 1/4 of the minimum clock period in units
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
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_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_tbuf_reg = 1'b0, delay_tbuf_next;
logic delay_scl_reg = 1'b0, delay_scl_next;
logic delay_sda_reg = 1'b0, delay_sda_next;
@@ -595,8 +602,10 @@ always_comb begin
phy_ready_next = 1'b0;
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_tbuf_next = delay_tbuf_reg;
delay_scl_next = delay_scl_reg;
delay_sda_next = delay_sda_reg;
@@ -613,13 +622,18 @@ always_comb begin
delay_sda_next = sda_o_reg && !sda_i_reg;
end else if (delay_run_reg) begin
// time delay
if (delay_count_reg != 0) begin
delay_count_next = delay_count_reg - 1;
if (delay_count_qb_reg != 0) begin
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
delay_run_next = 1'b0;
delay_tbuf_next = 1'b0;
end
end else begin
delay_count_next = prescale;
delay_count_qb_next = prescale;
delay_count_tbuf_next = {tbuf_cyc, 2'b00};
end
if (phy_release_bus) begin
@@ -662,6 +676,7 @@ always_comb begin
phy_ready_next = 1'b0;
sda_o_next = 1'b1;
delay_run_next = 1'b1;
delay_tbuf_next = 1'b1;
phy_state_next = PHY_STATE_REPEATED_START_1;
end else if (phy_write_bit && phy_ready_reg) begin
phy_ready_next = 1'b0;
@@ -818,6 +833,7 @@ always_comb begin
sda_o_next = 1'b1;
delay_run_next = 1'b1;
delay_tbuf_next = 1'b1;
phy_state_next = PHY_STATE_STOP_3;
end
PHY_STATE_STOP_3: begin
@@ -852,8 +868,10 @@ always_ff @(posedge clk) begin
mode_write_multiple_reg <= mode_write_multiple_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_tbuf_reg <= delay_tbuf_next;
delay_scl_reg <= delay_scl_next;
delay_sda_reg <= delay_sda_next;
@@ -892,8 +910,10 @@ always_ff @(posedge clk) begin
if (rst) begin
state_reg <= 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_tbuf_reg <= 1'b0;
delay_scl_reg <= 1'b0;
delay_sda_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,
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)
async def reset(self):

View File

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