Search code examples
c++arduinoaccelerometer

ADXL345 library for sparkfun redboard turbo giving wrong readings


I am running an ADXL345 using I2C on both a sparkfun redboard turbo(processor samd21g18) and an old arduino uno (processor mega16u2). The library and sketch I'm using on both boards are same with the exception that the serial port is changed to SerialUSB to accommodate the redboard.

The issue appears to be that the uno interprets the xyz registers (2 bytes per axis in registers 0x32 - 0x37) as 16 bit twos compliment (as per the datasheet) and the redboard does not. The uno's output is correct and the redboard output which is incorrect is all positive integer output.

The image below shows the output for the redboard on left and uno on right for same relative position of the ADXL345).

enter image description here

I believe the offending code is in the following library code.

/*********************** READING ACCELERATION ***********************/
/*    Reads Acceleration into Three Variables:  x, y and z          */

void ADXL345::readAccel(int *xyz){
    readAccel(xyz, xyz + 1, xyz + 2);
}

void ADXL345::readAccel(int *x, int *y, int *z) {
    readFrom(ADXL345_DATAX0, ADXL345_TO_READ, _buff);   // Read Accel Data from ADXL345

    // Each Axis @ All g Ranges: 10 Bit Resolution (2 Bytes)
    *x = (((int)_buff[1]) << 8) | _buff[0];
    *y = (((int)_buff[3]) << 8) | _buff[2];
    *z = (((int)_buff[5]) << 8) | _buff[4];
}

The sketch code is as follows:

#include <SparkFun_ADXL345.h>


/*********** COMMUNICATION SELECTION ***********/
/*    Comment Out The One You Are Not Using    */
//ADXL345 adxl = ADXL345(10);           // USE FOR SPI COMMUNICATION, ADXL345(CS_PIN);
ADXL345 adxl = ADXL345();             // USE FOR I2C COMMUNICATION

/****************** INTERRUPT ******************/
/*      Uncomment If Attaching Interrupt       */
//int interruptPin = 2;                 // Setup pin 2 to be the interrupt pin (for most Arduino Boards)


/******************** SETUP ********************/
/*          Configure ADXL345 Settings         */
void setup(){

  SerialUSB.begin(9600);                 // Start the SerialUSB terminal
  SerialUSB.println("SparkFun ADXL345 Accelerometer Hook Up Guide Example");
  SerialUSB.println();

  adxl.powerOn();                     // Power on the ADXL345

  adxl.setRangeSetting(2);           // Give the range settings
                                      // Accepted values are 2g, 4g, 8g or 16g
                                      // Higher Values = Wider Measurement Range
                                      // Lower Values = Greater Sensitivity

} 
/****************** MAIN CODE ******************/
/*     Accelerometer Readings and Interrupt    */
void loop(){

  // Accelerometer Readings
  int x,y,z;   
  adxl.readAccel(&x, &y, &z);         // Read the accelerometer values and store them in variables declared above x,y,z

  // Output Results to SerialUSB
  /* UNCOMMENT TO VIEW X Y Z ACCELEROMETER VALUES */  
  SerialUSB.print(x);
  SerialUSB.print(", ");
  SerialUSB.print(y);
  SerialUSB.print(", ");
  SerialUSB.println(z);
  adxl.printAllRegister();
  delay(10); 
}

The code that declares _buff[] which is in the header .h file:

private:
    void writeTo(byte address, byte val);
    void writeToI2C(byte address, byte val);
    void writeToSPI(byte address, byte val);
    void readFrom(byte address, int num, byte buff[]);
    void readFromI2C(byte address, int num, byte buff[]);
    void readFromSPI(byte address, int num, byte buff[]);
    void setRegisterBit(byte regAdress, int bitPos, bool state);
    bool getRegisterBit(byte regAdress, int bitPos);
    byte _buff[6] ;     //  6 Bytes Buffer
    int _CS = 10;
    bool I2C = true;
    unsigned long SPIfreq = 5000000;

I believe that the library for the redboard needs to be modified to read the output registers 0x32-0x37 as 16 bit twos compliment. I am new to this programming environment so any help is appreciated.

Thanks - Jerry


Solution

  • I suspect from the Sparkfun board notes (https://www.sparkfun.com/products/14812) that the problem is that the Redboard Turbo is a 32-bit processor, with a 32-bit int instead of a 16-bit int. On such a processor, all 16 bit values stored in an int are positive.

    To test my theory, run the following Sketch on your Redboard Turbo:

    void setup() {
      Serial.begin(9600);
      while (!Serial) {}
    
      Serial.print("sizeof(int) = ");
      Serial.println(sizeof(int));
    }
    
    void loop() {
    }
    

    On my Arduino Uno - a 16-bit environment - the output says that an int is two bytes (16 bits)

    sizeof(int) = 2
    

    If your Redboard Turbo instead prints

    sizeof(int) = 4
    

    then its int is 4 bytes (32 bits).

    I suspect that the library wasn't written for 32-bit processors, and may show several problems on the Redboard Turbo. To fix the particular readAccel() function, rewrite it to sign-extend the 16-bit number to 32 bits:

      int16_t i16;  // the 16-bit result, signed.
    
      i16 = (int16_t) ((((uint16_t)_buff[1]) << 8) | _buff[0]);
      *x = (int) i16;
    
      i16 = (int16_t) ((((uint16_t)_buff[3]) << 8) | _buff[2]);
      *y = (int) i16;
    
      i16 = (int16_t) ((((uint16_t)_buff[5]) << 8) | _buff[4]);
      *z = (int) i16;
    

    By the way, in the above rewrite of readAccel() I've used uint16_t to make sure the byte shifting happens on an unsigned value, because left-shifting a signed number can produce unexpected results on some processors.