2021-10-27 06:38 AM
Desired behavior is shown on the first attachment (mma8451_sensor). When I read and parse LIS3DH data it seems that data are fluctuating(lis3dh_sensor) and cannot remain stable. Could you help me what am I doing wrong ?
bool LIS3DH_Init(void)
{
uint8_t tx_data[STD_TWO_BYTE_SIZE] = {0};
uint8_t ctrl_reg1_val = LIS3DH_CTRL1_DEFAULT_POWER_DOWN_VAL;
uint8_t ctrl_reg2_val = LIS3DH_FDS_ENABLE;
uint8_t ctrl_reg4_val = (LIS3DH_BDU_ENABLED | LIS3DH_RESOLUTION_2G);
if (false == read_who_am_i())
{
return false;
}
/* Writing to CTRL_REG1 register to enable low power mode and set measurement frequency */
tx_data[0] = LIS3DH_ADDR_CTRL_REG1;
tx_data[1] = ctrl_reg1_val;
CoM_i2c_write(LIS3DH_ADDR, &tx_data[0], STD_TWO_BYTE_SIZE, false);
/* Writing to CTRL_REG2 register to enable high pass filter */
tx_data[0] = LIS3DH_ADDR_CTRL_REG2;
tx_data[1] = ctrl_reg2_val;
CoM_i2c_write(LIS3DH_ADDR, &tx_data[0], STD_TWO_BYTE_SIZE, false);
/* Writing to CTRL_REG4 register to disable high-resolution mode and enable block data update feature */
tx_data[0] = LIS3DH_ADDR_CTRL_REG4;
tx_data[1] = ctrl_reg4_val;
CoM_i2c_write(LIS3DH_ADDR, &tx_data[0], STD_TWO_BYTE_SIZE, false);
/* Dummy read to force the HP filter to current acceleration value */
uint8_t dummy_reference_reg = LIS3DH_ADDR_REFERENCE;
uint8_t dummy_reference_val = 0x00;
CoM_i2c_write(LIS3DH_ADDR, &dummy_reference_reg, STD_ONE_BYTE_SIZE, true);
CoM_i2c_read(LIS3DH_ADDR, &dummy_reference_val, STD_ONE_BYTE_SIZE);
if (NRF_SUCCESS != change_mode(HIGH_RESOLUTION_MODE))
return false;
return true;
}
/* Change mode of the LIS3DH chip */
static uint32_t change_mode(lis3dh_mode mode)
{
uint8_t ctrl_reg1_val = 0x00;
uint8_t ctrl_reg4_val = 0x00;
uint8_t reg;
if (mode > HIGH_RESOLUTION_MODE)
{
NRF_LOG_RAW_INFO("[ERROR] lis3dh unsupported mode request");
return NRF_ERROR_NOT_SUPPORTED;
}
/* Read current configuration */
reg = LIS3DH_ADDR_CTRL_REG1;
CoM_i2c_write(LIS3DH_ADDR, ®, STD_ONE_BYTE_SIZE, true);
CoM_i2c_read(LIS3DH_ADDR, &ctrl_reg1_val, STD_ONE_BYTE_SIZE);
reg = LIS3DH_ADDR_CTRL_REG4;
CoM_i2c_write(LIS3DH_ADDR, ®, STD_ONE_BYTE_SIZE, true);
CoM_i2c_read(LIS3DH_ADDR, &ctrl_reg4_val, STD_ONE_BYTE_SIZE);
/* Clear the ODR related bits */
ctrl_reg1_val &= 0x0F;
switch(mode)
{
case POWER_DOWN_MODE:
{
//ToDo
break;
}
case LOW_POWER_MODE:
{
/* Enable LPen bit in CTRL_REG1
* Decrase ODR value
* Disable HR bit in CTRL_REG4
*/
ctrl_reg1_val = LIS3DH_CTRL1_DEFAULT_LOW_POWER_VAL;
ctrl_reg4_val &= ~LIS3DH_HIGH_RES_ENABLE;
break;
}
case HIGH_RESOLUTION_MODE:
{
/* Disable LPen bit in CTRL_REG1
* Increase ODR value
* Enable HR bit in CTRL_REG4
*/
ctrl_reg1_val &= ~LIS3DH_LOW_POWER_ENABLE;
ctrl_reg1_val |= LIS3DH_MODE_50HZ;
ctrl_reg4_val |= LIS3DH_HIGH_RES_ENABLE;
break;
}
case NORMAL_MODE:
default:
{
/* Disable LPen bit in CTRL_REG1
* Increase ODR value
* Disable HR bit in CTRL_REG4
*/
ctrl_reg1_val &= ~LIS3DH_LOW_POWER_ENABLE;
ctrl_reg1_val |= LIS3DH_MODE_50HZ;
ctrl_reg4_val &= ~LIS3DH_HIGH_RES_ENABLE;
break;
}
}
/* Update power mode */
uint8_t tx_data[STD_TWO_BYTE_SIZE] = {0};
tx_data[0] = LIS3DH_ADDR_CTRL_REG1;
tx_data[1] = ctrl_reg1_val;
CoM_i2c_write(LIS3DH_ADDR, &tx_data[0], STD_TWO_BYTE_SIZE, false);
tx_data[0] = LIS3DH_ADDR_CTRL_REG4;
tx_data[1] = ctrl_reg4_val;
CoM_i2c_write(LIS3DH_ADDR, &tx_data[0], STD_TWO_BYTE_SIZE, false);
return NRF_SUCCESS;
}
void LIS3DH_Read_Data(uint8_t *data, uint8_t len)
{
//int16_t x, y, z;
uint8_t raw_data[STD_XYZ_AXIS_DATA_LEN];
uint8_t reg = LIS3DH_STATUS;
uint8_t status = 0x00;
/* Read current status */
CoM_i2c_write(LIS3DH_ADDR, ®, STD_ONE_BYTE_SIZE, true);
CoM_i2c_read(LIS3DH_ADDR, &status, STD_ONE_BYTE_SIZE);
if (!(status & LIS3DH_ZYX_OR))
{
NRF_LOG_RAW_INFO("[WARN] lis3dh_status no data\r\n");
return;
}
/* Read XYZ data */
reg = (LIS3DH_OUT_X_L | LIS3DH_READ_AUTO_INCREMENT);
CoM_i2c_write(LIS3DH_ADDR, ®, STD_ONE_BYTE_SIZE, true);
CoM_i2c_read(LIS3DH_ADDR, &raw_data[0], STD_XYZ_AXIS_DATA_LEN);
/* x = raw_data[0];
x |= ((uint16_t)raw_data[1]) << 8;
y = raw_data[2];
y |= ((uint16_t)raw_data[3]) << 8;
z = raw_data[4];
z |= ((uint16_t)raw_data[5]) << 8;
*/
data[0] = raw_data[1];
data[1] = raw_data[0];
data[2] = raw_data[3];
data[3] = raw_data[2];
data[4] = raw_data[5];
data[5] = raw_data[4];
}
Plotted stuff is:
LOG("x: %d\r\n", (data[2] << 8) | data[3]);
LOG("y: %d\r\n", (data[4] << 8) | data[5]);
LOG("z: %d\r\n", (data[6] << 8) | data[7]);
BR,
Jakub
2021-10-28 08:46 AM
Hi Jakub, are you sure you are correctly concatenating the MSB and LSB of the data? And correctly converting the LSB units into physical units? Note that the data are not defined on 16 bits:
https://www.st.com/resource/en/datasheet/lis3dh.pdf
Check also these drivers on Github
https://github.com/STMicroelectronics/lis3dh/tree/6a82fc90cfb688686d0b344c82184c33ee844697
\Tom
2021-10-28 09:51 AM
Hello, thanks for the response. Casting the MSB to int16_t has partially solved the problem.
There is a difference in behavior between mma8451 and lis3dh. As You can see on the plots, the lis3dh returns to the '0' value when there is no movement, but the mma8451 chip 'remains' in the current position. Is there any possibility to provoke lis3dh sensor to get current position, not only the 'movement' related value ?
Please take a look on below pictures that will explain what I mean:
BR,
Jakub
2021-11-16 05:49 AM
Hi Jakub,
probably in the mma8451 there is an embedded (default) high pass filter, that removes (also) the Earth acceleration (so your steady reading along Z is not 1g but 0g).
You can enable this filter also on the LIS3DH, by configuring the HPM1 and HPM0 bits of the CTRL_REG2 (21h) register (datasheet p.36).
https://www.st.com/resource/en/datasheet/lis3dh.pdf
It is explained in more detail in the application note, p.17.
\Tom