Tracker One with SparkFun SX1509 IO Expander?

Heyall - long time lurker, first time poster.

I’m looking to do some “external” i2c gpio using the Tracker One M8 connector, and would like to use the SX1509 to sense a bunch of switch state-changes and control lights.

I’m not sure, however, how to enable Wire3 here as the invocation interface for the Particle-ized SX1509 doesn’t seem to allow specifying which Wire implementation to use and looks to be hard coded to just use Wire.

I say this because simply saying:

SX1509 gpio(Wire3,[address])

…results in a bunch of errors. So I think that this library isn’t set up the way the more recent examples are (ie. the MCP23008 with only 8 gpio).

Any pointers/tips on where to start?

Thx!

Welcome to the community :+1: :wave:

Unfortunately that library is not set out to use an alternative I2C interface.
The easiest for your would probably be to alter the library sources and replace any instance of Wire with Wire3.

That’s what I was thinking, ok.

Quick update on this - replacing Wire with Wire3 in the SX base library works a treat, and I was pleasantly surprised to see that this works with minimal fuss.

Now a follow-on question - because the m8 connector can be disconnected and reconnected, I’m trying to implement an i2c test/recover function that resets i2c if the m8 is removed.

I’ve consolidated my i2c startup code to:

void init_i2c() {
    // cycle can pwr
    Log.trace("Cycling can power");
    digitalWrite(CAN_PWR, LOW);
    delay(500);
    digitalWrite(CAN_PWR, HIGH);
    delay(500);

    // start talking to i2c
    io.begin(SX1509_ADDRESS);
   // Wire3.setClock(100000);

    for (int i = 0; i < NUM_BUTTONS; i++) {
        Log.trace("Setting pin %d to INPUT",BUTTONS[i]);
        io.pinMode(BUTTONS[i], INPUT);
        delay(100);
    }
    
    // set led pins to outputs, give them a flash for good feels
    for (int i = 0; i < NUM_LEDS; i++) {
        Log.trace("Setting pin %d to ANALOG_OUTPUT",LEDS[i]);
        io.pinMode(LEDS[i], ANALOG_OUTPUT);
        delay(100);
        io.analogWrite(LEDS[i], 255);
        delay(100);
        io.analogWrite(LEDS[i], 0);
        // initialize our state tracker to off
        LED_STATE[i] = 0;
    }
}

In my setup(), I do:

void setup()
{
    Tracker::instance().init();

    // start i2c
    init_i2c();

    publishQueue.setup();
    Particle.subscribe("LED_STATE", receive_led_state);
    Particle.connect();
}

In loop() I do:

void loop()
{
    Tracker::instance().loop();

    // test i2c connected
    byte error;
    Wire3.beginTransmission(SX1509_ADDRESS);
    error = Wire3.endTransmission();
    if (error != 0) {
            blinkRed.setActive(true);
            Log.trace("No i2c devices connected (Error: %d)...trying again...", error);
            init_i2c();
            return;
    }
    blinkRed.setActive(false);

    for (int i = 0; i < NUM_BUTTONS; i++) {
        //Log.trace("Pin %d is: %d", BUTTONS[i], io.digitalRead(BUTTONS[i]));
        if (io.digitalRead(BUTTONS[i]) == HIGH) {
            while (io.digitalRead(BUTTONS[i]) == HIGH)
            ; //pause till button released
            button_pressed(i);
        }
    }
}

The error detection works fine, and it appears to reset ok - and in fact, my buttons (INPUTS) read fine after multiple disconnect/reconnect cycles. But my LED (ANALOG_OUTPUT) never recovers and it will no longer go on/off via analogWrite() later in loop();

I’ve tried several variations of placing io.begin, etc inside my loop, in setup only, etc, and can’t seem to get the LED to recover. If the m8 is connected at boot time, the LED works fine. And after disconnect/reconnect, if I usb reset it also recovers fine.

Since tracker doesn’t have it’s own external reset button, I’d really like it if it just reconnected and kept going.

Thoughts?

(built on toolchain 3.0.0, tracker-edge v12)

Fixed it - needed to add some longer delays to allow things to quiesce I guess. This allows me to disconnect the m8, and reconnect it - the system recovers and my leds work ok again.

void loop()
{
    Tracker::instance().loop();

    // test i2c connected
    byte error;
    Wire3.beginTransmission(SX1509_ADDRESS);
    error = Wire3.endTransmission();
    if (error != 0) {
            blinkRed.setActive(true);
            Log.trace("No i2c devices connected (Error: %d)...trying again...", error);
            delay(2000);
            init_i2c();
            return;
    }
    blinkRed.setActive(false);

    for (int i = 0; i < NUM_BUTTONS; i++) {
        //Log.trace("Pin %d is: %d", BUTTONS[i], io.digitalRead(BUTTONS[i]));
        if (io.digitalRead(BUTTONS[i]) == HIGH) {
            while (io.digitalRead(BUTTONS[i]) == HIGH)
            ; //pause till button released
            button_pressed(i);
        }
    }
}

…then…

void init_i2c() {
    // cycle can pwr
    Log.trace("Cycling can power");
    digitalWrite(CAN_PWR, LOW);
    delay(1000);
    digitalWrite(CAN_PWR, HIGH);
    delay(1000);

    // start talking to i2c
    io.begin(SX1509_ADDRESS);

    for (int i = 0; i < NUM_BUTTONS; i++) {
        Log.trace("Setting pin %d to INPUT",BUTTONS[i]);
        io.pinMode(BUTTONS[i], INPUT);
        delay(100);
    }
    
    // set led pins to outputs, give them a flash for good feels
    for (int i = 0; i < NUM_LEDS; i++) {
        Log.trace("Setting pin %d to ANALOG_OUTPUT",LEDS[i]);
        io.pinMode(LEDS[i], ANALOG_OUTPUT);
        delay(100);
        io.analogWrite(LEDS[i], 255);
        delay(100);
        io.analogWrite(LEDS[i], 0);
        // initialize our state tracker to off
        LED_STATE[i] = 0;
    }
}
1 Like