Crash when addressing Adafruit_TMAG5273

Hi All. I did a basic test of this sensor, and it was working fine, using the following code:

/*!
 * @file simpletest.ino
 * @brief Simple test for the Adafruit TMAG5273 3-axis Hall-effect sensor
 *
 * Reads magnetic field (X, Y, Z in uT) and temperature, prints to serial.
 *
 * Written by Limor 'ladyada' Fried with assistance from Claude Code
 * MIT license
 */

#include <Adafruit_TMAG5273.h>

Adafruit_TMAG5273 tmag;

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    delay(10);
  }

  Serial.println(F("Adafruit TMAG5273 Simple Test"));

  if (!tmag.begin()) {
    Serial.println(F("Failed to find TMAG5273 sensor!"));
    while (1) {
      delay(10);
    }
  }
  Serial.println(F("TMAG5273 found!"));

  Serial.print(F("Manufacturer ID: 0x"));
  Serial.println(tmag.getManufacturerID(), HEX);
  Serial.print(F("Device ID: 0x"));
  Serial.println(tmag.getDeviceID(), HEX);
  bool is_x2 = (tmag.getDeviceID() & 0x03) == 0x02;
  Serial.print(F("Variant: "));
  Serial.println(is_x2 ? F("x2 (+/-133/266 mT)") : F("x1 (+/-40/80 mT)"));

    // Smoothest is 32x
  tmag.setConversionAverage(TMAG5273_CONV_AVG_32X);
  // low noise uses more power
  tmag.setLowNoiseMode(true);
  // for rare earth magnets
  tmag.setMagTempComp(TMAG5273_TEMPCO_NDFEB);
  // magnetic trigger available for power saving, see docs.
  // may need to recalibrate
  tmag.setXYRangeWide(false);
}

void loop() {
  float y = tmag.readMagneticY();
  y = - y;
  if (y < 2000) y = 2000;
  if (y > 14400) y = 14400;
  Serial.println(y);


  delay(2000);
}

Then I connected several up to a multiplexer, and I'm getting a crash when I try to read the sensor with this code:

#include <ESP32Servo.h>
#include <Adafruit_TMAG5273.h>
#include <Wire.h>

// create servo object to control a servo
Servo servo1;

///once this is working, try an array
Adafruit_TMAG5273 knee1;
Adafruit_TMAG5273 knee2;

//should have an array here
int k1bus = 1;  //this is the bus number
int k2bus = 2;

//int servo1Bus = 1;

// GPIO pin used to connect the servo
// Recommended PWM GPIO pins on the ESP32 include 2,4,12-19,21-23,25-27,32-33
int servoPin = 2;

// Select MPX Out
void setBus(uint8_t bus){
  Wire.beginTransmission(0x70);  // TCA9548A address
  Wire.write(1 << bus);          // send byte to select bus
  Wire.endTransmission();
}

void initSensor(uint8_t bus, Adafruit_TMAG5273 sensor) {
  setBus(bus);  
  if (!sensor.begin(0x35)) {  //sensor.begin(0x35, &I2C_1);
    Serial.print(F("Failed to find sensor "));
    Serial.println(bus);
    while (1); 
  }
  Serial.print(F("sensor found: "));
  Serial.println(bus);
  Serial.print(F("Manufacturer ID: 0x"));
  Serial.println(sensor.getManufacturerID(), HEX);
  Serial.print(F("Device ID: 0x"));
  Serial.println(sensor.getDeviceID(), HEX);
  bool is_x2 = (sensor.getDeviceID() & 0x03) == 0x02;
  Serial.print(F("Variant: "));
  Serial.println(is_x2 ? F("x2 (+/-133/266 mT)") : F("x1 (+/-40/80 mT)"));

  sensor.setConversionAverage(TMAG5273_CONV_AVG_32X);
  sensor.setLowNoiseMode(true);
  sensor.setMagTempComp(TMAG5273_TEMPCO_NDFEB);
  sensor.setXYRangeWide(false);
}

void setup() {
  // Allow allocation of all timers
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);

  Serial.begin(115200);
  while (!Serial) {
    delay(10);
  }

  //Wire.begin(SDA_1, SCL_1, I2C_FREQ1);  //which color cable is which?
  Wire.begin();

  //I2C_1.begin(SDA_1, SCL_1, I2C_FRQ1);  //Multiple busses
  //I2C_2.begin(SDA_2, SCL_2, I2C_FRQ2);

  initSensor(k1bus, knee1);
  delay(1000);
  initSensor(k2bus, knee2);

  // Standard 50hz servo.  can it run at 100??   
  servo1.setPeriodHertz(100);
  servo1.write(90);
  // attach the servoPin to the servo object and set the sweep range
  // For SG90, 500 and 2400 might be more suitable
  // different servos may require different min/max settings
  servo1.attach(servoPin, 500, 2500 ); //do we halve these when we double period??? guess not.

setBus(k1bus);
  delay(5000);
  float test = knee1.readMagneticY();  //EPS crashes here!
  Serial.println(test);
  //setTune(k1bus, knee1, servo1Bus, servo1);
}

void loop() {
}

Both sensors initialize fine. The multiplexing seems to work:

08:35:39.595 -> 
08:35:39.759 -> Rebooting...
08:35:39.759 -> ���ESP-ROM:esp32s3-20210327
08:35:39.759 -> Build:Mar 27 2021
08:35:39.759 -> rst:0xc (RTC_SW_CPU_RST),boot:0x28 (SPI_FAST_FLASH_BOOT)
08:35:39.759 -> Saved PC:0x40378cda
08:35:39.759 -> SPIWP:0xee
08:35:39.759 -> mode:DIO, clock div:1
08:35:39.759 -> load:0x3fce2820,len:0x10cc
08:35:39.759 -> load:0x403c8700,len:0xc2c
08:35:39.759 -> load:0x403cb700,len:0x30b0
08:35:39.759 -> entry 0x403c88b8
08:35:39.921 -> sensor found: 1
08:35:39.921 -> Manufacturer ID: 0x5449
08:35:39.921 -> Device ID: 0x5
08:35:39.921 -> Variant: x1 (+/-40/80 mT)
08:35:40.935 -> sensor found: 2
08:35:40.935 -> Manufacturer ID: 0x5449
08:35:40.935 -> Device ID: 0x5
08:35:40.935 -> Variant: x1 (+/-40/80 mT)

But when I try to read the first sensor I get a crash:

08:35:40.935 -> Getting Pedal Position:  Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
08:35:41.067 -> 
08:35:41.067 -> Core  1 register dump:
08:35:41.067 -> PC      : 0x4202850d  PS      : 0x00060730  A0      : 0x8200364d  A1      : 0x3fcec020  
08:35:41.067 -> A2      : 0x00ff0000  A3      : 0x3fcec04e  A4      : 0x00000001  A5      : 0x3fcec0a5  
08:35:41.067 -> A6      : 0x00000002  A7      : 0x00000000  A8      : 0x00ff0000  A9      : 0x3fcec010  
08:35:41.067 -> A10     : 0x3fcefc70  A11     : 0x00000000  A12     : 0x00000000  A13     : 0x00060f23  
08:35:41.067 -> A14     : 0x00000001  A15     : 0x3fcefc1c  SAR     : 0x00000000  EXCCAUSE: 0x0000001c  
08:35:41.067 -> EXCVADDR: 0x00ff0010  LBEG    : 0x400556d5  LEND    : 0x400556e5  LCOUNT  : 0xfffffff9  
08:35:41.067 -> 
08:35:41.067 -> 
08:35:41.067 -> Backtrace: 0x4202850a:0x3fcec020 0x4200364a:0x3fcec040 0x4200365d:0x3fcec070 0x42003222:0x3fcec090 0x4200329d:0x3fcec0d0 0x42002342:0x3fcec0f0 0x420025fb:0x3fcec120 0x420026c5:0x3fcec160 0x42009270:0x3fcec1f0 0x4037c331:0x3fcec210
08:35:41.067 -> 
08:35:41.067 -> 
08:35:41.067 -> 
08:35:41.067 -> 
08:35:41.067 -> ELF file SHA256: e94dc9079
08:35:41.067 -> 
08:35:41.197 -> Rebooting...

I really don't know how to further troubleshoot this. To be clear, the first code does run fine, even with the multiplexer in line. It just runs through output 0 to the sensor.

Thoughts?

And when you ran the backtrace through an analyzer, what part of your code did it indicate it crashed in? That's among the most important bits of information and you left it out.

Never Mind

I didn't scroll the serial monitor all the way down.... at the least, this is not the actual problem. Please close.

EDIT: see the actual problem code below

Please explain:

I have not heard of such a thing.

Okay, here is the code that is actually breaking:

#include <ESP32Servo.h>
#include <Adafruit_TMAG5273.h>
#include <Wire.h>



// create servo object to control a servo
Servo servo1;

///once this is working, try an array
Adafruit_TMAG5273 knee1;
Adafruit_TMAG5273 knee2;

//should have an array here
int k1bus = 2;  //this is the bus number
int k2bus = 3;

//int servo1Bus = 1;

// GPIO pin used to connect the servo
// Recommended PWM GPIO pins on the ESP32 include 2,4,12-19,21-23,25-27,32-33
int servoPin = 2;



// Select I2C BUS
void setBus(uint8_t bus){
  Wire.beginTransmission(0x70);  // TCA9548A address
  Wire.write(1 << bus);          // send byte to select bus
  Wire.endTransmission();
}


