Hello….I have the SparkFun Qwiic Mux Breakout - 8 Channel (TCA9548A) and I am using chatgpt to help me code for a project. i am making a 6 foot rope light with 6 pods and each pod has 1 led and 1 SparkFun Triple Axis Magnetometer Breakout - MLX90393 (Qwiic)
| I am also using the redboard with the qwiic connector built in. Channels 0-3 work perfectly but channels 4-7 do nothing. I am only using 6 channels and I have tested using channels 6 and 7 and still nothing happens. I have ran some test code to see if the channels are being seen when a sensor is plugged into it and it does but when i run the full code, nothing happens. Chatgpt suggests that something is wrong with the soldering but i wanted to reach out here to see if I could get some help. here is the full code I am using.
| /************ 6× MLX90393 via TCA9548A + 6× WS2812B |
|---|
- Fast updates • per-pod re-zero • auto sensitivity per environment
- Idle = low-intensity deep purple; Level 6 = pulsing red
- Board: SparkFun RedBoard Qwiic (Uno-compatible)
- MUX: TCA9548A @ 0x70, channels 0..5 (pod 1→CH0 … pod 6→CH5)
- Sensor: MLX90393 @ 0x0C
- LED: WS2812B on D6 (add 330Ω in series to first DIN; ≥470µF cap across 5V/GND)
*************************************************************************************/
#include <Wire.h>
#include <Adafruit_MLX90393.h>
#include <Adafruit_NeoPixel.h>
#include <math.h>
// ---------------------- CONFIG ----------------------
#define NUM_NODES 6
#define TCA_ADDR 0x70
#define MLX_ADDR 0x0C
#define LED_PIN 6
#define LED_BRIGHTNESS 120
#define LOOP_DELAY_MS 20 // snappy updates
// Node → MUX channel mapping (0..5 nodes → mux 0..5)
const uint8_t muxChannel[NUM_NODES] = {0, 1, 2, 3, 4, 5};
// Base thresholds (relative to baseline), in microteslas (sensitive)
const float BASE_THRESH[6] = { 1.0, 3.0, 8.0, 25.0, 60.0, 120.0 };
// Effective thresholds (after environment scaling)
float effThresh[6];
// Colors for levels 0..6: {R,G,B}
// Level 6 is Red (pulsing), Level 5 is Purple
uint8_t COLORS[7][3] = {
{ 0, 0, 0 }, // 0: Off (we override with idle purple)
{ 0, 0, 40 }, // 1: Blue
{ 0, 80, 160 }, // 2: Aqua
{ 0, 200, 40 }, // 3: Green
{ 220,140, 0 }, // 4: Amber
{ 180, 0, 200 }, // 5: Purple
{ 220, 20, 0 } // 6: Red (pulsing)
};
// Idle (no detection) color (low-intensity deep purple)
const uint8_t IDLE_R = 50, IDLE_G = 0, IDLE_B = 80;
// Pulse settings (for Level 6)
const uint16_t PULSE_PERIOD_MS = 1200; // full pulse period
const uint8_t PULSE_MIN = 40; // min intensity (0..255)
const uint8_t PULSE_MAX = 255; // max intensity (0..255)
// Environment scaling params
const float NOISE_LOW = 0.5f; // uT: very quiet
const float NOISE_HIGH = 5.0f; // uT: very noisy
const float SCALE_MIN = 0.5f; // thresholds = 0.5× base in quiet env (more sensitive)
const float SCALE_MAX = 2.0f; // thresholds = 2× base in noisy env (less sensitive)
// ---------------------- GLOBALS ----------------------
Adafruit_MLX90393 mlx[NUM_NODES];
bool sensorOK[NUM_NODES] = {false};
float baseline[NUM_NODES] = {0.0f};
float ambientNoise[NUM_NODES] = {0.0f}; // avg |mag - baseline| during calibration
Adafruit_NeoPixel strip(NUM_NODES, LED_PIN, NEO_GRB + NEO_KHZ800);
// ---------------------- MUX ----------------------
void tcaSelectNode(uint8_t node) {
if (node >= NUM_NODES) return;
uint8_t ch = muxChannel[node];
Wire.beginTransmission(TCA_ADDR);
Wire.write(1 << ch);
Wire.endTransmission();
}
// ---------------------- LED helpers ----------------------
void ledSet(uint8_t idx, uint8_t r, uint8_t g, uint8_t b) {
if (idx < NUM_NODES) strip.setPixelColor(idx, strip.Color(r,g,b));
}
void ledAll(uint8_t r, uint8_t g, uint8_t b) {
for (uint8_t i=0;i<NUM_NODES;i++) strip.setPixelColor(i, strip.Color(r,g,b));
strip.show();
}
void ledAllOff() { ledAll(0,0,0); }
void fadeOne(uint8_t idx, uint8_t maxV=160, uint8_t step=12, uint16_t d=5) {
for (uint8_t v=0; v<=maxV; v+=step){ ledSet(idx,v,v,v); strip.show(); delay(d); }
for (int v=maxV; v>=0; v-=step){ ledSet(idx,v,v,v); strip.show(); delay(d); }
ledSet(idx,0,0,0); strip.show();
}
void blinkAll(uint8_t r,uint8_t g,uint8_t b,uint8_t times=2,uint16_t onMs=80,uint16_t offMs=60){
for(uint8_t i=0;i<times;i++){ ledAll(r,g,b); delay(onMs); ledAllOff(); delay(offMs); }
}
void startupAnimation(){
ledAllOff();
for(uint8_t i=0;i<NUM_NODES;i++){ fadeOne(i,160,12,5); delay(10); }
blinkAll(180,180,180,2,80,60);
// go to idle purple
for (uint8_t i=0;i<NUM_NODES;i++) ledSet(i, IDLE_R, IDLE_G, IDLE_B);
strip.show();
}
// Level mapping using effective thresholds
uint8_t levelFromDelta(float d){
if (d < effThresh[0]) return 0;
if (d < effThresh[1]) return 1;
if (d < effThresh[2]) return 2;
if (d < effThresh[3]) return 3;
if (d < effThresh[4]) return 4;
if (d < effThresh[5]) return 5;
return 6;
}
// Cosine-based pulse (smooth 0..1..0)
uint8_t pulseValue() {
float phase = (float)(millis() % PULSE_PERIOD_MS) / (float)PULSE_PERIOD_MS * 6.2831853f; // 2π
float f = 0.5f * (1.0f - cosf(phase)); // 0..1
float val = PULSE_MIN + f * (PULSE_MAX - PULSE_MIN);
if (val < 0) val = 0; if (val > 255) val = 255;
return (uint8_t)(val + 0.5f);
}
// ---------------------- Threshold scaling ----------------------
void recomputeEffectiveThresholds() {
// Compute global noise estimate (average of channels that had noise)
float sumNoise = 0.0f;
uint8_t count = 0;
for (uint8_t ch=0; ch<NUM_NODES; ch++) {
if (sensorOK[ch] && ambientNoise[ch] > 0.0f) {
sumNoise += ambientNoise[ch];
count++;
}
}
float globalNoise = 0.0f;
if (count > 0) globalNoise = sumNoise / count;
// Map noise → scale factor
float scale;
if (globalNoise <= NOISE_LOW) {
scale = SCALE_MIN;
} else if (globalNoise >= NOISE_HIGH) {
scale = SCALE_MAX;
} else {
float t = (globalNoise - NOISE_LOW) / (NOISE_HIGH - NOISE_LOW); // 0..1
scale = SCALE_MIN + t * (SCALE_MAX - SCALE_MIN);
}
// Compute effective thresholds
for (uint8_t i=0; i<6; i++) {
effThresh[i] = BASE_THRESH[i] * scale;
}
// Debug output
Serial.print(F("Global noise ~ “));
Serial.print(globalNoise, 2);
Serial.print(F(” uT, sensitivity scale = "));
Serial.println(scale, 2);
Serial.println(F(“Effective thresholds (uT):”));
for (uint8_t i=0; i<6; i++) {
Serial.print(F(" T"));
Serial.print(i);
Serial.print(F(" = "));
Serial.println(effThresh[i], 2);
}
Serial.println();
}
// ---------------------- Baselines + noise ----------------------
void captureBaselineFor(uint8_t node, uint8_t samples=16, uint16_t sampleDelayMs=10) {
ambientNoise[node] = 0.0f;
baseline[node] = 0.0f;
if (!sensorOK[node]) return;
tcaSelectNode(node);
delay(2);
float mags[32];
if (samples > 32) samples = 32;
uint8_t good = 0;
// Collect samples
for (uint8_t i=0; i<samples; i++) {
float x,y,z;
if (mlx[node].readData(&x,&y,&z)) {
float m = sqrtf(xx + yy + z*z);
if (good < 32) {
mags[good] = m;
good++;
}
}
delay(sampleDelayMs);
}
if (good == 0) {
baseline[node] = 0.0f;
ambientNoise[node] = 0.0f;
Serial.print(F(“Re-zero node “)); Serial.print(node);
Serial.println(F(” → no valid samples”));
return;
}
// Compute baseline
float sum = 0.0f;
for (uint8_t i=0; i<good; i++) sum += mags[i];
float base = sum / good;
baseline[node] = base;
// Compute average absolute deviation as noise measure
float devSum = 0.0f;
for (uint8_t i=0; i<good; i++) {
devSum += fabs(mags[i] - base);
}
ambientNoise[node] = devSum / good;
Serial.print(F(“Re-zero node “)); Serial.print(node);
Serial.print(F(” (mux ch “)); Serial.print(muxChannel[node]);
Serial.print(F(”) → baseline=”)); Serial.print(baseline[node],2);
Serial.print(F(" uT, noise=“)); Serial.print(ambientNoise[node],2);
Serial.println(F(” uT"));
}
void captureBaselinesAll(uint8_t samples=16, uint16_t sampleDelayMs=10) {
Serial.println(F(“Baseline in 2s… keep magnets away.”));
delay(1000); Serial.println(F(“1…”)); delay(900);
for (uint8_t node=0; node<NUM_NODES; node++) {
captureBaselineFor(node, samples, sampleDelayMs);
}
// After all nodes sampled, compute environment-based thresholds
recomputeEffectiveThresholds();
}
// ---------------------- SETUP ----------------------
void setup() {
Serial.begin(9600);
while(!Serial){}
Serial.println(F(“\n== EMF String v2 (mux 0..5): Idle purple, auto sensitivity, pulsing red max ==”));
Wire.begin(); // ~100kHz
delay(5);
strip.begin();
strip.setBrightness(LED_BRIGHTNESS);
strip.show();
startupAnimation();
// Init sensors with higher gain/OSR/filter for better range
for (uint8_t node=0; node<NUM_NODES; node++) {
tcaSelectNode(node);
delay(2);
Wire.beginTransmission(MLX_ADDR);
uint8_t err = Wire.endTransmission();
Serial.print(F(“Node “)); Serial.print(node);
Serial.print(F(” (mux ch “)); Serial.print(muxChannel[node]); Serial.print(F(”)”));
if (err != 0) {
Serial.println(F(" : no I2C response"));
sensorOK[node] = false;
continue;
}
if (mlx[node].begin_I2C(MLX_ADDR, &Wire)) {
mlx[node].setGain(MLX90393_GAIN_5X);
mlx[node].setOversampling(MLX90393_OSR_2);
mlx[node].setFilter(MLX90393_FILTER_4);
sensorOK[node] = true;
Serial.println(F(" : MLX90393 OK (gain/OSR/filter set)“));
} else {
sensorOK[node] = false;
Serial.println(F(” : begin_I2C failed"));
}
}
// Initial baselines + environment-based thresholds
captureBaselinesAll();
Serial.println(F(“Serial keys: ‘0’..‘5’ re-zero that pod; ‘a’ re-zero ALL.\n”));
}
// ---------------------- LOOP ----------------------
void loop() {
// Re-zero controls
if (Serial.available()) {
char c = Serial.read();
if (c >= ‘0’ && c <= ‘5’) {
uint8_t node = (uint8_t)(c - ‘0’);
if (node < NUM_NODES) {
captureBaselineFor(node);
recomputeEffectiveThresholds(); // thresholds may change slightly
}
} else if (c == ‘a’ || c == ‘A’) {
captureBaselinesAll();
}
}
// Pulse value for Level 6 once per frame
uint8_t pulse = pulseValue();
for (uint8_t node=0; node<NUM_NODES; node++) {
if (!sensorOK[node]) {
ledSet(node, IDLE_R, IDLE_G, IDLE_B);
continue;
}
tcaSelectNode(node);
delayMicroseconds(120);
float x,y,z;
if (mlx[node].readData(&x,&y,&z)) {
float mag = sqrtf(x*x + y*y + z*z);
float d = mag - baseline[node];
uint8_t lvl = levelFromDelta(d);
if (lvl == 0) {
// No detection → idle purple
ledSet(node, IDLE_R, IDLE_G, IDLE_B);
} else if (lvl == 6) {
// Level 6: pulsing red
uint8_t r = (uint16_t)COLORS[6][0] * pulse / 255;
uint8_t g = (uint16_t)COLORS[6][1] * pulse / 255;
uint8_t b = (uint16_t)COLORS[6][2] * pulse / 255;
ledSet(node, r, g, b);
} else {
// Normal levels 1..5 (solid colors)
uint8_t *c = COLORS[lvl];
ledSet(node, c[0], c[1], c[2]);
}
} else {
// Read failed → idle purple
ledSet(node, IDLE_R, IDLE_G, IDLE_B);
}
}
strip.show();
delay(LOOP_DELAY_MS);
}