Skip to content

Commit

Permalink
applet.memory.24x: use chunked reads.
Browse files Browse the repository at this point in the history
Currently the I2C applet cannot handle reads of 64K and more,
and 64K I2C EEPROMs exist; before this commit, trying to read exactly
64K from one would result in a hang.
  • Loading branch information
whitequark committed Jan 13, 2020
1 parent d494ace commit b8f138f
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 18 deletions.
1 change: 1 addition & 0 deletions software/glasgow/applet/interface/i2c_master/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ async def _cmd_stop(self):
await self.lower.write([CMD_STOP])

async def _cmd_count(self, count):
assert count < 0xffff
msb = (count >> 8) & 0xff
lsb = (count >> 0) & 0xff
await self.lower.write([CMD_COUNT, msb, lsb])
Expand Down
47 changes: 29 additions & 18 deletions software/glasgow/applet/memory/_24x/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,35 @@ def _carry_addr(self, addr):
return (i2c_addr, [addr & 0xff])

async def read(self, addr, length):
i2c_addr, addr_bytes = self._carry_addr(addr)

# Note that even if this is a 1-byte address EEPROM and we write 2 bytes here, we will not
# overwrite the contents, since the actual write is only initiated on stop, not repeated
# start condition.
self._log("i2c-addr=%#04x addr=%#06x", i2c_addr, addr)
result = await self.lower.write(i2c_addr, addr_bytes)
if result is False:
self._log("unacked")
return None

self._log("read=%d", length)
data = await self.lower.read(i2c_addr, length, stop=True)
if data is None:
self._log("unacked")
else:
self._log("data=<%s>", data.hex())
return data
chunks = []

while length > 0:
i2c_addr, addr_bytes = self._carry_addr(addr)

# Our lower layer can't do reads of 64K and higher, so use 32K chunks.
chunk_size = min(length, 0x8000)

# Note that even if this is a 1-byte address EEPROM and we write 2 bytes here,
# we will not overwrite the contents, since the actual write is only initiated
# on stop, not repeated start condition.
self._log("i2c-addr=%#04x addr=%#06x", i2c_addr, addr)
result = await self.lower.write(i2c_addr, addr_bytes)
if result is False:
self._log("unacked")
return None

self._log("read=%d", chunk_size)
chunk = await self.lower.read(i2c_addr, chunk_size, stop=True)
if chunk is None:
self._log("unacked")
else:
self._log("chunk=<%s>", chunk.hex())
chunks.append(chunk)

length -= chunk_size
addr += chunk_size

return b"".join(chunks)

async def write(self, addr, data):
while len(data) > 0:
Expand Down

0 comments on commit b8f138f

Please sign in to comment.