PBASIC I2C protocol issue
Phil Pilgrim (PhiPi)
Posts: 23,514
in BASIC Stamp
I've been tearing my hair out for two weeks over this one. I'm using the BASIC Stamp 2pe to get data from a sensor that communicates via I2C. I was getting really sporadic results from it for no apparent reason. The sensor manufacturer was at a loss to explain what was happening. Signals were clean, timing was spot-on, no noise or sags, and the device was behaving normally, except that it was returning mostly zeroes instead of good data.
So I connected the device to a Propeller and wrote some I2C methods to access it. 'Got perfect data! What was the difference? My Spin routines always send a NAK after the last byte read in a sequence. The BS2pe ACKs after every byte read, including the last one, which goes against the I2C spec. Now most I2C devices don't care, since the subsequent STOP condition resets the protocol engine anyway. But when I changed my Spin code to ACK after the last byte, the device behaved as it did with the BS2pe. So I guess, with some devices the ACK/NAK situation does matter.
I've gone ahead and hand-coded some I2C routines in the BS2pe, and now I get good data with that chip as well. But I'm curious as to why the BS2pe's hard-coded I2C routines do not NAK the last byte read.
-Phil
So I connected the device to a Propeller and wrote some I2C methods to access it. 'Got perfect data! What was the difference? My Spin routines always send a NAK after the last byte read in a sequence. The BS2pe ACKs after every byte read, including the last one, which goes against the I2C spec. Now most I2C devices don't care, since the subsequent STOP condition resets the protocol engine anyway. But when I changed my Spin code to ACK after the last byte, the device behaved as it did with the BS2pe. So I guess, with some devices the ACK/NAK situation does matter.
I've gone ahead and hand-coded some I2C routines in the BS2pe, and now I get good data with that chip as well. But I'm curious as to why the BS2pe's hard-coded I2C routines do not NAK the last byte read.
-Phil
Comments
-Phil
I'm curious about that too. If the SCL signal is cycled far enough, then I can imagine what KeithE said is a possibility, but I don't remember if the BASIC Stamp cycles it beyond the sample edge when delivering the ACK or not.
The "NAK after the last byte is read" was a feature of I2C that was ambiguously written in the protocol spec when we reviewed it the first time, and even more recently (a couple years ago, I think), giving us the impression that it was truly optional and only perhaps necessary if you want the slave device to know that it can switch to a low-power mode again (or something like that). We hadn't seen any problems with the I2C devices we had tested and used over the years.
I didn't write the I2C routines in the BASIC Stamp firmware, but as it happens, I wrote an I2C object for the Propeller that defaults to ACK but later added an optional NAK after a read... I think because I wasn't sure if ACK would work in every case. I made it optional because I was concerned about cycle time in that example and it takes extra effort from a routine to check for and indicate it's reading the last byte in a sequence.
I hope you have hair left, not all yet torn out!
The problem I was having seems to be a combination of two issues:
1. The BS2pe's ACK after the last byte, and
2. The slave device expecting another byte read as a consequence and not resetting its protocol engine after a legitimate STOP.
-Phil
All I2C data transactions are 8-bit and require 8 clocks. After the 8th clock, the master sends a 9th clock in which time the slave has the opportunity to respond with a NACK/ACK.
This 9th clock is part of the I2C spec and is mandatory.
The master does not "send" a NACK/ACK on the SDA line.
During the time of the 9th clock, SDA (which is supposed to be a bi-directional line) should sample and detect the slave's NACK/ACK.
Check out page 10 (3.6 Acknowledge...) of the attached I2C spec.
DJ
-Phil
>Check out page 10 (3.6 Acknowledge...) of the attached I2C spec.
If the master is reading data from a slave then it is the receiver, then it is therefore master's responsibility to send the ACK/NACK for each byte. If the master is writing data, then the slave is the receiver and it is the slave's responsibility.
Regarding the NACK, it seems pretty well spelled out in 3.6.
"There are five conditions that lead to the generation of a NACK:
...
5. A master-receiver needs to signal the end of the transfer to the slave transmitter."
Based on what Phil says, it's my opinion that the Basic Stamp is violating the protocol, but most slaves can deal with it. I guess that the sensor in question isn't using I2C STOP to reset its protocol state machine from all states. When I last did an I2C slave I was always looking for I2C start/stop regardless of state. You want to make it as easy as possible for I2C masters to reset the bus in the event of an anomoly.
BTW: as far as I know Rev. 6 — 4 April 2014 is the latest revision of the I2C specification. I'm not sure what changed as the revision history gets a bit vague. (There's also an I3C specification now, but that's from MIPI ;-)
Also a statement from an NXP data sheet (SC16IS740/750/760 I2C UART):
"There are two exceptions to the ‘acknowledge after every byte’ rule. The first occurs when a master is a receiver: it must signal an end of data to the transmitter by not signalling an acknowledge on the last byte that has been clocked out of the slave. The acknowledge related clock, generated by the master should still take place, but the SDA line will not be pulled down. In order to indicate that this is an active and intentional lack of acknowledgement, we shall term this special condition as a ‘negative acknowledge’.
The second exception is that a slave will send a negative acknowledge when it can no longer accept additional data bytes. This occurs after an attempted transfer that cannot be accepted."