Go Down

Topic: MultiSpeed I2C Scanner - 50,100,200,400 KHz. (Read 10733 times) previous topic - next topic

#15
Jun 17, 2014, 07:46 pm Last Edit: Jun 17, 2014, 07:55 pm by orangkucing Reason: 1
Two modifications were necessary for MultiSpeed I2C Scanner to work with Due.

1. TWBR must be emulated by adding the following code after the #include statements (cf.  https://github.com/jrowberg/i2cdevlib/issues/48):

#if defined(__arm__)
class TWBRemulation
{
public:
   inline TWBRemulation & operator = (int val) __attribute__((always_inline)) {
   if (val == 12 || val == ((F_CPU / 400000) - 16) / 2) {
       #if F_BUS == 48000000
       I2C0_F = 0x1A; // 400 kHz
       #elif F_BUS == 24000000
       I2C0_F = 0x45; // 400 kHz
       #endif
   }
   return *this;
}
};
TWBRemulation TWBR;
#endif


2. Due's pull-up resistors are unsuitable for most I2C devices (cf. http://forum.arduino.cc/index.php?PHPSESSID=n5nfq19euhrhc12gtv03r0j3j2&topic=146802.15). Thus I removed the onboard network resistor, and used external 4.7k pull-ups.

(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.)

And please use a Nightly build version of Arduino IDE. Because the Wire library before 1.5.7 including the current 1.5.6r2 has a serious bug on the return values of TwoWire::endTransmission function. (cf. https://github.com/arduino/Arduino/pull/1994 )

robtillaart

Thanks for these additions  (have no time to confirm, sorry )

Did you get meaningful results with the I2C scanner now?
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#17
Jun 18, 2014, 12:49 am Last Edit: Jun 18, 2014, 01:06 am by orangkucing Reason: 1
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.

(cf. http://www.i2cdevlib.com/forums/topic/88-mpu-dmp6-with-arduino-due-twbr-not-declared/)

robtillaart

#18
Jul 05, 2014, 11:02 am Last Edit: Jul 05, 2014, 11:38 am by robtillaart Reason: 1
updated to 0.1.04  (see first post)

main change is restricting the # addresses to be scanned as I2C address 0..7 and 120..127 have special meanings.

or download from here - https://github.com/RobTillaart/Arduino/tree/master/sketches/MultiSpeedI2CScanner -
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

updated to version 0.1.05 on github
- https://github.com/RobTillaart/Arduino/tree/master/sketches/MultiSpeedI2CScanner -

not tested enough imho, so not updated in the first post.

as always comments and remarks are welcome.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Peter_n

Hi,
I have added the Multi Speed I2C to my webserver, running on a Arduino Mega 2560.

But when I let it try 500kHz my webserver crashes.
Is it possible to detect a I2C error without causing a crash ?

In Arduino 1.5.8 the new Wire.setClock() can be used.

robtillaart

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?

You may post your code ....
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Peter_n

#22
Dec 08, 2014, 02:12 am Last Edit: Dec 08, 2014, 02:17 am by Peter_n
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.

Code: [Select]

// 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>&nbsp;</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("<br>"));
    pClient->print(count);
    pClient->print(F(" devices found in "));
    pClient->print(stopScan - startScan);
    pClient->print(F(" milliseconds."));
    pClient->println(F("<br>"));
  }
}

robtillaart

The problem might be that the interrupts of printing interfere with the bits of the I2C bus.
You need a logic analyser for that I guess.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Peter_n

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 :smiley-grin:

Well, I didn't buy an oscilloscope (yet) : http://forum.arduino.cc/index.php?topic=281572.0

derniwi

#25
Dec 17, 2014, 09:07 am Last Edit: Dec 17, 2014, 09:11 am by derniwi
Hi,

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:
Code: [Select]

      TWBR = (F_CPU/(speed[s]*1000) - 16)/2;

with this part
Code: [Select]
#if ARDUINO >= 158
      Wire.setClock(speed[s]*1000);
#else
      TWBR = (F_CPU/(speed[s]*1000) - 16)/2;
#endif

I tried this with the Arduino nightly build of 1.6.0 and it works fine on my Due.

Best regards
Nils

robtillaart

added this to the scanner 0.1.06 version

- https://github.com/RobTillaart/Arduino/tree/master/sketches/MultiSpeedI2CScanner -
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up