ESP32 mit zwei Multiplexern TCA9548a und VL6180X-Sensoren --> I2C-Probleme

Hallo zusammen,

nach einigen Mühen habe ich es geschafft, mit einem ESP32 zwei Mulitplexer des Typs TCA9548a und mehreren (Ziel sind 16) der o.g. Abstandssensoren (von Pololu) in Betrieb zu nehmen. Ich nehme den ESP32, da ich die Daten über Bluetooth versenden möchte.

Die anfängliche Freude ist mittlerweile jedoch getrübt, da ich nunmehr gemerkt habe, dass die Sensorwerte nicht mehr stimmen. Das ist mir anfangs leider nicht aufgefallen…

Wenn ich nur einen TCA9548a anschließe sind die Werte korrekt, sobald ich jedoch den anderen anschließe, bzw. die Sensoren , dann geben die falschen Werte aus. Stecke ich die Sensoren aus dem zweiten Mulitplexer aus oder nehme ihm die Spannung komplett weg, werden die Sensorwerte des ersten Mulitplexers wieder völlig korrekt angezeigt…?!

Nachdem ich mich etwas schlau gemacht habe, vermute ich, dass das etwas mit dem I2C-Bus zu tun hat, bzw. mit der Verbindung oder Verkabelung…Bitte korrigiert mich, wenn ich Quatsch rede oder auf der falschen Spur bin.

Ich habe jeweils an der SDA und der SDL-Leitung einen Pullup-Widerstand von 4,7 Ohm, unmittelbar an meinen Eingangspins des ESP zu 3V3. Über die Software schalte ich über einen Code-Schnipsel von combie https://forum.arduino.cc/index.php?topic=408117.0. die Register an oder aus.

Der gesamte Code lautet (zum Testen sind bisher 5 Sensoren am ersten und 2 am zweiten Mulitplexer angeschlossen):

#include <Wire.h>
#include <VL6180X.h>

#define TCA 0x70    // 1st TCA9548A 1-to-8 I2C Multiplexer Breakout
#define TCB 0x71   // 2nd TCA9548A 1-to-8 I2C Multiplexer Breakout

#define SDA 21
#define SCL 22

const int noSensors = 7;  // number of VL6180X sensors

int sensorIdx = 0;

VL6180X sensor0;
VL6180X sensor1;
VL6180X sensor2;
VL6180X sensor3;
VL6180X sensor4;

VL6180X sensor5;
VL6180X sensor6;

uint8_t sensVals[noSensors]; // array to store the sensor values
float sensPos[noSensors]; // array to store sensor positions

// variables to calculate the scale / sensor position along the scale
float startPos = 0.00;  // position of 1st sensor (0 mm in general)
float inc = 5.00; // increment between the sensors

void tcaselect(uint8_t i) {

      Wire.beginTransmission(TCB);
      Wire.write(0); // alle Ausgänge aus
      Wire.endTransmission(); 

      if (i > 7) return;
     
      Wire.beginTransmission(TCA);
      Wire.write(1 << i);
      Wire.endTransmission(); 
    }
    
void tcbselect(uint8_t i) {
      Wire.beginTransmission(TCA);
      Wire.write(0);  // alle Ausgänge aus
      Wire.endTransmission(); 

      if (i > 7) return;
     
      Wire.beginTransmission(TCB);
      Wire.write(1 << i);
      Wire.endTransmission(); 
}


void calcSensorPos(float* sensPos, float startPos, float inc) {

   for(int i = 0; i < noSensors; i++){
     sensPos[i] = inc*i + startPos;
   }
}

void setup(void) 
{
  Serial.begin(115200);  
  Wire.begin(SDA,SCL);  // Wire.begin([SDA], [SCL])

  Serial.println("VL6180X ToF-sensor Test"); Serial.println("");
  
  /* Initialise 1st sensor */
  tcaselect(0);
  sensor0.init();
  sensor0.configureDefault();
  sensor0.setTimeout(200);
    
  /* Initialise the 2nd sensor */
  tcaselect(1);
  sensor1.init();
  sensor1.configureDefault();
  sensor1.setTimeout(200);

    /* Initialise the 3rd sensor */
  tcaselect(2);
  sensor2.init();
  sensor2.configureDefault();
  sensor2.setTimeout(200);

  /* Initialise the 4th sensor */
  tcaselect(3);
  sensor3.init();
  sensor3.configureDefault();
  sensor3.setTimeout(200);

  /* Initialise sensor no. 5 */
  tcaselect(4);
  sensor4.init();
  sensor4.configureDefault();
  sensor4.setTimeout(200);

    /* Initialise sensor no. 6 */
  tcbselect(0);
  sensor5.init();
  sensor5.configureDefault();
  sensor5.setTimeout(200);

  /* Initialise sensor no. 7 */
  tcbselect(1);
  sensor6.init();
  sensor6.configureDefault();
  sensor6.setTimeout(200);

  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Print out the sensor position values of the scale
  //
  Serial.println("sensor positions in mm:");
  calcSensorPos(sensPos,startPos,inc);  
  for(int i = 0; i < noSensors; i++)
  {
    Serial.print(sensPos[i]);Serial.print(" | ");
  }
  Serial.println();
  Serial.println();

  delay(5000);
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++
}

