I used your MultispeedScanner 0.1.03 for Test an I2C Circuit. It works fine with a Duemilanova, but if I use an Arduino Due (with levelshifter from 3.3V to 5V) I got no Answer from any I2C chip. The change for the Due I did is to comment out the "TWBR-Statement". I used IDE 1.5.6-R2.
In this Postings you can find als some scope and small pieces from the a logic analyzer. http://forum.arduino.cc/index.php?topic=234999.msg1692208#msg1692208
(Maybe using the Wire1 library instead of Wire and connecting an externally-pulluped I2C bus to SCL1/SDA1 pins will work, too, but I just checked the above mentioned workaround works.)
Oh....
I'm sorry. This morning I found the addition 1 is meaningless and not working as multi speeds. It only scans at 100kHz.
So if you only need to scan at 100kHz, simply comment out the TWBR code and use the nightly ide 1.5.7.
Peter_n:
Is it possible to detect a I2C error without causing a crash ?
Really depends on the cause of the crash.
Does the I2C scanner work when used standalone (no webserver)?
Does the webserver crash if you just set the I2C clock to 500KHz?
I found the problem, but I don't know how to solve it.
Setting the TWBR down to 2 (for 800kHz) is normally no problem.
Only in the situation when I have a Arduino as Slave at 5V and another Arduino as Slave at 3.3V (using a level shifter). In that situation the sketch never returnes from Wire.endTransmission() when the speed is too high. At the moment it happens at 670kHz, when TWBR becomes 3.
Below is my function to make a webpage.
On the 'home' page I have a link to "SCAN". When I click it, the file "SCAN" is requested. But instead loading it from the SD card, I recognize the keyword and call the function "MultiSpeedI2CScanner".
Everything (table, colspan) is only up to 400kHz. To allow the higher speeds, the html code for the table should be adjusted.
// MultiSpeedI2CScanner
// To be used in a webserver, it outputs HTML code with the result
// The new Wire.setClock() is available in Arduino IDE 1.5.8, but that is not used yet.
// It is assumed that Wire.begin() has been called already.
//
// Using:
//
// FILE: MultiSpeedI2CScanner.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.04
// PURPOSE: I2C scanner @different speeds
// DATE: 2013-11-05
// URL: http://forum.arduino.cc/index.php?topic=197360
//
// Released to the public domain
//
#include <Wire.h>
#include <Ethernet.h>
// scans devices from 50 to 800KHz I2C speeds.
// lower than 50 is not possible
// DS3231 RTC works on 800 KHz. TWBR = 2; (?)
const long speed[] = { // 'const' added
50, 100, 200, 250, 400 }; // , 500, 800 }; // only up to 400 !
const int speeds = sizeof(speed)/sizeof(speed[0]);
// DELAY BETWEEN TESTS
#define RESTORE_LATENCY 5 // for delay between tests of found devices.
bool delayFlag = false;
// MINIMIZE OUTPUT
bool printAll = false;
bool header = true;
void MultiSpeedI2CScanner(EthernetClient *pClient)
{
// Wire.begin(); // already called in the sketch of my webserver
pClient->println(F("<html>"));
pClient->println(F("<head>"));
pClient->println(F("<meta content=\"text/html; charset=UTF-8\" http-equiv=\"content-type\">"));
pClient->println(F("<title>Multi Speed I2C scanner</title>"));
// Make a nice style for the table.
pClient->println(F("<style type=\"text/css\">"));
pClient->println(F("table { color:#303030; border-width: 1px; border-color: #0000A0; border-collapse: collapse; }"));
pClient->println(F("table th { border-width: 1px; padding: 6px; border-style: solid; border-color: #0000A0; background-color: #C0FFFF; }"));
pClient->println(F("table td { border-width: 1px; padding: 6px; border-style: solid; border-color: #0000A0; background-color: #D0D0FF; }"));
pClient->println(F("</style>"));
pClient->println(F("</head>"));
pClient->println(F("<body>"));
I2Cscan( pClient);
pClient->println(F("</body>"));
pClient->println(F("</html>"));
}
void I2Cscan(EthernetClient *pClient)
{
uint32_t startScan;
uint32_t stopScan;
startScan = millis();
uint8_t count = 0;
// The style is defined in the header.
pClient->println(F("<table>"));
pClient->println(F("<tbody>"));
if (header)
{
pClient->print(F("<tr>"));
pClient->print(F("<th colspan=\"8\">Multi Speed I2C scanner</th>"));
pClient->println(F("</tr>"));
pClient->print(F("<tr>"));
pClient->print(F("<th>TIME</th>"));
pClient->print(F("<th colspan=\"2\">Address</th>"));
pClient->print(F("<th colspan=\"5\">Speed [kHz]</th>"));
pClient->println(F("</tr>"));
pClient->print(F("<tr>"));
pClient->print(F("<th> </th>"));
pClient->print(F("<th>DEC</th>"));
pClient->print(F("<th>HEX</th>"));
for (uint8_t s = 0; s < speeds; s++)
{
pClient->print(F("<th>"));
pClient->print(speed[s]);
pClient->print(F("</th>"));
}
pClient->println(F("</tr>"));
}
// TEST
// 0.1.04: tests only address range 8..120
// --------------------------------------------
// Address R/W Bit Description
// 0000 000 0 General call address
// 0000 000 1 START byte
// 0000 001 X CBUS address
// 0000 010 X reserved - different bus format
// 0000 011 X reserved - future purposes
// 0000 1XX X High Speed master code
// 1111 1XX X reserved - future purposes
// 1111 0XX X 10-bit slave addressing
for (uint8_t address = 8; address < 120; address++)
{
bool printLine = printAll;
bool found[speeds];
bool fnd = false;
for (uint8_t s = 0; s < speeds ; s++)
{
TWBR = (F_CPU/(speed[s]*1000) - 16)/2;
Wire.beginTransmission (address);
found[s] = (Wire.endTransmission () == 0);
fnd |= found[s];
// give device 5 millis
if (fnd && delayFlag)
delay(RESTORE_LATENCY);
}
if (fnd) count++;
printLine |= fnd;
if (printLine)
{
pClient->print(F("<tr>"));
pClient->print(F("<td>"));
pClient->print(millis());
pClient->print(F("</td>"));
pClient->print(F("<td>"));
pClient->print(address, DEC);
pClient->print(F("</td>"));
pClient->print(F("<td>0x"));
pClient->print(address, HEX);
pClient->print(F("</td>"));
for (uint8_t s = 0; s < speeds ; s++)
{
pClient->print(F("<td>"));
pClient->print(found[s]? F("V"):F("."));
pClient->print(F("</td>"));
}
pClient->println(F("</tr>"));
}
}
pClient->println(F("</table>"));
stopScan = millis();
if (header)
{
pClient->println(F("
"));
pClient->print(count);
pClient->print(F(" devices found in "));
pClient->print(stopScan - startScan);
pClient->print(F(" milliseconds."));
pClient->println(F("
"));
}
}
I think that my I2C bus is crumbling down at 670kHz. The sketch for the webpage is the resulting sketch with the client.prints. I tested it with your sketch with and without Serial.prints, with and without delay and so on. I even did Serial.flush() everywhere to be sure that the Serial library was not longer busy. The result was still the same.
I was assuming that my I2C could be best at 100kHz, because of wires and Arduino Slaves, but now I feel confident to use 200kHz
for using Arduino Due you need at least Arduino IDE 1.5.8. The guys have changed some parts including wire. So you can use this tool if you replace this line from the code:
for using Arduino Due you need at least Arduino IDE 1.5.8. The guys have changed some parts including wire. So you can use this tool if you replace this line from the code: