Artemis I2C/qwiic returns garbage at 100 KHz.

My I2C bus communicates fine when I choose pretty much anything other than 100 or 200 kHz clock speeds. For example, 10, 50, 80, 90, 110, 400 kHz all work fine. When using 100 or 200 kHz, I get acknowledgements from the sensor, but the sensor data is corrupted.

This took me a little while to figure out so I thought I’d share the “work-around”. It’d also be great if someone could explain what’s going on.

Hardware setup:

Board: Artemis OpenLogIn

Arduino IDE “board” is: Redboard Artemis ATP (as specified by the Artemis OpenLog git repo)

Core/Apollo3 Library: 2.1.1

I2C Sensor: Lidar v4LED

Software:

#include <Wire.h> 
#include "LIDARLite_v4LED.h"

// Artemis OLA pins.
const byte PIN_QWIIC_SCL = 8; 
const byte PIN_QWIIC_SDA = 9;
const byte PIN_QWIIC_POWER = 18; // Qwiic bus power control.

// Set up a I2C using Wire.h.
TwoWire qwiic(PIN_QWIIC_SDA, PIN_QWIIC_SCL);

// Instantiate a lidar class.
const byte ADDR_LIDAR = 0x62;
LIDARLite_v4LED myLIDAR; // Click here to get the library: http://librarymanager/All#SparkFun_LIDARLitev4 by SparkFun


void setup() {
  Serial.begin(115200); 

  // Setup the I2C bus.
  Serial.println("Setup the I2C (qwiic) bus...");
  pinMode(PIN_QWIIC_POWER, OUTPUT);
  digitalWrite(PIN_QWIIC_POWER, HIGH); // Turn on qwiic power.

  // Start the I2C bus.
  qwiic.begin();
  qwiic.setClock(90000); // 100k and 200k do NOT work. All others I've tried DO work.
  setQwiicPullups(1);  // Set pull up resistors to 1.5k. I've tried the other values too.
  delay(500); // Seems like qwiic.begin() requires some time to finish.
  lidarBegin(ADDR_LIDAR, qwiic);

  Serial.println("Finished setup.");
}


void loop() {
  float distance_cm;

  // getDistance() returns the distance in cm.
  distance_cm = myLIDAR.getDistance();

  Serial.print(distance_cm);
  Serial.print(" cm");
  Serial.println();
  
  delay(100); // Don't hammer the I2C bus.
}


//check if LIDAR will acknowledge over I2C
void lidarBegin(const byte address, TwoWire &qwiic) { 
  if (myLIDAR.begin(address, qwiic) == false) {   
    Serial.printf("LIDAR at address 0x%02X is missing.\r\n", address);
  } else {
    Serial.printf("LIDAR at address 0x%02X acknowledged!\r\n", address);
  }
}


// Setup the values for the I2C pull up resistors. This code was taken from
// I2C_Detector.ino in the Artemis OpenLog repo.
void setQwiicPullups(uint32_t qwiicBusPullUps)
{
  //Change SCL and SDA pull-ups manually using pin_config
  am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM1_SCL;
  am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM1_SDA;

  if (qwiicBusPullUps == 0)
  {
    sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // No pull-ups
    sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
  }
  else if (qwiicBusPullUps == 1)
  {
    sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; // Use 1K5 pull-ups
    sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K;
  }
  else if (qwiicBusPullUps == 6)
  {
    sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_6K; // Use 6K pull-ups
    sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_6K;
  }
  else if (qwiicBusPullUps == 12)
  {
    sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_12K; // Use 12K pull-ups
    sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_12K;
  }
  else
  {
    sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_24K; // Use 24K pull-ups
    sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_24K;
  }

  pin_config(PinName(PIN_QWIIC_SCL), sclPinCfg);
  pin_config(PinName(PIN_QWIIC_SDA), sdaPinCfg);
}

Try fiddling with the logging rate of the Artemis discussed in the ‘configuration’ section here https://learn.sparkfun.com/tutorials/op … -guide/all and see if that helps at all?

I do experience this problem when running the (massive) [ OpenLog_Artemis software which provides the cool serial interface you can use to configure the logging rate (as you suggest). However, in the simple one-INO-file example I provided above, the only thing setting the logging rate is the delay(100) in the loop() function, and the only sensor being logged to serial is the lidar. I’ve tried several other delay times as well. Same problem.](GitHub - sparkfun/OpenLog_Artemis: The OpenLog Artemis is an open source datalogger the comes preprogrammed to automatically log IMU, GPS, serial data, and various pressure, humidity, and distance sensors. All without writing a single line of code!)

There seems to be an issue with clock stretch on Artemis. (https://github.com/sparkfun/Arduino_Apollo3/issues/400) Have not got to the detail of it as I don’t have that hardware. It is not completely clear however whether that is the root cause in this case.

The LIDAR-Lite 4 led data states :

“If the slave address corresponds to the LIDAR device address, the LIDAR device responds by pulling SDA low during the ninth clock pulse. This operation is considered the acknowledge bit. At this stage, all other devices on the bus remain idle while the selected LIDAR device waits for data to be written to or read from its shift register

This last sentence COULD mean clock stretch is enabled when waiting for the data. Only to discover with a logic analyzer.

Fyi, I’ve got the same problem with my Artemis connected over I2C to an ultrasonic distance sensor (SEN-17777).

When the object is 100 mm away, here is what I see

Platform  I2Cspeed  HighByte  LowByte  Total
Uno        100k     0         100      100 mm
Artemis    90k      0         100      100 mm
Artemis    100k     128       100      32868 mm

So it looks like either the first or last bit of the transmission is getting corrupted when I run Artemis at 100k.

What Sparkfun library version do you run 2.1.1 ? In that case try 2.1.0 or run at 200Khz.

Per your suggestion, I tried 200 kHz with my sonar, and that seems to work. (btw, that is in contrast with my original post, which found that the Lidar worked at all frequencies except 100 and 200 kHz).