[2014-May-9: updated to work with Arduino 1.0 and moved into github]
One of the challenges of working with I2C (aka “two-wire” or “TWI” or “Wire”) devices is knowing the I2C address of the device. Older devices have a fixed address, or a “choose one-of-four” approach. But newer I2C devices have fully programmable addresses, leading to cases of not knowing what address a device is at.
Fortunately, there’s a technique one can use to “scan” an I2C bus and determine these addresses. Conceptually it’s very similar to a network “ping”. Below is an Arduino sketch “I2CScanner.pde” that turns an Arduino into an I2C bus scanner.
– I2CScanner.ino — Turn Arduino into I2C bus scanner (github repo)
When loaded up on an Arduino, the sketch will immediately scan the I2C network, showing which addresses are responding.
For example, the above output is from an I2C bus with four slave devices on it (one BlinkM MaxM, three regular BlinkMs).
(Notice the 2 pull-up resistors on SDA & SCL. This is needed for longer bus lengths)
One thing to notice about the I2CScanner output is that although there are four devices on the bus, only three addresses were detected. This is because unlike IP networks and “ping”, you can’t tell if two devices have the same address. They’ll both respond to commands sent to them just fine, you just can’t read back data from them.
How it works
In I2C, the first byte transmitted/written by the master to a slave is the address of the slave. If there is a slave at that address, the slave will signal the I2C bus, otherwise it leaves it alone. We can use this to implement a bus scanner.
The Arduino “Wire” library utilizes a set of C functions called “twi.c”. One of those functions is “twi_writeTo()”. This function is used to both send the address of the slave down the bus and also to write data to slaves. It returns 0 if it was able to successfully transmit a byte or non-zero if it couldn’t. Since the very first write to a slave is its address, a very simple bus scanner using it would be:
void scanI2CBus(byte from_addr, byte to_addr) { byte data = 0; // not used, just a ptr to feed to twi_writeTo() for( byte addr = from_addr; addr < = to_addr; addr++ ) { byte rc = twi_writeTo(addr, &data, 0, 1, 0); if( rc == 0 ) { Serial.printl("device found at address "); Serial.println(addr,DEC); } } }
In the I2CScanner sketch, this function is extended a bit to support a callback function. The callback function is called with the result of every address scan. In I2CScanner, this callback function is called “scanFunc()” and just prints out “found!” or nothing, but it could be modified to do more complex tasks like doing additional I2C transactions to figure out what kind of device it is, or setting all the devices to a known state, etc.
Great program, thanks. Allowed me to determine the address of my LCD
i am using atmega 8 .Will the i2c scanner work for it(above provided) ?
Hi John,
The code was a bit stale and didn’t track the minor changes to Arduino 1.0. It’s now been updated and I put the code on github at https://github.com/todbot/arduino-i2c-scanner
Thanks!
This doesn’t work for me. I receive this error:
/Applications/Arduino.app/Contents/Resources/Java/libraries/Wire/utility/twi.h:44: error: too few arguments to function ‘uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t, uint8_t)’
I2C_Scanner:24: error: at this point in file
I’m using Arduino version 1.0.5 and have all the libraries installed correctly.
Any ideas?
Thanks!
– John
Hi
Thank you Tod. This is great. One thing using a nano 3.0 that I found (well not sure if this is just me) but in case the display is garbled in the output change the baud rate to 9600. Also the 1.0.2 of the arduino software the utility wants 5 parameters to the byte rc = twi_writeTo(addr, &data, 0, 1); stopSend so can change this to be byte rc = twi_writeTo(addr, &data, 0, 1, true);
Thank you
Jack
Hi Tod,
Your code almost works on the new Arduino v1.x IDE. The only thing required is to add an additional argument to your scanI2CBus function. In the for-loop the function rc = twi_writeTo(addr, &data, 0, 1); should have an additional ,0 (comma zero), like so: rc = twi_writeTo(addr, &data, 0, 1, 1);
The reason for this being that in the new v1.x IDE the twi_writeTo function now includes a 5th argument for ‘SendStop’.
Thanks for sharing your very effective code to the community! :-)
Thanks for this cool example of scanning the I2C / TWI Bus.
in the Arduino IDE Version 1.0.3 you need to make a small change in the code:
twi_writeTo needs one additional parameter: 0 for a normal stop command.
i also found a modified version of this sketch in the arduino.cc forum:
http://arduino.cc/forum/index.php/topic,95067.msg1047997.html#msg1047997
Have fun with I2C TWI!!
sunny greetings
Stefan
Hi,
Thanks for your code, it is helping me to understand why of the three sensors plugged I have, two are in a sort of conflict. Maybe it is just my case but to make the scanner run on my IDE 1.0.1 with my Mega 2560, I had to change the call to the twi_writeTo(…) fucntion,
from:
rc = twi_writeTo(addr, &data, 0, 1);
to:
rc = twi_writeTo(addr, &data, 0, 1, 0);
Thanks for the time you spent on this ! :)
I copied this code from your blog site but I cant compile it can you help me.
Thanks
The code from
https://todbot.com/blog/2009/11/29/i2cscanner-pde-arduino-as-i2c-bus-scanner/
THE CODE FOR
* I2CScanner.pde — I2C bus scanner for Arduino
COMPILE RESULTS
C:\Documents and Settings\Barry\My Documents\Downloads\arduino-1.0.1-windows\arduino-1.0.1\libraries\Wire/utility/twi.h: In function ‘void scanI2CBus(byte, byte, void (*)(byte, byte))’:
C:\Documents and Settings\Barry\My Documents\Downloads\arduino-1.0.1-windows\arduino-1.0.1\libraries\Wire/utility/twi.h:44: error: too few arguments to function ‘uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t, uint8_t)’
i2ctest:23: error: at this point in file
This worked well for me.. The only tweaks being to increase to scan to 127, display hex addresses too and to account for Arduino 1.0.1.