On Wed, Aug 29, 2018 at 8:59 PM Christopher Collins <ch...@runtime.io>
wrote:

> Hello all,
>
> I noticed the HAL master I2C API does not include any retry logic.  As
> you probably know, in I2C, the default state of the SCL line is NACK.
>

Euh... ACK/NACK is on SDA while the master cycles SCL.


> This means an unresponsive peripheral is indistinguishable from one that
> is actively nacking the master's writes.


Yeup!


>   If the master's writes are
> being NACKed because the slave is simply not ready to receive data, then
> retrying seems like the appropriate solution.
>

Retry is also good if a bus conflict is detected (on a multi-master bus).


> I can think of two ways to add I2C retries.  Each of them requires
> changes:
>
>     (1) Delegate the retry logic to the code calling into the HAL (e.g.,
>         drivers).
>     (2) Implement retry logic directly in the HAL.
>
> The problem with (1) is that HAL implementations currently return
> MCU-specific error codes.  A generic driver cannot determine if a retry
> is in order just from inspecting the error code.  If there were a common
> set of error codes that all HAL I2C implementations returned, drivers
> would have the information they need.  Actually, even ignoring the
> subject of retries, I think common error codes here makes sense.
>

Agreed, on common codes. I would suggest a common retry system. The retry
stuff can get pretty ugly/wrong, so a common hunk o' code is best (IMO).


> Re: (2) - I was thinking this could be implemented by adding two new
> members to the `hal_i2c_master_data` struct that gets passed to every
> master I2C function:
>
>     /**
>      * Total number of times to attempt the I2C operation.  Certain
>      * failures get retried:
>      *     o NACK received after sending address.
>      *     o (if configured) NACK received after sending data byte.
>      */
>     uint8_t tries;
>
>     /** Whether to retry when a data byte gets NACKed. */
>     uint8_t retry_on_dnack:1;
>
> (I hate to complicate things with the `retry_on_dnack` member, but some
> peripherals seem to become unresponsive in the middle of a transaction.)
>

Or that something monkeyed the bus, so the peripheral decided to stop
receiving/processing. ... Your basic point holds: a peripheral might just
go away for any number of reasons. I wouldn't even bother with the on_dnack
flag. Seems better to consider retry at the whole-packet level. It all gets
sent, or it did not and should be retried.

Since these additions are members of a struct, rather than new function
> parameters, this change would be mostly backwards-compatible.  There is
> still a problem here, though: code that doesn't zero-out the
> `hal_i2c_master_data` struct will likely get retries when it isn't
> expecting them, which could conceivably be a problem.
>

Yeah, or code compiled against old-headers being linked/run against a
new-header mynewt (which then looks past the end of the passed-in-struct).

I'm not familiar enough with the mynewt API paradigms to make any
suggestion. I just know I2C well after writing MCU code for both master and
slave, from scratch (PIC16F688 has no built-in I2C).

Cheers,
-g

Reply via email to