I²C Driver
I²C Master bus functional model for cocotb testbenches. Generates accurate I²C bus traffic for testing I²C slaves and sniffers. Supports both separate-signal and combined-vector pin modes, with configurable timing and error injection for glitches and clock stretching.
Quick Start
import cocotb
from routertl.sim import Tb
from routertl.sim.cocotb.tb.drivers.i2c_master import I2cMasterDriver, I2cTiming
@cocotb.test()
async def test_i2c_write(dut):
tb = Tb(dut)
await tb.start_clock()
await tb.reset()
# Separate-signal mode (individual SDA/SCL pins)
i2c = I2cMasterDriver(tb, sda=dut.I2C_SDA, scl=dut.I2C_SCL)
await i2c.initialize()
# Write 3 bytes to slave address 0x50
acks = await i2c.write_transaction(addr=0x50, data=[0x00, 0x42, 0xFF])
assert all(acks), "Slave did not ACK all bytes"
# Combined-vector mode (2-bit I2C bus: bit1=SDA, bit0=SCL)
i2c_combined = I2cMasterDriver(tb, i2c_pins=dut.I2C_PINS)
await i2c_combined.initialize()
Signal Modes
The driver supports two pin configurations:
| Mode | Signals | Use When |
|---|---|---|
| Separate | sda, scl (+ optional sda_in) | Standard I²C with individual ports |
| Combined | i2c_pins (2-bit vector) | Compact bus representations [SDA, SCL] |
Error Injection
# Inject a glitch on SDA (tests GLITCH_ERROR detection)
await i2c.inject_glitch(duration_ns=20)
# Hold SCL low for extended period (tests STRETCH_ERROR / clock timeout)
await i2c.stretch_scl(duration_ms=50)
Timing Configuration
timing = I2cTiming(
period_ns=10_000, # 100 kHz standard mode
setup_ns=250, # SDA setup time before SCL rise
hold_ns=300, # SDA hold time after SCL fall
)
i2c = I2cMasterDriver(tb, sda=dut.SDA, scl=dut.SCL, timing=timing)
Classes
::: sim.cocotb.tb.drivers.i2c_master.I2cTiming options: show_root_heading: true
::: sim.cocotb.tb.drivers.i2c_master.I2cMasterDriver options: show_root_heading: true show_source: true members: - init - initialize - start - stop - write_byte - read_byte - write_transaction - inject_glitch - stretch_scl