void initSensor(uint8_t bus, Adafruit_TMAG5273 sensor) {
  setBus(bus);  
  if (!sensor.begin(0x35)) {  //sensor.begin(0x35, &I2C_1);
    Serial.print(F("Failed to find sensor "));
    Serial.println(bus);
    while (1); 
  }
  Serial.print(F("sensor found: "));
  Serial.println(bus);
  Serial.print(F("Manufacturer ID: 0x"));
  Serial.println(sensor.getManufacturerID(), HEX);
  Serial.print(F("Device ID: 0x"));
  Serial.println(sensor.getDeviceID(), HEX);
  bool is_x2 = (sensor.getDeviceID() & 0x03) == 0x02;
  Serial.print(F("Variant: "));
  Serial.println(is_x2 ? F("x2 (+/-133/266 mT)") : F("x1 (+/-40/80 mT)"));

  sensor.setConversionAverage(TMAG5273_CONV_AVG_32X);
  sensor.setLowNoiseMode(true);
  sensor.setMagTempComp(TMAG5273_TEMPCO_NDFEB);
  sensor.setXYRangeWide(false);
}
// min and max vals get mapped to tenths of a degree for ped up and dn
int getPedalPos(Adafruit_TMAG5273 pedal) {
  Serial.print("Getting Pedal Position:  ");
  int min = 2000;  //we will query these from prefs
  float test = pedal.readMagneticY();   //ESP CRASHES HERE
  Serial.println(test);
  int val = round(test);
  if (val == min) return -1; //at rest, don't compute anything
  else {
    int max = 14400;
    int pull = 700; // 0-1000, from UI/prefs. Need to convert to degrees
    val = abs(val);           // vals all negative or all positive, I think!
    if (val < min) val = min;
    if (val > max) val = max;            // will be different for each pedal
    val = map(val, min, max, 500, pull);     // min pedal pos is always 500. Pull is 0-1000.
    val = map(val, 0, 1000, 450, 1350);    //convert to tenths of a degree. PULL is between 45 and 135 degrees. Rest is 900.
    return val;
  }
  
}

void setup() {
  // Allow allocation of all timers
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);

  Serial.begin(115200);
  while (!Serial) {
    delay(10);
  }

  //Wire.begin(SDA_1, SCL_1, I2C_FREQ1);  //which color cable is which?
  Wire.begin();

  //I2C_1.begin(SDA_1, SCL_1, I2C_FRQ1);  //Multiple busses
  //I2C_2.begin(SDA_2, SCL_2, I2C_FRQ2);

  initSensor(k1bus, knee1);
  delay(1000);
  initSensor(k2bus, knee2);

  // Standard 50hz servo.  can it run at 100??   
  servo1.setPeriodHertz(100);
  servo1.write(90);
  servo1.attach(servoPin, 500, 2500 ); //do we halve these when we double period??? guess not.

setBus(k1bus);
  delay(5000);
  //float test = knee1.readMagneticY();
 int test = getPedalPos(knee1);
  Serial.println(test);
  //setTune(k1bus, knee1, servo1Bus, servo1);
}

void loop() { 
}

In the meantime, I will try to find out what a backtrace analyzer is.

I read v2 of the arduino ide does not support tools.

Do I need to install a 1.x version to use the exception decoder?

At any rate, I'm not seeing it in the tools menu, after putting the .jar file in the tools folder in my sketch folder at:

Arduino/tools/EspExceptionDecoder/tool

I did restart the IDE

I think something may be wrong with the sensor initialization.

Try changing

void initSensor(uint8_t bus, Adafruit_TMAG5273 sensor)

to

void initSensor(uint8_t bus, Adafruit_TMAG5273 &sensor)

You are currently passing the sensor object by value, so initSensor() initializes a copy rather than knee1 or knee2 itself.

It is still crashing at the same spot. Do I need to call the getPedalPos() method differently?

I wonder if I'll ever get C++ pointers figured out...

EDIT:

I tried also

int getPedalPos(Adafruit_TMAG5273 &pedal)

and it still crashes on the same line....

You have to pass the sensor by reference in both functions. Just add & here:

void initSensor(uint8_t bus, Adafruit_TMAG5273 &sensor)

and here:

int getPedalPos(Adafruit_TMAG5273 &pedal)

That's all. The function calls stay unchanged.

Okay that did it.

THANKS!!!!!!!!!!!!!!!!!

I still cannot get used to the serial monitor not clearing between compilation sequences....

Great, glad that fixed it.

And yes, the Serial Monitor keeping old output between uploads can be pretty confusing while debugging. There is a Clear Output button in the Serial Monitor, though. You have to clear it manually — it doesn't clear automatically between uploads.

Right, and you can't clear it while uploading because the Output window keeps topping....

That's why I normally put this directly after Serial.begin(), three times:

Serial.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++");
Serial.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++");
Serial.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++");

Makes it easy to see where the new run starts.

Brilliant!

Okay, so if I want to address a particular sensor by the bus number associated with it, and I have the sensors in an array, how do I change my method? I just re-read the pointer docs, and I'm still not sure. I'm guessing there are multiple ways to do it....

Here's what I mean:


Adafruit_TMAG5273 sensors[4];

void setTune(uint8_t bus, uint8_t srv) {
  setBus(bus);  //set the i2c bus
  //what's the syntax here?
  Adafruit_TMAG5273 &sensor = sensors[bus];  
  int pos = getPedalPos(sensor);
}

Looking at it fresh, I think I can just do:


Adafruit_TMAG5273 sensors[4];

void setTune(uint8_t bus, uint8_t srv) {
  setBus(bus);  //set the i2c bus 
  int pos = getPedalPos(sensor[bus]);
}

Just use the global reference...