Jump to content
blur3d

Tiva C adxl345 SPI weird readings

Recommended Posts

I'm trying to get my Tiva C (lm4f120) to read a adxl345 (accelerometer) and output 

the x, y and z values.

 

I'm using the SSI2 peripheral, and everything seems to be wired correctly.

 

By moving the adxl345 around, I can get the values to change, however they 

seem to overflow or something weird. They seem to tend toward 65535 when 

it should be reading 0.

65332	279	65519
65313	274	65528
65289	273	0
65271	275	1
65259	274	38
65318	238	69
65304	220	135
65303	207	134
65312	125	202
65308	67	242
65311	87	214
65316	69	222
65312	66	221
65310	68	219
65305	63	224
65513	65434	65430
58	68	65509
20	65518	3
33	21	33
11	65522	65532
18	65520	0
10	65527	65533
17	0	14
6	65528	65527
12	65525	2
19	65514	65532
22	65515	2
65526	65452	6
65368	65315	64
65353	65384	105
65379	65497	240
65340	84	270
65289	78	245
65234	70	205
65284	215	133
65277	228	107
65282	233	80
65297	184	67
65285	270	8
65281	274	65529
65281	273	65532

The code I'm using is below

//Add the SPI library so we can communicate with the ADXL345 sensor
#include <SPI.h>

//Assign the Chip Select signal to pin 2.
int CS = 2;

//This is a list of some of the registers available on the ADXL345.
//To learn more about these and the rest of the registers on the ADXL345, read the datasheet!
char POWER_CTL = 0x2D;	//Power Control Register
char DATA_FORMAT = 0x31;
char DATAX0 = 0x32;	//X-Axis Data 0
char DATAX1 = 0x33;	//X-Axis Data 1
char DATAY0 = 0x34;	//Y-Axis Data 0
char DATAY1 = 0x35;	//Y-Axis Data 1
char DATAZ0 = 0x36;	//Z-Axis Data 0
char DATAZ1 = 0x37;	//Z-Axis Data 1

//This buffer will hold values read from the ADXL345 registers.
char values[10];
//These variables will be used to hold the x,y and z axis accelerometer values.
long x,y,z;

void setup(){ 
  //Initiate an SPI communication instance.
  SPI.begin();
  
  //Configure the SPI connection for the ADXL345.
  SPI.setDataMode(SPI_MODE3);
  
  //Create a serial connection to display the data on the terminal.
  Serial.begin(115200);
  Serial.println("GO!");
  
  //Set up the Chip Select pin to be an output from the Arduino.
  pinMode(CS, OUTPUT);
  //Before communication starts, the Chip Select pin needs to be set high.
  digitalWrite(CS, HIGH);
  
  //Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
  writeRegister(DATA_FORMAT, 0x00);
  //Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
  writeRegister(POWER_CTL, 0x08);  //Measurement mode  
}

void loop(){
  //Reading 6 bytes of data starting at register DATAX0 will retrieve the x,y and z acceleration values from the ADXL345.
  //The results of the read operation will get stored to the values[] buffer.
  readRegister(DATAX0, 6, values);

  //The ADXL345 gives 10-bit acceleration values, but they are stored as bytes (8-bits). To get the full value, two bytes must be combined for each axis.
  //The X value is stored in values[0] and values[1].
  x = ((long)values[1]<<8)|(long)values[0];
  //The Y value is stored in values[2] and values[3].
  y = ((long)values[3]<<8)|(long)values[2];
  //The Z value is stored in values[4] and values[5].
  z = ((long)values[5]<<8)|(long)values[4];
  
  //Print the results to the terminal.
  Serial.print(x);
  Serial.print('\t');
  Serial.print(y);
  Serial.print('\t');
  Serial.println(z);      
  delay(100); 
}

//This function will write a value to a register on the ADXL345.
//Parameters:
//  char registerAddress - The register to write a value to
//  char value - The value to be written to the specified register.
void writeRegister(char registerAddress, char value){
  //Set Chip Select pin low to signal the beginning of an SPI packet.
  digitalWrite(CS, LOW);
  //Transfer the register address over SPI.
  SPI.transfer(registerAddress);
  //Transfer the desired register value over SPI.
  SPI.transfer(value);
  //Set the Chip Select pin high to signal the end of an SPI packet.
  digitalWrite(CS, HIGH);
}

