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)
|
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()
|
||||||
|
|
Loading…
Reference in New Issue