2
\$\begingroup\$

I’m experiencing some issue in trying to make ADXL345 accelerometer works in SPI by using an nRF52 feather. I'm using the ADXL345 SparkFun library read values from it.

Here are the connections

nrf52             ADXL345
SCK               SCL
MISO              SDO
MOSI              SDA
PIN 11            CS

The same code I’m posting works perfectly on my Arduino Uno, but if I try to run it on the feather it get stuck on powerOn method.

#include <SparkFun_ADXL345.h>         // SparkFun ADXL345 Library

ADXL345 adxl = ADXL345(11);           // USE FOR SPI COMMUNICATION, ADXL345(CS_PIN);

void setup(){

  Serial.begin(115200);                 // Start the serial terminal
    while ( !Serial ) delay(10);   // for nrf52840 with native usb
  pinMode(11, OUTPUT);
  Serial.println("SparkFun ADXL345 Accelerometer Hook Up Guide Example");
  Serial.println();
  adxl.powerOn();                     // Power on the ADXL345
  Serial.println("Setting range");

  adxl.setRangeSetting(16);           
  Serial.println("Setting 4 wire");
  adxl.setSpiBit(0);                  // Configure the device to be in 4 wire SPI mode when set to '0' or 3 wire SPI mode when set to 1

}

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 Serial
  Serial.print(x);
  Serial.print(", ");
  Serial.print(y);
  Serial.print(", ");
  Serial.println(z); 

}

The initialization code in sparkfun starts the SPI Library and sets the mode to 3, it also configure the CS pin to OUTPUT as it supposed to be, the it puts the CS to HIGH.

ADXL345::ADXL345(int CS) {
    // ... other code
    _CS = CS;
    I2C = false;
    SPI.begin();
    SPI.setDataMode(SPI_MODE3);
    pinMode(_CS, OUTPUT);
    digitalWrite(_CS, HIGH);
}

The powerOn function sets the power settings on the sensor:

void ADXL345::powerOn() {
    // ... other code
    //ADXL345 TURN ON
    writeTo(ADXL345_POWER_CTL, 0);  // Wakeup     
    writeTo(ADXL345_POWER_CTL, 16); // Auto_Sleep
    writeTo(ADXL345_POWER_CTL, 8);  // Measure
}

My code hangs exactly when I call powerOn(). I do not understand why since on my Arduino Uno works perfectly. I'm wondering if I must use some particular settings while opening the SPI transaction due to the different micro controller architecture (ARM vs AVR) or clock (64MHz vs 16MHz).

[UPDATE] Here the relevant code in the writeTo function, since the library supports both I2C and SPI, I only post the part from SPI writing:

void ADXL345::writeTo(byte address, byte val) {
    if(I2C) {
        writeToI2C(address, val);
    }
    else {
        writeToSPI(address, val);
    }
}
void ADXL345::writeToSPI(byte __reg_address, byte __val) {
  digitalWrite(_CS, LOW);
  SPI.transfer(__reg_address); 
  SPI.transfer(__val); 
  digitalWrite(_CS, HIGH); 
}

What I've seen this morning is that if I move the sensor initialization in the setup method instead of a GVar the powerOn method doesn't hang and the log starts to show some values. But those values in some axis are just 16bit Uint max values. While on the Arduino Uno I obtain values with "sense". #include // SparkFun ADXL345 Library

ADXL345 adxl;           // USE FOR SPI COMMUNICATION, ADXL345(CS_PIN);

void setup(){

  Serial.begin(115200);                 // Start the serial terminal
    while ( !Serial ) delay(10);   // for nrf52840 with native usb
  pinMode(11, OUTPUT);
  adxl = ADXL345(11);
  Serial.println("SparkFun ADXL345 Accelerometer Hook Up Guide Example");
  Serial.println();
  adxl.powerOn();                     // Power on the ADXL345
  Serial.println("Setting range");

  adxl.setRangeSetting(16);           
  Serial.println("Setting 4 wire");
  adxl.setSpiBit(0);                  // Configure the device to be in 4 wire SPI mode when set to '0' or 3 wire SPI mode when set to 1

}

[UPDATE x 2] I was able to extract some functions from the original library and copy them into the .ino file. The comment from Chris was correct, building the sensor object inside the setup function and getting an update from there works and shows correct values.
But now the problem is that since C++ will both declare and define variable by using the default constructor, if I declare the variable as a GVar and then assign a new sensor inside the setup() to be used also in the loop() function I obtain values with no sense. Is there a way to just declare a variable in C++? I tried by declaring as a pointer but I still get senseless values.

