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.
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);
}
};
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."
'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().