|
| 1 | +# Test I2CTarget IRQs and clock stretching. |
| 2 | +# |
| 3 | +# Requires two instances with their SCL and SDA lines connected together. |
| 4 | +# Any combination of the below supported boards can be used. |
| 5 | +# |
| 6 | +# Notes: |
| 7 | +# - pull-up resistors may be needed |
| 8 | +# - alif use 1.8V signalling |
| 9 | + |
| 10 | +import sys |
| 11 | +import time |
| 12 | +from machine import I2C, I2CTarget |
| 13 | + |
| 14 | +if not hasattr(I2CTarget, "IRQ_ADDR_MATCH_READ"): |
| 15 | + print("SKIP") |
| 16 | + raise SystemExit |
| 17 | + |
| 18 | +ADDR = 67 |
| 19 | +clock_stretch_us = 200 |
| 20 | + |
| 21 | +# Configure pins based on the target. |
| 22 | +if sys.platform == "alif": |
| 23 | + i2c_args = (1,) # pins P3_7/P3_6 |
| 24 | + i2c_kwargs = {} |
| 25 | +elif sys.platform == "mimxrt": |
| 26 | + i2c_args = (0,) # pins 19/18 on Teensy 4.x |
| 27 | + i2c_kwargs = {} |
| 28 | + clock_stretch_us = 50 # mimxrt cannot delay too long in the IRQ handler |
| 29 | +elif sys.platform == "rp2": |
| 30 | + i2c_args = (0,) |
| 31 | + i2c_kwargs = {"scl": 9, "sda": 8} |
| 32 | +elif sys.platform == "pyboard": |
| 33 | + i2c_args = ("Y",) |
| 34 | + i2c_kwargs = {} |
| 35 | +elif sys.platform == "samd": |
| 36 | + i2c_args = () # pins SCL/SDA |
| 37 | + i2c_kwargs = {} |
| 38 | +elif "zephyr-rpi_pico" in sys.implementation._machine: |
| 39 | + i2c_args = ("i2c1",) # on gpio7/gpio6 |
| 40 | + i2c_kwargs = {} |
| 41 | +else: |
| 42 | + print("Please add support for this test on this platform.") |
| 43 | + raise SystemExit |
| 44 | + |
| 45 | + |
| 46 | +def simple_irq(i2c_target): |
| 47 | + flags = i2c_target.irq().flags() |
| 48 | + if flags & I2CTarget.IRQ_ADDR_MATCH_READ: |
| 49 | + print("IRQ_ADDR_MATCH_READ") |
| 50 | + if flags & I2CTarget.IRQ_ADDR_MATCH_WRITE: |
| 51 | + print("IRQ_ADDR_MATCH_WRITE") |
| 52 | + |
| 53 | + # Force clock stretching. |
| 54 | + time.sleep_us(clock_stretch_us) |
| 55 | + |
| 56 | + |
| 57 | +class I2CTargetMemory: |
| 58 | + def __init__(self, i2c_target, mem): |
| 59 | + self.buf1 = bytearray(1) |
| 60 | + self.mem = mem |
| 61 | + self.memaddr = 0 |
| 62 | + self.state = 0 |
| 63 | + i2c_target.irq( |
| 64 | + self.irq, |
| 65 | + I2CTarget.IRQ_ADDR_MATCH_WRITE | I2CTarget.IRQ_READ_REQ | I2CTarget.IRQ_WRITE_REQ, |
| 66 | + hard=True, |
| 67 | + ) |
| 68 | + |
| 69 | + def irq(self, i2c_target): |
| 70 | + # Force clock stretching. |
| 71 | + time.sleep_us(clock_stretch_us) |
| 72 | + |
| 73 | + flags = i2c_target.irq().flags() |
| 74 | + if flags & I2CTarget.IRQ_ADDR_MATCH_WRITE: |
| 75 | + self.state = 0 |
| 76 | + if flags & I2CTarget.IRQ_READ_REQ: |
| 77 | + self.buf1[0] = self.mem[self.memaddr] |
| 78 | + self.memaddr += 1 |
| 79 | + i2c_target.write(self.buf1) |
| 80 | + if flags & I2CTarget.IRQ_WRITE_REQ: |
| 81 | + i2c_target.readinto(self.buf1) |
| 82 | + if self.state == 0: |
| 83 | + self.state = 1 |
| 84 | + self.memaddr = self.buf1[0] |
| 85 | + else: |
| 86 | + self.mem[self.memaddr] = self.buf1[0] |
| 87 | + self.memaddr += 1 |
| 88 | + self.memaddr %= len(self.mem) |
| 89 | + |
| 90 | + # Force clock stretching. |
| 91 | + time.sleep_us(clock_stretch_us) |
| 92 | + |
| 93 | + |
| 94 | +# I2C controller |
| 95 | +def instance0(): |
| 96 | + i2c = I2C(*i2c_args, **i2c_kwargs) |
| 97 | + multitest.next() |
| 98 | + for iteration in range(2): |
| 99 | + print("controller iteration", iteration) |
| 100 | + multitest.wait("target stage 1") |
| 101 | + i2c.writeto_mem(ADDR, 2, "0123") |
| 102 | + multitest.broadcast("controller stage 2") |
| 103 | + multitest.wait("target stage 3") |
| 104 | + print(i2c.readfrom_mem(ADDR, 2, 4)) |
| 105 | + multitest.broadcast("controller stage 4") |
| 106 | + print("done") |
| 107 | + |
| 108 | + |
| 109 | +# I2C target |
| 110 | +def instance1(): |
| 111 | + multitest.next() |
| 112 | + |
| 113 | + for iteration in range(2): |
| 114 | + print("target iteration", iteration) |
| 115 | + buf = bytearray(b"--------") |
| 116 | + if iteration == 0: |
| 117 | + # Use built-in memory capability of I2CTarget. |
| 118 | + i2c_target = I2CTarget(*i2c_args, **i2c_kwargs, addr=ADDR, mem=buf) |
| 119 | + i2c_target.irq( |
| 120 | + simple_irq, |
| 121 | + I2CTarget.IRQ_ADDR_MATCH_READ | I2CTarget.IRQ_ADDR_MATCH_WRITE, |
| 122 | + hard=True, |
| 123 | + ) |
| 124 | + else: |
| 125 | + # Implement a memory device by hand. |
| 126 | + i2c_target = I2CTarget(*i2c_args, **i2c_kwargs, addr=ADDR) |
| 127 | + I2CTargetMemory(i2c_target, buf) |
| 128 | + |
| 129 | + multitest.broadcast("target stage 1") |
| 130 | + multitest.wait("controller stage 2") |
| 131 | + print(buf) |
| 132 | + multitest.broadcast("target stage 3") |
| 133 | + multitest.wait("controller stage 4") |
| 134 | + |
| 135 | + i2c_target.deinit() |
| 136 | + |
| 137 | + print("done") |
0 commit comments