LIS3DH Accelerometer sensor does not update value 3 axis XYZ

Status
Not open for further replies.

BiNa2605

Full Member level 3
Joined
Sep 1, 2015
Messages
179
Helped
6
Reputation
12
Reaction score
4
Trophy points
18
Location
VietNam
Visit site
Activity points
1,357
Hi everyone,

I am working with LIS3DH and have some problems relating to getting data from XYZ axis. In LIS3DH (accelerometer from ST), I enabled FIFO function and operate in stream mode. I use visual C# to display data for testing and debugging. My problem is the data I read it is still one value and does not change even though I move the accelerometer sensor.
And this all of my code.
Code:
/******************************************************************************/
//This codes are used for communicate with Accelerometer sensor LISDH 3-axis
//Write and Read data from Accelerometer sensor
//Author: Dang Trung Nam
//Date: 2016 - Jan - 21
//Hardware: PIC16F1513 Extreme Low Power Consumption (MCU)- LIS3DH (Accelerometer)
//Software: MikroC Pro for PIC
//SPI interface
/******************************************************************************/
#define CS      PORTC.B1     //Chip Select on PORTC.B1
#define WRS     0x00         //Written into the device (sensor) and the address remains unchanged
#define WRI     0x40         //Written into the device (sensor) and the address is auto incremented
#define RES     0x80         //The device (sensor) is read and the address remains unchanged
#define REI     0xC0         //The device (sensor) is read and the address is auto incremented

//Declare Global variables
int iXYZ[6], isample;        //Store 3-axis value
int iX[2],iY[2],iZ[2];
unsigned char txt[6]="123";
unsigned char _data = 0x30;
//Declare sub-functions
void InitGPIO();               //Initiate GPIO and SPI interface
unsigned char ISenID();       //Determine Accelerometer Sensor
void InitLIS3DH();             //Initiate Sensor mode and operation
unsigned char OVRN_StreamMode();
void Read_XYZ();       //SPI Read function
void Read_X(int);
void Read_Y(int);
void Read_Z(int);

void ToggleLed();

void main() {
     unsigned char ucSensor,ucOVRN;
     int j;
     short sTest,sXTest;
     char txt[9];
     char ctest;

     InitGPIO();            //Initiate GPIO and SPI interface
     InitLIS3DH();          //Initiate Sensor mode
     CS = 1; //Stop all SPI

     
     while(1)
     {
           ucSensor = ISenID();

           if(ucSensor == 0x33)
           {
              Read_XYZ();
              while((ucOVRN = OVRN_StreamMode())&0x02);
              /*
              for(j = 0; j < 6; j++)
              {
                  UART1_Write(iXYZ[j]);
                  delay_ms(100);
              }
              */
              for(j = 0; j<32; j++)
              {
                    Read_X(j);
                    Read_Y(j);
                    Read_Z(j);
                    UART1_Write(iX[1]);
                    delay_ms(100);
                    UART1_Write(iX[0]);
                    delay_ms(100);
                    UART1_Write(iY[1]);
                    delay_ms(100);
                    UART1_Write(iY[0]);
                    delay_ms(100);
                    UART1_Write(iZ[1]);
                    delay_ms(100);
                    UART1_Write(iZ[0]);
              }
              ToggleLed();
           }
           else {PORTB.B4 = 0;}
     }
}

//Initiate GPIO and SPI interface
void InitGPIO(){
     OSCCON = 0b01101010;        //Internal oscillator clock 4MHz
     ANSELC = 0;
     ANSELB = 0;
     TRISB.B4 = 0;      //PORTB pin4 output --- Test LED
     PORTB.B4 = 1;      //Led off
     TRISC.B1 = 0;      //PORTC pin1 output --- Chip select
     //Master Mode - clock FOSC/4 (4Mhz/4) - clock idle state low
     //Data transmitted on low to high edge
     //Input data sampled at the middle of internal
     //SPI1_Init();       //Initiate SPI interface
     SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_HIGH_2_LOW);
     UART1_Init(115200);
     delay_ms(500);         //Wait for UART module stablize
}

//Initiate Sensor
//Mode: Normal --- Output Data Rate (ODR) = 50Hz
void InitLIS3DH(){
     //Enable ADC block
     CS = 0;      //Enable SPI
     delay_ms(1);
     SPI1_Write(WRS | 0x1F);  //I want to setup (write) in the TEMP_CFG_REG register
     SPI1_Write(0x80);        //ADC enable
     delay_ms(1);
     CS = 1;
     delay_ms(1);
     
     //Setup Operation for sensor
     CS = 0;      //Enable SPI
     delay_ms(1);
     SPI1_Write(WRS | 0x20);  //I want to setup (write) in the CTRL_REG1 register
     SPI1_Write(0x47);        //Data rate 50Hz, normal mode, 3-axis enable
     delay_ms(1);
     CS = 1;
     delay_ms(1);

     CS = 0;     //Enable SPI
     delay_ms(1);
     SPI1_Write(WRS | 0x21);  //CTRL_REG2 register
     SPI1_Write(0b00000000);  //Don't use High Pass Filter
     delay_ms(1);
     CS = 1;     //Disable SPI
     delay_ms(1);

     CS = 0;     //Enable SPI
     delay_ms(1);
     SPI1_Write(WRS | 0x22);  //CTRL_REG3 register
     SPI1_Write(0b00000010);  //FIFO overrun interrupt.
     delay_ms(1);
     CS = 1;     //Disable SPI
     delay_ms(1);

     //Normal mode, high resolution
     //Scale selection: 2G
     //Block continous update
     //SPI 4 wire interface CS, SPC, SDI, SDA
     //Self test disable
     CS = 0;     //Enable SPI
     delay_ms(1);
     SPI1_Write(WRS | 0x23);  //CTRL_REG4 register
     SPI1_Write(0b00001000);  //Described above HR = 1 - high resolution
     delay_ms(1);
     CS = 1;     //Disable SPI
     delay_ms(1);

     //Enable FIFO
     CS = 0;
     delay_ms(1);
     SPI1_Write(WRS | 0x24);
     SPI1_Write(0x40);      //Enable FIFO
     delay_ms(1);
     CS = 1;
     delay_ms(1);

     //Enable FIFO Mode for measure X,Y,Z data
     //Trigger event liked to trigger signal on INT1
     CS = 0;
     delay_ms(1);
     SPI1_Write(WRS | 0x2E);
     SPI1_Write(0x80);      //Enable stream Mode
     delay_ms(1);
     CS = 1;
     delay_ms(1);

     //Configure INT1_CFG
     CS = 0;
     delay_ms(1);
     SPI1_Write(WRS | 0x30);
     SPI1_Write(0x00);      //Default Direction
     delay_ms(1);
     CS = 1;
}

//Read Address of Accelerometer at WHO_AM_I register 0x0F
unsigned char ISenID(){
     unsigned char ucID;
        //ucTemp = RES | 0x0F;       //ucTemp = 0x8F;
        CS = 0;    //Pull-down CS pin to enable SPI
        delay_ms(1);               //delay for setup time
        //Send the SPI1_Write function with the aim
        //I want to Read data from 0x0F register
        SPI1_Write(RES | 0x0F);
        //Read value from 0x8F register and store in ucID variable
        ucID = SPI1_Read(0);
        delay_ms(1);               //delay for holding time
        CS = 1;    //Pull-up CS pin to disable SPI
     return ucID;
     //Default value of WHO_AM_I value is 0x33
     //Run the while loop until satisfy the condition ucID = 0x33
     //That is the expected sensor
}
unsigned char OVRN_StreamMode()
{
    unsigned char ucFlag;
    CS = 0;       //Enable SPI
    delay_ms(1);
    SPI1_Write(RES | 0x22);
    ucFlag = SPI1_Read(0);
    delay_ms(1);
    CS = 1;     //Disable SPI
    return ucFlag;
}
//Read 3-axis value
void Read_XYZ(){
     unsigned char ucstt;
     unsigned int i;
     //Read Status Register STATUS_REG 0x27
     do{
     CS = 0;       //Enable SPI
     delay_ms(1);
     SPI1_Write(RES | 0x27);   //Send I want to read Status register
     ucstt = SPI1_Read(0);      //Read value from STATUS_AUX register
     delay_ms(1);
     CS = 1;       //Disable SPI
     delay_ms(1);
     }while(ucstt & 0x08);    //Stop the while loop when STATUS_REG[3] = 1
                             //1: a new set of data is available
     /*
     //Checking whether data has overwritten or not. This using for interrupt_function
     if((ucst & 0x80) == 0x80)     //A new set of data has over written the previous ones
     {
         //Using LED to notify that
         PORTB.B4 = 0;
         delay_ms(500);
         PORTB.B4 = 1;
         delay_ms(500);
     }

     */
     //Read XYZ value (read continously: Address will be incremented)
     ucstt = 0;         //Clear value

     /*
     CS = 0;    //Enable SPI
     delay_ms(1);
     SPI1_Write(REI | 0x28);  //0xE8
     for(i = 0; i < 6; i++ ){
          iXYZ[i] = 0;
          iXYZ[i] = SPI1_Read(0);
          delay_us(200);
     }
     delay_ms(1);
     CS = 1;       //Disable SPI
     */
}
void Read_X(int index)
{
 //Read OUTX_H
     CS = 0;
     delay_ms(1);
     SPI1_Write(RES | 0x29);
     iX[1] = 0;
     iX[1] = SPI1_Read(index);
     delay_ms(1);
     CS = 1;
     delay_ms(1);
 //Read OUTX_L
     CS = 0;
     delay_ms(1);
     SPI1_Write(RES | 0x28);
     iX[0] = 0;
     iX[0] = SPI1_Read(index);
     delay_ms(1);
     CS = 1;
}
void Read_Y(int index)
{
 //Read OUTY_H
     CS = 0;
     delay_ms(1);
     SPI1_Write(RES | 0x2B);
     iY[1] = 0;
     iY[1] = SPI1_Read(index);
     delay_ms(1);
     CS = 1;
     delay_ms(1);
 //Read OUTY_L
     CS = 0;
     delay_ms(1);
     SPI1_Write(RES | 0x2A);
     iY[0] = 0;
     iY[0] = SPI1_Read(index);
     delay_ms(1);
     CS = 1;
}

void Read_Z(int index)
{
 //Read OUTZ_H
     CS = 0;
     delay_ms(1);
     SPI1_Write(RES | 0x2D);
     iZ[1] = 0;
     iZ[1] = SPI1_Read(index);
     delay_ms(1);
     CS = 1;
     delay_ms(1);
 //Read OUTZ_L
     CS = 0;
     delay_ms(1);
     SPI1_Write(RES | 0x2C);
     iZ[0] = 0;
     iZ[0] = SPI1_Read(index);
     delay_ms(1);
     CS = 1;
}
void ToggleLed()
{
     PORTB.B4 = 0;
     delay_ms(200);
     PORTB.B4 = 1;
     delay_ms(200);
}
 

Does anyone know how to configure SPI in MikroC like that
Code:
#define SPI_MODE_2 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
I programmed these codes in CCS and it worked. The received data that I get from 3 axis sensitively changed when I moved the sensor

- - - Updated - - -

I fixed my problem
Code:
     SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_HIGH, _SPI_LOW_2_HIGH);
I changed _SPI_CLK_IDLE_HIGH, _SPI_LOW_2_HIGH. It is described very clear in the datasheet of MCU.
 

Does anyone know how to convert received data from 3 axis to acceleration (g = 9.8m/s^2)?
 

Hi,

This table is not in the datasheet..Where is it from?

LIS3DH Datasheet says:
FS bit = "00" --> 1mg/digit. (+/- 2g Full scale)

9.81m/s^2 = 1 g = 1000mg
1000(d) = 3E8(h)

--> if you multiply the integer OUT value with (9.81/1000) = 0.00981, then you get the result in m/s^2

Klaus
 
The table is in the application note of LIS3DH (attached file). I think your recommendation is not right in this case. If you do that how can you get the negative acceleration.
In my case, I get acceleration value from 3-axis in FIFO by setting stream mode (FIFO 10 bit level) and I choose the 2G scale that you mentioned above, FS = 00 so 1mg/digit.
In the application note, when BLE = 0 (default) 0400H = 1024 (10 bit), the acceleration value will be 1g.
I read 2 byte from FIFO (High and Low), so I have 16 bit output. +/- 2G scale <--> [-32768 32767]. If the value (2 bytes) is larger than 32767 that is the negative acceleration.
I am not sure that I know it right or wrong. I am sucking in how to convert data to acceleration value.
 

Attachments

  • LIS3DHappnote.pdf
    1.4 MB · Views: 230

Zip and attach complete mikroC PRO PIC project files as it is easier to study the code after opening it in Compiler.
 

That is my code. I just send acceleration value via UART. All of the processing data I will do in Visual C to ease the MCU burden.
 

Attachments

  • Accelerometer.rar
    33.1 KB · Views: 185

Hi,

If you do that how can you get the negative acceleration.
The IC´s output is two´s complement. So with the 16 bit the (decimal) range is -32768...32767.
You have to assign your variable as "INT16".

-1000 means -1000mg = -1g = -9.81m/s^2

Klaus
 
Dear KlauST, I think I know what you say and it is really help me. But how about the Application Note when the value 15E0H means 5600mg = 5.6g and it is over 2g (scale). So if I shift 4 bit right, that equal when I divide it to 16 means 350mg. That is the right answer. Could you give me the suggestion?
 

Hi,

Hard to say...when datasheet and application note differ..
How can one know?

Only try...

How to try?
There is a simple test written in the datasheet: put the head (of sensor) up and measure acceleration. Expect +1g.
Then put the head down and again measure acceleration. Now expect -1g.

Read both decimal sensor values and decide if datasheet or application note is true.

Klaus
 

Hi Klaus, I tested following the Application Note. At the normal state the result was wrong.

the value of Y-axis is -2g.
The graph is terrible. Could you give me the suggestion?
This is the graph from the Internet

I will test another method, following the datasheet.
 

Hi,

The upper graph, blue line is almost perfect.
You just have to correct the offseterror. You see it is about -1g, so you have to add about 1g.

The lower graph seems to be like throwing a ball.

Maybe you should read some articles about accelerometers, acceleration, earth gravitation...

Klaus
 
I get stuck in reading temperature of that sensor. In the datasheet, just enable TEMP_EN and ADC_PD in the TEMP_CFG_REG (1Fh) and enable automatic update BDU. After that read the value from 2 ADC register OUT_3_L(0Ch) and OUT_3_H(0Dh) but I always read value 232 = 0xE8 in the 0x0Dh higher register~ -24 degree. Beside that temperature value is very sensitive with a changing of accelration value. Does anyone know that? High appreciate for any suggestion.
 

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…