Hello friends, I need help with this issue which is way beyond me.
The setup uses a pico with cheap no-name GY-ADS1115 breakout boards from AliExpress. The ADS1115 boards have 10 kΩ pull-up resistors on SDA and SCL. Everything so far has been powered solely through the 3.3v pin of the pico.
The original setup used two ADS1115 boards connected to the pico in a star topology. ADDR was wired to VCC and GND. Each board had 4 SS49E hall effect sensors attached. The VCC and GND pins of the sensors were wired directly to the pico's 3.3v and GND pins. That setup worked successfully for an extended time with no sign of failure.
As soon as a third ADS1115 board (ADDR to SDA) was added with a single hall effect sensor, the two pico GPIO pins used for SDA and SCL got fried. I did not get it to work for a single second. As far as I could tell, they fried instantly.
I now know that TI recommends wiring ADDR to SCL for the 3rd board. But surely this wouldn't cause it to fry GPIO pins?
Anyway. The wiring was then changed from a star topology to a daisy-chain topology, with the third ADS1115 board placed first after the pico. Two new GPIOs were used for SDA and SCL.
That setup initially worked and read nominal hall effect sensor values from all 9 sensors, but after roughly 10 minutes, SCL began intermittently getting stuck low. The problem was initially transient: unplugging the pico and leaving it unpowered for several minutes could make the problem disappear temporarily. Eventually the two GPIOs used for SDA/SCL became permanently damaged.
I checked for solder bridges and miswiring, and I reflowed the SDA and SCL lines in case it was a cold joint which would explain why it got better after being unplugged for a bit. I kept the 2 known working boards and replaced the 3rd I had just added with a new one in case the 3rd board was defective. The same problem happened again. This time only SCL failed; SDA remained functional. So right now I'm standing at 5 burnt pins on this pico. I have no desire to risk a brand new pico or healthy pins until I have narrowed down the issue and have a way to guard against it.
I have tested the ADS boards with the pico disconnected from SDA and SCL :
For boards 1 and 2:
- VCC to GND: 3.31 V
- VCC to SCL: 0 V
- VCC to SDA: 0 V
For board 3:
- VCC to GND: 3.31 V
- VCC to SCL: 0 V
- VCC to SDA: 1.65 V when ADDR is connected to SDA
- VCC to SDA: 0 V when ADDR is disconnected from SDA
- SCL remained at the expected level regardless of ADDR
With power removed and disconnected from one another (i.e. broke the daisy chain), both board 1 and board 3 measured approximately:
- VCC to GND: 1.5 kΩ
- VCC to SDA: 10 kΩ
- SDA to GND: 11.5 kΩ
- VCC to SCL: 10 kΩ
- SCL to GND: 11.4 kΩ
The ADDR network was also measured:
- ADDR to VCC: 11.5 kΩ
- ADDR to GND: 10 kΩ
- ADDR to SCL: open
- ADDR to SDA: open
Both Board 1 and Board 3 showed essentially identical results.
With the ADS1115 connected as they would be in the setup, but with SCL and SDA disconnected from the pico :
- SDA to GND: 2.48v
- SCL to GND: 3.3v
The system was left in that state for at least 20 minutes and there was no change in the voltages. So no change spontaneously happens on the ADS side that would cause this.
The failed GPIOs were tested independently using code that would output the pin number and whether they read high or low. This was used with nothing connected to the pico for 20 minutes. The fried pins constantly reported being pulled low. No healthy pin started being pulled low for no reason.
The first SDA pin that was fried has approximately 64 Ω resistance to ground while the RP2040 is unpowered. The other fried pins are open.
As for the code, without pasting the whole thing here, this is what I do :
static void setup_i2c() {
Wire.setSDA(ADS1115_SDA_PIN); // GPIO12
Wire.setSCL(ADS1115_SCL_PIN); // GPIO13
Wire.begin();
Wire.setClock(100000); // 100 kHz
Wire.setTimeout(25); // 25 ms bus timeout
delay(100);
}
The ADS1115 initialization is:
[/code]void initSphereADC() {
setup_i2c();
uint8_t addrs[3] = {
ADS1115_I2C_1_ADDR,
ADS1115_I2C_2_ADDR,
ADS1115_I2C_3_ADDR
};
Adafruit_ADS1115 *boards[3] = {
&ads1, &ads2, &ads3
};
for (int b = 0; b < 3; b++) {
if (!boards[b]->begin(addrs[b])) {
// error reporting
}
boards[b]->setGain(ADS1115_GAIN);
boards[b]->setDataRate(RATE_ADS1115_860SPS);
}
}
The active firmware reads nine sensor channels. Each conversion uses startADCReading() followed by repeated calls to conversionComplete() for up to 10 ms.
[/code]static int16_t boundedADCRead(
Adafruit_ADS1115 &ads,
uint8_t channel,
int16_t &lastVal)
{
if (channel > 3) {
adcTotalReads++;
adcFaultReads++;
return lastVal;
}
ads.startADCReading(MUX_BY_CHANNEL[channel], false);
uint32_t t0 = millis();
while (!ads.conversionComplete() &&
(uint32_t)(millis() - t0) < ADC_READ_TIMEOUT_MS) {
// bounded wait
}
adcTotalReads++;
if (!ads.conversionComplete()) {
adcFaultReads++;
adcFaultStreak++;
if (adcFaultStreak > ADC_FAULT_BACKOFF_MAX)
adcFaultStreak = ADC_FAULT_BACKOFF_MAX;
delay(ADC_FAULT_BACKOFF_MS);
return lastVal;
}
adcFaultStreak = 0;
int16_t v = ads.getLastConversionResults();
if (v <= 0) {
adcFaultReads++;
adcFaultStreak++;
delay(ADC_FAULT_BACKOFF_MS);
return lastVal;
}
lastVal = v;
return v;
}
The active sensor-reading function accesses the three boards according to a fixed channel mapping:
static Adafruit_ADS1115 *boards[3] = {
&ads1, &ads2, &ads3
};
for (int i = 0; i < TOTAL_SENSORS; i++) { // TOTAL_SENSORS is 9.
sensorReads[i] =
boundedADCRead(
*boards[board_map[i]],
chan_map[i],
lastValid[i]);
}
I don't have a scope or a logic analyzer to test with.
I am at a loss as to why this setup is frying pins and would really like your input. Thank you!