Hello, Arduino-ers, I'm pretty new at Arduino and programming and any help would be greatly appreciated.
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...
- 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)
- 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.
- 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.
- 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...
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);
}