void setup(){

  Serial.begin(115200);                 // Start the serial terminal
    while ( !Serial ) delay(11);   // for nrf52840 with native usb
  ADXL345 adxl = ADXL345(11);
  Serial.println("SparkFun ADXL345 Accelerometer Hook Up Guide Example");
  Serial.println();
  adxl.powerOn();                     // Power on the ADXL345
  Serial.println("Setting range");

  adxl.setRangeSetting(16);           
  Serial.println("Setting 4 wire");
  adxl.setSpiBit(0);                  // Configure the device to be in 4 wire SPI mode when set to '0' or 3 wire SPI mode when set to 1
  delay(100);
    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 Serial
    Serial.print(x);
    Serial.print(", ");
    Serial.print(y);
    Serial.print(", ");
    Serial.println(z); 
}

The code above works, but since the accelerator is declared just in the scope of the setup() function I can't access inside loop().

ADXL345 adxl;          // USE FOR SPI COMMUNICATION, ADXL345(CS_PIN);

void setup(){

  Serial.begin(115200);                 // Start the serial terminal
    while ( !Serial ) delay(11);   // for nrf52840 with native usb
//  pinMode(11, OUTPUT);
  ADXL345 adxl = ADXL345(11);
  Serial.println("SparkFun ADXL345 Accelerometer Hook Up Guide Example");
  Serial.println();
  adxl.powerOn();                     // Power on the ADXL345
  Serial.println("Setting range");

  adxl.setRangeSetting(16);           
  Serial.println("Setting 4 wire");
  adxl.setSpiBit(0);                  // Configure the device to be in 4 wire SPI mode when set to '0' or 3 wire SPI mode when set to 1

}

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 Serial
    Serial.print(x);
    Serial.print(", ");
    Serial.print(y);
    Serial.print(", ");
    Serial.println(z); 

}

The code above doesn't hang as the one at the top of the answer, but gives useless values.

\$\endgroup\$
  • \$\begingroup\$ Are you trying a bare bones example sketch for the ADXL345? or also adding more code not shown? \$\endgroup\$ – vicatcu Jun 4 at 12:49
  • \$\begingroup\$ probably scope traces will be needed fyi each a definite conclusion \$\endgroup\$ – vicatcu Jun 4 at 12:55
  • \$\begingroup\$ With no implementation provided for the writeTo() method you can't really expect to receive any help here. Actually success of communication should be irrelevant to program progress until the program reaches a point where a read needs to have a specific value, and no such situations seems to be shown before the point where you claim it fails. \$\endgroup\$ – Chris Stratton Jun 4 at 13:44
  • \$\begingroup\$ @vicatcu I'm trying to extrapolate just a bare implementation of the library functions, but I will not have time to try until next days. I will post result later. What I've seen this morning is that if I move the sensor initialization in the setup method instead of a GVar the powerOn method doesn't hang and the log starts to show some values. But those values in some axis are just 16bit Uint max values. While on the Arduino Uno I obtain values with "sense". \$\endgroup\$ – Andrea Jun 4 at 14:50
  • \$\begingroup\$ Hello @ChrisStratton I've updated the answer with the writeTo implementation \$\endgroup\$ – Andrea Jun 4 at 14:54
1
\$\begingroup\$

Here's what you should do:

ADXL345 * adxl;          // USE FOR SPI COMMUNICATION, ADXL345(CS_PIN);

void setup(){

  Serial.begin(115200);                 // Start the serial terminal
    while ( !Serial ) delay(11);   // for nrf52840 with native usb
//  pinMode(11, OUTPUT);
  adxl = new ADXL345(11);
  Serial.println("SparkFun ADXL345 Accelerometer Hook Up Guide Example");
  Serial->println();
  adxl->powerOn();                     // Power on the ADXL345
  Serial.println("Setting range");

  adxl->setRangeSetting(16);           
  Serial.println("Setting 4 wire");
  adxl->setSpiBit(0);                  // Configure the device to be in 4 wire SPI mode when set to '0' or 3 wire SPI mode when set to 1

}

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 Serial
    Serial.print(x);
    Serial.print(", ");
    Serial.print(y);
    Serial.print(", ");
    Serial.println(z); 

}

Basically declare a global pointer, then use the new in setup to initialize it, and then use the pointer with arrow syntax (->) from then on. I'm generally opposed to the use of dynamic memory allocation, but I can make an exception for using it during initialization only situations.

\$\endgroup\$
  • 1
    \$\begingroup\$ Awesome... thanx!!! \$\endgroup\$ – Andrea Jun 6 at 5:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.