Passing Wire or Wire1 selection to a class instance

Help!
While __SPISettings creates a way to pass an SPI channel structure to a class I cannot find how to pass a Wire (I2C) channel to a class. I am using two I2C channels and need to pass the channel number/structure to the class. Something like __SPISettings would be great.

What do you mean with I2C channel?

If you refer to the slave ID then you will pass that in the Wire.beginTransmission() call.

If you refert to the I2C interface object (Wire vs. Wire1) you need to do that via a “placeholder” variable (for that case that’d be the same for SPI vs. SPI1).

Thanks for your reply. I want to pass Wire or Wire1 to a class or sub-class as a parameter when initialized. Ideal would be with something like __SPISettings.

I’m pretty certain SPISettings doesn’t do that either.
SPISettings() are to be used with a SPI.beginTransaction() or SPI1.beginTransaction() call respectively. There is no way to pass in which SPI interface object you intend to “tie” it to.

Can you provide a link where this “feature” would be suggested to exist?

However, as I said, you can make the interface selection dynamic.

e.g. like this


void someWireCall(TwoWire& wire) {
  wire.beginTransmission(id);
  wire.write(0xFF);
  wire.endTransmission();
}

void loop() {
  ...
  someWireCall(Wire);
  someWireCall(Wire1);
  ...
}

Thanks again for your reply.
Yes it works great. The __SPI Setting is a struct which holds the variable data to configure an SPI channel. You define the struct then you can pass the pointer to the struct when you instigate a class giving that instance the correct configuration for that SPI channel. For example, create the struct:
__SPISettings spi_sd(30* MHZ, MSBFIRST, SPI_MODE0); // create the SPISetting for the SD card, 35Mhz MAX
then pass it:
SdCardPrintHandler SdPrintToCard(sd, SD_cs_pin, spi_sd); // enable printf to SD log.

If you have another way to accomplish what I need I am all ears. I have several I2C classes which are inherited by layers of classes adding methods. I want to reuse the class changing the I2C channel when instantiated.

Exactly what I'm saying. Via SPISettings you are not passing anything containing a reference to SPI or SPI1 but only some information about how you want to set the interface.
In your call above the sd parameter is the reference to which SPI interface you want these settings applied to.

So again, as you would pass SPI or SPI1 into the function via sp (not spi_sd) you'd pass Wire or Wire1 into the function the way I already outlined above (by use of a reference parameter of type TwoWire& - also works for classes :wink: / alternatively you could use a pointer TwoWire* wire and then in your classes use wire->write()).

Which other settings pertaining to Wire or Wire1 would you want to pass?
Via a WireTransmission object you can pass some settings like the slave ID, timeout and stop flag. You cannot change the bus speed or enable/disable clock stretching between clients that way tho'.

Got it, you are right. I misunderstood this. I see what you are saying and I am going back to implement this in my code. Thanks.

1 Like

More confusion. I cannot see how I pass the TwoWire &wire to a class. What am I missing?

If you show what you tried and how we may be able to see the issue :wink:

Thanks again for your help with this.
I have multiple instances of the oxygen cell class which have alternate inherited classes based in the driver method. The issue I have is when the oxygen class inherits an I2C class. I need to pass either Wire or Wire1 and the I2C address to the I2C (INA) class. I do not understand how to get the Wire or Wire1 to the INA class.
For example, in the task I create the objects:
O2CELL Cell1 (size, 2100, 0x40, Wire);
O2CELL Cell2 (size, 2100, 0x41, Wire1);

In the I2C driver class I have:

class INA{
 public:
  INA(int addr, TwoWire& wire);
 private:
  TwoWire *wire;
  int _addr;
};
INA::INA(int addr, TwoWire& wire) 
{
  _addr = addr;
}

Then methods like this:

void INA::begin(void)
 {
  if (!wire->isEnabled()) { wire->begin(); }    
 };

In the oxygen cell class:

#include "INA.h"
class O2CELL : public INA{
public:
O2CELL(int size, int seed, int addr, TwoWire& wire);
};
O2CELL::O2CELL(int size, int seed, int addr, TwoWire& wire)
{
 _size = size;
_seed = seed:
 };

When you are using a reference (TwoWire& wire) you would use it as wire.begin().
References are not pointers but just another "name" for the original entity.

This syntax wire->begin() would require _wire to be a pointer (i.e. TwoWire *_wire) any you'd need to assign the pointer as this._wire = &wire (have the member variable _wire point to the address of the parameter reference wire). To keep things clear it's good practice to use distinct names for parameters and member variables.

However, when you are using a reference variable in a class you'd need to initialize it via the construction initialization list.

class INA {
  public:
    INA(TwoWire& wire, uint8_t addr) : _wire(wire), _addr(addr) { };

  private:
    TwoWire& _wire;
    uint8_t  _addr;
}

Derived classes can call the base constructor like this

class O2CELL : public INA {
  public:
    O2CELL(TwoWire& wire, uint8_t addr, int size, int seed) 
    : INA(wire, addr), _size(size), _seed(seed) { };
  ...
}
2 Likes

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