|
|
|
@ -1,17 +1,132 @@ |
|
|
|
|
#include "lsm6ds3_accel.h" |
|
|
|
|
|
|
|
|
|
#include <cassert> |
|
|
|
|
#include <cmath> |
|
|
|
|
#include <cstring> |
|
|
|
|
|
|
|
|
|
#include "common/swaglog.h" |
|
|
|
|
#include "common/timing.h" |
|
|
|
|
#include "common/util.h" |
|
|
|
|
|
|
|
|
|
LSM6DS3_Accel::LSM6DS3_Accel(I2CBus *bus, int gpio_nr, bool shared_gpio) : |
|
|
|
|
I2CSensor(bus, gpio_nr, shared_gpio) {} |
|
|
|
|
|
|
|
|
|
void LSM6DS3_Accel::wait_for_data_ready() { |
|
|
|
|
uint8_t drdy = 0; |
|
|
|
|
uint8_t buffer[6]; |
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
read_register(LSM6DS3_ACCEL_I2C_REG_STAT_REG, &drdy, sizeof(drdy)); |
|
|
|
|
drdy &= LSM6DS3_ACCEL_DRDY_XLDA; |
|
|
|
|
} while (drdy == 0); |
|
|
|
|
|
|
|
|
|
read_register(LSM6DS3_ACCEL_I2C_REG_OUTX_L_XL, buffer, sizeof(buffer)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void LSM6DS3_Accel::read_and_avg_data(float* out_buf) { |
|
|
|
|
uint8_t drdy = 0; |
|
|
|
|
uint8_t buffer[6]; |
|
|
|
|
|
|
|
|
|
float scaling = 0.061f; |
|
|
|
|
if (source == cereal::SensorEventData::SensorSource::LSM6DS3TRC) { |
|
|
|
|
scaling = 0.122f; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 5; i++) { |
|
|
|
|
do { |
|
|
|
|
read_register(LSM6DS3_ACCEL_I2C_REG_STAT_REG, &drdy, sizeof(drdy)); |
|
|
|
|
drdy &= LSM6DS3_ACCEL_DRDY_XLDA; |
|
|
|
|
} while (drdy == 0); |
|
|
|
|
|
|
|
|
|
int len = read_register(LSM6DS3_ACCEL_I2C_REG_OUTX_L_XL, buffer, sizeof(buffer)); |
|
|
|
|
assert(len == sizeof(buffer)); |
|
|
|
|
|
|
|
|
|
for (int j = 0; j < 3; j++) { |
|
|
|
|
out_buf[j] += (float)read_16_bit(buffer[j*2], buffer[j*2+1]) * scaling; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; i++) { |
|
|
|
|
out_buf[i] /= 5.0f; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int LSM6DS3_Accel::self_test(int test_type) { |
|
|
|
|
float val_st_off[3] = {0}; |
|
|
|
|
float val_st_on[3] = {0}; |
|
|
|
|
float test_val[3] = {0}; |
|
|
|
|
uint8_t ODR_FS_MO = LSM6DS3_ACCEL_ODR_52HZ; // full scale: +-2g, ODR: 52Hz
|
|
|
|
|
|
|
|
|
|
// prepare sensor for self-test
|
|
|
|
|
|
|
|
|
|
// enable block data update and automatic increment
|
|
|
|
|
int ret = set_register(LSM6DS3_ACCEL_I2C_REG_CTRL3_C, LSM6DS3_ACCEL_IF_INC_BDU); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (source == cereal::SensorEventData::SensorSource::LSM6DS3TRC) { |
|
|
|
|
ODR_FS_MO = LSM6DS3_ACCEL_FS_4G | LSM6DS3_ACCEL_ODR_52HZ; |
|
|
|
|
} |
|
|
|
|
ret = set_register(LSM6DS3_ACCEL_I2C_REG_CTRL1_XL, ODR_FS_MO); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// wait for stable output, and discard first values
|
|
|
|
|
util::sleep_for(100); |
|
|
|
|
wait_for_data_ready(); |
|
|
|
|
read_and_avg_data(val_st_off); |
|
|
|
|
|
|
|
|
|
// enable Self Test positive (or negative)
|
|
|
|
|
ret = set_register(LSM6DS3_ACCEL_I2C_REG_CTRL5_C, test_type); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// wait for stable output, and discard first values
|
|
|
|
|
util::sleep_for(100); |
|
|
|
|
wait_for_data_ready(); |
|
|
|
|
read_and_avg_data(val_st_on); |
|
|
|
|
|
|
|
|
|
// disable sensor
|
|
|
|
|
ret = set_register(LSM6DS3_ACCEL_I2C_REG_CTRL1_XL, 0); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// disable self test
|
|
|
|
|
ret = set_register(LSM6DS3_ACCEL_I2C_REG_CTRL5_C, 0); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// calculate the mg values for self test
|
|
|
|
|
for (int i = 0; i < 3; i++) { |
|
|
|
|
test_val[i] = fabs(val_st_on[i] - val_st_off[i]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// verify test result
|
|
|
|
|
for (int i = 0; i < 3; i++) { |
|
|
|
|
if ((LSM6DS3_ACCEL_MIN_ST_LIMIT_mg > test_val[i]) || |
|
|
|
|
(test_val[i] > LSM6DS3_ACCEL_MAX_ST_LIMIT_mg)) { |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int LSM6DS3_Accel::init() { |
|
|
|
|
int ret = 0; |
|
|
|
|
uint8_t buffer[1]; |
|
|
|
|
uint8_t value = 0; |
|
|
|
|
bool do_self_test = false; |
|
|
|
|
|
|
|
|
|
const char* env_lsm_selftest =env_lsm_selftest = std::getenv("LSM_SELF_TEST"); |
|
|
|
|
if (env_lsm_selftest != nullptr && strncmp(env_lsm_selftest, "1", 1) == 0) { |
|
|
|
|
do_self_test = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ret = read_register(LSM6DS3_ACCEL_I2C_REG_ID, buffer, 1); |
|
|
|
|
if(ret < 0) { |
|
|
|
@ -29,11 +144,29 @@ int LSM6DS3_Accel::init() { |
|
|
|
|
source = cereal::SensorEventData::SensorSource::LSM6DS3TRC; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ret = self_test(LSM6DS3_ACCEL_POSITIVE_TEST); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
LOGE("LSM6DS3 accel positive self-test failed!"); |
|
|
|
|
if (do_self_test) goto fail; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ret = self_test(LSM6DS3_ACCEL_NEGATIVE_TEST); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
LOGE("LSM6DS3 accel negative self-test failed!"); |
|
|
|
|
if (do_self_test) goto fail; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ret = init_gpio(); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// enable continuous update, and automatic increase
|
|
|
|
|
ret = set_register(LSM6DS3_ACCEL_I2C_REG_CTRL3_C, LSM6DS3_ACCEL_IF_INC); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO: set scale and bandwidth. Default is +- 2G, 50 Hz
|
|
|
|
|
ret = set_register(LSM6DS3_ACCEL_I2C_REG_CTRL1_XL, LSM6DS3_ACCEL_ODR_104HZ); |
|
|
|
|
if (ret < 0) { |
|
|
|
|