//This function will read a certain number of registers starting from a specified address and store their values in a buffer.
//Parameters:
//  char registerAddress - The register addresse to start the read sequence from.
//  int numBytes - The number of registers that should be read.
//  char * values - A pointer to a buffer where the results of the operation should be stored.
void readRegister(char registerAddress, int numBytes, char * values){
  //Since we're performing a read operation, the most significant bit of the register address should be set.
  char address = 0x80 | registerAddress;
  //If we're doing a multi-byte read, bit 6 needs to be set as well.
  if(numBytes > 1)address = address | 0x40;
  
  //Set the Chip select pin low to start an SPI packet.
  digitalWrite(CS, LOW);
  //Transfer the starting register address that needs to be read.
  SPI.transfer(address);
  //Continue to read registers until we've read the number specified, storing the results to the input buffer.
  for(int i=0; i<numBytes; i++){
    values[i] = SPI.transfer(0x00);
  }
  //Set the Chips Select pin high to end the SPI packet.
  digitalWrite(CS, HIGH);
}

If someone is able to provide some guidance on how to test or fix this, that would be great. Thanks :)

 

Share this post


Link to post
Share on other sites

I've changed the code to use uint16_t and seem to be getting better values. I'll keep testing things and post an update.

//Add the SPI library so we can communicate with the ADXL345 sensor
#include <SPI.h>

//Assign the Chip Select signal to pin 2.
int CS = 2;

//This is a list of some of the registers available on the ADXL345.
//To learn more about these and the rest of the registers on the ADXL345, read the datasheet!
char POWER_CTL = 0x2D;	//Power Control Register
char DATA_FORMAT = 0x31;
char DATAX0 = 0x32;	//X-Axis Data 0
char DATAX1 = 0x33;	//X-Axis Data 1
char DATAY0 = 0x34;	//Y-Axis Data 0
char DATAY1 = 0x35;	//Y-Axis Data 1
char DATAZ0 = 0x36;	//Z-Axis Data 0
char DATAZ1 = 0x37;	//Z-Axis Data 1

//This buffer will hold values read from the ADXL345 registers.
char values[10];
//These variables will be used to hold the x,y and z axis accelerometer values.
int16_t x,y,z;

void setup(){ 
  //Initiate an SPI communication instance.
  SPI.begin();
  
  //Configure the SPI connection for the ADXL345.
  SPI.setDataMode(SPI_MODE3);
  
  //Create a serial connection to display the data on the terminal.
  Serial.begin(115200);
  Serial.println("------------------------------------");
  
  //Set up the Chip Select pin to be an output from the Arduino.
  pinMode(CS, OUTPUT);
  //Before communication starts, the Chip Select pin needs to be set high.
  digitalWrite(CS, HIGH);
  
  //Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
  writeRegister(DATA_FORMAT, 0x01);
  //Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
  writeRegister(POWER_CTL, 0x08);  //Measurement mode  
}

void loop(){
  //Reading 6 bytes of data starting at register DATAX0 will retrieve the x,y and z acceleration values from the ADXL345.
  //The results of the read operation will get stored to the values[] buffer.
  readRegister(DATAX0, 6, values);

  //The ADXL345 gives 10-bit acceleration values, but they are stored as bytes (8-bits). To get the full value, two bytes must be combined for each axis.
  //The X value is stored in values[0] and values[1].
  x = ((int16_t)values[1]<<8)|(int16_t)values[0];
  //The Y value is stored in values[2] and values[3].
  y = ((int16_t)values[3]<<8)|(int16_t)values[2];
  //The Z value is stored in values[4] and values[5].
  z = ((int16_t)values[5]<<8)|(int16_t)values[4];
  
  //Print the results to the terminal.
  Serial.print(x);
  Serial.print('\t');
  Serial.print(y);
  Serial.print('\t');
  Serial.println(z);      
  delay(100); 
}

//This function will write a value to a register on the ADXL345.
//Parameters:
//  char registerAddress - The register to write a value to
//  char value - The value to be written to the specified register.
void writeRegister(char registerAddress, char value){
  //Set Chip Select pin low to signal the beginning of an SPI packet.
  digitalWrite(CS, LOW);
  //Transfer the register address over SPI.
  SPI.transfer(registerAddress);
  //Transfer the desired register value over SPI.
  SPI.transfer(value);
  //Set the Chip Select pin high to signal the end of an SPI packet.
  digitalWrite(CS, HIGH);
}

//This function will read a certain number of registers starting from a specified address and store their values in a buffer.
//Parameters:
//  char registerAddress - The register addresse to start the read sequence from.
//  int numBytes - The number of registers that should be read.
//  char * values - A pointer to a buffer where the results of the operation should be stored.
void readRegister(char registerAddress, int numBytes, char * values){
  //Since we're performing a read operation, the most significant bit of the register address should be set.
  char address = 0x80 | registerAddress;
  //If we're doing a multi-byte read, bit 6 needs to be set as well.
  if(numBytes > 1)address = address | 0x40;
  
  //Set the Chip select pin low to start an SPI packet.
  digitalWrite(CS, LOW);
  //Transfer the starting register address that needs to be read.
  SPI.transfer(address);
  //Continue to read registers until we've read the number specified, storing the results to the input buffer.
  for(int i=0; i<numBytes; i++){
    values[i] = SPI.transfer(0x00);
  }
  //Set the Chips Select pin high to end the SPI packet.
  digitalWrite(CS, HIGH);
}

Share this post


Link to post
Share on other sites
  //The X value is stored in values[0] and values[1].
  x = ((int16_t)values[1]<<8)|(int16_t)values[0];
  //The Y value is stored in values[2] and values[3].
  y = ((int16_t)values[3]<<8)|(int16_t)values[2];
  //The Z value is stored in values[4] and values[5].
  z = ((int16_t)values[5]<<8)|(int16_t)values[4]; 

I see a possible problem by converting char to int16_t, char is a signed type, therefore when you typecast it into int16_t it gets extended, for example:

 

-1 is hexadecimal FF, typecasting to int16_t -> FFFF

 

the problem is that values[0] is unsigned, and values[1] is signed, for example:

values[1] is 4 (04), typecast to int16_t (0040), shift left by 8 bit (0400)

values[0] is 129 (81), typecast to int16_t (FF81)

bitwise OR, 0400 | FF81 -> FF81 which is -127 decimal, but it should have been 1153 decimal (0481 hex)

 

i might be wrong, its late ;)

Share this post


Link to post
Share on other sites

Thanks for your reply. I'll have another play with it soon. But I think you are right.

 

I was actually trying to get it working in Energia first, to help me write it using the TivaWare libraries.

 

I can get the x, y and z to change with different movements, but with this code, I seem to have a similar issue. However, 

it seems to be around 65535 with no movement, and peak at 0 with lots of movement. So it's obviously a similar issue. And 

I actually think that y and z were always reading the same value.

 

Anyway, I'll have a play and post an update.

#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/ssi.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"

// Register Codes
#define DEVID           0x00
#define THRESH_TAP      0x1D
#define OFSX            0x1E
#define OFSY            0x1F
#define OFSZ            0x20
#define DUR             0x21
#define LATENT          0x22
#define WINDOW          0x23
#define THRESH_ACT      0x24
#define THRESH_INACT    0x25
#define TIME_INACT      0x26
#define ACT_INACT_CTL   0x27
#define THRESH_FF       0x28
#define TIME_FF         0x29
#define TAP_AXES        0x2A
#define ACT_TAP_STATUS  0x2B
#define BW_RATE         0x2C
#define POWER_CTL       0x2D
#define INT_ENABLE      0x2E
#define INT_MAP         0x2F
#define INT_SOURCE      0x30
#define DATA_FORMAT     0x31
#define DATAX0          0x32
#define DATAX1          0x33
#define DATAY0          0x34
#define DATAY1          0x35
#define DATAZ0          0x36
#define DATAZ1          0x37
#define FIFO_CTL        0x38
#define FIFO_STATUS     0x39

void InitConsole(void) {
    // Enable GPIO port A which is used for UART0 pins.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    // Configure the pin muxing for UART0 functions on port A0 and A1.
    // This step is not necessary if your part does not support pin muxing.
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);

    // Enable UART0 so that we can configure the clock.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    // Use the internal 16MHz oscillator as the UART clock source.
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);

    // Select the alternate (UART) function for these pins.
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    // Initialize the UART for console I/O.
    UARTStdioConfig(0, 115200, 16000000);
}

void InitSPI(void) {
    // The SSI2 peripheral must be enabled for use.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2);

    // Enable Port B
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    // SETUP SPI CS Pin (to output)
    GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_5);

    // Set SPI CS to HIGH (active-low)
    GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_6, 0xFF);

    // Configure the pin muxing for SSI2 functions on port B4, B5, B6, and B7.
    GPIOPinConfigure(GPIO_PB4_SSI2CLK);
    GPIOPinConfigure(GPIO_PB5_SSI2FSS);
    GPIOPinConfigure(GPIO_PB6_SSI2RX);
    GPIOPinConfigure(GPIO_PB7_SSI2TX);

    // Configure the GPIO settings for the SSI pins.
    GPIOPinTypeSSI(GPIO_PORTB_BASE, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 |
                   GPIO_PIN_7);

    // Configure and enable the SSI port for SPI master mode.  Use SSI0,
    // system clock supply, idle clock level low and active low clock in
    // freescale SPI mode, master mode, 1MHz SSI frequency, and 8-bit data.
    // For SPI mode, you can set the polarity of the SSI clock when the SSI
    // unit is idle.  You can also configure what clock edge you want to
    // capture data on.  Please reference the datasheet for more information on
    // the different SPI modes.
    SSIConfigSetExpClk(SSI2_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_3,
                       SSI_MODE_MASTER, 1000000, 8);

    // Enable the SSI0 module.
    SSIEnable(SSI2_BASE);

    // Read any residual data from the SSI port.  This makes sure the receive
    // FIFOs are empty, so we don't read any unwanted junk.  This is done here
    // because the SPI SSI mode is full-duplex, which allows you to send and
    // receive at the same time.  The SSIDataGetNonBlocking function returns
    // "true" when data was returned, and "false" when no data was returned.
    // The "non-blocking" function checks if there is any data in the receive
    // FIFO and does not "hang" if there isn't.
    uint32_t scrap;
    while(SSIDataGetNonBlocking(SSI2_BASE, &scrap));
}


int main(void) {

    // Set the clocking to run directly from the external crystal/oscillator.
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                   SYSCTL_XTAL_16MHZ);

    // Set up UART Serial Output
    InitConsole();

    // Set up SSI2 for SPI Communication
    InitSPI();

    UARTprintf("............................................\n");

    GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_5, 0x00);
    SSIDataPut(SSI2_BASE, 0x31); // DATA_FORMAT
    while(SSIBusy(SSI2_BASE));
    SSIDataPut(SSI2_BASE, 0x01); // +/- 4g
    GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_5, 0xFF);

    GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_5, 0x00);
    SSIDataPut(SSI2_BASE, 0x2D); // POWER_CTL
    while(SSIBusy(SSI2_BASE));
    SSIDataPut(SSI2_BASE, 0x08);
    GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_5, 0xFF);

    while (1) {

      char values[10];
      int16_t x, y, z;

      char address = 0x80 | DATAX0 | 0x40; //Set MSB for read, start at X0 and enable multi-byte

      GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_5, 0x00);

      SSIDataPut(SSI2_BASE, address); // ask for data

      for(int i=0; i < 6; i++){
        SSIDataPut(SSI2_BASE, 0x00);
        while(SSIBusy(SSI2_BASE));
        SSIDataGet(SSI2_BASE, &values[i]);
      }

      GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_5, 0xFF);

      for(int i = 0; i < 6; i++){
        UARTprintf("%i\t", values[i]);
      }
      UARTprintf("\n");

      //The X value is stored in values[1] and values[2].
      x = ((int16_t)values[1]<<8)|(int16_t)values[0];
      //The Y value is stored in values[2] and values[3].
      y = ((int16_t)values[3]<<8)|(int16_t)values[2];
      //The Z value is stored in values[4] and values[5].
      z = ((int16_t)values[5]<<8)|(int16_t)values[4];

      UARTprintf("%i\t\t%i\t\t%i\n", x, y, z);

      SysCtlDelay(50 * (SysCtlClockGet() /1000 /3));
    }

    return(0); // will never return
}

Share this post


Link to post
Share on other sites

Hello! 

 

I am using your code recently and I can communicating with the module. But the outputs are really wired. They are all -1,-1,-1. If I move the ADXL345 module, the outputs would become 0,0,0 or like -2,-1,-768723 or -240,0,1.  Can someone help me to see what might be wrong? Thanks.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×