1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/lsm6dsxx/lsm6dsxx.c
2024-03-26 18:13:19 +01:00

312 lines
8.5 KiB
C

/*
* Copyright (C) 2017 OTA keys S.A.
* Copyright (C) 2024 HAW Hamburg.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
*/
/**
* @ingroup drivers_lsm6dsxx
* @{
*
* @file
* @brief Device driver implementation for the LSM6DSXX 3D accelerometer/gyroscope.
*
* @author Vincent Dupont <vincent@otakeys.com>
* @author Sebastian Meiling <s@mlng.net>
* @author Miquel Borrell <miquel.borrell@haw-hamburg.de>
*
* @}
*/
#include <assert.h>
#include "ztimer.h"
#include "macros/utils.h"
#include "lsm6dsxx.h"
#include "lsm6dsxx_internal.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#define BUS (dev->params.i2c)
#define ADDR (dev->params.addr)
/**
* order in array [0, 1, 2, 3] is
* LSM6DSXX_ACC_FS_2G, LSM6DSXX_ACC_FS_16G, LSM6DSXX_ACC_FS_4G, LSM6DSXX_ACC_FS_8G
*/
static const int16_t range_acc[] = { 2000, 16000, 4000, 8000 };
/**
* order in array [0, 1, 2, 3] is
* LSM6DSXX_GYRO_FS_245DPS, LSM6DSXX_GYRO_FS_500DPS,
* LSM6DSXX_GYRO_FS_1000DPS, LSM6DSXX_GYRO_FS_2000DPS
*/
static const int16_t range_gyro[] = { 2450, 5000, 10000, 20000 };
int lsm6dsxx_init(lsm6dsxx_t *dev, const lsm6dsxx_params_t *params)
{
uint8_t tmp;
int res;
assert(dev && params);
dev->params = *params;
i2c_acquire(BUS);
/* Reboot */
i2c_write_reg(BUS, ADDR, LSM6DSXX_REG_CTRL3_C, LSM6DSXX_CTRL3_C_BOOT, 0);
ztimer_sleep(ZTIMER_MSEC, LSM6DSXX_BOOT_WAIT_MS);
if (i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_WHO_AM_I, &tmp, 0) < 0) {
i2c_release(BUS);
DEBUG("[ERROR] lsm6dsxx_init: i2c_read_reg LSM6DSXX_REG_WHO_AM_I!\n");
return -LSM6DSXX_ERROR_BUS;
}
if (tmp == LSM6DS33_WHO_AM_I) {
dev->temperature_scaling_factor = 4;
}
else if (tmp == LSM6DSL_WHO_AM_I) {
dev->temperature_scaling_factor = 8;
}
else {
DEBUG("[ERROR] lsm6dsxx_init: WHO_AM_I\n");
return -LSM6DSXX_ERROR_DEV;
}
/* Set acc odr / full scale */
tmp = (dev->params.acc_odr << LSM6DSXX_CTRL_ODR_SHIFT) |
(dev->params.acc_fs << LSM6DSXX_CTRL_FS_SHIFT);
res = i2c_write_reg(BUS, ADDR, LSM6DSXX_REG_CTRL1_XL, tmp, 0);
/* Set gyro odr / full scale */
tmp = (dev->params.gyro_odr << LSM6DSXX_CTRL_ODR_SHIFT) |
(dev->params.gyro_fs << LSM6DSXX_CTRL_FS_SHIFT);
res += i2c_write_reg(BUS, ADDR, LSM6DSXX_REG_CTRL2_G, tmp, 0);
/* Set continuous mode */
uint8_t fifo_odr = MAX(dev->params.acc_odr, dev->params.gyro_odr);
tmp = (fifo_odr << LSM6DSXX_FIFO_CTRL5_FIFO_ODR_SHIFT) |
LSM6DSXX_FIFO_CTRL5_CONTINUOUS_MODE;
res += i2c_write_reg(BUS, ADDR, LSM6DSXX_REG_FIFO_CTRL5, tmp, 0);
tmp = (dev->params.gyro_decimation << LSM6DSXX_FIFO_CTRL3_GYRO_DEC_SHIFT) |
dev->params.acc_decimation;
res += i2c_write_reg(BUS, ADDR, LSM6DSXX_REG_FIFO_CTRL3, tmp, 0);
i2c_release(BUS);
if (res < 0) {
DEBUG("[ERROR] lsm6dsxx_init: config\n");
return -LSM6DSXX_ERROR_CNF;
}
return LSM6DSXX_OK;
}
int lsm6dsxx_read_acc(const lsm6dsxx_t *dev, lsm6dsxx_3d_data_t *data)
{
int res;
uint8_t tmp;
i2c_acquire(BUS);
i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_STATUS_REG, &tmp, 0);
DEBUG("lsm6dsxx status: %x\n", tmp);
res = i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_OUTX_L_XL, &tmp, 0);
data->x = tmp;
res += i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_OUTX_H_XL, &tmp, 0);
data->x |= tmp << 8;
res += i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_OUTY_L_XL, &tmp, 0);
data->y = tmp;
res += i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_OUTY_H_XL, &tmp, 0);
data->y |= tmp << 8;
res += i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_OUTZ_L_XL, &tmp, 0);
data->z = tmp;
res += i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_OUTZ_H_XL, &tmp, 0);
data->z |= tmp << 8;
i2c_release(BUS);
if (res < 0) {
DEBUG("[ERROR] lsm6dsxx_read_acc\n");
return -LSM6DSXX_ERROR_BUS;
}
assert(dev->params.acc_fs < LSM6DSXX_ACC_FS_MAX);
data->x = ((int32_t)data->x * range_acc[dev->params.acc_fs]) / INT16_MAX;
data->y = ((int32_t)data->y * range_acc[dev->params.acc_fs]) / INT16_MAX;
data->z = ((int32_t)data->z * range_acc[dev->params.acc_fs]) / INT16_MAX;
return LSM6DSXX_OK;
}
int lsm6dsxx_read_gyro(const lsm6dsxx_t *dev, lsm6dsxx_3d_data_t *data)
{
int res;
uint8_t tmp;
i2c_acquire(BUS);
i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_STATUS_REG, &tmp, 0);
DEBUG("lsm6dsxx status: %x\n", tmp);
res = i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_OUTX_L_G, &tmp, 0);
data->x = tmp;
res += i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_OUTX_H_G, &tmp, 0);
data->x |= tmp << 8;
res += i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_OUTY_L_G, &tmp, 0);
data->y = tmp;
res += i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_OUTY_H_G, &tmp, 0);
data->y |= tmp << 8;
res += i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_OUTZ_L_G, &tmp, 0);
data->z = tmp;
res += i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_OUTZ_H_G, &tmp, 0);
data->z |= tmp << 8;
i2c_release(BUS);
if (res < 0) {
DEBUG("[ERROR] lsm6dsxx_read_gyro\n");
return -LSM6DSXX_ERROR_BUS;
}
assert(dev->params.gyro_fs < LSM6DSXX_GYRO_FS_MAX);
data->x = ((int32_t)data->x * range_gyro[dev->params.gyro_fs]) / INT16_MAX;
data->y = ((int32_t)data->y * range_gyro[dev->params.gyro_fs]) / INT16_MAX;
data->z = ((int32_t)data->z * range_gyro[dev->params.gyro_fs]) / INT16_MAX;
return LSM6DSXX_OK;
}
int lsm6dsxx_read_temp(const lsm6dsxx_t *dev, int16_t *data)
{
uint8_t tmp;
uint16_t traw;
/* read raw temperature */
i2c_acquire(BUS);
if (i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_OUT_TEMP_L, &tmp, 0) < 0) {
i2c_release(BUS);
return -LSM6DSXX_ERROR_BUS;
}
traw = tmp;
if (i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_OUT_TEMP_H, &tmp, 0) < 0) {
i2c_release(BUS);
return -LSM6DSXX_ERROR_BUS;
}
traw |= (uint16_t)tmp << 8;
i2c_release(BUS);
/* convert temperature to degC x 100 */
traw += LSM6DSXX_TEMP_OFFSET << dev->temperature_scaling_factor;
*data = (int16_t)(((int32_t)traw * 100) >> dev->temperature_scaling_factor);
return LSM6DSXX_OK;
}
int lsm6dsxx_acc_power_down(const lsm6dsxx_t *dev)
{
int res;
uint8_t tmp;
i2c_acquire(BUS);
res = i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_CTRL1_XL, &tmp, 0);
if (res < 0) {
i2c_release(BUS);
DEBUG("[ERROR] lsm6dsxx_acc_power_down\n");
return -LSM6DSXX_ERROR_BUS;
}
tmp &= ~(LSM6DSXX_CTRL_ODR_MASK);
res = i2c_write_reg(BUS, ADDR, LSM6DSXX_REG_CTRL1_XL, tmp, 0);
i2c_release(BUS);
if (res < 0) {
DEBUG("[ERROR] lsm6dsxx_acc_power_down\n");
return -LSM6DSXX_ERROR_BUS;
}
return LSM6DSXX_OK;
}
int lsm6dsxx_gyro_power_down(const lsm6dsxx_t *dev)
{
int res;
uint8_t tmp;
i2c_acquire(BUS);
res = i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_CTRL2_G, &tmp, 0);
if (res < 0) {
i2c_release(BUS);
DEBUG("[ERROR] lsm6dsxx_gyro_power_down\n");
return -LSM6DSXX_ERROR_BUS;
}
tmp &= ~(LSM6DSXX_CTRL_ODR_MASK);
res = i2c_write_reg(BUS, ADDR, LSM6DSXX_REG_CTRL2_G, tmp, 0);
i2c_release(BUS);
if (res < 0) {
DEBUG("[ERROR] lsm6dsxx_gyro_power_down\n");
return -LSM6DSXX_ERROR_BUS;
}
return LSM6DSXX_OK;
}
int lsm6dsxx_acc_power_up(const lsm6dsxx_t *dev)
{
int res;
uint8_t tmp;
i2c_acquire(BUS);
res = i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_CTRL1_XL, &tmp, 0);
if (res < 0) {
i2c_release(BUS);
DEBUG("[ERROR] lsm6dsxx_acc_power_up\n");
return -LSM6DSXX_ERROR_BUS;
}
tmp &= ~(LSM6DSXX_CTRL_ODR_MASK);
tmp |= dev->params.acc_odr << LSM6DSXX_CTRL_ODR_SHIFT;
res = i2c_write_reg(BUS, ADDR, LSM6DSXX_REG_CTRL1_XL, tmp, 0);
i2c_release(BUS);
if (res < 0) {
DEBUG("[ERROR] lsm6dsxx_acc_power_up\n");
return -LSM6DSXX_ERROR_BUS;
}
return LSM6DSXX_OK;
}
int lsm6dsxx_gyro_power_up(const lsm6dsxx_t *dev)
{
int res;
uint8_t tmp;
i2c_acquire(BUS);
res = i2c_read_reg(BUS, ADDR, LSM6DSXX_REG_CTRL2_G, &tmp, 0);
if (res < 0) {
i2c_release(BUS);
DEBUG("[ERROR] lsm6dsxx_gyro_power_up\n");
return -LSM6DSXX_ERROR_BUS;
}
tmp &= ~(LSM6DSXX_CTRL_ODR_MASK);
tmp |= dev->params.gyro_odr << LSM6DSXX_CTRL_ODR_SHIFT;
res = i2c_write_reg(BUS, ADDR, LSM6DSXX_REG_CTRL2_G, tmp, 0);
i2c_release(BUS);
if (res < 0) {
DEBUG("[ERROR] lsm6dsxx_gyro_power_up\n");
return -LSM6DSXX_ERROR_BUS;
}
return LSM6DSXX_OK;
}