I'm using the Arduino IDE (v1.8.19) with the Earle Philhower core to program a Raspberry Pi Pico (RP2040) board.
I2C bus 0 of the Pico (pins 4 (SDA) and 5 (SCL) are coupled to a first MCP23017 port expander (address 0x26) which drives 16 leds.
I2C bus 1 of the Pico (pins 26 (SDA) and 27 (SCL) are coupled to a second MCP23017 port expander (address 0x21) which drives a second set of 16 leds.
I want to be able to initialize and control each of the two separate I2C busses. I've been able to do that successfully using the following code which has a function init_IIC(..) that I can pass TwoWire class objects Wire (for i2c0) and Wire1 (for i2c1). That code is below and it works perfectly in that it causes the connected LEDs on each MCP23017 to blink sequentially.
My question is why doesn't my OOP version of that code, which is set out further below work?
//This is the 'function' initializing version of the code which is working on Rpi Pico
// with two separate IIC bus devices running.
#include <Adafruit_MCP23X17.h>
#include <Wire.h>
#define SDA0_PIN 4 //IIC pins for the Wire device (i2c0)
#define SCL0_PIN 5
#define SDA1_PIN 26 //IIC pins for the Wire1 device (i2c1)
#define SCL1_PIN 27
Adafruit_MCP23X17 mcp0;
const byte addr0 = 0x26;
Adafruit_MCP23X17 mcp1;
const byte addr1 = 0x21;
void init_IIC (Adafruit_MCP23X17 &mcp, byte addr, byte sdaPin, byte sclPin, TwoWire &iicDevice) {
TwoWire &icDevice = iicDevice;
bool initialised = false;
icDevice.setSDA(sdaPin);
icDevice.setSCL(sclPin);
icDevice.begin();
while (!initialised) {
initialised = mcp.begin_I2C(addr, &icDevice);
delay(80);
}
// iicDevice = icDevice; //Turns out this line isn't necessary for it to work.
}
void setup() {
init_IIC (mcp0, addr0, SDA0_PIN, SCL0_PIN, Wire);
for (byte i = 0; i < 16; i++) {
mcp0.pinMode(i, OUTPUT);
mcp0.digitalWrite(i, LOW);
}
init_IIC (mcp1, addr1, SDA1_PIN, SCL1_PIInN, Wire1);
for (byte i = 0; i < 16; i++) {
mcp1.pinMode(i, OUTPUT);
mcp1.digitalWrite(i, LOW);
}
}
void loop() {
for (byte i = 0; i < 16; i++) {
mcp0.digitalWrite(i, HIGH);
mcp1.digitalWrite(i, HIGH);
delay(170);
mcp0.digitalWrite(i, LOW);
mcp1.digitalWrite(i, LOW);
delay(200);
}
}
Below is the OOP version of the code. Although the code compiles, it doesn't cause the LEDs to blink sequentially.
#include <Adafruit_MCP23X17.h>
#include <Wire.h>
#define SDA0_PIN 4
#define SCL0_PIN 5
#define SDA1_PIN 26
#define SCL1_PIN 27
Adafruit_MCP23X17 mcp0;
const byte addr0 = 0x26;
Adafruit_MCP23X17 mcp1;
const byte addr1 = 0x21;
class MCPiic {
private:
Adafruit_MCP23X17 mcp;
byte addr = 0;
byte sdaPin = 0;
byte sclPin = 0;
TwoWire &iicDevice = Wire;
public:
MCPiic() {};
MCPiic(Adafruit_MCP23X17 &_mcp, byte _addr, byte _sdaPin, byte _sclPin, TwoWire &_iicDevice) {
mcp = _mcp;
addr = _addr;
sdaPin = _sdaPin;
sclPin = _sclPin;
iicDevice = _iicDevice;
}
void init() {
bool initialised = false;
iicDevice.setSDA(sdaPin);
iicDevice.setSCL(sclPin);
iicDevice.begin();
while (!initialised) {
initialised = mcp.begin_I2C(addr, &iicDevice);
delay(80);
}
for(byte i=0; i<16; i++){
mcp.pinMode(i,OUTPUT);
mcp.digitalWrite(i,LOW);
}
}
void on(byte onPin){
mcp.digitalWrite(onPin,HIGH);
}
void off(byte offPin){
mcp.digitalWrite(offPin,LOW);
}
};
MCPiic mcpIIC_0 (mcp0, addr0, SDA0_PIN, SCL0_PIN, Wire);
MCPiic mcpIIC_1 (mcp1, addr1, SDA1_PIN, SCL1_PIN, Wire1);
void setup() {
mcpIIC_0.init();
mcpIIC_1.init();
}
void loop() {
for (byte i = 0; i < 16; i++) {
mcpIIC_0.on(i);
mcpIIC_1.on(i);
delay(170);
mcpIIC_0.off(i);
mcpIIC_1.off(i);
delay(200);
}
}
The second (OOP) version (i.e. the one that doesn't work) makes one LED on one port of each MCP23017 turn on. All the other LEDs remain off and there is no sequential blinking of the LEDs, as occurs with the first (function) version of the code. By "sequential blinking" I mean that the led on A0 (pin 0) port of each MCP turns on and then turns off and then the led on the A1 port of each turns on and then off up to port B7 (pin 15) and then repeats, as coded in the loop() of each of the posted codings.
More precisely, it is the LED that is connected to port B4 of the MCP23017 on the first (i2c0) bus that comes on when the OOP code is uploaded. No other LEDs come on on either of the MCP23017s and the Rpi PICO seems to freeze and a "the last USB device you connected has malfunctioned" warning message comes up in Windows 10. I then have to reboot the Rpi PICO to be able to upload the first version of the code again.
I suspect that the problem with the OOP version is to do with passing by reference but I'm not sure and although I've tried many different variations I can't get the OOP version to make the LEDs blink in the same manner as the first "function" version. Any helpful suggestions would be greatly appreciated. I realise that I could put both MCP23017s on the same i2c bus with different addresses but I don't want to do that. If possible I would like to get the OOP version to work. Thanks!
mcp.pinMode(i,LOW);
in theMCPiic::init()
basically canceled what you are setting one line beforemcp.pinMode(i,OUTPUT);
, it should really bemcp.digitalWrite(i, LOW);
.