rust-embedded / embedded-hal

A Hardware Abstraction Layer (HAL) for embedded systems
Apache License 2.0
1.95k stars 197 forks source link

i2c: Merging of consecutive operations in transaction contract #582

Open sgoll opened 6 months ago

sgoll commented 6 months ago

The following question concerns the transaction contract in I2c, i.e. when using the transaction() method.

Due to the specified merging of consecutive operations of the same type (e.g. two writes one after the other), it does not seem possible to issue separate operations (of the same type) right after each other, using a repeated start condition, without adding another "dummy" operation of the other type in-between. Is this correct?

Was this behavior intended when embedded-hal reached stable version 1, or was it an oversight, or kept deliberately out of scope?[^1]

[^1]: Unfortunately, I am not able to find any relevant discussions for this here on GitHub.

The main reason for having support for this kind of explicit repeated start condition is write operations (not so much read operations): many I2C devices expect a control register or address as the first byte (or first two bytes) of each write. But when consecutive write operations are always merged, it is not possible to write to two or more separate such locations in the target device.


Example: TLC59116 LED driver

I want to be able to set several PWM values at once. Using the driver's auto-increment feature, I can easily set a range by writing the address of the first register, then writing the target values of this register and the following registers.

But in order to set only two specific PWM values (say LED 5 and LED 11), I would want to make two writes, i.e. with a repeated start condition in-between: write first value's address followed by its value, generate a repeated start condition, then write second value's address followed by its value.

Right now, this can only be achieved by separate write() calls but with the side effect of generating both a stop and start condition (instead of repeated start without stop) which releases the bus in-between the two writes.


Unfortunately, I don't have a good suggestion on how to best model an API that allows both: the merging of consecutive operations (which is still very useful in and of itself) and the explicit repeated start between such operations.

The only thing I can think of is the addition of an explicit Operation::Restart (or similar) which would serve as sentinel or marker to keep two operations from being merged.

The question then is if this could even be introduced without breaking compatibility concerning the Operation enum and downstream implementations of the I2c trait. Probably not.