From 4f139c2887542954b7bea19ef22495033ea59261 Mon Sep 17 00:00:00 2001 From: Gerhard Sittig Date: Fri, 14 Jul 2023 17:28:32 +0200 Subject: i2c: add support for 10bit slave addresses Slave addresses can be of 7bit or 10bit type, which occupies one or two bytes at the start of the frame. Detect when a 10bit address is seen, and classify the following byte as yet another address byte (which the previous implementation incorrectly classified as data byte). This commit only accumulates the address value and adjusts the class of annotations. It does not introduce new annotation classes or rows, to not change the decoder in incompatible ways. --- decoders/i2c/pd.py | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'decoders') diff --git a/decoders/i2c/pd.py b/decoders/i2c/pd.py index 7309226..36c8d1e 100644 --- a/decoders/i2c/pd.py +++ b/decoders/i2c/pd.py @@ -113,6 +113,7 @@ class Decoder(srd.Decoder): self.bitcount = 0 self.databyte = 0 self.is_write = None + self.rem_addr_bytes = None self.is_repeat_start = False self.state = 'FIND START' self.pdu_start = None @@ -150,6 +151,7 @@ class Decoder(srd.Decoder): self.bitcount = self.databyte = 0 self.is_repeat_start = True self.is_write = None + self.rem_addr_bytes = None self.data_bits = [] # Gather 8 bits of data plus the ACK/NACK bit. @@ -181,10 +183,31 @@ class Decoder(srd.Decoder): d = self.databyte if self.state == 'FIND ADDRESS': - # The READ/WRITE bit is only in address bytes, not data bytes. - self.is_write = False if (self.databyte & 1) else True - if self.options['address_format'] == 'shifted': - d = d >> 1 + # The READ/WRITE bit is only in the first address byte, not + # in data bytes. Address bit pattern 0b1111_0xxx means that + # this is a 10bit slave address, another byte follows. Get + # the R/W direction and the address bytes count from the + # first byte in the I2C transfer. + addr_byte = d + if self.rem_addr_bytes is None: + if (addr_byte & 0xf8) == 0xf0: + self.rem_addr_bytes = 2 + self.slave_addr_7 = None + self.slave_addr_10 = addr_byte & 0x06 + self.slave_addr_10 <<= 7 + else: + self.rem_addr_bytes = 1 + self.slave_addr_7 = addr_byte >> 1 + self.slave_addr_10 = None + is_seven = self.slave_addr_7 is not None + if self.is_write is None: + read_bit = bool(addr_byte & 1) + shift_seven = self.options['address_format'] == 'shifted' + if is_seven and shift_seven: + d = d >> 1 + self.is_write = False if read_bit else True + else: + self.slave_addr_10 |= addr_byte bin_class = -1 if self.state == 'FIND ADDRESS' and self.is_write: @@ -210,7 +233,7 @@ class Decoder(srd.Decoder): for bit in self.data_bits: self.put(bit[1], bit[2], self.out_ann, [5, ['%d' % bit[0]]]) - if cmd.startswith('ADDRESS'): + if cmd.startswith('ADDRESS') and is_seven: self.ss, self.es = self.samplenum, self.samplenum + self.bitwidth w = ['Write', 'Wr', 'W'] if self.is_write else ['Read', 'Rd', 'R'] self.putx([proto[cmd][0], w]) @@ -230,9 +253,16 @@ class Decoder(srd.Decoder): cmd = 'NACK' if (sda == 1) else 'ACK' self.putp([cmd, None]) self.putx([proto[cmd][0], proto[cmd][1:]]) - # There could be multiple data bytes in a row, so either find - # another data byte or a STOP condition next. - self.state = 'FIND DATA' + # Slave addresses can span one or two bytes, before data bytes + # follow. There can be an arbitrary number of data bytes. Stick + # with getting more address bytes if applicable, or enter or + # remain in the data phase of the transfer otherwise. + if self.rem_addr_bytes: + self.rem_addr_bytes -= 1 + if self.rem_addr_bytes: + self.state = 'FIND ADDRESS' + else: + self.state = 'FIND DATA' def handle_stop(self, pins): # Meta bitrate -- cgit v1.2.3-70-g09d2