I am using I2C communication with a Particle Electron as the master and an MMA8451 accelerometer as the slave, and I can’t seem to write to registers correctly. I have no prior experience writing to registers, and very little experience with the Particle Electron itself, so simplified answers would be really appreciated.
For a project that I’m working on, I need to be able to wake up the particle from sleep when the accelerometer senses movement. I’m not having any trouble with the sleep/wake part of the problem, just the accelerometer. The MMA8451 has embedded functions that, when active, will send an interrupt signal when movement is sensed. The notes on these embedded functions are here:
Everything about the accelerometer:
https://www.nxp.com/docs/en/data-sheet/MMA8451Q.pdf
Just motion detection: (probably more useful in this case)
http://cache.freescale.com/files/sensors/doc/app_note/AN4070.pdf?fpsp=1
This is my current code:
#include <Wire.h>
#include <Adafruit_MMA8451.h>
#include <Adafruit_Sensor.h>
Adafruit_MMA8451 mma = Adafruit_MMA8451();
void setup(void) {
Serial.begin(9600);
Wire.begin();
Serial.println("Adafruit MMA8451 test!");
if (! mma.begin()) {
Serial.println("Couldnt start");
while (1);
}
Serial.println("MMA8451 found!");
mma.setRange(MMA8451_RANGE_8_G);
Serial.print("Range = "); Serial.print(2 << mma.getRange());
Serial.println("G");
pinMode(WKP, INPUT_PULLUP);
Wire.beginTransmission(0x1C);
Wire.write(0x2A);
Wire.write(0x18);
Wire.endTransmission(0x1C);
Wire.beginTransmission(0x1C);
Wire.write(0x15);
Wire.write(0xD8);
Wire.endTransmission(0x1C);
Wire.beginTransmission(0x1C);
Wire.write(0x17);
Wire.write(0x30);
Wire.endTransmission(0x1C);
Wire.beginTransmission(0x1C);
Wire.write(0x18);
Wire.write(0x0A);
Wire.endTransmission(0x1C);
Wire.beginTransmission(0x1C);
Wire.write(0x2D);
Wire.write(0x04);
Wire.endTransmission(0x1C);
Wire.beginTransmission(0x1C);
Wire.write(0x2E);
Wire.write(0x04);
Wire.endTransmission(0x1C);
}
int maxX = 0;
int minX = 0;
void loop() {
// Read the 'raw' data in 14-bit counts
mma.read();
Serial.print("X:\t"); Serial.print(mma.x);
Serial.print("\tY:\t"); Serial.print(mma.y);
Serial.print("\tZ:\t"); Serial.print(mma.z);
Serial.println();
/* Get a new sensor event */
sensors_event_t event;
mma.getEvent(&event);
/* Display the results (acceleration is measured in m/s^2) */
Serial.print("X: \t"); Serial.print(event.acceleration.x); Serial.print("\t");
Serial.print("Y: \t"); Serial.print(event.acceleration.y); Serial.print("\t");
Serial.print("Z: \t"); Serial.print(event.acceleration.z); Serial.print("\t");
Serial.println("m/s^2 ");
Serial.println();
int interrupt = digitalRead(WKP);
Serial.println(interrupt);
Serial.println();
// int z = mma.z;
delay(100);
}
Just the register writing part:
Wire.begin();
Wire.beginTransmission(0x1C);
Wire.write(0x2A);
Wire.write(0x18);
Wire.endTransmission(0x1C);
Wire.beginTransmission(0x1C);
Wire.write(0x15);
Wire.write(0xD8);
Wire.endTransmission(0x1C);
Wire.beginTransmission(0x1C);
Wire.write(0x17);
Wire.write(0x30);
Wire.endTransmission(0x1C);
Wire.beginTransmission(0x1C);
Wire.write(0x18);
Wire.write(0x0A);
Wire.endTransmission(0x1C);
Wire.beginTransmission(0x1C);
Wire.write(0x2D);
Wire.write(0x04);
Wire.endTransmission(0x1C);
Wire.beginTransmission(0x1C);
Wire.write(0x2E);
Wire.write(0x04);
Wire.endTransmission(0x1C);
As far as I can tell, I am doing what the papers I’ve read on both the accelerometer and the particle have told me. When writing 1 byte to a register you call the slave, write the register, write the data, then end the conversation. There is supposed to be an acknowledgment of the slave between each of these steps, but the particle, or perhaps Wire.h, seems to do that automatically, judging by the example codes I’ve seen.
I’m pretty sure that I’m writing to the correct slave address, 0x1C, even though two are mentioned in the MMA8451 data sheet, 0x1D and 0x1C, because 0x1C is the only address I get a response from when using Wire.read(); and here is the code I used to find that out:
//#include <Wire.h>
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial for output
}
void loop()
{
Wire.requestFrom(0x1C, 6); // request 6 bytes from slave device #2
while(Wire.available()) // slave may send less than requested
{
char c = Wire.read(); // receive a byte as character
Serial.print(c); // print the character
}
delay(500);
}
The accelerometer will do it’s basic functions correctly, and it’s connected SDA to D0 and SCL to D1 with pull up resistors (4.7k) I am not using AssetTracker. I have gotten the wake-up function to work by connecting the WKP pin high when I want it to wake, I just need the accelerometer to give me the interrupt.