Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zero-length I2c transfers #570

Open
G33KatWork opened this issue Jan 18, 2024 · 3 comments
Open

Zero-length I2c transfers #570

G33KatWork opened this issue Jan 18, 2024 · 3 comments

Comments

@G33KatWork
Copy link

Hi,

I am having a bit of a fight here with the I2c trait in embedded-hal 1.0.0.

Let's suppose I have an I2C EEPROM that I just sent some data for writing to. The EEPROM needs some time after the STOP condition on the I2C bus to actually write the data into the memory page. During that time, it stops ACKing its address on the I2C bus.

Now in order to poll when the chip is done writing, I thought I would be smart and perform a read transaction to its address with an empty buffer, just to see if it ACKs its address. I assumed that the code I wrote which implements the transaction trait method would put the address on the bus, wait for an ACK or NACK, either return a NACK-Error in case the chip is still busy or try to read 0 bytes followed by putting a STOP condition on the bus in case the chip is idle again.

Now comes the roadblock: I do this on an ATtiny817 and its I2C hardware state machine is relatively clever and it tries to perform as much bus stuff in hardware as it can. As it stands, I can not get it to NOT read at least one byte from the bus after a successful ACK and my code gets stuck with an occupied bus, because I never ACK or NACK that byte. I tried handling a special case when the passed slice in the Read operation has a length of 0 where I just read one byte, discard it, NACK the transfer and issue a STOP condition, but even that doesn't work for some weird reason.

Long story short, before I debug this further: Are zero-length reads or writes on an I2C bus even a thing? Does it even make sense to support this? Should we support something like this as I2c trait implementers or should we just error out early or even ignore such a transaction when we encounter it? This edge case isn't specified in the trait description so I thought I'd ask here.

Also, I think even the i2cdetect utility in i2c-utils performs actual read or write transfers of at least one byte to detect devices on an I2C bus.

@G33KatWork
Copy link
Author

Okay, so after actually understanding how that peripheral works and how to trigger certain state changes in the state machine and what transitions happen automatically as a side-effect on a read or write of certain registers, like for example the I2C data shift register or address register, I made it work.

Turns out, yes, zero-length transactions are a thing and they can be used for exactly what I wanted them to be used for.

Should still be clarified in the docs that this should be supported?

@Dirbaio
Copy link
Member

Dirbaio commented Jan 22, 2024

Should still be clarified in the docs that this should be supported?

Yes! Can you send a PR?

@sgoll
Copy link

sgoll commented Mar 21, 2024

Turns out, yes, zero-length transactions are a thing and they can be used for exactly what I wanted them to be used for.

Is this correct? I was under the impression that the I2C specification does not allow for zero-length read transfers (as in it is not possible to do that on the wire).

After the R/W bit is transmitted, the slave device becomes the transmitting device on the bus for 9 bits (i.e. ACK to indicate its presence, followed by one byte transfer), and only afterwards can the master transmit ACK/NACK to tell the slave device to continue or not continue. During the ongoing transfer of one byte, even the master is not able to send a stop condition.1

On the other hand, zero-length write transfers can be done because the master device becomes the transmitting device again right after the slave device has ACK'ed its presence, and it can thus send a stop condition without a single byte transfer.

Footnotes

  1. Technically, it could if the slave device were transmitting high at the exact bit that the master device wants to stop at. If the slave device were transmitting low, however, the master device would not be able to do the necessary transition on SDA for the stop condition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants