lis3dh debugging experience, read the correct acceleration value

Recently, in debugging the lis3dh accelerometer, a search on the Internet can find a lot of information, but the description is correct, I feel not much, so here I would like to summarize, is also in the netizen blog based on the correct place will be sorted out.

1.   First of all, the driver, which is circulated on the Internet, is basically a. h.c file can be downloaded to the lis3dh driver by any search. Because my company computer is my company computer and the file is encrypted, there is no need to upload the driver. You can search other resources to download. After the driver is downloaded, the user needs to complete the underlying SPI (here I use SPI read-write method, IIC is useless I pasted my own function of reading and writing registers. For your reference, the HAL function is used. Here, I need to explain the speed configuration of SPI. Start the 6M I configured and read WHO_AM_I register and any register read out are all 0x88, check many places can not find the reason, and then accidentally changed to 3M, unexpectedly read ID successfully 0x33, LIS3DH datasheet write the maximum supported SPI rate is 10MHz. It seems that the actual speed can not support such a large

/*Note: if the baud rate of lis3dh is set to 3M, it can be read correctly. If the baud rate is set to 8, the baud rate can not be set to 6M*/
extern SPI_HandleTypeDef hspi2;
uint8_t LIS3DHInit(void)//Initializing SPI
{ 
    LIS3DH_CS_DISABLE; ////Cancel selection  
    MX_SPI2_Init();
    return HAL_OK;
}
/*******************************************************************************
* Function Name                : LIS3DH_ReadReg
* Description                : Generic Reading function. It must be fullfilled with either
*                        : I2C or SPI reading functions                                       
* Input                        : Register Address
* Output                : Data REad
* Return                : None
*******************************************************************************/
uint8_t LIS3DH_ReadReg(uint8_t Reg, uint8_t* Data) {
  
    uint8_t ret;
    uint8_t txdata;
    /* Start SPI transmission */
    LIS3DH_CS_ENABLE;
    /* Add read bit */
    Reg |= 0x80; 
    /* Send address */
    HAL_SPI_Transmit(&hspi2,&Reg,1,100);
    /* Receive data */
    txdata = LIS302DL_LIS3DSH_DUMMY_BYTE;
    ret = HAL_SPI_TransmitReceive(&hspi2,&txdata,Data,1,100);       
    /* Stop SPI transmission */
    LIS3DH_CS_DISABLE;
    return ret;
}


/*******************************************************************************
* Function Name                : LIS3DH_WriteReg
* Description                : Generic Writing function. It must be fullfilled with either
*                        : I2C or SPI writing function
* Input                        : Register Address, Data to be written
* Output                : None
* Return                : None
*******************************************************************************/
uint8_t LIS3DH_WriteReg(uint8_t WriteAddr, uint8_t Data) 
{ 
    uint8_t txdata[2],ret;
    txdata[0] = WriteAddr;
    txdata[1] = Data;
    /* Start SPI transmission */
    LIS3DH_CS_ENABLE;    
    /* Send address */
    ret = HAL_SPI_Transmit(&hspi2,txdata,2,100);
    /* Stop SPI transmission */
    LIS3DH_CS_DISABLE;
    
    return ret;
}
uint8_t LIS3DH_MultiRead(uint8_t start_addr,uint8_t len,uint8_t *data)//Continuous read register
{
    uint8_t ret,txdata;
    
    /* Add read bit and autoincrement bit */
    start_addr |= 0xC0;
    txdata = start_addr;
    /* Start SPI transmission */
    LIS3DH_CS_ENABLE;
    /* Send address */
    HAL_SPI_Transmit(&hspi2,&txdata,1,100);    
    /* Receive data */
    ret = HAL_SPI_TransmitReceive(&hspi2,data,data,len,1000);    
    /* Stop SPI transmission */
    LIS3DH_CS_DISABLE;
    
    return ret;
}

2. Initialization and parameter configuration:

This function is implemented in lis3dinit(); / / 1. It is mainly used for SPI initialization and chip selection signal raising
    Reset_LIS3DH(); / / reset each register
    ret = gsensor_init(); / / configuration parameters
    if(ret != RT_EOK){
        rt_kprintf("gsensor_init failed:%d.\r\n",ret);
        ret = -RT_ERROR;
        return ret;
    }
    gsensor_set_threshold(44,1); / / interrupt threshold setting. Here, the interrupt threshold is set. When the acceleration reaches this value, interrupt 1 will be triggered

The specific implementation of each function is given below

void Reset_LIS3DH(void)
{
    LIS3DH_WriteReg(LIS3DH_TEMP_CFG_REG,0x00); 
	LIS3DH_WriteReg(LIS3DH_CTRL_REG1,0x07); //XYZ axis enable
	LIS3DH_WriteReg(LIS3DH_CTRL_REG2,0x00);
	LIS3DH_WriteReg(LIS3DH_CTRL_REG3,0x00);
	LIS3DH_WriteReg(LIS3DH_CTRL_REG4,0x00);
	LIS3DH_WriteReg(LIS3DH_CTRL_REG5,0x00);
	LIS3DH_WriteReg(LIS3DH_CTRL_REG6,0x00);	
	LIS3DH_WriteReg(LIS3DH_REFERENCE_REG,0x00);
    LIS3DH_WriteReg(LIS3DH_FIFO_CTRL_REG,0x00);
    LIS3DH_WriteReg(LIS3DH_INT1_CFG,0x00);	
	LIS3DH_WriteReg(LIS3DH_INT1_THS,0x00);	
	LIS3DH_WriteReg(LIS3DH_INT1_DURATION,0x00);
	LIS3DH_WriteReg(LIS3DH_CLICK_CFG,0x00);	
	LIS3DH_WriteReg(LIS3DH_CLICK_THS,0x00);	
	LIS3DH_WriteReg(LIS3DH_TIME_LIMIT,0x00);	
	LIS3DH_WriteReg(LIS3DH_TIME_LATENCY,0x00);	
	LIS3DH_WriteReg(LIS3DH_TIME_WINDOW,0x00);	
}
int gsensor_init(void)
{
    uint8_t response = 0;
    response |= LIS3DH_SetODR(LIS3DH_ODR_100Hz);//Set data output frequency
    response  = response << 1;
    response |= LIS3DH_SetMode(LIS3DH_NORMAL);//Set normal mode
    response  = response << 1;
    response |= LIS3DH_SetFullScale(LIS3DH_FULLSCALE_2);//Set the range to ± 2g, BIT6:DATA LSB
    response  = response << 1;
    response |= LIS3DH_SetAxis(LIS3DH_X_ENABLE | LIS3DH_Y_ENABLE | LIS3DH_Z_ENABLE);//Enable triaxial data output
    response  = response << 1;
    return response;
}
uint8_t gsensor_set_threshold(uint8_t threshold_value,uint8_t interrupt_ID)
{
    /*
    1 LSb = 16 mg @ FS = ±2 g
    1 LSb = 32 mg @ FS = ±4 g
    1 LSb = 62 mg @ FS = ±8 g
    1 LSb = 186 mg @ FS = ±16 g
    */
    uint8_t response = 0;
    if(interrupt_ID == 1)
    {
        LIS3DH_HPFAOI1Enable(MEMS_DISABLE);//High pass filter enabled for AOI function on interrupt 1,
        response|= LIS3DH_SetIntConfiguration(LIS3DH_INT1_ZHIE_ENABLE|LIS3DH_INT1_ZLIE_ENABLE|
                                                  LIS3DH_INT1_YHIE_ENABLE|LIS3DH_INT1_YLIE_ENABLE|
                                                  LIS3DH_INT1_XHIE_ENABLE|LIS3DH_INT1_XLIE_ENABLE);//INT1_ enable in CFG
        response|= LIS3DH_SetInt6D4DConfiguration(LIS3DH_INT1_6D_ENABLE);
        response|= LIS3DH_SetIntMode(LIS3DH_INT_MODE_6D_POSITION);
        response|= LIS3DH_SetInt1Threshold(threshold_value);//16 * 16mg == 256mg
        response|= LIS3DH_SetInt1Pin(LIS3DH_I1_INT1_ON_PIN_INT1_ENABLE);
    }
}

3. There are two methods of data collection and calculation

1) Through the formula calculation, we can get:

First call LIS3DH_GetAccAxesRaw() gets register values in three directions of xyz, and then calculates them by formula. The reference article is this:

https://blog.csdn.net/sinat_23338865/article/details/51612872

Firstly, in the 2 parameter configuration, the full scale is ± 2g, LIS3DH is 16bit data output, and one bit is sign bit, so there are 15bit data values left, 2 ^ 15 = 32768, 2g = 2000mg. Therefore, the values in three directions can be calculated as follows:

X = X * 2000 /32768; unit: mg

Y= Y * 2000 /32768 in mg

Z = Z * 2000 /32768; unit: mg

2) By means of shift, the following results were obtained

void LIS3DH_Get_AccRaw(int16_t* pdata)
{
    uint8_t i = 0;
    uint8_t regValue[6] = {0, 0, 0, 0, 0, 0};
    int16_t symbol[3] = {0,0,0};
    for(i=0;i<6;i++)
    {
        LIS3DH_ReadReg(LIS3DH_OUT_X_L+i, regValue+i);            
    }
    /* Format the data. */
    for(i=0;i<3;i++)
    {
        if(regValue[2*i+1] & 0x80) symbol[i] = 0xF000;
        else symbol[i] = 0x0000;                
    }
    pdata[0] =symbol[0]  | ((( ( ( int16_t )regValue[1] ) << 8 ) + ( int16_t )regValue[0] ) >> 4);
    pdata[1] =symbol[1]  | ((( ( ( int16_t )regValue[3] ) << 8 ) + ( int16_t )regValue[2] ) >> 4);
    pdata[2] =symbol[2]  | ((( ( ( int16_t )regValue[5] ) << 8 ) + ( int16_t )regValue[4] ) >> 4);
     
}
/*
*function:LIS3DH_Get_Sensitivity
*Function: read the full scale value: (00: +/- 2G; 01: +/- 4G; 10: +/- 8G; 11: +/- 16G)
*/
static void LIS3DH_Get_Sensitivity(uint8_t* sensitivity)
{
    uint8_t fullscale = 0;    
    LIS3DH_ReadReg(LIS3DH_CTRL_REG4,&fullscale);
    fullscale    = (fullscale & 0x30) >> 4; //0x30:0011 0000
    switch (fullscale)
    {
        case 0:*sensitivity = 1;break;
        case 1:*sensitivity = 2;break;
        case 2:*sensitivity = 4;break;
        case 3:*sensitivity = 12;break;
        default : break;
    }
}

void LIS3DH_Get_AccValue(AxesRaw_t *pdata)
{
    int16_t dataRaw[3];
    uint8_t sensitivity = 0;
    LIS3DH_Get_AccRaw(dataRaw);//The acceleration values in three directions are obtained,
    LIS3DH_Get_Sensitivity(&sensitivity);
    pdata->AXIS_X  =  ( int32_t )( dataRaw[0] * sensitivity );
    pdata->AXIS_Y  =  ( int32_t )( dataRaw[1] * sensitivity );
    pdata->AXIS_Z  =  ( int32_t )( dataRaw[2] * sensitivity );
}

In fact, I don't quite understand the above method of displacement, who can give me contact to explain, ha ha!

Methods 2 reference articles: https://www.pianshen.com/article/2045248726/

4. Test results:

void cmd_lis3dh_test(char *args){
    rt_device_t lis3dh_dev;
    int8_t ret;
    AxesRaw_t acc,acc1;
    int32_t x,y,z;

    lis3dh_dev =  n_device_find("lis3dh");//Code based on RTTthrea
    if(lis3dh_dev == NULL){
        cmd_printf("lis3dh not find.\r\n");
    }
    ret = n_device_open(lis3dh_dev,RT_DEVICE_FLAG_RDWR);
    if(ret != HAL_OK)
        cmd_printf("lis3dh open failed!.\r\n");
    uint8_t lis_id;
    n_device_control(lis3dh_dev,N_LIS3DH_CTRL_ID,&lis_id);
    rt_kprintf("data= 0x%x\r\n",lis_id);

    LIS3DH_GetAccAxesRaw(&acc);//Method 1)
    cmd_printf("LIS3DH read Acceleration adval, x:%d, y:%d, z:%d.\r\n",acc.AXIS_X,acc.AXIS_Y,acc.AXIS_Z);

    acc.AXIS_X = acc.AXIS_X * 2000 / 32768;
    acc.AXIS_Y = acc.AXIS_Y * 2000 / 32768;
    acc.AXIS_Z = acc.AXIS_Z * 2000 / 32768;
    cmd_printf("LIS3DH read Acceleration mg, x:%d, y:%d, z:%d.\r\n",acc.AXIS_X,acc.AXIS_Y,acc.AXIS_Z);
    LIS3DH_Get_AccValue(&acc1); //Method 2)
    cmd_printf("LIS3DH read Acceleration g, x:%d, y:%d, z:%d.\r\n",acc1.AXIS_X,acc1.AXIS_Y,acc1.AXIS_Z);    
    cmd_printf("LIS3DH read INT1 Level: %d\r\n ",n_gpio_readpin(GPIOE,GPIO_PIN_13));//Display accelerometer interrupt

    n_device_close(lis3dh_dev);
}

5. Test results:

0x33 is the ID of lis3dh.

adval is the value in the register; mg is the result of method 1, g is the result of method 2, and the unit is not marked correctly.

Posted on Mon, 29 Jun 2020 03:22:52 -0400 by markl999