-
Notifications
You must be signed in to change notification settings - Fork 67
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
added wait for ACK after a I2C transaction #250
Conversation
libraries/Wire/src/Wire.cpp
Outdated
@@ -245,6 +245,8 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres | |||
XMC_I2C_CH_MasterStart(XMC_I2C_config->channel, (txAddress << 1), XMC_I2C_CH_CMD_READ); | |||
} | |||
|
|||
while((XMC_I2C_CH_GetStatusFlag(XMC_I2C_config->channel) & XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mmm... I have no context info about this issue, but adding a blocking assert there entails that we are very sure that ack is received.
In a i2c communication, how can you ensure that the other end is sending an ack?
if it is doesn´t send and ack, I would expect there should be a way to handle that error without the system getting stuck forever.
Such blocking assertions are present in any other Wire function or built-in library?
Taking into account all the concerns, a timeout provision is implemented which will quit the loop incase a valid ACK is not received within a certain time interval. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the absence of formal testing 👍
I personally would like to know what sensors under what configuration and scopeshots of timing. |
Yes the timeout is ARBITRARY and probably uses a value based on 12MHz AVR on the UNO, so wil have different timings due to CPU speed of XMC1 series at 32 MHz and XMC4700 at 144 MHz. The whole function/method requestFrom( ) has lots of assumptions and MAGIC NUMBERS, that assumes the function will only be used on SMALL EEPROM or RAM devices. Most notable is isize parameter checks that CORRUPT data passed in by assuming only 3 bytes can be sent. There is NO specification for that, and the same process could be used for an ADC subsystem and be longer than 3 bytes. Instead of corrupting data onto I2C bus it should error with parameter error BEFORE sending anything on the I2C bus. The limit is by Magic Number not a constant in xmc_i2c_conf.h, with better notes and different values for WIRE_COMMUNICATION_TIMEOUT based on CPU Freq. A better construct would be a while loop with tests for flags inside the loop. Non-understanding of I2C and available flags is what worries me here. Without knowing WHICH devices this fails on I suspect the issue is NOT a Wire library issue but trying too quickly to do this function when this device is internally busy doing something else.. An example of this would be an EEPROM, which on many devices must NOT be accessed in any way whilst it is busy doing a byte/page erase function and may well do a long wait state/Clock stretch if accessed, rather than say it is not on the bus, or give garbled data or cause even internal address counters to be overwritten whilst using them for erase operations. This is a higher level operation issues NOT Wire library. Your first description said the first byte after Start or Repeated Start, but your implementation is for the first byte of an INTERNAL address which is the second byte of the transmission. This is because the Start or repeated start methods send the start condition and I2C address byte., This timeout method is repeated not called in many places and I see random checking of ACK/NACK flags or possible error codes of got NACK when expected ACK, even on I2C address phase. I fail to see when READING multiple bytes from a slave, that you need to check for RECEIVE ACK or NACK on DATA phase as this is sent by the I2C master the processor. You have RBIF and other flags for receive buffer full. Looking at some of this code I am amazed some of it works I will ask AGAIN what DEVICES are you having problems with to show it is a Wire library problem nd not higher operational errors? |
As a comparison the problems in Wire and then seen same in Serail and SPI with pin setting not following the specfication causing problems was highlighted and tested better in issue #234 |
Explanation on worries with mod using timeout wrong and incorrect flags..Most of the Wire library assumes everything always works without wait states There are no COMMON error codes for
Many checks are done in wrong order so device or bus can get stuck easily. There is NO indication in data sheets, manuals for USIC on how a master handles RECEIVING Wait states (wrongly called Byte Stretching) and fanciful wish statements of slave devices sending error interrupts that do NOT exist on 99.99% of I2C Slave devices. A simplified check for ACK checks for ACK OR NACK bits to be set as this means one of those states has actived after the SCL line has been released to go from Low to High on the 9th clock cycle. You need to check for both and if NACK received when expecting ACK error and reset bus (often STOP). A timeout condition means SCL has not transitioned to HIGH level, for many reasons. IF SCL STILL "STUCK" LOW THE ONLY WAY TO GET THE BUS UNSTUCK IS A RESET OR If SCL is STUCK LOW NOTHING else can happen, and this happens OUTSIDE of the micro, no amount bit twiddling will change that. Checking higher levels are not controlling the device BADLY can stop these situations occuring. When master writing to slave data bytes (they may be internal address or other control) receiving a NACK from SLAVE when address was ACKed then means
When Master RECEIVES bytes from Slave the hardware should be automatically ACKing the data bytes in hardware as the controller should have been set to ACK data with exception of Master read from slave on LAST Byte of transaction CAN be a NACK but rareley implemented in Slave devices, as no action other than not incrementing an internal counter has any meaning. for last byte. Often Master always send ACK when READING as easier to the send STOP symbol/condition next. A better construct that should be in a COMMON function to check for ACK is
Note better handling of timeout would be unsigned long calculations based on microseconds() values and a timeout value in microseconds in Wire.h allowing for different CPU Freq. A nominal value of 5 to 10 ms would be a good starting point. |
…th different frequencies
Thank you for your concerns @techpaul and the probable flaws and pitfalls have been noted. However, the changes to the BSP are part of an internal process and will be executed incrementally in the future. The issue was diagnosed as a part of the development process of Arduino libraries for Infineon’s XENSIV 3D magnetic sensors families, shown here: https://www.infineon.com/cms/en/product/sensor/magnetic-sensors/magnetic-position-sensors/3d-magnetics/ As the XMC devices run on different frequencies, the execution of timeout would be variable. Hence, a time-based delay logic is added to make the execution fairer for all the range of frequencies. The checks currently in the Wire library are done based on the documentation given here in Chapter 14.5.5.2. wherein all the relevant flags are enlisted as bitfields. The test framework is being improved to provide robust testing with multiple I2C devices. |
Oh well marketing rarely listens and only repeats scripts even if they do not undersatnd them, or it totally contradicts any eveidence presented. |
By creating this pull request you agree to the terms in CONTRIBUTING.md.
https://github.com/Infineon/.github/blob/master/CONTRIBUTING.md
--- DO NOT DELETE ANYTHING ABOVE THIS LINE ---
CONTRIBUTING.md also tells you what to expect in the PR process.
Description
Added wait in I2C transaction
Context
Added a wait state until ACK is received after sending a START or REP_START. This was absent before so it leads to a intermittent erroneous reading from I2C sensors.