Is there a general I2C command to see if a device is still present on the bus after it is initialized once? For example an OLED display. The reason I ask this is to avoid the main program will freeze (when a device is disconnected) because of infinite loops present in the library code, in for example, the Wire library.
At startup of the MCU I want to check if a device is available or not, and initialize it when it is available. I do this with this function and works fine .....
bool MyClass::isPnpDeviceAvailable( uint8_t iAddress, bool bIsInitOnce = false )
{
// Try to start connection
Wire.beginTransmission( iAddress );
// End connection without STOP command if already is initialized
return ( Wire.endTransmission( !bIsInitOnce ) == 0x00 ); // No Error?, return true
}
.... however, when I want to check if a device is still there, before I perform an update, when I do this:
// 1.
if( isPnpDeviceAvailable( 0x3C, true ))
{ /* Cause program hang */ }
// 2.
if( isPnpDeviceAvailable( 0x3C ))
{ /* Cause display to turn off */ }
Is there a general command available, to say/send just a "Hello, are you there" and wait for a reply without sending START and STOP commands and without interrupting device/bus status?
Here is the proto-type device I made with attached (optional PNP I2C) display.
Allright, it takes a longer journey to figure it out and test it. Also made a video of it, see link at the bottom of this answer. All credits go to @user0042 who points me into the right direction. The default Wire library is actually of no use when it comes to stability, reliability, so it is required to 'replace' it with this:
The I2C Master library - http://dsscircuits.com/articles/arduino-i2c-master-library
There are more benefits to use this library, it is smaller in compile size, read the article above for more information.
I changed my software, the 'key' to detect a device on the bus could be simplified to this:
Notice: The (int) typecasting is required to avoid a compiler warning but it does work fine without.
I send a
**0x00 command**
which do nothing, however, the device seems to answer. The function I made returns true when plugged in and false if not.I doesn't test it with other i2c devices yet, however, will try later and update this question. For now it seems to working fine.
NOTICE: SEE UPDATE BELOW:The PNP approach
Step #1
In the first version I didn't use any resistors (lazyness) but it is a good idea to stabilize the readouts of the bus. Add two resistors (4.7K) on the +5V output to the data lines. It is very important to do this to avoid false detections and to avoid your Arduino can still freeze because of that.
Step #2
You need to keep track on changes/device state of each I2C device. I use three states:
Step #3
If you use a class to 'speak' to a device, it must be dynamically created when device comes available. In my example it is something like this:
Step #4
Before each update, you need to check the availability and the state of initialization (the three states mentioned in step #3). This is very important to avoid unnecessary delays/code execution (stress).
Step #5
You need to check for changes, in a loop or an interrupt. Better do it in a loop instead of an interrupt.
Step #6
Perform updates when changes are detected. Use a little delay of about 200ms seconds before the real update.
Some example code
You cannot use this code, however, it can give you some idea how to design your code. I use many macro's to simplify my actual code, so it is easier to read:
Demo video
I also create a demo video, proof of concept, to show you this method is working fine. You can watch the video on YouTube: https://www.youtube.com/watch?v=ODWqPQJk8Xo
Thank you all for the help and hopefully this info can help others too.
UPDATE:
My method seems to work fine with several I2C devices. I wrote this renewed I2CScanner:
I2CScanner code that you can use: