Multiplexer issue

Hey, I have run into a programming question, if someone might be able to help me. I'm trying to work with an Adafruit TCA9548A multiplexer, but haven't yet been able to control / or read a motor / sensor connected to it.

I am trying to send messages to a DRV2605 haptic motor driver. The attached code works where I connect the haptic driver directly to the Lolin ESP32 module I'm using - I am sending 1 / 0s over serial from a music software programme to trigger the pre-programmed waveforms on the LRA motor attached to the haptic driver.

However, when, I put the multiplexer in the circuit (as in the photo attached - consistent with the recommended Adafruit setup Wiring & Test | Adafruit TCA9548A 1-to-8 I2C Multiplexer Breakout | Adafruit Learning System ) - and direct the haptic activation code to the scl/sda address the haptic driver is connected to, the LRA motor doesn't respond.

I don't think it's a hardware issue - I have run a scanner sketch on the I2C device and the microcontroller recognises a multiplexer at the 0X70 address. So, it's more likely that there is an error in my code.

Would greatly appreciate any feedback on where I may be going wrong

Best
Jess


vibrotactile14.ino (1.3 KB)

Hard to say until some actual code is seen.

The OP may want to go to the Github Adafruit site for the AdaFruit library that is being used. There the OP can read about recent issues with the library and see if they apply to the OP.

OP as the TCA9548A operating voltage is between 1.8 and 5V, would you happen to be running the TCA9548A at 5V and the O/P lines of the TCA9548A are directly connected to the ESP32? I ask because the ESP32 is NOT 5V tolerant.

After zooming the image, I see 3.3V is being used.

And you may need pull up resistors on the SCL/SDA lines.

Hi,
Can you post a circuit diagram please, so we can see the I/O and power supply connections.

To add code please click this link;

Thanks.. Tom... :grinning: :+1: :coffee: :australia:

Hi, sorry I added the code as an attachment... here it is..

#include <Wire.h>
#include <drv2605.h>
#define TCAADDR 0x70

DRV2605 haptic;

int incomingByte = 0; // for incoming serial data

void tcaselect(uint8_t i2c_bus) {
    if (i2c_bus > 7) return;
    Wire.beginTransmission(TCAADDR);
    Wire.write(1 << i2c_bus);
    Wire.endTransmission();   
}

void setup() {

  Serial.begin(115200); // opens serial port, sets data rate 
      if (haptic.init(false, true) != 0) Serial.println("init failed!");
    if (haptic.drv2605_AutoCal() != 0) Serial.println("auto calibration failed!");
    delay(2000);
}

// Initialize the displays 
void hapticInit(){
    for (int i = 0; i < 7; i++) {
      tcaselect(i);   // Loop through each connected displays on the I2C buses  
      haptic.drv2605_Play_Waveform(4);
    }
}

void loop() 

{
  tcaselect(0);
    
  // send data only when you receive data:
  if (Serial.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial.read();

    // say what you got:
    Serial.print("I received: ");
    Serial.println(incomingByte, DEC);

    if(incomingByte == 0) {
      haptic.drv2605_Play_Waveform(1); // play  xx
      //haptic.goWait();    
    }

    else{
      if(incomingByte == 1) {
      haptic.drv2605_Play_Waveform(4); // play  xx
     // haptic.goWait();
    }    
  }
}
}

I'm using:

The pinouts are the same as in the adafruit tutorial;

The TCA Multiplexer breakout board is connected to 3.3V, Ground, SCL and SDA on the microcontroller. I use a 3.3V supply because that is the operating voltage of the Lolin D32 board and adafruit recommend connecting the multiplexer at the power supply of the controller. The DRV2605 haptic driver board is then connected to the SC0/SD0 pins on the multiplexer.

TCA Vin -> D32 3.3V
TCA Gnd -> D32 Gnd
TCA SDA -> D32 SDA
TCA SCL -> D32 SCL
TCA SC0 -> DRV SCL
TCA SD0 -> DRV SDA
DRV Vin -> D32 3.3V
DRV Gnd -> D32 Gnd

I asked the adafruit customer support forum about resistors for the circuit for a setup of 8 haptic driver / LRA pairs with their multiplexer (Adafruit customer service forums • View topic - Multiple DRV2605 project). I will be independently powering the LRAs, but for now I'm using the microcontroller's power with just have the one haptic driver / LRA pair setup while I'm working on the coding. I am using a 2ohm 2 watt resistor and I have this connected in-between the DRV2605 driver and the LRA attached to it.

In terms of testing - if I connect the haptic driver / LRA setup directly to the D32 controller, it works fine. It is only when I add the multiplexer as an intermediary that I am encountering a problem. I have also run some basic setup tests on the multiplexer and the controller is able to detect an I2C device attached to the D32 at the 0x70 address.

Best
Jess

An Adafruit Metro, as pictured in post #5 is not a Lolin ESP32 module. Which only serves to confuse the issue and is a step backwards in trying to solve your issue.

Hi,

TECHNICAL DETAILS

Detailed specifications:

  • ATmega328 microcontroller with Optiboot (UNO) Bootloader
  • USB Programming and debugging via the well-supported genuine CP2104
  • Input voltage: 7-9V (a 9VDC power supply is recommended)
  • 5V regulator can supply peak ~800mA as long as the die temp of the regulator does not exceed 150*C
  • 3.3V regulator can supply peak ~150mA as long as the die temp of the regulator does not exceed 150*C
  • 5V logic with 3.3V compatible inputs, can be converted to 3.3V logic operation
  • 20 Digital I/O Pins: 6 are also PWM outputs and 6 are also Analog Inputs
  • 6-pin ICSP Header for reprogramming
  • 32KB Flash Memory - 0.5K for bootloader, 31.5KB available after bootloading
  • 16MHz Clock Speed
  • Compatible with "Classic" and "R3" Shields
  • Adafruit Black PCB with gold plate on pads
  • 53mm x 71mm / 2.1" x 2.8"
  • Height (w/ barrel jack): 13mm / 0.5"
  • Weight: 19g

Tom.... :grinning: :+1: :coffee: :australia:

Hi,
Can I suggest you;
Get a pen(cil).
Get a piece of paper.
And DRAW your circuit.
Include pin labels and component names.
Then post a picture of your circuit.

You are in troubleshooting mode and need to produce a diagram that will help us all.
Picture of your project does help, but actual connections are hard ti see and comprehend.

Tom... :grinning: :+1: :coffee: :australia:

if (haptic.init(false, true) != 0) Serial.println("init failed!");
    if (haptic.drv2605_AutoCal() != 0) Serial.println("auto calibration failed!")

Do you see these error messages on serial monitor?

If so, maybe you need to use tcaselect() before them in setup() because those code lines may be attempting to access the device over the i2c bus.

I'm curious, given you have a breadboard-friendly esp32 board, why are you not allowing it to be friends with your breadboard?

Hi, sorry, here's a drawing of the circuit..

Thanks PaulRB - I don't receive either of the error messages, but I was wondering about that too. I tried the following modification to the code, interestingly the "I received: 1" etc is now printing to the serial monitor in-line with the messages I am sending over serial from the music software programme. However, the LRA motor is still not activating.

#include <Wire.h>
#include <drv2605.h>
#define TCAADDR 0x70

DRV2605 haptic;

int incomingByte = 0; // for incoming serial data

void tcaselect(uint8_t i2c_bus) {
    if (i2c_bus > 7) return;
    Wire.beginTransmission(TCAADDR);
    Wire.write(1 << i2c_bus);
    Wire.endTransmission();   
}

// Initialize the displays 
void hapticInit(){
    for (int i = 0; i < 7; i++) {
      tcaselect(i);   // Loop through each connected displays on the I2C buses  
      if (haptic.init(false, true) != 0) Serial.println("init failed!");
    if (haptic.drv2605_AutoCal() != 0) Serial.println("auto calibration failed!");
    delay(2000);
    }
}

void setup() {

  Serial.begin(115200); // opens serial port, sets data rate 

}


void loop() 

{
  tcaselect(0);
    
  // send data only when you receive data:
  if (Serial.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial.read();

    // say what you got:
    Serial.print("I received: ");
    Serial.println(incomingByte, DEC);

    if(incomingByte == 0) {
      haptic.drv2605_Play_Waveform(1); // play  xx
      //haptic.goWait();    
    }

    else{
      if(incomingByte == 1) {
      haptic.drv2605_Play_Waveform(4); // play  xx
     // haptic.goWait();
    }    
  }
}
}

When I first upload a new code to the D32 with the DRV haptic driver and LRA attached directly to the microcontroller the LRA buzzes when the code is done uploading, but when I have it attached to the multiplexer it does not.

(yes not trying to be unfriendly with my breadboard! - just keeping space for the extra haptic drivers I'll be adding and not sure on the layout yet.)

Best
Jess

Hi,
Do you have pullup resistors on the I2C bus lines?

Tom.. :grinning: :+1: :coffee: :australia:

Hi Tom, I don't no. I had assumed that the adafruit multiplexer breakout would have pull-ups integrated, but I've gone through their data sheets and I can't find confirmation that they are built in. It's odd though, that the tutorial diagram doesn't show any resistors being used. But perhaps you are right.

Hi,
Worth a try...
:grinning: :+1: :coffee: :australia:

Looks like you created a new function hapticInit()? It's not used!

Get more breadboards. You can clip them together.

Thanks all.

Paul RB, ah ok, thanks I added the hapticInit function to the void setup.

I did go through the resistors / circuit in some detail with adafruit, and the wiring is standard, so I suspect the issue is with the code. I pieced it together from examples off the internet and some existing code I had for triggering the DRV waveforms. But, perhaps, I'm missing something?

Currently you have one haptic driver attached to channel 0 of the multiplexer?

I think Adafruit made a special version of the i2c scanner sketch which scans all the channels of a multiplexer and detects all devices attached to each channel. Does that pick up your haptic driver? The standard i2c scanner sketch will only detect the multiplexer itself.

If not, you may have a hardware problem. If it does detect the haptic driver, maybe try changing your code so it does not loop round all 8 multiplexer channels, just limit it to using channel 0 only ( i < 1 in the for loops).

oh yes, you are right, thanks I checked the Adafruit scanner and it does recognise the haptic driver at "TCA Port #0 Found I2C 0x5A" so at least that confirms its not a hardware issue.

It must be my code. I'll keep looking into other examples to see if I can figure out what I'm missing. Ideally I'd like to preserve the cycling through functions because I will be adding other haptic drivers to the setup.

What I'm thinking is that it the code might be failing because it is trying to access 7 haptic drivers that are not there. If you limit the for-loop in hapticInit() to just the one that exists, does that work?

oh of course, yes I see thanks. I've got a bit further with the code, making some edits - I tested it with and without cycling through the haptic drivers and got the same result. Now, when I upload the code the LRA buzzes when the code is uploaded when it is connected via the multiplexer. Also, if I load the code when the DRV / LRA is directly connected to the D32 controller, and then switch over the connection to the multiplexer, when I send serial bytes to the controller the waveforms play through the LRA.

(New code - full)

#include <Wire.h>
#include <drv2605.h>
#define TCAADDR 0x70

DRV2605 haptic0;
DRV2605 haptic1;
DRV2605 haptic2;
DRV2605 haptic3;
DRV2605 haptic4;
DRV2605 haptic5;
DRV2605 haptic6;
DRV2605 haptic7;

int incomingByte = 0; // for incoming serial data

void useLRA();

void tcaselect(uint8_t i) {
    if (i > 7) return;
    Wire.beginTransmission(TCAADDR);
    Wire.write(1 << i);
    Wire.endTransmission();   
}

void setup() {

  while (!Serial);
    delay(1000);

    Wire.begin();
  
  Serial.begin(115200); // opens serial port, sets data rate 
  hapticInit(); // Initialize the motors 

}

void hapticInit(){
    for (uint8_t t=0; t<8; t++) {
     tcaselect(t);   // Loop through each connected displays on the I2C buses
     //tcaselect(0); 
      if (haptic0.init(false, true) != 0) Serial.println("init failed!");
    if (haptic0.drv2605_AutoCal() != 0) Serial.println("auto calibration failed!");
        delay(2000);
    }
}


void loop() {

    tcaselect(0);
    
  // send data only when you receive data:
  if (Serial.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial.read();

    // say what you got:
    Serial.print("I received: ");
    Serial.println(incomingByte, DEC);

    if(incomingByte == 0) {
      haptic0.drv2605_Play_Waveform(1); // play  Strong Click 1 - 100%
      //haptic.goWait();    
    }

    else{
      if(incomingByte == 1) {
      haptic0.drv2605_Play_Waveform(4); // play  Pulsing Medium 1 – 60%
     // haptic.goWait();
    }
      

}
}
}

What's not yet working though, is if I try to upload the code with the DRV / LRV connected via the multiplexer. The message in the console says that initialisation failed, (although it also says this when the DRV / LRA is directly connected to the controller and then works ok), which suggests it's to do with this part of the code..

(New code - exert)

void setup() {

  while (!Serial);
    delay(1000);

    Wire.begin();
  
  Serial.begin(115200); // opens serial port, sets data rate 
  hapticInit(); // Initialize the motors 

}

void hapticInit(){
    for (uint8_t t=0; t<8; t++) {
     tcaselect(t);   // Loop through each connected displays on the I2C buses
     //tcaselect(0); 
      if (haptic0.init(false, true) != 0) Serial.println("init failed!");
    if (haptic0.drv2605_AutoCal() != 0) Serial.println("auto calibration failed!");
        delay(2000);
    }
}

Replace

DRV2605 haptic0;
DRV2605 haptic1;
DRV2605 haptic2;
DRV2605 haptic3;
DRV2605 haptic4;
DRV2605 haptic5;
DRV2605 haptic6;
DRV2605 haptic7;

with

DRV2605 haptic[8];

and in hapticInit(), change it to

    tcaselect(t);   // Loop through each connected haptic drivers on the I2C buses
    Serial.print("Initialising haptic driver on channel ");
    Serial.print(t);
    Serial.print(": ");
    if (haptic[t].init(false, true) != 0) Serial.println("init failed!");
    else if (haptic[t].drv2605_AutoCal() != 0) Serial.println("auto calibration failed!");
    else Serial.println("OK");

Also please Auto-Format your code before you post it again!