adafruit/Adafruit_Arduino_Boards

feather m0: i2c frequencies are incorrect

killer4king opened this issue · 0 comments

Hi All,

I'm new with the Adafruit Feather M0 .. (but not so new with Arduino)
And lately I have been experimenting with i2C bus speeds and found the multispeed I2C scanner from Rob Tillaart
it seems to work well
BUT, the speeds that are supposed to be set, turn out not to be correct!
is there something wrong in the bootloader or in the wire lib?!

below the code I currently use (i have modifeid it a bit to in my view optimize it and show only scan timing)
`//
// FILE: MultiSpeedI2CScanner.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.9
// PURPOSE: I2C scanner at different speeds
// DATE: 2013-11-05
// URL: http://forum.arduino.cc/index.php?topic=197360
//
// Released to the public domain
//
// added 1000Hz and timed only the scanning, not output!
// still need to add some code to double check the detected devices identifiers

#include <Wire.h>
#include <Arduino.h>

TwoWire *wi;

const char version[] = "0.1.9b";

// INTERFACE COUNT (TESTED TEENSY 3.5 AND ARDUINO DUE ONLY)
int wirePortCount = 1;
int selectedWirePort = 0;

// scans devices from 50 to 800KHz I2C speeds.
// lower than 50 is not possible
// DS3231 RTC works on 800 KHz. TWBR = 2; (?)

const long allSpeed[] = {
50, 100, 200, 300, 400, 500, 600, 700, 800, 1000
};
long speed[sizeof(allSpeed) / sizeof(allSpeed[0])];
int speeds;

int addressStart = 0;
int addressEnd = 127;

// DELAY BETWEEN TESTS
#define RESTORE_LATENCY 5 // for delay between tests of found devices.
bool delayFlag = false;

// MINIMIZE OUTPUT
bool printAll = true;
bool header = true;

// STATE MACHINE
enum states {
STOP, ONCE, CONT, HELP
};
states state = STOP;

void setup()
{
Serial.begin(115200);
while (!Serial);
Wire.begin();

#if defined WIRE_IMPLEMENT_WIRE1 || WIRE_INTERFACES_COUNT > 1
Wire1.begin();
wirePortCount++;
#endif
#if defined WIRE_IMPLEMENT_WIRE2 || WIRE_INTERFACES_COUNT > 2
Wire2.begin();
wirePortCount++;
#endif
#if defined WIRE_IMPLEMENT_WIRE3 || WIRE_INTERFACES_COUNT > 3
Wire3.begin();
wirePortCount++;
#endif

wi = &Wire;

setSpeed('9');
displayHelp();
}

void loop()
{
char command = getCommand();
switch (command)
{
case '@':
selectedWirePort = (selectedWirePort + 1) % wirePortCount;
Serial.print(F("I2C PORT=Wire"));
Serial.println(selectedWirePort);
switch (selectedWirePort)
{
case 0:
wi = &Wire;
break;
case 1:
#if defined WIRE_IMPLEMENT_WIRE1 || WIRE_INTERFACES_COUNT > 1
wi = &Wire1;
#endif
break;
case 2:
#if defined WIRE_IMPLEMENT_WIRE2 || WIRE_INTERFACES_COUNT > 2
wi = &Wire2;
#endif
break;
case 3:
#if defined WIRE_IMPLEMENT_WIRE3 || WIRE_INTERFACES_COUNT > 3
wi = &Wire3;
#endif
break;
}
break;

case 's':
  state = ONCE;
  break;
case 'c':
  state = CONT;
  break;
case 'd':
  delayFlag = !delayFlag;
  Serial.print(F("<delay="));
  Serial.println(delayFlag ? F("5>") : F("0>"));
  break;

case 'e':
  // eeprom test TODO
  break;

case 'h':
  header = !header;
  Serial.print(F("<header="));
  Serial.println(header ? F("yes>") : F("no>"));
  break;
case 'p':
  printAll = !printAll;
  Serial.print(F("<print="));
  Serial.println(printAll ? F("all>") : F("found>"));
  break;

case '0':
case '1':
case '2':
case '4':
case '5':
case '7':
case '8':
case '9':
  setSpeed(command);
  break;

case 'a':
  setAddress();
  break;

case 'q':
case '?':
  state = HELP;
  break;
default:
  break;

}

switch (state)
{
case ONCE:
I2Cscan();
state = HELP;
break;
case CONT:
I2Cscan();
delay(1000);
break;
case HELP:
displayHelp();
state = STOP;
break;
case STOP:
break;
default: // ignore all non commands
break;
}
}

void setAddress()
{
if (addressStart == 0)
{
addressStart = 8;
addressEnd = 120;
}
else
{
addressStart = 0;
addressEnd = 127;
}
Serial.print(F("<address Range = "));
Serial.print(addressStart);
Serial.print(F(".."));
Serial.print(addressEnd);
Serial.println(F(">"));

}

void setSpeed(char sp)
{
Serial.print(F("<Speed="));
switch (sp)
{
case '1':
speed[0] = 100;
speeds = 1;
Serial.println(F("100 KHz>"));
break;
case '2':
speed[0] = 200;
speeds = 1;
Serial.println(F("200 KHz>"));
break;
case '4':
speed[0] = 400;
speeds = 1;
Serial.println(F("400 KHz>"));
break;
case '5':
speed[0] = 50;
speeds = 1;
Serial.println(F("50 KHz>"));
break;
case '7':
speed[0] = 1000;
speeds = 1;
Serial.println(F("1000 KHz>"));
break;
case '8':
speed[0] = 800;
speeds = 1;
Serial.println(F("800 KHz>"));
break;
case '9': // limited to 400KHz
speeds = 5;
Serial.println(F("50, 100, 200, 300, 400 KHz>"));
for (int i = 0; i < speeds; i++)
{
speed[i] = allSpeed[i];
}
break;
case '0': // reset
speeds = sizeof(allSpeed) / sizeof(allSpeed[0]);
Serial.println(F("50, 100, 200, 300, 400, 500, 600, 700, 800, 1000 KHz>"));
for (int i = 0; i < speeds; i++)
{
speed[i] = allSpeed[i];
}
break;

}
}

char getCommand()
{
char c = '\0';
if (Serial.available())
{
c = Serial.read();
}
return c;
}

void displayHelp()
{
Serial.print(F("\nArduino MultiSpeed I2C Scanner - "));
Serial.println(version);
Serial.println();
Serial.print(F("we have arduino: "));
Serial.println(ARDUINO);
Serial.println();
Serial.print(F("CPU speed: "));
Serial.println(F_CPU);
Serial.print(F("I2C ports: "));
Serial.println(wirePortCount);
Serial.println(F("\t@ = toggle Wire - Wire1 - Wire2 [TEENSY 3.5 or Arduino Due]"));
Serial.println(F("Scanmode:"));
Serial.println(F("\ts = single scan"));
Serial.println(F("\tc = continuous scan - 1 second delay"));
Serial.println(F("\tq = quit continuous scan"));
Serial.println(F("\td = toggle latency delay between successful tests. 0 - 5 ms"));
Serial.println(F("Output:"));
Serial.println(F("\tp = toggle printAll - printFound."));
Serial.println(F("\th = toggle header - noHeader."));
Serial.println(F("\ta = toggle address range, 0..127 - 8..120"));
Serial.println(F("Speeds:"));
Serial.println(F("\t0 = 50 - 1000 Khz (EXPERIMENTAL! - can block!!)"));
Serial.println(F("\t1 = 100 KHz only"));
Serial.println(F("\t2 = 200 KHz only"));
Serial.println(F("\t4 = 400 KHz only"));
Serial.println(F("\t5 = 50 KHz only"));
Serial.println(F("\t7 = 1000 KHz only (EXPERIMENTAL! - can block!)"));
Serial.println(F("\t8 = 800 KHz only (warning - can block!)"));
Serial.println(F("\t9 = 50 - 400 Khz <<< DEFAULT >>>"));
Serial.println(F("\n\t? = help - this page"));
Serial.println();
}

void I2Cscan()
{
uint32_t startloop;
uint32_t stoploop;
uint32_t startScan;
uint32_t stopScan[speeds];

if (header)
{
// TIMING

Serial.print(F("DEC\tHEX\t"));
for (uint8_t s = 0; s < speeds; s++)
{
  Serial.print(F("\t"));
  Serial.print(speed[s]);
}
Serial.println(F("\t[KHz]"));
for (uint8_t s = 0; s < speeds + 5; s++)
{
  Serial.print(F("--------"));
}
Serial.println();

}

// 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

uint8_t count = 0;
bool found[addressEnd][speeds];
bool printLine[addressEnd];
for (int i = addressStart; i <= addressEnd; i++)printLine[i] = printAll;

bool fnd = false;
uint8_t address;
uint8_t s;
startloop = millis();

for ( s = 0; s < speeds ; s++)
{

#if ARDUINO >= 158
wi->setClock(speed[s] * 1000);
#else
TWBR = (F_CPU / (speed[s] * 1000) - 16) / 2;
#endif

startScan = micros();
for ( address = addressStart; address <= addressEnd; address++)
{
  wi->beginTransmission (address);
  if (wi->endTransmission () == 0) printLine[address] = found[address][s] = 255;
  // give device 5 millis
  if (delayFlag && found[address][0]) delay(RESTORE_LATENCY);
}
stopScan[s] = micros() - startScan;

}
stoploop=millis();

for (uint8_t address = addressStart; address <= addressEnd; address++)
{
if (printLine[address])
{
if (found[address][0]) count++;
Serial.print(address, DEC);
Serial.print(F("\t0x"));
if (address < 0x10) Serial.print(0, HEX);
Serial.print(address, HEX);
Serial.print(F("\t"));

  for (s = 0; s < speeds ; s++)
  {
    Serial.print(F("\t"));
    Serial.print(found[address][s] ? F("V") : F("."));
  }
  if (address == 0x00) Serial.print("\t(also PCA9685 12xPWM)");
  if (address == 0x38) Serial.print("\t(BMA020 gravity plug)");
  if (address == 0x3C) Serial.print("\t(SSD1306 OLED 128x32)");
  if (address == 0x3E) Serial.print("\t(SX1509 16x AIO)");
  if (address == 0x40) Serial.print("\t(SHT20 TEMP/HUM, also PCA9685 12xPWM)");
  if (address == 0x57) Serial.print("\t(DS3231 I2C Precision Clock)");
  if (address == 0x68) Serial.print("\t(AT24C32 Memory)");
  if (address == 0x70) Serial.print("\t(also PCA9685 12xPWM)");
  Serial.println("");
  //Serial.println();
}

}

if (header)
{
Serial.print(F("time (μs) :\t\t"));
for (s = 0; s < speeds; s++) {
Serial.print(stopScan[s]);
Serial.print(F("\t"));
}
Serial.println();
Serial.print(count);
Serial.print(F(" devices found in total time: "));
Serial.print(stoploop-startloop);
Serial.println(F(" milliseconds"));
}
}`

I hooked up a 1Ms/s scoop to the SCL line and up to 200KHz I should be able to read the freq, I get following results:
speed: frequency
50KHz: 95KHz
100KHz: 88KHz
200KHz: 173KHz

any idea's?!