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:
parent
b779933a5f
commit
13811aeacb
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue