I2C communication

hI! I am using an arduino and a microchip MCP23008 to test how fast an I2C communcation can be. To see that I am controlling a LED. The LED blinks for some time and then it stays on. After some time blinks again and stays on. So it keeps doint that. My intention is to blink nonstop. The other problem is that thic microchip is 400kHz. When I set the delay in 20 miliseconds or 10 is not able to handle. I think the problem is the code.

#include <Wire.h>

// I2C address of the MCP23008
#define MCP23008_ADDRESS 0x20

// MCP23008 registers
#define IODIR 0x00   // I/O direction register
#define OLAT  0x0A   // Output latch register

void setup() {
  // Start the I2C communication
  Wire.begin();
  
  // Set I2C clock speed to 400kHz
  Wire.setClock(400000);

  // Set all pins to output (IODIR register to 0x00)
  Wire.beginTransmission(MCP23008_ADDRESS);
  Wire.write(IODIR);
  Wire.write(0x00); // All pins as outputs
  Wire.endTransmission();

  // Turn off all pins initially (OLAT register to 0x00)
  Wire.beginTransmission(MCP23008_ADDRESS);
  Wire.write(OLAT);
  Wire.write(0x00); // All pins low
  Wire.endTransmission();
}

void loop() {
  // Turn on the LED connected to pin 0
  Wire.beginTransmission(MCP23008_ADDRESS);
  Wire.write(OLAT);
  Wire.write(0x01); // Set pin 0 high
  Wire.endTransmission();

  // Wait for 10 milliseconds
  delay(100);

  // Turn off the LED connected to pin 0
  Wire.beginTransmission(MCP23008_ADDRESS);
  Wire.write(OLAT);
  Wire.write(0x00); // Set pin 0 low
  Wire.endTransmission();

  // Wait for 10 milliseconds
  delay(100);
}

This is a forum for Particle devices, not Arduino. I'd recommend going to one of the Arduino forums.

But Particle firmware is similar to Arduino, and I was curious about how fast you can toggle a GPIO on the MCP23008. I used a Boron LTE and a MCP23008 Feather:

And this firmware:

#include "Particle.h"

#include "MCP23008-RK.h"

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);

// GP7 is pin 17, next to the VDD pin on the top left
// GP0 is pin 10 on the top right

MCP23008 gpio(Wire, 0);

const unsigned long loopDelayMs = 1;
Thread *workerThread;
os_thread_return_t threadFunction(void);
bool pinState = false;

void setup() {
    Wire.setSpeed(CLOCK_SPEED_400KHZ);

	gpio.begin();
	gpio.pinMode(0, OUTPUT);

    workerThread = new Thread("MyClass", threadFunction, OS_THREAD_PRIORITY_DEFAULT, 3072);
}

void loop() {
}

os_thread_return_t threadFunction(void) {
    while(true) {
        pinState = !pinState;
        gpio.digitalWrite(0, pinState);

        delay(loopDelayMs);
    }
}

There's a little jitter about every 100 milliseconds, but it's able to output a period of 2 ms (500 Hz) without difficulty at the default I2C clock speed of 100 kHz. It also works at 400 kHz.

The chip can probably go faster than 1 millisecond per high or low cycle, but the thread scheduler on Particle cannot.

1 Like

I tested to see how fast you could actually toggle a GPIO on a MCP23008 with 400 kHz I2C on a P2/Photon 2. Running this code is a bad idea because it basically takes over the MCU doing nothing but I2C transactions, but it was interesting nonetheless.

os_thread_return_t threadFunction(void) {
    while(true) {
        SINGLE_THREADED_BLOCK() {
            for(int ii = 0; ii < 10; ii++) {
                pinState = !pinState;
                gpio.digitalWrite(0, pinState);
            }
        }
        delay(loopDelayMs);
    }
}

Basically, it tops out at about 1.8 kHz, but the MCU can't do anything else like manage the cloud connection, so it's a bad idea to try to do this. The SPI version of this chip is probably faster.

2 Likes