rambo / TinyWire

My modifications to TinyWire Arduino libs
284 stars 121 forks source link

How to return specific address data #35

Closed mitchins closed 6 years ago

mitchins commented 7 years ago

In regards to the requestEvent, I.e. when a master is requesting data from the slave the is a count (or how many), how come th actual address isn’t available? When I am using MicroPython for instance read_mem allows both the start address and the count of bytes to read. It seems strange to me that it’s not present.

Is there either a limitation or concept I’m missing here? (Most example shows incrementint the register address after every read - why can’t we just return what is asked for)

rambo commented 6 years ago

read_mem (likely, I have not personally verified this) wraps a very common convention of I2C devices that the first byte of a write is a register address, it's implemented on the examples here: https://github.com/rambo/TinyWire/blob/master/TinyWireS/examples/attiny85_i2c_slave/attiny85_i2c_slave.ino#L103

On actual protocol level read_mem should look something like this (for single byte read)

START SLAVE_WRITE_ADDRESS REGISTER_ADDRESS START SLAVE_READ_ADDRESS READ STOP

For reading more bytes just more READ commands are added. In some cases that second start is STOP START in stead, depending on implementation details... The problem is that some devices are very strict about I2C sessions so they require a repeated START instead of STOP START (they throw away internal state at STOP since that marks end of a session) and some other devices are just broken and can't handle repeated START (the recommended way) correctly...

Also the auto-increment for the register on each read is a common convention (and in fact read_mem must depend on it, otherwise you would get X copies of the same register value), though on some devices it's not done, or it's not done if the current register is a specific data register (if the common use case is one write session for setting up sensor parameters and then reading single register for the sensor data over and over again). Some super-simple sensors have no (externally accessible) registers at all, you just read a single value (and thus don't write the REGISTER_ADDRESS anymore)

And the problem with those wrappers is that while they're quite handy for most of the "normal" cases where the chips follow the conventions (and do note that they're exactly that, the protocol spec says absolutely nothing about it) they will fail in super weird and hard to debug ways when you come across a chip that doesn't.

mitchins commented 6 years ago

Thanks, that is very helpful. I'll check that with the micro python implementation of i2c and see how it works with the ATTINY, and list my findings.

mitchins commented 6 years ago

I can confirm following the example, it works nicely reading one address at a time.

>>> i2c.writeto_mem(0x5F, 2, b'\x02')
>>> i2c.writeto_mem(0x5F, 1, b'\x01')
>>> i2c.writeto_mem(0x5F, 0, b'\x00')
>>> i2c.readfrom_mem(0x5F, 2, 1)
b'\x02'
>>> i2c.readfrom_mem(0x5F, 1, 1)
b'\x01'
>>> i2c.readfrom_mem(0x5F, 0, 1)
b'\x00'

Weird results happen if I do more than one byte at a time, I get 0xFF, but that's probably something I'm doing and I can live without it.

Thanks for your help!