From 13811aeacbbe19a415a82ff9e17e3b8e94fa992e Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Mon, 28 Aug 2023 15:49:49 +1000 Subject: [PATCH] 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' --- test/test_i2c.py | 92 ++++++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 35 deletions(-) diff --git a/test/test_i2c.py b/test/test_i2c.py index eeb0aaf65..147ad063c 100755 --- a/test/test_i2c.py +++ b/test/test_i2c.py @@ -79,16 +79,19 @@ class TestI2C(unittest.TestCase): dut = I2CMaster(pads) 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 while True: - timeout += 1 - self.assertLess(timeout, 20) - 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) + scl_now, sda_now = (yield dut.scl_t.i), (yield dut.sda_t.i) + if scl_now == scl and sda_now == sda: 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 def wait_idle(do=lambda: ()): @@ -102,28 +105,56 @@ class TestI2C(unittest.TestCase): yield def write_bit(value): + #print(f"write_bit:{value}") yield from check_trans(scl=False, sda=value) yield from check_trans(scl=True, sda=value) def write_ack(value): + #print(f"write_ack:{value}") yield from check_trans(scl=False, sda=not value) yield from check_trans(scl=True, sda=not value) yield from wait_idle() def read_bit(value): - yield from check_trans(scl=False, sda=True) - yield dut.sda_t.i.eq(value) - yield from check_trans(scl=True, sda=True) + #print(f"read_bit:{value}") + yield from check_trans(scl=False, sda=(yield dut.sda_tristate.i_mock)) + 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): + #print(f"read_ack:{value}") yield from check_trans(scl=False, sda=True) - yield dut.sda_t.i.eq(not value) - yield from check_trans(scl=True, sda=True) + yield dut.sda_tristate.i_mock.eq(not value) + yield from check_trans(scl=True, sda=not value) yield from wait_idle() + yield dut.sda_tristate.i_mock.eq(True) ack = ((yield from dut.bus.read(I2C_XFER_ADDR)) & I2C_ACK) != 0 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(): + yield from dut.bus.write(I2C_CONFIG_ADDR, 4) data = (yield from dut.bus.read(I2C_CONFIG_ADDR)) & 0xff self.assertEqual(data, 4) @@ -132,39 +163,30 @@ class TestI2C(unittest.TestCase): yield from check_trans(scl=True, sda=False) yield from wait_idle() - yield from dut.bus.write(I2C_XFER_ADDR, I2C_WRITE | 0x82) - for i in [True, False, False, False, False, False, True, 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 i2c_write(0x82) + yield from i2c_write(0x18, ack=False) yield from dut.bus.write(I2C_XFER_ADDR, I2C_START | I2C_STOP) yield from check_trans(scl=True, sda=False) yield from wait_idle() - yield from dut.bus.write(I2C_XFER_ADDR, I2C_READ) - for i in [False, False, False, True, True, False, False, False]: - 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 i2c_read(0x18, ack=False) + yield from i2c_read(0x88) yield from dut.bus.write(I2C_XFER_ADDR, I2C_STOP) yield from check_trans(scl=False, sda=False) 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__": unittest.main()