test_i2c: update to use improved _MockTristate

* test now checks the actual i2c bus state, not the I2CMaster output
* refactor to eliminate some copy/paste
* tests now work again with this change: 'only change SDA when SCL is stable'
This commit is contained in:
Andrew Dennison 2023-08-28 15:49:49 +10:00
parent b779933a5f
commit 13811aeacb
1 changed files with 57 additions and 35 deletions

View File

@ -79,16 +79,19 @@ class TestI2C(unittest.TestCase):
dut = I2CMaster(pads) dut = I2CMaster(pads)
def check_trans(scl, sda): def check_trans(scl, sda):
scl_init, sda_init = (yield dut.i2c.scl_o), (yield dut.i2c.sda_o) scl, sda = int(scl), int(sda)
scl_init, sda_init = (yield dut.scl_t.i), (yield dut.sda_t.i)
timeout = 0 timeout = 0
while True: while True:
timeout += 1 scl_now, sda_now = (yield dut.scl_t.i), (yield dut.sda_t.i)
self.assertLess(timeout, 20) if scl_now == scl and sda_now == sda:
scl_now, sda_now = (yield dut.i2c.scl_o), (yield dut.i2c.sda_o)
if scl_now != scl_init or sda_now != sda_init:
self.assertEqual(scl_now, scl)
self.assertEqual(sda_now, sda)
return return
timeout += 1
self.assertLess(timeout, 20,
"\n*** timeout waiting for: " +
f"scl:{scl_now} checking:{scl_init}=>{scl} " +
f"sda:{sda_now} checking:{sda_init}=>{sda} ***"
)
yield yield
def wait_idle(do=lambda: ()): def wait_idle(do=lambda: ()):
@ -102,28 +105,56 @@ class TestI2C(unittest.TestCase):
yield yield
def write_bit(value): def write_bit(value):
#print(f"write_bit:{value}")
yield from check_trans(scl=False, sda=value) yield from check_trans(scl=False, sda=value)
yield from check_trans(scl=True, sda=value) yield from check_trans(scl=True, sda=value)
def write_ack(value): def write_ack(value):
#print(f"write_ack:{value}")
yield from check_trans(scl=False, sda=not value) yield from check_trans(scl=False, sda=not value)
yield from check_trans(scl=True, sda=not value) yield from check_trans(scl=True, sda=not value)
yield from wait_idle() yield from wait_idle()
def read_bit(value): def read_bit(value):
yield from check_trans(scl=False, sda=True) #print(f"read_bit:{value}")
yield dut.sda_t.i.eq(value) yield from check_trans(scl=False, sda=(yield dut.sda_tristate.i_mock))
yield from check_trans(scl=True, sda=True) yield dut.sda_tristate.i_mock.eq(value)
yield from check_trans(scl=True, sda=value)
# need to restore i_mock elsewhere
def read_ack(value): def read_ack(value):
#print(f"read_ack:{value}")
yield from check_trans(scl=False, sda=True) yield from check_trans(scl=False, sda=True)
yield dut.sda_t.i.eq(not value) yield dut.sda_tristate.i_mock.eq(not value)
yield from check_trans(scl=True, sda=True) yield from check_trans(scl=True, sda=not value)
yield from wait_idle() yield from wait_idle()
yield dut.sda_tristate.i_mock.eq(True)
ack = ((yield from dut.bus.read(I2C_XFER_ADDR)) & I2C_ACK) != 0 ack = ((yield from dut.bus.read(I2C_XFER_ADDR)) & I2C_ACK) != 0
self.assertEqual(ack, value) self.assertEqual(ack, value)
def i2c_write(value, ack=True):
value = int(value)
test_bin = '{0:08b}'.format(value)
#print(f"I2C_WRITE | {hex(value)}:0x{test_bin}")
yield from dut.bus.write(I2C_XFER_ADDR, I2C_WRITE | value)
for i in list(test_bin):
yield from write_bit(int(i))
yield from read_ack(True)
def i2c_read(value, ack=True):
value = int(value)
test_bin = '{0:08b}'.format(value)
#print(f"I2C_READ | {hex(value)}:0x{test_bin}")
yield from dut.bus.write(I2C_XFER_ADDR, I2C_READ | (I2C_ACK if ack else 0))
for i in list(test_bin):
yield from read_bit(int(i))
yield dut.sda_tristate.i_mock.eq(True)
data = (yield from dut.bus.read(I2C_XFER_ADDR)) & 0xff
self.assertEqual(data, value)
yield from write_ack(ack)
def check(): def check():
yield from dut.bus.write(I2C_CONFIG_ADDR, 4) yield from dut.bus.write(I2C_CONFIG_ADDR, 4)
data = (yield from dut.bus.read(I2C_CONFIG_ADDR)) & 0xff data = (yield from dut.bus.read(I2C_CONFIG_ADDR)) & 0xff
self.assertEqual(data, 4) self.assertEqual(data, 4)
@ -132,39 +163,30 @@ class TestI2C(unittest.TestCase):
yield from check_trans(scl=True, sda=False) yield from check_trans(scl=True, sda=False)
yield from wait_idle() yield from wait_idle()
yield from dut.bus.write(I2C_XFER_ADDR, I2C_WRITE | 0x82) yield from i2c_write(0x82)
for i in [True, False, False, False, False, False, True, False]: yield from i2c_write(0x18, ack=False)
yield from write_bit(i)
yield from read_ack(True)
yield from dut.bus.write(I2C_XFER_ADDR, I2C_WRITE | 0x18)
for i in [False, False, False, True, True, False, False, False]:
yield from write_bit(i)
yield from read_ack(False)
yield from dut.bus.write(I2C_XFER_ADDR, I2C_START | I2C_STOP) yield from dut.bus.write(I2C_XFER_ADDR, I2C_START | I2C_STOP)
yield from check_trans(scl=True, sda=False) yield from check_trans(scl=True, sda=False)
yield from wait_idle() yield from wait_idle()
yield from dut.bus.write(I2C_XFER_ADDR, I2C_READ) yield from i2c_read(0x18, ack=False)
for i in [False, False, False, True, True, False, False, False]: yield from i2c_read(0x88)
yield from read_bit(i)
data = (yield from dut.bus.read(I2C_XFER_ADDR)) & 0xff
self.assertEqual(data, 0x18)
yield from write_ack(False)
yield from dut.bus.write(I2C_XFER_ADDR, I2C_READ | I2C_ACK)
for i in [True, False, False, False, True, False, False, False]:
yield from read_bit(i)
data = (yield dut.i2c.data)
self.assertEqual(data, 0x88)
yield from write_ack(True)
yield from dut.bus.write(I2C_XFER_ADDR, I2C_STOP) yield from dut.bus.write(I2C_XFER_ADDR, I2C_STOP)
yield from check_trans(scl=False, sda=False) yield from check_trans(scl=False, sda=False)
yield from wait_idle() yield from wait_idle()
run_simulation(dut, check(), special_overrides={Tristate: _MockTristate}, vcd_name="i2c.vcd") clocks = {
"sys": 10,
"async": (10, 3),
}
generators = {
"sys": [
check(),
],
}
run_simulation(dut, generators, clocks, special_overrides={Tristate: _MockTristate}, vcd_name="i2c.vcd")
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()