Electron to MMA8451 Accelerometer I2C communication

electron
Tags: #<Tag:0x00007fe228e0b318>

#1

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.


#2

Are you enabling the interrupts?
Which INT pin are you connected to? By default it outputs to INT2

Having a quick look at the Datasheet seems you need to enable the INT and configure them with the three CTRL reg on reg 0x2c,0x2d,0x2e, but can’t see that you have actually written to these registers.


#3

@MackD,

I use this accelerometer all the time but it has some quirks. It had been a while but it has to do with the way you end transmission on an i2c session. The answer was not to use Wire.

Here is a Github repo with code that works with this sensor: https://github.com/chipmc/Cellular-MMA8452Q

Hope this helps,

Chip


#4

@johnnyfp
I’ve been using INT2, but I’ve also been changing the wiring while I’m testing each code iteration to see if INT1 is working. I didn’t write to 0x2C, I’ve tried that now, writing 0x08 to it. I did write to 0x2D and 0x2E in my original code. Here are the changed writes:

  Wire.beginTransmission(0x1C);
    Wire.write(0x15);       //Configuration
    Wire.write(0xD8);
  Wire.endTransmission(0x1C);
  Wire.beginTransmission(0x1C);
    Wire.write(0x17);       //Threshold
    Wire.write(0x30);
  Wire.endTransmission(0x1C); 
  Wire.beginTransmission(0x1C);
    Wire.write(0x18);       //debounce
    Wire.write(0x0A);
  Wire.endTransmission(0x1C);
  Wire.beginTransmission(0x1C);
    Wire.write(0x2C);       //newly added
    Wire.write(0x08);
  Wire.endTransmission(0x1C);
  Wire.beginTransmission(0x1D);
    Wire.write(0x2D);       //interrupt
    Wire.write(0x04);
  Wire.endTransmission(0x1C);
  Wire.beginTransmission(0x1C);
    Wire.write(0x2E);       //interrupt
    Wire.write(0x04);
  Wire.endTransmission(0x1C); 

@chipmc
I can’t seem to get the libraries to work. I’m uploading over CLI like I’m supposed to but it won’t allow me to apply these libraries mentioned in the code. However, I can understand some of what’s going on in some of these codes, so hopefully, I can figure something out without using the libraries.


#5

@chipmc
I was able to work through the code you suggested and I got it to work! I successfully wrote and read to register. My issue was that I didn’t put the accelerometer on standby, so thank you for the help!


#6

@MackD,

Very happy to hear you got this working. This is my cheap and cheerful goto accelerometer.

Looking for a good magnetometer, any ideas?

When you are ready to roll your own:

OSHPark: https://oshpark.com/shared_projects/gd22lN54