labjack / LabJackPython

The official Python modules and classes for interacting with the LabJack U3, U6, UE9 and U12
https://labjack.com/support/software/examples/ud/labjackpython
MIT License
117 stars 79 forks source link

I2C: not possible to wait for ACK #112

Closed mickp closed 4 years ago

mickp commented 5 years ago

After receiving a byte that initiates a slow operation, (as an alternative to clock stretching) some devices do not indicate ACK until that operation has completed. This can be useful when the operation results in data that can be fetched, and prevents attempts to fetch the data too early. Sending additional bytes before ACK is indicated can invalidate the data.

As far as I can tell, LabJackPython does not support operation in this way: it simply tests for ACK immediately after each byte is sent before proceeding to send the next byte, and reports how many bytes in the sequence were ACKed. This means that some devices (e.g. TSYS01) are unusable over I2C unless arbitrary timeouts are used.

davelopez01 commented 5 years ago

Here is the response from one of our engineers:

I don't see anything in the TSYS01 datasheet about waiting for an ACK. What I see is a command structure similar to many other I2C sensors. That being send a command to start a conversion, wait a specified amount of time, send a second command to read the result.

On the topic of wait for ACK, I have never heard of that. The ACK/NoAck is based on the data line state when the clock line transitions high. So, to delay the ACK we would have to delay the clock edge, which would be clock-stretching.

My response regarding LabJackPython and I2C functionality, for "send a command to start a conversion, wait a specified amount of time, send a second command to read the result", sending a command is an i2c call and waiting is a software delay. To only send I2C bytes, set I2CBytes and NumI2CBytesToReceive=0. To only read the result bytes, set NumI2CBytesToReceive and I2CBytes=[] (empty list).

mickp commented 5 years ago

Thanks for the quick and detailed response. Here's the relevant section ('conversion sequence - i2c') from TE's TSYS01 datasheet.

image

I read it (past tense) that the intended sequence is: send conversion instruction, then send a read instruction "when an acknowledge appears from TSYS01". If the read (or anything else) is sent early, conversion appears to be interrupted and the result is empty (0xFFFFFF). The device does not appear to hold the clock line low during conversion.

Maybe I've read this wrong ("when an acknowledge appears" is perhaps consequential, not causative).

I looked at the U6's low-level instructions, and it doesn't look like this is possible to fix in LabJackPython without changes to the underlying instruction. It's easily worked around with a fixed delay in software and checks on the result ... I just like to avoid that pattern when I can!

Thanks again for taking the time to look into this.

davelopez01 commented 5 years ago

From our engineer:

The datasheet is trying to say that if we do not want to use a simple delay before reading we can repeatedly send an I2C start and address. While that address is NACK'd, the device is still busy.

To do this with the U6 I would continuously attempt to read the data until the address is acknowledged. All the data before the ACK will be invalid.

On a side note: T-Series LabJacks (T7 and T4) can run Lua scripts. That script can be used to run the serial comm to the sensor and the host application just needs to read the results from Lua. That removes most of the details of working with the sensor, including hard delays, from the host application.