SCL line "pauses" for no reason?

Hello, Arduino-ers, I'm pretty new at Arduino and programming and any help would be greatly appreciated. :slight_smile:

So, I am working on a project where I have nine 3-axis magnetic sensors (MMC5603), an accelerometer, and an EEPROM connected to the Arduino, all with which I want to communicate using I2C (But for the scope of this question, I will be focusing only on the magnet sensors). The I2C signal is distributed to the nine magnetic sensors through a 16 channel Multiplexer (CD74HC4067), which is switched/controlled by 4 digital pins. The I2C sensors all require 3.3V, but the MUX requires a 5V power supply. I checked all the device addresses, they are different from each other.

After building a PCB with incorrect Arduino Nano schematics (idk how that happened), I connected the Analog pins for SDA (A4) and SCL (A5) to the correct traces. I wrote some code using the Wire library, having it output the raw magnet sensor values to a serial monitor. I noticed that it would not always print data to the serial monitor, but if I uploaded/ran the code several times, I could sometimes get data that looked reasonable, but oftentimes I would get raw values of -1 and 0. (this corresponds to all 1s or 0s in two's complement binary)

I hooked up an oscilloscope to the SDA and SCL lines to see what was happening and I saw some really weird stuff, even when I tried this code on both an Arduino Uno and Nano...

  1. Before I re-uploaded the code, the SCL line was creating a PWM of random? widths varying between .5-5? ms, with a total range of about 4.6-4.7V. When I was previously communicating with an experimental board that only had one magnet sensor, I saw that the usual SCL wavelength was usually 10 us. (I did get good data back from this experimental board)
  2. When I uploaded the code, the oscilloscope saw the SCL line begin to create a 5 us waveform and it looked like the SDA line was sending data to the appropriate sensor. After about 100-150 us, in the middle of a byte (and sometimes in the middle of a pulse), the SCL line pulls low/high (whichever state the SDA line closest to, as this sometimes happens in the middle of a pulse), and holds it low for about 100 us, then picks back up right where it left off, often in the middle of a byte. (see picture) This happens several times while writing/reading to/from the sensor, and I think these interruptions are what are causing the correct outputs to not be given.
  3. When I disconnected the 5V line from the Uno board, the power drops to 0V, then jumps back up to 5V, then degrades into a PWM with a decreasing duty cycle over maybe .5 s. When I reconnect it, it goes back to the random .5-5 ms width square wave as mentioned in 1.
  4. Even though I wrote the code to repeatedly ping the magnet sensor, the Arduino would eventually "give up" or time out, because it would go back to the state mentioned in 1, and there would be no signals sent on the SDA line.

I don't understand what's going on, especially since the code worked on a single sensor previously. And honestly, it's probably a stupid-simple reason that I'm unaware of... Or maybe my board is haunted. Please help me to not believe in ghosts... :stuck_out_tongue:

Thank you!!!
Please see attached schematic and code.

Puzzlebox controller rev_.pdf (138.9 KB)

#include <Wire.h>
#include <WireData.h>

const int MMCAddressW = 0x30; //device write address

#define Control_Register0 0x1B
#define Device_Status1 0x18

int X0,X1,Y0,Y1,Z0,Z1,X_out,Y_out,Z_out;
unsigned long X_byt, Y_byt, Z_byt;


void setup() {
  Wire.begin(); // Initiate the Wire library
  //Wire.setClock(115200);
  Serial.begin(115200);
  delay(100);

}
void loop() {
  // Set chip for accurate measurements
  Wire.beginTransmission(MMCAddressW);
  Wire.write(Control_Register0);
  Wire.write(0x08); //Set signal
  Wire.endTransmission();
  
  // Enable measurement
  Wire.beginTransmission(MMCAddressW);
  Wire.write(Control_Register0);
  Wire.write(0x21); // m measuring enable with auto-reset (0010 0001) 
  Wire.endTransmission(); 

  delayMicroseconds(10); //10 us delay for sensor to detect m field

  // reads registers 0x00 to 0x05, the internal memory address pointer automatically moves to the next byte.
  Wire.beginTransmission(MMCAddressW);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(MMCAddressW,6);
  X0 = Wire.read();
  X1 = Wire.read();
  Y0 = Wire.read();
  Y1 = Wire.read();
  Z0 = Wire.read();
  Z1 = Wire.read();
  //data manipulation to 16 bit value
  X_out = 0;
  Y_out = 0;
  Z_out = 0;
  X_byt = (X0<<8) | (X1);
  Y_byt = (Y0<<8) | (Y1);
  Z_byt = (Z0<<8) | (Z1);
  X_out = X_byt-32768; 
  Y_out = Y_byt-32768;
  Z_out = Z_byt-32768; 

  //prints and separates raw data output
  
  Serial.println("--------------------");
  Serial.println(X_out);
  Serial.println(Y_out);
  Serial.println(Z_out);
  Serial.println("--------------------");
  Serial.println("");

  delayMicroseconds(100);
}

could you edit your post and use code tags? Yea, that thingy you skipped over reading had all the poop on how to do postings and other good things.

So, yea, code tags?

BTW how fast are you asking the magnetothingy to send you data vs how fast does the mangetothingy gather data? You may be reading the manetothingy too fast, see the magnetothingy spec sheet for the magnetothingy data ready rates.

Ok, looks like the sensor default time to take sensor data is 6.6 ms. I added a 7 ms delay into my code before reading the sensor. Unfortunately, that did not fix anything.

Thanks for the tip about the code tags!

Are you using pull up resistors? Does the sensor have built in pullup resistors? Does adding a new sensor put another set of pull up resistors across the lines?

If you are not using pull up resistors it may be time to add them.

Have you changed the sensors I2C address's?

I guess my first question is does the same issue appear without the multiplexer?

Yes, I have connected the 10k pull-up resistors correctly.

No, I haven't changed the I2C addresses.

I have another evaluation board, some gridboard with 3.3 kohm pull-up resistors and a 2.2 uF capacitor. I'm able to communicate with it just fine, no issues. The MUX is active when the Enable line is pulled LOW (this line is connected to GND so it's always on), then it reads the state of the 4 address pins (which don't have any signal going to them, so, default state is LOW).

It should work, I think.

Thank you to JohnRob and Idahowalker for such quick responses!

There is so much going on !

You may share the SCL, but perhaps a buffer/amplifier is needed for the SCL. If there are no processors that can pull the SCL low, then you don't need the open-drain with the pullup and it can be a strong HIGH/LOW signal. However, the magnetometers say that they do processing on the chip. That is confusing.

The multiplexer should have valid signals on the address pins. They are now floating ?

Is your Arduino Nano a 5V board ? Then you have a voltage mismatch on the I2C bus. With so many things connected to the I2C bus, it must match.

SDA is not D4
SCL is not D5

Who is making the 3.3V ? Some Arduino Nano boards use the 3.3V from a usb-serial chip, that is not a serious voltage that can be used for so many things.

Does the INT1 signal have a pullup resistor ?

I suggest to take a step back.
Make a small sketch that sets A0...A3 for the mux and then run a I2C Scanner function for every I2C bus. Let it run for some time. It should be 100% reliable.

[ADDED] Applying either 5V or 3.3V to VIN is not okay for your circuit if it is a 16MHz board.

What is your ODR register set at?

When I think I have a timing issue I don't add a delay of "just enough" I add a huge delay to be sure I'm still not on the edge of some timing issue.

Haha, yeah, there's a LOT going on...

They are grounded with a clip wire.

The Nano is a 5V board, I am powering it using a mini-usb cable connected to my computer.
The schematic is wrong- I corrected for the SDA and SCL lines, I have connected SCL and SDA to A5 and A4, respectively.

I thought that the Nano was providing 3.3V by an onboard voltage reducing circuit?

Yes, it appears INT1 has a resistor connected.

I'll do the I2C scanner in a bit, should have a response by tomorrow.

I am not applying voltage to VIN right now.

I'm not using continuous measurement mode with this code, it should be the default values.

Besides this, I have used this same code (with the 7 ms delay between requesting measurements) and gotten good data on the evaluation board. The issue is more that the PCB with the nine magnet sensors will return bogus data, all 1s or 0s, or not communicate at all.

After doing some looking, the oscilloscope shows that when the SDA and SCL lines are not connected to the PCB that has the nine magnet sensors, both lines go between 0 - 5V.

On the evaluation board (the one that has a single magnet sensor), the SDA and SCL lines both go between 0 - 3.3V. (I am connecting the 3.3V line to the sensor).

Is your detector output connected to SCL ?

Hi, I think we got it figured out.

Turns out the speaker system on the board was connected to the 5V line and was picking up 60 Hz noise. This resulted in two different voltage differentials for the SCL and the SDA lines. Apparently, the magnet sensors (or maybe the Arduino?) don't like it when these two lines have different voltage differentials. :man_shrugging:
The nine magnet sensors are SMD chips and were installed by hand, a non-trivial task. So, after doing some testing, I found that 3 of the 9 sensors were not connected. :sweat_smile: Good news, though- the multiplexer is working just as it should! It looks like I'm able to communicate just fine, now!

Thanks to all who helped! :grin: