From 21a48711ec1c199181baf840aa8903c433eeaddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 18 Jun 2018 09:34:04 +0000 Subject: [PATCH] i2c: refactor common operations --- artiq/coredevice/i2c.py | 139 +++++++++++++++++++++++++++++++--------- 1 file changed, 109 insertions(+), 30 deletions(-) diff --git a/artiq/coredevice/i2c.py b/artiq/coredevice/i2c.py index 44b3f9094..61be474e4 100644 --- a/artiq/coredevice/i2c.py +++ b/artiq/coredevice/i2c.py @@ -33,6 +33,110 @@ def i2c_read(busno: TInt32, ack: TBool) -> TInt32: raise NotImplementedError("syscall not simulated") +@kernel +def i2c_poll(busno, busaddr): + """Poll I2C device at address. + + :param busno: I2C bus number + :param busaddr: 8 bit I2C device address (LSB=0) + :returns: True if the poll was ACKed + """ + i2c_start(busno) + ack = i2c_write(busno, busaddr) + i2c_stop(busno) + return ack + + +@kernel +def i2c_write_byte(busno, busaddr, data, ack=True): + """Write one byte to a device. + + :param busno: I2C bus number + :param busaddr: 8 bit I2C device address (LSB=0) + :param data: Data byte to be written + :param nack: Allow NACK + """ + i2c_start(busno) + try: + if not i2c_write(busno, busaddr): + raise I2CError("failed to ack bus address") + if not i2c_write(busno, data) and ack: + raise I2CError("failed to ack write data") + finally: + i2c_stop(busno) + + +@kernel +def i2c_read_byte(busno, busaddr): + """Read one byte from a device. + + :param busno: I2C bus number + :param busaddr: 8 bit I2C device address (LSB=0) + :returns: Byte read + """ + i2c_start(busno) + data = 0 + try: + if not i2c_write(busno, busaddr | 1): + raise I2CError("failed to ack bus read address") + data = i2c_read(busno, ack=False) + finally: + i2c_stop(busno) + return data + + +@kernel +def i2c_write_many(busno, busaddr, addr, data, ack_last=True): + """Transfer multiple bytes to a device. + + :param busno: I2c bus number + :param busaddr: 8 bit I2C device address (LSB=0) + :param addr: 8 bit data address + :param data: Data bytes to be written + :param ack_last: Expect I2C ACK of the last byte written. If `False`, + the last byte may be NACKed (e.g. EEPROM full page writes). + """ + n = len(data) + i2c_start(busno) + try: + if not i2c_write(busno, busaddr): + raise I2CError("failed to ack bus address") + if not i2c_write(busno, addr): + raise I2CError("failed to ack data address") + for i in range(n): + if not i2c_write(busno, data[i]) and ( + i < n - 1 or ack_last): + raise I2CError("failed to ack write data") + finally: + i2c_stop(busno) + + +@kernel +def i2c_read_many(busno, busaddr, addr, data): + """Transfer multiple bytes from a device. + + :param busno: I2c bus number + :param busaddr: 8 bit I2C device address (LSB=0) + :param addr: 8 bit data address + :param data: List of integers to be filled with the data read. + One entry ber byte. + """ + m = len(data) + i2c_start(busno) + try: + if not i2c_write(busno, busaddr): + raise I2CError("failed to ack bus address") + if not i2c_write(busno, addr): + raise I2CError("failed to ack data address") + i2c_restart(busno) + if not i2c_write(busno, busaddr | 1): + raise I2CError("failed to ack bus read address") + for i in range(m): + data[i] = i2c_read(busno, ack=i < m - 1) + finally: + i2c_stop(busno) + + class PCA9548: """Driver for the PCA9548 I2C bus switch. @@ -53,14 +157,7 @@ class PCA9548: :param mask: Bit mask of enabled channels """ - i2c_start(self.busno) - try: - if not i2c_write(self.busno, self.address): - raise I2CError("PCA9548 failed to ack address") - if not i2c_write(self.busno, mask): - raise I2CError("PCA9548 failed to ack control word") - finally: - i2c_stop(self.busno) + i2c_write_byte(self.busno, self.address, mask) @kernel def set(self, channel): @@ -72,15 +169,7 @@ class PCA9548: @kernel def readback(self): - i2c_start(self.busno) - r = 0 - try: - if not i2c_write(self.busno, self.address | 1): - raise I2CError("PCA9548 failed to ack address") - r = i2c_read(self.busno, False) - finally: - i2c_stop(self.busno) - return r + return i2c_read_byte(self.busno, self.address) class TCA6424A: @@ -97,19 +186,9 @@ class TCA6424A: self.address = address @kernel - def _write24(self, command, value): - i2c_start(self.busno) - try: - if not i2c_write(self.busno, self.address): - raise I2CError("TCA6424A failed to ack address") - if not i2c_write(self.busno, command): - raise I2CError("TCA6424A failed to ack command") - for i in range(3): - if not i2c_write(self.busno, value >> 16): - raise I2CError("TCA6424A failed to ack data") - value <<= 8 - finally: - i2c_stop(self.busno) + def _write24(self, addr, value): + i2c_write_many(self.busno, self.address, addr, + [value >> 16, value >> 8, value]) @kernel def set(self, outputs):