Crashes when using I2C i/o expander inside a class

I've been trying to figure this out for hours and I don't understand the problem, any ideas?

I'm using a sparkfun SX1509 i/o expander board connected to 16 leds with the arduino Giga. When I do everything in my main .ino file it all works as expected but when I try to create a class containing everything related to the SX1509 and it's leds the Giga crashes.

The sketch compiles without problems or warnings but the Giga crashes when upload is finished.

main.ino file:

#include <Wire.h>
#include <SparkFunSX1509.h>
#include "Leds.h"
//initialize the SX1509 object to be used to interface with it
SX1509 io;

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

  //Sets the I2C adress for the SX1509
  const byte SX1509_ADDRESS = 0x3E;
  if (io.begin(SX1509_ADDRESS) == false) {
    Serial.println("Failed to communicate. Check wiring and address of SX1509.");
  }
}

//Initializing the leds object passing a reference to the io object.
//Without this line the Giga does NOT crash.
Leds leds(io); //Putting this line inside the setup() prevents the giga from crashing but then it is out of scope to use in my code. 

void loop() {
  //method for testing if it works. The Giga does crashes without this to. 
  leds.ledOn(3);
}

This is my Leds.h file:

#ifndef LEDS_H
#define LEDS_H

#include <Wire.h>
#include <SparkFunSX1509.h>

class Leds {
private:
  SX1509& io;  // Reference to SX1509 object
  int nrOfPinsUsed = 15;
public:
  Leds(SX1509& sx1509)
    : io(sx1509) {

    //Set pinMode for all SX1509 pins.
    for (int i = 0; i <= nrOfPinsUsed; i++) {
      io.pinMode(i, OUTPUT);
    }
  }

  //Leds are setup in a sinking way so writing LOW turnes the leds on.
  void ledOn(int i) {
    io.digitalWrite(i, LOW);
  }
};

#endif

Your constructor runs before the setup function. I.e. before the platform and the I2C interface are initialized. Add a separate begin function to initialize the pin modes, and call that at the end of your setup.

1 Like

Also tried declaring and initialising the SX1509 object inside a class and it compiles fine but the Giga still crashes when doing it this way.

main.ino code:

#include <Wire.h>
#include <SparkFunSX1509.h>
#include "IOExpander.h"

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

IOExpander leds;

void loop() {
  //testing if it works, crashes with loop() empty to.
  leds.setPinModeAll();
  leds.ledOn(3);
}

IOExpander.h code:

#include <Wire.h>
#include <SparkFunSX1509.h>

class IOExpander {
private:

public:
  SX1509 io;
  const int nrOfPinsUsed = 16;

  IOExpander() {
    const byte SX1509_ADDRESS = 0x3E;
    io.begin(SX1509_ADDRESS);
  }

  //Set pinMode for all SX1509 pins.
  void setPinModeAll() {
    for (int i = 0; i < nrOfPinsUsed; i++)
      io.pinMode(i, OUTPUT);
  }


  //Leds are setup in a sinking way so writing LOW turnes the led on.
  void ledOn(int i) {
    io.digitalWrite(i, LOW);
  }
};

Did you read Post #2???

2 Likes

I removed the for loop for setting the pinMode from the constructor and it works now. But I'm a little confused about why?

The leds objects is not initialised until after the setup() function if I write it after the setup() function right? So I'm not sure I understand why my "constructor runs before the setup function. I.e. before the platform and the I2C interface are initialized."

I have now but did not see it before my second post, sorry!

'io' is a global variable. The constructors for global variables will run before the setup() function. That means your constructor calls io.pinMode() before Wire.begin() is called in setup().

Damn, I did not know that. Thank you very much!!!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.