I2C Max Speed (Arduino Yun)

Hello,
I want to use the i2c fm+ (fast mode plus) on the arduino yun.
Fast mode plus is 1000kbit/s instead of 100kbit/s in the standard mode.

I only found this Thread, which is for the Due!

Do you know if is possible to use and set this frequency with the Wire lib?

Hi, welcome to the forum.

The Arduino Yun is a Arduino Leonardo plus a wifi/linux/OpenWRT module.
The microcontroller for the Arduino part is the ATmega32U4, that is a normal 16MHz microcontroller. It is not a ARM processor like the Arduino Due has.

This tests the speed up to 800kHz.
http://forum.arduino.cc/index.php?topic=197360

For which chip do you need that high speed ? Perhaps that chip can do SPI as well, or perhaps you don't need that high speed.

Thanks for your reply.
I want to use it with an MLX90621 Thermal Sensor Array (16x4).
It is possible to disable fm+ and use it with 400kHz, but I'm not sure how that affects the results.
The chip only supports i2c and I would like to test if my arduino Yun is capable of the speed, before purchasing it.
Is it possible to test the speed with an ordinary i2c temperature sensor like the LM92?

I'm very confused :confused: I hope you can help me out here.
The MLX90620 can go up to 400kHz for the I2C clock.
The MLX90621 doesn't seem to have a datasheet (if that is true, then that is wrong, just so very wrong), and I can't read that it can go faster than 400kHz.

What makes you think that the MLX90621 can go faster than 400kHz ?

Do you have a LM92 ? That chip is also specified for a maximum of 400kHz. You can use it to test the Wire library at 400kHz.

The I2C speed is not everything, the Wire library has overhead, and your sketch is also very important.

Thanks again,
yes you are right, I didn't find a datasheet for the MLX90620, too. :o
There is a document available, which describes the differences between the MLX90620 and MLX90621.
This is an excerpt from the MLX90620 datasheet:
0 - I2C FM+ mode enabled (max bit transfer rates up to 1000 kbit/s) (default)
1 - I2C FM+ mode disabled (max bit transfer rates up to 400 kbit/s)

But I think for my application the 400kbit/s will be sufficient, because it supports up to 512Hz Refresh rate of the image and I plan to use just 2Hz or 4Hz!

Yes I ordered the LM92 Yesterday and will try the I2C communication with it.
When I get it I will also test it with the tool you posted and see if the 400kHz mode works with that.

Manufacturer's page : http://www.melexis.com/Infrared-Thermometer-Sensors/Infrared-Thermometer-Sensors/MLX90621-823.aspx

Okay, now I see in the MLX90620 datasheet the bit for I2C FM+ mode for 1000kbit/s :stuck_out_tongue:
The MLX90621 has also that bit.
So as far as I know, both can do the I2C FM+ mode.

The LM92 at 400kHz should work of course.
Use short wires and a pullup resistors of 4k7.
Use the default Arduino Wire library, and set the speed with the new Wire.setClock() function.

  Wire.begin();
  Wire.setClock(400000L);         // 400 kHz, the 'L' is to indicate that it is a long integer

The Multi Speed Scanner that I mentioned before can test 500kHz and 800kHz as well. For that you might have to lower the pullup resistors to 2k2 or so. That is beyond the limits of the chips, but it is fun to test.

P.S.: The Wire.setClock() can not do any frequency. The 100k, 200k, 400k do work, but the function does not check for limits or wrong values.

Okay I will report back, when I received the LM92 and tested it.

I just tested the LM92 and the benchmark works up to 800k.
Then I made a small test to find the data transfer rate and ended up with 144kbit/s @800kHz and 115kbit/s @400khz.
The default speed gives me only a transfer rate of 48kbit/s!

Thanks for your help and tips.
I think I can try the mlx now :slight_smile:

My test Code:

#include <Wire.h>

void setup()
{
  Serial.begin(115200);
  Wire.begin();
  Wire.setClock(400000L);         
}
unsigned long t1 = millis();
unsigned long c = 0;
void loop()
{
  Wire.requestFrom(0x48,2);
  if(Wire.available()) 
  {
    Wire.read(); // read 2 byte
    Wire.read();
    c++;
    if(millis()-t1>1000)
    {
      Serial.print((16*c)/1000);
      Serial.println("kbit/s");
      c=0;
      t1=millis();
    }
  }
}

Ps: The accuracy of the sensor is really very good and I already made a small graphing display for it :wink:

Should it be "(2*c) / 1000" ?
Every increment of 'c' is only for 2 bytes.
The Wire.available() is not needed. If the Wire.requestFrom() returns, the I2C transmission has already ended and the data is in the buffer inside the Wire library. The number of bytes waiting in the buffer is the return value of Wire.requestFrom().

(2c)/1000 would return the kBytes/second, and (28*c)/1000 returns the kBit/second, which I used, because most transfer speeds (e.g. in the Datasheet) use this unit.

Thanks for the tip, with the Wire.available() method. I replaced the condition with if(Wire.requestFrom(0x48,2)>0) . This also improved the speed by 2kBit/s :wink:

I didn't see the "bit" :slight_smile:
I should have seen it :frowning:

It is possible to check the amount of requested bytes with the amount of received bytes. To detect errors.
For example like this:

int n = Wire.requestFrom( 0x48, 2);
if( n == 2)
{
  // 2 bytes requested and 2 bytes received, that's okay
  c++;
  Wire.read();
  Wire.read();
}
else
{
  // A bus error or slave not ready
  error++;
}

The extra integer and the Wire.requestFrom() outside the if-statement might slow down it a little, but perhaps it is just a s fast. The compiler can do all kind of funny optimizations.

If you have the MLX90621, can you post the results for 400kHz in this topic ? It might even work at 800kHz in normal mode, just like the LM92.

Good idea. I tried it and the speed did not change at all. Error rate is 0 for all speeds.
Then I extended it a little, by using this code, to check if the results are similar to the previously measured temperature:

#include <Wire.h>

void setup()
{
  Serial.begin(115200);
  Wire.begin();
  Wire.setClock(800000L);         
}
unsigned long t = millis();
unsigned long c = 0;
int error = 0;
void loop()
{
  int n = Wire.requestFrom( 0x48, 2);
  if(n == 2)
  {
    int tmp = ((Wire.read() << 5) + (Wire.read() >> 3));
    if(tmp > 400 && tmp < 420)
    {
      c++; //correct temperature -> increase counter
    }
    else
    {
      error++; //wrong temperature -> error
    }
    if(millis()-t>1000)
    {
      Serial.print((16*c)/1000);
      Serial.println("kbit/s   -   ");
      Serial.print(error);
      Serial.println(" errors");
      c=0;
      error=0;
      t=millis();
    }
  }
  else
  {
    error++;
  }
}

Again no errors and still 141kbit/s @ 800kHz. I think that this is a very good result, because it is only 3kbit/s slower with the added calculation!

When I have the MLX90621 I will post here and share the results.