void loop(void) 
{

  //++++++++++++++++++++++++++++
  // 1st multiplexer +++++++++++
  //++++++++++++++++++++++++++++
  
  // sensor 1 -------------------------
  tcaselect(0);
  //Serial.print(sensor1.readRangeSingleMillimeters());
  if (sensor0.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
  sensVals[0]=sensor0.readRangeSingleMillimeters();
  // ----------------------------------
   
  // sensor 2 -------------------------
  tcaselect(1);
  //Serial.print(sensor1.readRangeSingleMillimeters());
  if (sensor1.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
  sensVals[1]=sensor1.readRangeSingleMillimeters();
  // ----------------------------------

  // sensor 3 -------------------------
  tcaselect(2);
  //Serial.print(sensor1.readRangeSingleMillimeters());
  if (sensor2.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
  sensVals[2]=sensor2.readRangeSingleMillimeters();
  // ----------------------------------

  // sensor 4 -------------------------
  tcaselect(3);
  //Serial.print(sensor1.readRangeSingleMillimeters());
  if (sensor3.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
  sensVals[3]=sensor3.readRangeSingleMillimeters();
  // ----------------------------------

  // sensor 5 -------------------------
  tcaselect(4);
  //Serial.print(sensor1.readRangeSingleMillimeters());
  if (sensor4.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
  sensVals[4]=sensor4.readRangeSingleMillimeters();
  // ----------------------------------

  //++++++++++++++++++++++++++++
  // 2nd multiplexer +++++++++++
  //++++++++++++++++++++++++++++
  
  // sensor 6 -------------------------
  tcbselect(0);
  //Serial.print(sensor1.readRangeSingleMillimeters());
  if (sensor5.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
  sensVals[5]=sensor5.readRangeSingleMillimeters();
  // ----------------------------------

  // sensor 7 -------------------------
  tcbselect(1);
  //Serial.print(sensor1.readRangeSingleMillimeters());
  if (sensor6.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
  sensVals[6]=sensor6.readRangeSingleMillimeters();
  // ----------------------------------
  
  // Print out the sensor values
  for(int i = 0; i < noSensors; i++)
  {
    Serial.print(sensVals[i]);Serial.print(" | ");
  }
  
  Serial.println();
    
  delay(200);
}

Die Verkabelung habe ich so wie im beigefügten Bild gemacht. Ich habe nur einen Sensor eingezeichnet. Die anderen werden analog, jeweils an den SCxx und SDxx-Pins angeschlossen.

Jetzt die Frage: Habt Ihr eine Idee, an was das liegen könnte? Was mich stutzig macht, ist die Tatsache, dass die Werte nach wegnehmen der Spannung / Ausstecken der Sensoren des zweiten Multiplexers wieder korrekt werden (und das auch ohne Software, die diesen berücksichtigt)? Das spricht doch für einen Hardware-Fehler, bzw. fehlerhafte Anschlüsse bei mir oder seht Ihr in der Software einen Fehler?

Es wäre sehr nett, wenn mir der eine oder andere einen Lösungshinweis hätte.

Meldet Euch bitte bei Fragen - ich bin nicht der Beste im Erklären. Habe mir aber Mühe gegeben.

Euch vielen Dank und viele Grüße

Bire

Tja...

Die Signalqualität kannst du mit einem Oszilloskop messen/sehen.
Die Daten mit einem LogicAnalyser untersuchen

Hier findest du solche Bildchen und auch Links zu I2C Dokus

Hallo Combie,

vielen Dank für Deine schnelle Antwort. Leider ist mir (erst jetzt) etwas ein-, bzw. aufgefallen: Wenn ich einen I2C-Scanner laufen lasse und ich nur ein Gerät (Adresse 0x70) finde, dann muss ich doch hier schon suchen, oder?

Nochmal Danke und Grüße

Bire

Du hast beide Multiplexer auf der selben I2C Adresse , also bei beiden sind die Adress-Ansclhüsse A0, A1, A2 offen. Somit reagieren beide auf die gleiche Adresse. So bekommen 2 Sensoren Gleichzeitig die Aufforderung, daten zu senden, und tun dies auch, damit können die Sensordaten nicht mehr korrekt sein.

Schliesse z.B. A0 des ersten Multiplexers an GND an. Und A0 des zweiten Multiplexers an V IN. dann reagieren beide auf unterschiedliche Adressen.
Welche das sind , kannst du in der Doku zu den Multiplexern rausfinden, oder Du lässt nen I2C-Scanner Sketch laufen und notierst dir die Adressen. Am einfachsten ist es, wenn du dazu nur einen Multiplexer anschliesst und den skecht 2 mal laufen lässt, 1 x mit A0 auf GND und 1x mit A0 auf V IN. und jedesmal die Adresse notieren auf der der Multiplexer gefunden wird.

LG Stefan

Die Adressen der Multiplexer musst du über die Pins A0-A2 einstellen. Das fehlt irgendwie. Wenn das nicht gemacht wird laufen beide mit der gleichen Adresse

Etwas Off Topic, aber lege dir mal vernünftige Datenstrukturen für deine Sensoren an:

struct Sensor
{
   VL6180X sensor;
   uint8_t sensVal;
   float sensPos;
};

Sensor sensors[noSensors];

Dann kannst du ganz einfach alle Sensoren ansprechen:

for (byte i = 0; i < noSensors; i++)
{
  tcaselect(i);
  sensors[i].sensor.init();
  sensors[i].sensor.configureDefault();
  sensors[i].sensor.setTimeout(200);
}

Das behebt nicht das eigentliche Problem, aber es macht den Code wesentlich kürzer und übersichtlicher

Die Auswahl des Multiplexers könnte man auch schöner machen und die Multiplexer Nummer direkt aus der Kanal-Nummer berechnen. Durch Division und Division mit Rest kann man eine Zahlenreihe bequem auf diskrete Blöcke aufteilen.
z.B.:
7 : 7 / 8 = 0 (MUX 0), 7 % 8 = 7 (Kanal 7)
8: 8 / 8 = 1 (MUX 1), 8 % 8 = 0 (Kanal 0)
10: 10 / 8 = 1 (MUX 1), 10 % 8 = 2 (Kanal 2)

Dann kannst du deine Sensoren durchnummerieren und für jeden Berechnen zu welchem Multiplexer und welchem Kanal darauf er gehört. Irgendwelche Fallunterscheidungen entfallen

Hallo Leute,

auf Schwäbisch heisst es: Herr schmeiss Hirn ra… :slightly_smiling_face: :blush: : Peinlich, peinlich…

Ich entschuldige mich bei Euch, dass ich Eure Zeit gestohlen habe. Ich denke, jetzt bin ich einen Schritt weiter…siehe Bilder.

Nochmal sorry, DANKE an Euch alle und Grüße

Bire

Forum_I2C_Scanner.PNG

Du hast mir keine Zeit gestohlen . Ich hab sie Dir geschenkt.

LG Stefan

Hallo Stefan,

trotzdem: VIELEN DANK!

Ihr seid wirklich klasse!

Ich werde das heute oder morgen noch einmal aufbereiten und dann hier reinstellen, damit nicht noch einmal jemand auf dem Schlauch steht wie ich.

Grüße

Bire