Skip to content

Conversation

@Alex-C-EE
Copy link

Problem:

When using the Pixy2 Arduino library over I2C, particularly on platforms like Teensy with potentially long I2C cables or noisy environments, intermittent communication errors could cause the library's receiving functions to enter an infinite loop. This resulted in the entire microcontroller program hanging indefinitely, making the system unresponsive. This issue was observed when Wire.requestFrom returned 0 (indicating an I2C NACK, timeout, or other bus error) while the library was still expecting to receive more bytes.

Solution:

  • This PR addresses the hang issue by modifying the I2C communication handling within the library:
    Robust Link2I2C::recv Method (Pixy2I2C.h):
  • The recv method now explicitly checks the return value of Wire.requestFrom.
  • If Wire.requestFrom returns 0 when bytes were expected, it is treated as an I2C communication error, and the function returns PIXY_RESULT_ERROR (if no bytes were read yet) or the number of bytes successfully read before the error. This prevents the infinite i+=0 loop condition.
  • The method now correctly returns the actual number of bytes successfully read from the I2C bus, rather than always returning the requested len.

Improved Error Checking in TPixy2.h:

  • The TPixy2::getSync and TPixy2::recvPacket methods have been updated to correctly interpret the return value from the modified Link2I2C::recv.
  • They now check if the number of bytes received matches the exact number expected for the current step in the Pixy packet protocol (sync bytes, header, payload).
  • Short reads (receiving fewer bytes than expected) or negative return values from m_link.recv are now consistently treated as errors (PIXY_RESULT_ERROR).
  • TPixy2::getSync timeout logic was slightly adjusted for potentially better recovery.
  • Return values from high-level API calls (like getVersion, setLED, etc.) now more accurately reflect errors encountered during packet reception.

Flexible I2C Bus Selection (Pixy2I2C.h, TPixy2.h):

  • The Link2I2C::open method and consequently TPixy2::init now accept an optional TwoWire& wireInstance parameter (defaulting to Wire). This allows users to explicitly specify which I2C bus (e.g., Wire1, Wire2 on Teensy) the Pixy2 is connected to, enhancing compatibility with multi-bus setups.

Impact:

  • These changes significantly improve the robustness of the Pixy2 library when communicating over I2C.
  • Prevents the microcontroller from hanging due to I2C communication glitches or device non-responsiveness.
  • Ensures that communication errors (including checksum errors, timeouts, NACKs, short reads) are properly detected and propagated as specific negative result codes (e.g., PIXY_RESULT_ERROR, PIXY_RESULT_TIMEOUT, PIXY_RESULT_CHECKSUM_ERROR).
  • Allows the calling application (e.g., a robot's camera interface) to handle these errors gracefully by checking the return codes, logging the issue, potentially retrying the operation, or temporarily marking the device as unavailable, without halting the entire system.
  • Increases flexibility by allowing users to explicitly choose the I2C bus instance.

Testing:

This fix was developed in response to observed hangs in a real-world application (NXP Cup race car) using long I2C cables where communication errors are more likely. Testing in the application showed that these changes successfully prevent the system hang and allow the application to continue operating, logging the I2C errors as they occur. Further testing across different platforms and I2C scenarios is welcome.

Fixed an infinite loop generated by when n=0 due to I2C bus errors ( NACK, Noise, etc.), which made the application get stuck in a for(i=0, i<len, i+=0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant