Skip to content

I2C sub-one cycle clock stretching causes problems. Me, I blame SMPCNT. #400

@PaulZC

Description

@PaulZC

The Qwiic Button uses sub-one cycle clock stretching on the I2C bus. This causes the standard beginTransmission endTransmission 'scanner' test for an I2C device to return a false positive.

Steps To Replicate:

Connect an unmodified Qwiic Button to e.g. an Artemis Thing Plus.
Load core v2.1.0.
Upload the following simple 'I2C scanner' sketch:

#include <Wire.h>

void setup()
{
  Serial.begin(115200);
  Wire.begin();
  Wire.setClock(100000);
  
  for (byte address = 1; address < 127; address++ )
  {
    Wire.beginTransmission(address);
    byte error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      Serial.println(address, HEX);
    }
    else
    {
      Serial.print("I2C error ");
      Serial.print(error);
      Serial.print(" at address 0x");
      Serial.println(address, HEX);
    }
  }
}

void loop()
{
}

The Qwiic Button has a default address of 0x6F, so you should see this (as captured with an ESP32 Thing Plus):

...
I2C error 2 at address 0x66
I2C error 2 at address 0x67
I2C error 2 at address 0x68
I2C error 2 at address 0x69
I2C error 2 at address 0x6A
I2C error 2 at address 0x6B
I2C error 2 at address 0x6C
I2C error 2 at address 0x6D
I2C error 2 at address 0x6E
I2C device found at address 0x6F
I2C error 2 at address 0x70
I2C error 2 at address 0x71
I2C error 2 at address 0x72
I2C error 2 at address 0x73
I2C error 2 at address 0x74
I2C error 2 at address 0x75
I2C error 2 at address 0x76
...

but instead we get this:

I2C device found at address 0x1
I2C device found at address 0x2
I2C device found at address 0x3
I2C device found at address 0x4
I2C device found at address 0x5
I2C device found at address 0x6
I2C device found at address 0x7
I2C device found at address 0x8
I2C device found at address 0x9
I2C device found at address 0xA
I2C device found at address 0xB
I2C device found at address 0xC
I2C device found at address 0xD
I2C device found at address 0xE
I2C device found at address 0xF
I2C device found at address 0x10
I2C device found at address 0x11
...

Diagnosis:

Looking at the I2C bus with a logic analyzer, we can see the sub-one cycle clock stretching (note the gap before the NACK):

image

The I2C bus traffic is correct and the processor should see this as a NACK (device not present). But endTransmission is returning zero. It shouldn't...

Here's the correct ACK at address 0x6F:

image

Here's the same test at 400kHz. It gives the same false positives. The clock stretching is much more obvious:

image

But at 50kHz (thank you v2!), all is well. Note the lack of clock-stretching:

image

...
I2C error 2 at address 0x6B
I2C error 2 at address 0x6C
I2C error 2 at address 0x6D
I2C error 2 at address 0x6E
I2C device found at address 0x6F
I2C error 2 at address 0x70
I2C error 2 at address 0x71
I2C error 2 at address 0x72
I2C error 2 at address 0x73
...

Suspected cause:

I think the root cause is our old friend SMPCNT:

image

100kHz and 400kHz set SMPCNT to 3:

https://github.com/sparkfun/mbed-os-ambiq-apollo3/blob/be07f057170a4e9ed4a286abb2170b9df3d52de3/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/sdk/mcu/apollo3/hal/am_hal_iom.c#L2203

https://github.com/sparkfun/mbed-os-ambiq-apollo3/blob/be07f057170a4e9ed4a286abb2170b9df3d52de3/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/sdk/mcu/apollo3/hal/am_hal_iom.c#L2223

But the default setting (which is what would be used for 50kHz), sets SMPCNT to 33 (0x21):

https://github.com/sparkfun/mbed-os-ambiq-apollo3/blob/be07f057170a4e9ed4a286abb2170b9df3d52de3/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/sdk/mcu/apollo3/hal/am_hal_iom.c#L2293

Now, I don't know what the answer to this is... I've tried manually setting SMPCNT for 100kHz and I can't find a value which works. There is a cryptic note in the Apollo3 Blue datasheet:

image

so maybe only certain values work for SMPCNT which "allow for synchronization time"? Multiples of three perhaps?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions