cancel
Showing results for 
Search instead for 
Did you mean: 

H3LIS200DL - Configuration and Readings

Rogers.Gary
Senior II
Posted on September 02, 2017 at 22:41

Hello:

I have been fighting with this accelerometer for a couple of months and it has now become imperative that I get it functioning.

I am using it with an STM32F405 controller. I have it set up in interrupt mode. When I get an interrupt, I read and process the X,Y,Z registers but the values are always (or almost nearly)  the same: -20, -3, -6.

I have absolutely not a clue what is going on. Can anyone please help me with this? Here is the code to process the data after the interrupt. Directly below is the call to SPI read that the handler uses

uint8_t SPI_read(uint8_t address)

{

  GPIO_SetPinLow(GPIOD, ACCHI_CS);

  address = 0x80 | address;   // 0b10 - reading and clearing status

 

  while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);

  SPI_I2S_SendData(SPI3, address);

  while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) == RESET);

  SPI_I2S_ReceiveData(SPI3);

 

  while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);

  SPI_I2S_SendData(SPI3, 0x00);

  while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) == RESET);

 

  GPIO_SetPinHigh(GPIOD, ACCHI_CS);

 

  return SPI_I2S_ReceiveData(SPI3);

}

/* Interrupt handler for EXT1 */

void EXTI1_IRQHandler(void)

{

    volatile uint8_t x = 0, y = 0, z = 0, reg;

    volatile float32_t cX = 0, cY = 0, cZ = 0;

    volatile int8_t accVal, xF,yF,zF;

      

    if (EXTI_GetITStatus(EXTI_Line1) != RESET )

    {

        EXTI_ClearITPendingBit(EXTI_Line1);   

        // who dunnit?

        reg = SPI_read( LIS200DL_INT1SRC );            

        

        if( reg & 0x40 )

        {

            x = SPI_read( LIS200DL_OUT_X );

            y = SPI_read( LIS200DL_OUT_Y );         

            z = SPI_read( LIS200DL_OUT_Z );         

        }

           

        if( x & 0x80 )

        {

            //it's negative, invert result

            accVal = x ^ 1;

            accVal += 0x1;

            cX = (accVal * 0.780);

            //printf('-X acc value = %.1f\n', cX);

        }

        else

        {

            cX = (x * 0.780) * -1.0;

            //printf('+X acc value = %.1f\n', cX);

        }

            

        if( y & 0x80 )

        {

            //invert result

            accVal = y ^ 1;

            accVal += 0x1;

            cY = (accVal * 0.780);

            //printf('+Y acc value = %.1f\n', cY);            

        }   

        else

        {

            cY = (y * 0.780) * -1.0;

            //printf('-Y acc value = %.1f\n', cY);

        }

              

        if( z & 0x80 )

        {

            //invert result

            accVal = z ^ 1;

            accVal += 0x1;

            cZ = (accVal * 0.780);

            //printf('+Z acc value = %.1f\n', cZ);            

        }

        else

        {

            cZ = (z * 0.780) * -1.0;

            //printf('-Z acc value = %.1f\n', cZ);

        }

       

        xF = (int8_t)cX;            

        yF = (int8_t)cY;            

        zF = (int8_t)cZ;                    

        if( (abs(xF) > 3) || (abs(yF) > 3) || (abs(zF) > 3) )  

        {

            myDataX = xF;

            myDataY = yF;

            myDataZ = zF;          

        }

    }

}

Please advise as to where I am making a mistake. If no one on this forum can help, how can I get official ST support? This device will be used on quite a few systems and right now, it is holding the project up.]\

Roger

1 ACCEPTED SOLUTION

Accepted Solutions
Posted on September 06, 2017 at 09:41

I have several notes:

- yes, the XOR operation was not correct

- if you fix the XOR operation the conversion will be correct except the sign. You are inverting the value. If the accelerometer output is positive you get negative value and vice versa. But maybe you are doing this intentionally.

- you are loosing some precision due to conversion from float to int (in this command 

xF = (int8_t)cX;)

- As C use two's complement for signed variables you can simply replace the whole if structure by one command: xF = (int8_t)x * 0.780f;

View solution in original post

10 REPLIES 10
Miroslav BATEK
ST Employee
Posted on September 04, 2017 at 11:52

Can you please provide your sensor configuration (register settings)?

Rogers.Gary
Senior II
Posted on September 05, 2017 at 04:29

Here is the setup that includes the SPI and registers. Below that is the register definitions.

uint8_t configH3LIS200DL( void )

{

    uint8_t rtnValue;

    

    GPIO_InitTypeDef GPIO_InitStructure;

    SPI_InitTypeDef  SPI_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);    

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);

    

    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;

    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set;

    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;

    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

    SPI_Init(SPI3, &SPI_InitStructure);

    //Initialize pins for SPI functionality

    GPIO_InitStructure.GPIO_Pin = ACCHI_SCK | ACCHI_MISO | ACCHI_MOSI;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_Init(GPIOC, &GPIO_InitStructure);

    

    //Initialize Chip Select pin

    GPIO_InitStructure.GPIO_Pin = ACCHI_CS;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_Init(GPIOD, &GPIO_InitStructure);

   

    //interrupt 1 configured in void Configure_PD1_EXTI(void) below...

    

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SPI3);

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_SPI3);

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SPI3);    

    

    // set initially HIGH

    GPIO_SetPinHigh(GPIOD, ACCHI_CS);    

    

    // enable SPI3

    SPI_Cmd(SPI3, ENABLE);

   

    SPI_send( LIS200DL_WHO_AM_I, 0x0 );        

    rtnValue = SPI_read( LIS200DL_WHO_AM_I );

    //printf('ID2 = %x\n', rtnValue);    

    

    SPI_send( LIS200DL_CTRL_REG1, 0x2F );    

    rtnValue = SPI_read( LIS200DL_CTRL_REG1 );    

    //printf('ctl1 = %x\n', rtnValue);

    

    SPI_send( LIS200DL_CTRL_REG3, 0x0 );    

    rtnValue = SPI_read( LIS200DL_CTRL_REG3 );    

    //printf('ctl1 = %x\n', rtnValue);     

    

    SPI_send( LIS200DL_CTRL_REG4, 0x0 );        

    //configure interrupt register

    SPI_send( LIS200DL_INT1CFG, 0x2A );    

    rtnValue = SPI_read( LIS200DL_INT1CFG );    

    //printf('int1 reg = %x\n', rtnValue);    

    

    //set threshold register = 3

    SPI_send( LIS200DL_INT1THS, 0x3 );    

    rtnValue = SPI_read( LIS200DL_INT1THS );    

    //printf('thr reg = %x\n', rtnValue);        

    

    return rtnValue;

}

REGISTER DEFS:

#define LIS200DL_WHO_AM_I 0x0F

#define LIS200DL_CTRL_REG1 0x20

#define LIS200DL_CTRL_REG2 0x21

#define LIS200DL_CTRL_REG3 0x22

#define LIS200DL_CTRL_REG4 0x23

#define LIS200DL_CTRL_REG5 0x24

#define LIS200DL_HP_RESET  0x25

#define LIS200DL_STATUS_REG 0x27

#define LIS200DL_OUT_X 0x29

#define LIS200DL_OUT_Y 0x2B

#define LIS200DL_OUT_Z 0x2D

#define LIS200DL_INT1CFG 0x30

#define LIS200DL_INT1SRC 0x31

#define LIS200DL_INT1THS 0x32

#define LIS200DL_INT1DUR 0x33

#define LIS200DL_INT2CFG 0x34

#define LIS200DL_INT2SRC 0x35

#define LIS200DL_INT2THS 0x36

#define LIS200DL_INT2DUR 0x37

// CTRL_REG1

#define LIS200DL_XEN 0x01

#define LIS200DL_YEN 0x02

#define LIS200DL_ZEN 0x04

#define LIS200DL_XYZ_NEW 0x08

#define LIS200DL_XOR 0x10

#define LIS200DL_YOR  0x20

#define LIS200DL_ZOR  0x40

#define LIS200DL_XYZOR 0x80

// CTRL_REG2

#define LIS200DL_HP_COEFF1  0x01

#define LIS200DL_HP_COEFF2  0x02

#define LIS200DL_HP_FF_WU1  0x04

#define LIS200DL_HP_FF_WU2  0x08

#define LIS200DL_FDS         0x10

#define LIS200DL_BOOT       0x40

#define LIS200DL_SIM        0x80

Thanks,

Roger

Miroslav BATEK
ST Employee
Posted on September 05, 2017 at 09:53

The configuration seems OK to me, it works as expected. You configured the sensor to generate the interrupt if acceleration in any axis is above 2.3g.

How do you stimulate the interrupt?

If you say: 'I read and process the X,Y,Z registers but the values are always (or almost nearly)  the same: -20, -3, -6.' are the values in LSB or in g?

What do you want to achieve? What is your target application?

Rogers.Gary
Senior II
Posted on September 05, 2017 at 17:00

Hi,

Thanks for taking the time to look at this and reply. First and most importantly, can you please advise if the conversions from raw data to values look correct? They should be converting from raw values to 'g' values. (in reference to your question about LSB or g values)

With respect to your other question - if the values were almost always '

-20, -3, -6.'

, wouldn't that look suspicious to you? I am interested in those values from +/-3g to +/-100g. The application is on a PCB in an industrial machine and there are all kinds of shake values in there that could potentially go to 100g. So why would it always produce these values?

Regards...

Rogers.Gary
Senior II
Posted on September 05, 2017 at 17:58

Ok, if you could check and verify this, I would be grateful - it may be where some of the problem is.

Also, values xF, yF and zF are declared as int8_t already. Is that the variables you were referring to ('you can simply change the type from uint8_t to int8_t ...') or did you mean something different?

Posted on September 05, 2017 at 17:23

At the first glance, I think it is not correct, but I will simulate exactly your code tomorrow.

You don't have to convert the raw value by so complex function, you can simply change the type from uint8_t to int8_t and multiply by sensitivity.

xF = (int_8)x * 0.780f;

Rogers.Gary
Senior II
Posted on September 06, 2017 at 05:25

This:

x = (x ^ 0xFF) + 1; // Two's complement

Fixed it. It was nonsense!

Thanks

Posted on September 06, 2017 at 03:39

  if( x & 0x80 )

        {

            //it's negative, invert result

            accVal = x ^ 1;

            accVal += 0x1;

            cX = (accVal * 0.780);

            //printf('-X acc value = %.1f\n', cX);

        }

What's the XOR ONE nonsense?

if (x & 0x80)

x = (x ^ 0xFF) + 1; // Two's complement

Or is it in sign-magnitude format?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on September 06, 2017 at 09:41

I have several notes:

- yes, the XOR operation was not correct

- if you fix the XOR operation the conversion will be correct except the sign. You are inverting the value. If the accelerometer output is positive you get negative value and vice versa. But maybe you are doing this intentionally.

- you are loosing some precision due to conversion from float to int (in this command 

xF = (int8_t)cX;)

- As C use two's complement for signed variables you can simply replace the whole if structure by one command: xF = (int8_t)x * 0.780f;