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

304 lines
8.1 KiB
C
Raw Normal View History

2017-03-16 16:44:04 +01:00
/*
* Copyright (C) 2017 OTA keys S.A.
*
* 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.
*
*/
/**
2017-07-02 13:21:42 +02:00
* @ingroup drivers_lsm6dsl
* @{
*
2017-03-16 16:44:04 +01:00
* @file
* @brief Device driver implementation for the LSM6DSL 3D accelerometer/gyroscope.
2017-03-16 16:44:04 +01:00
*
* @author Vincent Dupont <vincent@otakeys.com>
2017-07-02 13:21:42 +02:00
* @author Sebastian Meiling <s@mlng.net>
*
* @}
2017-03-16 16:44:04 +01:00
*/
#include <assert.h>
2021-12-01 17:39:33 +01:00
#include "ztimer.h"
#include "macros/utils.h"
2017-03-16 16:44:04 +01:00
#include "lsm6dsl.h"
#include "lsm6dsl_internal.h"
2020-10-22 11:34:31 +02:00
#define ENABLE_DEBUG 0
2017-03-16 16:44:04 +01:00
#include "debug.h"
2017-07-02 13:21:42 +02:00
#define BUS (dev->params.i2c)
#define ADDR (dev->params.addr)
/**
2019-10-23 21:20:30 +02:00
* order in array [0, 1, 2, 3] is
2017-07-02 13:21:42 +02:00
* LSM6DSL_ACC_FS_2G, LSM6DSL_ACC_FS_16G, LSM6DSL_ACC_FS_4G, LSM6DSL_ACC_FS_8G
*/
static const int16_t range_acc[] = { 2000, 16000, 4000, 8000 };
/**
2019-10-23 21:20:30 +02:00
* order in array [0, 1, 2, 3] is
2017-07-02 13:21:42 +02:00
* LSM6DSL_GYRO_FS_245DPS, LSM6DSL_GYRO_FS_500DPS,
* LSM6DSL_GYRO_FS_1000DPS, LSM6DSL_GYRO_FS_2000DPS
*/
static const int16_t range_gyro[] = { 2450, 5000, 10000, 20000 };
2017-03-16 16:44:04 +01:00
int lsm6dsl_init(lsm6dsl_t *dev, const lsm6dsl_params_t *params)
{
uint8_t tmp;
int res;
assert(dev && params);
dev->params = *params;
2017-07-02 13:21:42 +02:00
i2c_acquire(BUS);
2017-03-16 16:44:04 +01:00
/* Reboot */
2018-05-25 11:44:41 +02:00
i2c_write_reg(BUS, ADDR, LSM6DSL_REG_CTRL3_C, LSM6DSL_CTRL3_C_BOOT, 0);
2017-03-16 16:44:04 +01:00
2021-12-01 17:39:33 +01:00
ztimer_sleep(ZTIMER_MSEC, LSM6DSL_BOOT_WAIT_MS);
2017-07-02 13:21:42 +02:00
if (i2c_read_reg(BUS, ADDR, LSM6DSL_REG_WHO_AM_I, &tmp, 0) < 0) {
2017-07-02 13:21:42 +02:00
i2c_release(BUS);
DEBUG("[ERROR] lsm6dsl_init: i2c_read_reg LSM6DSL_REG_WHO_AM_I!\n");
return -LSM6DSL_ERROR_BUS;
}
2017-03-16 16:44:04 +01:00
2017-07-02 13:21:42 +02:00
if (tmp != LSM6DSL_WHO_AM_I) {
DEBUG("[ERROR] lsm6dsl_init: WHO_AM_I\n");
return -LSM6DSL_ERROR_DEV;
2017-03-16 16:44:04 +01:00
}
/* Set acc odr / full scale */
2017-07-02 13:21:42 +02:00
tmp = (dev->params.acc_odr << LSM6DSL_CTRL_ODR_SHIFT) |
(dev->params.acc_fs << LSM6DSL_CTRL_FS_SHIFT);
2018-05-25 11:44:41 +02:00
res = i2c_write_reg(BUS, ADDR, LSM6DSL_REG_CTRL1_XL, tmp, 0);
2017-03-16 16:44:04 +01:00
/* Set gyro odr / full scale */
2017-07-02 13:21:42 +02:00
tmp = (dev->params.gyro_odr << LSM6DSL_CTRL_ODR_SHIFT) |
(dev->params.gyro_fs << LSM6DSL_CTRL_FS_SHIFT);
2018-05-25 11:44:41 +02:00
res += i2c_write_reg(BUS, ADDR, LSM6DSL_REG_CTRL2_G, tmp, 0);
2017-03-16 16:44:04 +01:00
/* Set continuous mode */
uint8_t fifo_odr = MAX(dev->params.acc_odr, dev->params.gyro_odr);
2017-07-02 13:21:42 +02:00
tmp = (fifo_odr << LSM6DSL_FIFO_CTRL5_FIFO_ODR_SHIFT) |
LSM6DSL_FIFO_CTRL5_CONTINUOUS_MODE;
2018-05-25 11:44:41 +02:00
res += i2c_write_reg(BUS, ADDR, LSM6DSL_REG_FIFO_CTRL5, tmp, 0);
2017-07-02 13:21:42 +02:00
tmp = (dev->params.gyro_decimation << LSM6DSL_FIFO_CTRL3_GYRO_DEC_SHIFT) |
dev->params.acc_decimation;
2018-05-25 11:44:41 +02:00
res += i2c_write_reg(BUS, ADDR, LSM6DSL_REG_FIFO_CTRL3, tmp, 0);
2017-03-16 16:44:04 +01:00
2017-07-02 13:21:42 +02:00
i2c_release(BUS);
2017-03-16 16:44:04 +01:00
if (res < 0) {
2017-07-02 13:21:42 +02:00
DEBUG("[ERROR] lsm6dsl_init: config\n");
return -LSM6DSL_ERROR_CNF;
2017-03-16 16:44:04 +01:00
}
2017-07-02 13:21:42 +02:00
return LSM6DSL_OK;
2017-03-16 16:44:04 +01:00
}
2017-06-20 17:32:45 +02:00
int lsm6dsl_read_acc(const lsm6dsl_t *dev, lsm6dsl_3d_data_t *data)
2017-03-16 16:44:04 +01:00
{
int res;
uint8_t tmp;
2017-07-02 13:21:42 +02:00
i2c_acquire(BUS);
2018-05-25 11:44:41 +02:00
i2c_read_reg(BUS, ADDR, LSM6DSL_REG_STATUS_REG, &tmp, 0);
2017-03-16 16:44:04 +01:00
DEBUG("lsm6dsl status: %x\n", tmp);
2018-05-25 11:44:41 +02:00
res = i2c_read_reg(BUS, ADDR, LSM6DSL_REG_OUTX_L_XL, &tmp, 0);
2017-03-16 16:44:04 +01:00
data->x = tmp;
2018-05-25 11:44:41 +02:00
res += i2c_read_reg(BUS, ADDR, LSM6DSL_REG_OUTX_H_XL, &tmp, 0);
2017-03-16 16:44:04 +01:00
data->x |= tmp << 8;
2018-05-25 11:44:41 +02:00
res += i2c_read_reg(BUS, ADDR, LSM6DSL_REG_OUTY_L_XL, &tmp, 0);
2017-03-16 16:44:04 +01:00
data->y = tmp;
2018-05-25 11:44:41 +02:00
res += i2c_read_reg(BUS, ADDR, LSM6DSL_REG_OUTY_H_XL, &tmp, 0);
2017-03-16 16:44:04 +01:00
data->y |= tmp << 8;
2018-05-25 11:44:41 +02:00
res += i2c_read_reg(BUS, ADDR, LSM6DSL_REG_OUTZ_L_XL, &tmp, 0);
2017-03-16 16:44:04 +01:00
data->z = tmp;
2018-05-25 11:44:41 +02:00
res += i2c_read_reg(BUS, ADDR, LSM6DSL_REG_OUTZ_H_XL, &tmp, 0);
2017-03-16 16:44:04 +01:00
data->z |= tmp << 8;
2017-07-02 13:21:42 +02:00
i2c_release(BUS);
2017-03-16 16:44:04 +01:00
if (res < 0) {
2017-07-02 13:21:42 +02:00
DEBUG("[ERROR] lsm6dsl_read_acc\n");
return -LSM6DSL_ERROR_BUS;
2017-03-16 16:44:04 +01:00
}
2017-07-02 13:21:42 +02:00
assert(dev->params.acc_fs < LSM6DSL_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;
2017-03-16 16:44:04 +01:00
2017-07-02 13:21:42 +02:00
return LSM6DSL_OK;
2017-03-16 16:44:04 +01:00
}
2017-06-20 17:32:45 +02:00
int lsm6dsl_read_gyro(const lsm6dsl_t *dev, lsm6dsl_3d_data_t *data)
2017-03-16 16:44:04 +01:00
{
int res;
uint8_t tmp;
2017-07-02 13:21:42 +02:00
i2c_acquire(BUS);
2018-05-25 11:44:41 +02:00
i2c_read_reg(BUS, ADDR, LSM6DSL_REG_STATUS_REG, &tmp, 0);
2017-03-16 16:44:04 +01:00
DEBUG("lsm6dsl status: %x\n", tmp);
2018-05-25 11:44:41 +02:00
res = i2c_read_reg(BUS, ADDR, LSM6DSL_REG_OUTX_L_G, &tmp, 0);
2017-03-16 16:44:04 +01:00
data->x = tmp;
2018-05-25 11:44:41 +02:00
res += i2c_read_reg(BUS, ADDR, LSM6DSL_REG_OUTX_H_G, &tmp, 0);
2017-03-16 16:44:04 +01:00
data->x |= tmp << 8;
2018-05-25 11:44:41 +02:00
res += i2c_read_reg(BUS, ADDR, LSM6DSL_REG_OUTY_L_G, &tmp, 0);
2017-03-16 16:44:04 +01:00
data->y = tmp;
2018-05-25 11:44:41 +02:00
res += i2c_read_reg(BUS, ADDR, LSM6DSL_REG_OUTY_H_G, &tmp, 0);
2017-03-16 16:44:04 +01:00
data->y |= tmp << 8;
2018-05-25 11:44:41 +02:00
res += i2c_read_reg(BUS, ADDR, LSM6DSL_REG_OUTZ_L_G, &tmp, 0);
2017-03-16 16:44:04 +01:00
data->z = tmp;
2018-05-25 11:44:41 +02:00
res += i2c_read_reg(BUS, ADDR, LSM6DSL_REG_OUTZ_H_G, &tmp, 0);
2017-03-16 16:44:04 +01:00
data->z |= tmp << 8;
2017-07-02 13:21:42 +02:00
i2c_release(BUS);
2017-03-16 16:44:04 +01:00
if (res < 0) {
2017-07-02 13:21:42 +02:00
DEBUG("[ERROR] lsm6dsl_read_gyro\n");
return -LSM6DSL_ERROR_BUS;
2017-03-16 16:44:04 +01:00
}
2017-07-02 13:21:42 +02:00
assert(dev->params.gyro_fs < LSM6DSL_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;
2017-03-16 16:44:04 +01:00
2017-07-02 13:21:42 +02:00
return LSM6DSL_OK;
2017-03-16 16:44:04 +01:00
}
2017-06-20 17:32:45 +02:00
int lsm6dsl_read_temp(const lsm6dsl_t *dev, int16_t *data)
2017-03-16 16:44:04 +01:00
{
uint8_t tmp;
uint16_t traw;
/* read raw temperature */
2017-07-02 13:21:42 +02:00
i2c_acquire(BUS);
if (i2c_read_reg(BUS, ADDR, LSM6DSL_REG_OUT_TEMP_L, &tmp, 0) < 0) {
2017-07-02 13:21:42 +02:00
i2c_release(BUS);
return -LSM6DSL_ERROR_BUS;
2017-03-16 16:44:04 +01:00
}
traw = tmp;
if (i2c_read_reg(BUS, ADDR, LSM6DSL_REG_OUT_TEMP_H, &tmp, 0) < 0) {
2017-07-02 13:21:42 +02:00
i2c_release(BUS);
return -LSM6DSL_ERROR_BUS;
}
traw |= (uint16_t)tmp << 8;
2017-07-02 13:21:42 +02:00
i2c_release(BUS);
/* convert temperature to degC x 100 */
traw += LSM6DSL_TEMP_OFFSET;
*data = (int16_t)(((int32_t)traw * 100) / 256);
2017-03-16 16:44:04 +01:00
2017-07-02 13:21:42 +02:00
return LSM6DSL_OK;
2017-03-16 16:44:04 +01:00
}
int lsm6dsl_acc_power_down(const lsm6dsl_t *dev)
{
int res;
uint8_t tmp;
i2c_acquire(BUS);
2018-05-25 11:44:41 +02:00
res = i2c_read_reg(BUS, ADDR, LSM6DSL_REG_CTRL1_XL, &tmp, 0);
if (res < 0) {
i2c_release(BUS);
DEBUG("[ERROR] lsm6dsl_acc_power_down\n");
return -LSM6DSL_ERROR_BUS;
}
tmp &= ~(LSM6DSL_CTRL_ODR_MASK);
2018-05-25 11:44:41 +02:00
res = i2c_write_reg(BUS, ADDR, LSM6DSL_REG_CTRL1_XL, tmp, 0);
i2c_release(BUS);
if (res < 0) {
DEBUG("[ERROR] lsm6dsl_acc_power_down\n");
return -LSM6DSL_ERROR_BUS;
}
return LSM6DSL_OK;
}
int lsm6dsl_gyro_power_down(const lsm6dsl_t *dev)
{
int res;
uint8_t tmp;
i2c_acquire(BUS);
2018-05-25 11:44:41 +02:00
res = i2c_read_reg(BUS, ADDR, LSM6DSL_REG_CTRL2_G, &tmp, 0);
if (res < 0) {
i2c_release(BUS);
DEBUG("[ERROR] lsm6dsl_gyro_power_down\n");
return -LSM6DSL_ERROR_BUS;
}
tmp &= ~(LSM6DSL_CTRL_ODR_MASK);
2018-05-25 11:44:41 +02:00
res = i2c_write_reg(BUS, ADDR, LSM6DSL_REG_CTRL2_G, tmp, 0);
i2c_release(BUS);
if (res < 0) {
DEBUG("[ERROR] lsm6dsl_gyro_power_down\n");
return -LSM6DSL_ERROR_BUS;
}
return LSM6DSL_OK;
}
int lsm6dsl_acc_power_up(const lsm6dsl_t *dev)
{
int res;
uint8_t tmp;
i2c_acquire(BUS);
2018-05-25 11:44:41 +02:00
res = i2c_read_reg(BUS, ADDR, LSM6DSL_REG_CTRL1_XL, &tmp, 0);
if (res < 0) {
i2c_release(BUS);
DEBUG("[ERROR] lsm6dsl_acc_power_up\n");
return -LSM6DSL_ERROR_BUS;
}
tmp &= ~(LSM6DSL_CTRL_ODR_MASK);
tmp |= dev->params.acc_odr << LSM6DSL_CTRL_ODR_SHIFT;
2018-05-25 11:44:41 +02:00
res = i2c_write_reg(BUS, ADDR, LSM6DSL_REG_CTRL1_XL, tmp, 0);
i2c_release(BUS);
if (res < 0) {
DEBUG("[ERROR] lsm6dsl_acc_power_up\n");
return -LSM6DSL_ERROR_BUS;
}
return LSM6DSL_OK;
}
int lsm6dsl_gyro_power_up(const lsm6dsl_t *dev)
{
int res;
uint8_t tmp;
i2c_acquire(BUS);
2018-05-25 11:44:41 +02:00
res = i2c_read_reg(BUS, ADDR, LSM6DSL_REG_CTRL2_G, &tmp, 0);
if (res < 0) {
i2c_release(BUS);
DEBUG("[ERROR] lsm6dsl_gyro_power_up\n");
return -LSM6DSL_ERROR_BUS;
}
tmp &= ~(LSM6DSL_CTRL_ODR_MASK);
tmp |= dev->params.gyro_odr << LSM6DSL_CTRL_ODR_SHIFT;
2018-05-25 11:44:41 +02:00
res = i2c_write_reg(BUS, ADDR, LSM6DSL_REG_CTRL2_G, tmp, 0);
i2c_release(BUS);
if (res < 0) {
DEBUG("[ERROR] lsm6dsl_gyro_power_up\n");
return -LSM6DSL_ERROR_BUS;
}
return LSM6DSL_OK;
}