From 48026bb824fd2d9cfb00ecd040db6ef3a416bae9 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Fri, 22 Jan 2021 21:43:36 -0500 Subject: upload initial port --- ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.c | 788 +++++++++++++++++ ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.h | 403 +++++++++ ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.mk | 10 + ChibiOS_20.3.2/os/ex/devices/ST/hts221.c | 781 ++++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/hts221.h | 707 +++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/hts221.mk | 10 + ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.c | 642 ++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.h | 725 +++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.mk | 10 + ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.c | 554 ++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.h | 566 ++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.mk | 10 + ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.c | 641 ++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.h | 708 +++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.mk | 10 + ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.c | 627 +++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.h | 670 ++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.mk | 10 + ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.c | 686 +++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.h | 724 +++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.mk | 10 + ChibiOS_20.3.2/os/ex/devices/ST/lps25h.c | 696 +++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lps25h.h | 740 ++++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lps25h.mk | 10 + ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.c | 906 +++++++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.h | 919 +++++++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.mk | 10 + ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.c | 1175 +++++++++++++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.h | 955 ++++++++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.mk | 10 + ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.c | 1109 +++++++++++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.h | 1034 ++++++++++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.mk | 10 + ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.c | 1119 +++++++++++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.h | 1055 ++++++++++++++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.mk | 10 + ChibiOS_20.3.2/os/ex/devices/ST/vl53l0x.h | 443 ++++++++++ ChibiOS_20.3.2/os/ex/devices/ST/vl53l0x.mk | 10 + 38 files changed, 19503 insertions(+) create mode 100644 ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.c create mode 100644 ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.h create mode 100644 ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.mk create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/hts221.c create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/hts221.h create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/hts221.mk create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.c create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.h create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.mk create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.c create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.h create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.mk create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.c create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.h create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.mk create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.c create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.h create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.mk create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.c create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.h create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.mk create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lps25h.c create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lps25h.h create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lps25h.mk create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.c create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.h create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.mk create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.c create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.h create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.mk create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.c create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.h create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.mk create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.c create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.h create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.mk create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/vl53l0x.h create mode 100644 ChibiOS_20.3.2/os/ex/devices/ST/vl53l0x.mk (limited to 'ChibiOS_20.3.2/os/ex/devices') diff --git a/ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.c b/ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.c new file mode 100644 index 0000000..61f6d13 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.c @@ -0,0 +1,788 @@ +/* + ChibiOS - Copyright (C) 2016..2017 Theodore Ateba + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file bmp085.c + * @brief BMP085 Digital pressure sensor interface module code. + * + * @addtogroup BMP085 + * @ingroup EX_BOSCH + * @{ + */ + +#include "hal.h" +#include "bmp085.h" + +/*==========================================================================*/ +/* Driver local definitions. */ +/*==========================================================================*/ + +#define BMP085_SAD 0x77 + +#define BMP085_CR_P_VAL0 0x34 +#define BMP085_CR_P_VAL1 0x74 +#define BMP085_CR_P_VAL2 0xB4 +#define BMP085_CR_P_VAL3 0xF4 + +#define BMP085_CR_T_VAL 0x2E + +/*==========================================================================*/ +/* Driver exported variables. */ +/*==========================================================================*/ + +/*==========================================================================*/ +/* Driver local variables and types. */ +/*==========================================================================*/ + +/*==========================================================================*/ +/* Driver local functions. */ +/*==========================================================================*/ + +#if (BMP085_USE_I2C) || defined(__DOXYGEN__) +/** + * @brief Reads registers value using I2C. + * @pre The I2C interface must be initialized and the driver started. + * + * @param[in] i2cp pointer to the I2C interface + * @param[in] reg first sub-register address + * @param[out] rxbufp pointer to an output buffer + * @param[in] n number of consecutive register to read + * + * @return the operation status + * @notapi + */ +msg_t bmp085I2CReadRegister(I2CDriver *i2cp, uint8_t reg, uint8_t *rxbufp, + size_t n) { + uint8_t txbuf = reg; + + return i2cMasterTransmitTimeout(i2cp, BMP085_SAD, &txbuf, 1, rxbufp, n, + TIME_INFINITE); +} + +/** + * @brief Writes a value into a register using I2C. + * @pre The I2C interface must be initialized and the driver started. + * + * @param[in] i2cp pointer to the I2C interface + * @param[in] txbufp buffer containing sub-address value in first position + * and values to write + * @param[in] n size of txbuf less one (not considering the first + * element) + * + * @return the operation status + * @notapi + */ +msg_t bmp085I2CWriteRegister(I2CDriver *i2cp, uint8_t *txbufp, size_t n) { + + return i2cMasterTransmitTimeout(i2cp, BMP085_SAD, txbufp, n + 1, NULL, 0, + TIME_INFINITE); +} +#endif /* BMP085_USE_I2C */ + +/** + * @brief Read all the calibration data from the BMP085 EEPROM. + * @pre The I2C interface must be initialized and the driver started. + * + * @param[in] devp pointer to the BMP085 device driver sensor + * @param[in] reg first calibration coefficient register to read + * + * @return msg the operation status + */ +static msg_t bmp085ReadCoefficient(BMP085Driver *devp, uint8_t reg) { + + uint8_t rxbuf[22]; + +#if BMP085_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); +#endif /* BMP085_SHARED_I2C */ + + msg_t msg = bmp085I2CReadRegister(devp->config->i2cp, reg, rxbuf, 22); + +#if BMP085_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* BMP085_SHARED_I2C */ + + if (msg == MSG_OK) { + devp->calibrationdata.ac1 = ((rxbuf[ 0] << 8) | rxbuf[ 1]); + devp->calibrationdata.ac2 = ((rxbuf[ 2] << 8) | rxbuf[ 3]); + devp->calibrationdata.ac3 = ((rxbuf[ 4] << 8) | rxbuf[ 5]); + devp->calibrationdata.ac4 = ((rxbuf[ 6] << 8) | rxbuf[ 7]); + devp->calibrationdata.ac5 = ((rxbuf[ 8] << 8) | rxbuf[ 9]); + devp->calibrationdata.ac6 = ((rxbuf[10] << 8) | rxbuf[11]); + devp->calibrationdata.b1 = ((rxbuf[12] << 8) | rxbuf[13]); + devp->calibrationdata.b2 = ((rxbuf[14] << 8) | rxbuf[15]); + devp->calibrationdata.mb = ((rxbuf[16] << 8) | rxbuf[17]); + devp->calibrationdata.mc = ((rxbuf[18] << 8) | rxbuf[19]); + devp->calibrationdata.md = ((rxbuf[20] << 8) | rxbuf[21]); + } + + return msg; +} + +/** + * @brief Calcul the true temperature. + * + * @param[in] devp pointer to the BMP085 device driver sensor + * @param[in] ut uncompensated temperature + * @param[out] ctp pointer of the compensated temperature + */ +static void calcul_t(BMP085Driver *devp, int32_t ut, float *ctp) { + + int32_t x1, x2; + + /* Converting the temperature value. */ + x1 = ((ut - devp->calibrationdata.ac6) * devp->calibrationdata.ac5) >> 15; + x2 = (devp->calibrationdata.mc << 11) / (x1 + devp->calibrationdata.md); + devp->calibrationdata.b5 = x1 + x2; + *ctp = (float)((devp->calibrationdata.b5 + 8) >> 4)*BMP085_T_RES; +} + +/** + * @brief Calcul the true pressure. + * + * @param[in] devp pointer to the BMP085 device driver sensor + * @param[in] up uncompensated pressure + * @param[in] oss over sampling setting + * @param[out] cpp pointer of the compensated pressure + */ +static void calcul_p(BMP085Driver *devp, int32_t up, uint8_t oss, float *cpp) { + + int32_t press; + int32_t x1,x2,x3; + int32_t b3,b6; + uint32_t b4,b7; + + /* Converting the pressure value. */ + b6 = devp->calibrationdata.b5 - 4000; + x1 = (devp->calibrationdata.b2 * ((b6 * b6) >> 12)) >> 11; + x2 = (devp->calibrationdata.ac2 * b6) >> 11; + x3 = x1 + x2; + b3 = ((((int32_t)devp->calibrationdata.ac1 * 4 + x3) << oss) + 2) >> 2; + x1 = ((devp->calibrationdata.ac3)*b6) >> 13; + x2 = (devp->calibrationdata.b1 * (b6*b6 >> 12)) >> 16; + x3 = ((x1 + x2) + 2) >> 2; + b4 = devp->calibrationdata.ac4 * (uint32_t)(x3 + 32768) >> 15; + b7 = ((uint32_t)up - b3)*(50000 >> oss); + + if (b7 < 0x80000000) + press = (b7*2)/b4; + else + press = (b7/b4)*2; + + x1 = (press >> 8)*(press >> 8); + x1 = (x1*3038) >> 16; + x2 = (-7357*press) >> 16; + *cpp =(float)((press + ((x1 + x2 + 3791) >> 4))*BMP085_P_RES); +} + +/** + * @brief Start temperature measurement. + * + * @param[in] devp pointer to the BMP085 device driver + * + * @return the operation status + */ +static msg_t start_t_measurement(BMP085Driver *devp) { + + uint8_t txbuf[2] = {BMP085_AD_CR, BMP085_CR_T_VAL}; + + i2cAcquireBus(devp->config->i2cp); + msg_t msg = bmp085I2CWriteRegister(devp->config->i2cp, txbuf, 2); + i2cReleaseBus(devp->config->i2cp); + + /* Conversion time for the temperature. */ + chThdSleepMilliseconds(BMP085_THERMO_CT_LOW); + //chThdSleepMilliseconds(devp->config.tct); // TODO: use this instead of the top line: + + return msg; +} + +/** + * @brief Start the pressure measurment. + * + * @param[in] devp pointer to the BMP085 driver + * @return msg the operation status + */ +static msg_t start_p_measurement(BMP085Driver *devp) { + + uint8_t oss, delay; + uint8_t txbuf[2]; + + oss = devp->config->oss; + txbuf[0] = BMP085_AD_CR; + + /* Check the oss according the bmp085 mode. */ + if (oss == BMP085_BARO_OSS_0) { + txbuf[1] = BMP085_CR_P_VAL0 + (oss << 6); + delay = BMP085_BARO_CT_LOW; + } + else if (oss == BMP085_BARO_OSS_1) { + txbuf[1] = BMP085_CR_P_VAL1 + (oss << 6); + delay = BMP085_BARO_CT_STD; + } + else if (oss == BMP085_BARO_OSS_2) { + txbuf[1] = BMP085_CR_P_VAL2 + (oss << 6); + delay = BMP085_BARO_CT_HR; + } + else { + txbuf[1] = BMP085_CR_P_VAL3 + (oss << 6); + delay = BMP085_BARO_CT_LUHR; + } + + /* Start the sensor for sampling. */ +#if BMP085_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); +#endif /* BMP085_SHARED_I2C */ + + msg_t msg = bmp085I2CWriteRegister(devp->config->i2cp, txbuf, 2); + +#if BMP085_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* BMP085_SHARED_I2C */ + + /* Conversion time for the pressure, max time for the moment. */ + chThdSleepMilliseconds(delay); + + return msg; +} + +/** + * @brief Read the uncompensated temperature from the BMP085 register. + * + * @param[in] devp pointer to the BMP085 driver + * @param[out] utemp uncompensated temperature read from the sensor register + * + * @return msg the operation status + */ +static msg_t acquire_ut(BMP085Driver *devp, int32_t *utemp) { + + uint8_t rxbuf[2]; + msg_t msg; + + /* Start the temperature measurement. */ + start_t_measurement(devp); + + /* Start the sensor for sampling. */ +#if BMP085_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); +#endif /* BMP085_SHARED_I2C */ + + /* Get the temperature. */ + msg = bmp085I2CReadRegister(devp->config->i2cp, BMP085_AD_T_DR_MSB, rxbuf, + 2); + +#if BMP085_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* BMP085_SHARED_I2C */ + + if(msg == MSG_OK){ + /* Building the uncompensated temperature value. */ + *utemp = (int32_t)((rxbuf[0] << 8) | rxbuf[1]); + } + + return msg; +} + +/** + * @brief Read the uncompensated pressure from the BMP085 register. + * + * @param[in] devp pointer to the BMP085 driver + * @param[out] upress uncompensated pressure read from the sensor register + * + * @return msg the operation status + */ +static msg_t acquire_up(BMP085Driver *devp, int32_t *upress) { + + uint8_t rxbuf[3]; + uint8_t oss; + msg_t msg; + + /* Get the oversampling setting from the driver configuratioin. */ + oss = devp->config->oss; + + /* Start the pressure measurement. */ + start_p_measurement(devp); + + /* Start the sensor for sampling. */ +#if BMP085_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); +#endif /* BMP085_SHARED_I2C */ + + /* Get the pressure */ + msg = bmp085I2CReadRegister(devp->config->i2cp, BMP085_AD_P_DR_MSB, rxbuf, + 3); + +#if BMP085_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* BMP085_SHARED_I2C */ + + if (msg == MSG_OK) { + /* Building the uncompensated pressure value. */ + *upress = (int32_t)((rxbuf[0] << 16)|(rxbuf[1] << 8)|rxbuf[2]); + *upress = *upress >> (8-oss); + } + + return msg; +} + +/*==========================================================================*/ +/* Interface implementation. */ +/*==========================================================================*/ + +/** + * @brief Get the barometer number of axes. + * + * @param[in] ip interface pointer of the BMP085 sensor + * + * @return barometer number of axes + */ +static size_t baro_get_axes_number(void *ip) { + + osalDbgCheck(ip != NULL); + + return BMP085_BARO_NUMBER_OF_AXES; +} + +/** + * @brief Get the thermometer number of axes. + * + * @param[in] ip interface pointer of the BMP085 sensor + * + * @return thermometer number of axes + */ +static size_t thermo_get_axes_number(void *ip) { + + osalDbgCheck(ip != NULL); + + return BMP085_THERMO_NUMBER_OF_AXES; +} + +/** + * @brief Get the sensor number of axes. + * + * @param[in] ip interface pointer of the BMP085 sensor + * + * @return sensor number of axes + */ +static size_t sens_get_axes_number(void *ip) { + + osalDbgCheck(ip != NULL); + + return (baro_get_axes_number(ip) + thermo_get_axes_number(ip)); +} + +/** + * @brief Read baromether raw data. + * + * @param[in] ip interface pointer of the sensor + * @param[in] axes buffer for various axes data + * + * @return msg the result of the reading operation + */ +static msg_t baro_read_raw(void *ip, int32_t axes[]) { + + osalDbgCheck((ip != NULL) && (axes != NULL)); + osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY), + "baro_read_raw(), invalid state"); + +#if BMP085_USE_I2C + osalDbgAssert((((BMP085Driver *)ip)->config->i2cp->state == I2C_READY), + "baro_read_raw(), channel not ready"); +#if BMP085_SHARED_I2C + i2cAcquireBus(((BMP085Driver *)ip)->config->i2cp); + i2cStart(((BMP085Driver *)ip)->config->i2cp, + ((BMP085Driver *)ip)->config->i2ccfg); +#endif /* BMP085_SHARED_I2C. */ + + /* Measure the uncompensated pressure. */ + msg_t msg = acquire_up(((BMP085Driver *)ip), axes); + +#if BMP085_SHARED_I2C + i2cReleaseBus(((BMP085Driver *)ip)->config->i2cp); +#endif /* BMP085_SHARED_I2C. */ +#endif /* BMP085_USE_I2C. */ + + return msg; +} + +/** + * @brief Read thermometer raw data. + * + * @param[in] ip interface pointer of the BMP085 sensor + * @param[in] axes buffer for various axes data + * + * @return msg the result of the reading operation + */ +static msg_t thermo_read_raw(void *ip, int32_t axes[]) { + + osalDbgCheck((ip != NULL) && (axes != NULL)); + osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY), + "thermo_read_raw(), invalid state"); + +#if BMP085_USE_I2C + osalDbgAssert((((BMP085Driver *)ip)->config->i2cp->state == I2C_READY), + "thermo_read_raw(), channel not ready"); +#if BMP085_SHARED_I2C + i2cAcquireBus(((BMP085Driver *)ip)->config->i2cp); + i2cStart(((BMP085Driver *)ip)->config->i2cp, + ((BMP085Driver *)ip)->config->i2ccfg); +#endif /* BMP085_SHARED_I2C. */ + + /* Measure the uncompensated temperature. */ + msg_t msg = acquire_ut(((BMP085Driver *)ip), axes); + +#if BMP085_SHARED_I2C + i2cReleaseBus(((LSM303DLHCDriver *)ip)->config->i2cp); +#endif /* BMP085_SHARED_I2C. */ +#endif /* BMP085_USE_I2C. */ + + return msg; +} + +/** + * @brief Read BMP085 sensor raw data. + * + * @param[in] ip interface pointer of the BMP085 sensor + * @param[in] axes buffer for various axes data + * + * @return msg the result of the reading operation + */ +static msg_t sens_read_raw(void *ip, int32_t axes[]) { + + int32_t* bp = axes; + msg_t msg; + + msg = baro_read_raw(ip, bp); + + if (msg != MSG_OK) + return msg; + + bp += BMP085_BARO_NUMBER_OF_AXES; + + msg = thermo_read_raw(ip, bp); + + return msg; +} + +/** + * @brief Read barometer cooked data. + * + * @param[in] ip interface pointer of the BMP085 sensor + * @param[in] axes buffer for various axes data + * + * @return msg the result of the reading operation + */ +static msg_t baro_read_cooked(void *ip, float axes[]) { + + uint32_t i; + int32_t raw[BMP085_BARO_NUMBER_OF_AXES]; + msg_t msg; + uint8_t oss; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY), + "baro_read_cooked(), invalid state"); + + msg = baro_read_raw(ip, raw); + oss = ((BMP085Driver *)ip)->config->oss; + + for (i = 0; i < BMP085_BARO_NUMBER_OF_AXES; i++) + calcul_p(ip, raw[i], oss, &axes[i]); + + return msg; +} + +/** + * @brief Read thermometer cooked data. + * + * @param[in] ip interface pointer of the BMP085 sensor + * @param[in] axes buffer for various axes data + * + * @return msg the result of the reading operation + */ +static msg_t thermo_read_cooked(void *ip, float axes[]) { + + uint32_t i; + int32_t raw[BMP085_THERMO_NUMBER_OF_AXES]; + msg_t msg; + + osalDbgCheck(((ip != NULL) && (axes != NULL))); + osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY), + "thermo_read_cooked(), invalid state"); + msg = thermo_read_raw(ip, raw); + + for (i = 0; i < BMP085_THERMO_NUMBER_OF_AXES; i++) + calcul_t(ip, raw[i], &axes[i]); + + return msg; +} + +/** + * @brief Read BMP085 sensor cooked data. + * + * @param[in] ip interface pointer of the BMP085 sensor + * @param[in] axes buffer for various axes data + * + * @return msg the result of the reading operation + */ +static msg_t sens_read_cooked(void *ip, float axes[]) { + + float* bp = axes; + msg_t msg; + + msg = baro_read_cooked(ip, bp); + + if (msg != MSG_OK) + return msg; + + bp += BMP085_BARO_NUMBER_OF_AXES; + msg = thermo_read_cooked(ip, bp); + + return msg; +} + +/** + * @brief Set the barometer bias. + * + * @param[in] ip interface pointer of the BMP085 sensor + * @param[in] bp pointer to the bias value + * + * @return msg the result of the setting operation + */ +static msg_t baro_set_bias(void *ip, float *bp) { + + osalDbgCheck((ip != NULL) && (bp !=NULL)); + osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY) || + (((BMP085Driver *)ip)->state == BMP085_STOP), + "baro_set_bias(), invalid state"); + return MSG_OK; +} + +/** + * @brief Set the thermometer bias. + * + * @param[in] ip interface pointer of the BMP085 sensor + * @param[in] bp pointer to the bias value + * + * @return msg the result of the setting operation + */ +static msg_t thermo_set_bias(void *ip, float *bp) { + + osalDbgCheck((ip != NULL) && (bp !=NULL)); + osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY) || + (((BMP085Driver *)ip)->state == BMP085_STOP), + "thermo_set_bias(), invalid state"); + return MSG_OK; +} + +/** + * @brief Reset the barometer bias. + * + * @param[in] ip interface pointer of the BMP085 sensor + * + * @return msg the result of the reset operation + */ +static msg_t baro_reset_bias(void *ip) { + + osalDbgCheck(ip != NULL); + osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY) || + (((BMP085Driver *)ip)->state == BMP085_STOP), + "baro_reset_bias(), invalid state"); + + return MSG_OK; +} + +/** + * @brief Reset the thermometer bias. + * + * @param[in] ip interface pointer of the BMP085 sensor + * + * @return msg the result of the reset operation + */ +static msg_t thermo_reset_bias(void *ip) { + + osalDbgCheck(ip != NULL); + osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY) || + (((BMP085Driver *)ip)->state == BMP085_STOP), + "thermo_reset_bias(), invalid state"); + + return MSG_OK; +} + +/** + * @brief Set the barometer sensivity. + * + * @param[in] ip interface pointer of the BMP085 sensor + * @param[in] sp pointer to the sensivity value + * + * @return msg the result of the setting operation + */ +static msg_t baro_set_sensivity(void *ip, float *sp) { + + osalDbgCheck((ip != NULL) && (sp !=NULL)); + osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY), + "baro_set_sensivity(), invalid state"); + + return MSG_OK; +} + +/** + * @brief Set the thermometer sensivity. + * + * @param[in] ip interface pointer of the BMP085 sensor + * @param[in] sp pointer to the sensivity value + * + * @return msg the result of the setting operation + */ +static msg_t thermo_set_sensivity(void *ip, float *sp) { + + osalDbgCheck((ip != NULL) && (sp !=NULL)); + osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY), + "thermo_set_sensivity(), invalid state"); + + return MSG_OK; +} + +/** + * @brief Reset the barometer sensivity. + * + * @param[in] ip interface pointer of the BMP085 sensor + * + * @return msg the result of the reset operation + */ +static msg_t baro_reset_sensivity(void *ip) { + + osalDbgCheck(ip != NULL); + osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY), + "baro_reset_sensivity(), invalid state"); + + return MSG_OK; +} + +/** + * @brief Reset the thermometer sensivity. + * + * @param[in] ip interface pointer of the BMP085 sensor + * + * @return msg the result of the reset operation + */ +static msg_t thermo_reset_sensivity(void *ip) { + + osalDbgCheck(ip != NULL); + osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY), + "thermo_reset_sensivity(), invalid state"); + + return MSG_OK; +} + +static const struct BaseSensorVMT vmt_basesensor = { + sens_get_axes_number, sens_read_raw, sens_read_cooked +}; + +static const struct BaseBarometerVMT vmt_basebarometer = { + baro_get_axes_number, baro_read_raw, baro_read_cooked, + baro_set_bias, baro_reset_bias, + baro_set_sensivity, baro_reset_sensivity +}; + +static const struct BaseThermometerVMT vmt_basethermometer = { + thermo_get_axes_number, thermo_read_raw, thermo_read_cooked, + thermo_set_bias, thermo_reset_bias, + thermo_set_sensivity, thermo_reset_sensivity +}; + +/*==========================================================================*/ +/* Driver exported functions. */ +/*==========================================================================*/ + +/** + * @brief Initializes an instance. + * + * @param[out] devp pointer to the @p BMP085Driver object + * + * @init + */ +void bmp085ObjectInit(BMP085Driver *devp) { + + devp->vmt_basesensor = &vmt_basesensor; + devp->vmt_basebarometer = &vmt_basebarometer; + devp->vmt_basethermometer = &vmt_basethermometer; + devp->config = NULL; + devp->state = BMP085_STOP; +} + +/** + * @brief Configures and activates BMP085 Complex Driver peripheral. + * + * @param[in] devp pointer to the @p BMP085Driver object + * @param[in] config pointer to the @p BMP085Config object + * + * @api + */ +void bmp085Start(BMP085Driver *devp, const BMP085Config *config) { + + osalDbgCheck((devp != NULL) && (config != NULL)); + osalDbgAssert((devp->state == BMP085_STOP) || + (devp->state == BMP085_READY), + "bmp085cStart(), invalid state"); + devp->config = config; +#if BMP085_USE_I2C +#if BMP085_SHARED_I2C + i2cAcquireBus((devp)->config->i2cp); +#endif /* BMP085_SHARED_I2C. */ + /* Read the Calibrations data. */ + i2cStart((devp)->config->i2cp, (devp)->config->i2ccfg); + bmp085ReadCoefficient(devp, BMP085_AD_CC_AC1_MSB); +#if BMP085_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* BMP085_SHARED_I2C. */ +#endif /* BMP085_USE_I2C. */ + if(devp->state != BMP085_READY) + devp->state = BMP085_READY; +} + +/** + * @brief Deactivates the BMP085 Complex Driver peripheral. + * + * @param[in] devp pointer to the @p BMP085Driver object + * + * @api + */ +void bmp085Stop(BMP085Driver *devp) { + + osalDbgCheck(devp != NULL); + osalDbgAssert((devp->state == BMP085_STOP) || + (devp->state == BMP085_READY), + "bmp085Stop(), invalid state"); +#if (BMP085_USE_I2C) + if (devp->state == BMP085_STOP) { +#if BMP085_SHARED_I2C + i2cAcquireBus((devp)->config->i2cp); + i2cStart((devp)->config->i2cp, (devp)->config->i2ccfg); +#endif /* BMP085_SHARED_I2C. */ +#if BMP085_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* BMP085_SHARED_I2C. */ + } +#endif /* BMP085_USE_I2C. */ + if (devp->state != BMP085_STOP) + devp->state = BMP085_STOP; +} +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.h b/ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.h new file mode 100644 index 0000000..f188c6b --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.h @@ -0,0 +1,403 @@ +/* + ChibiOS - Copyright (C) 2016..2017 Theodore Ateba + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file bmp085.h + * @brief BMP085 Digital pressure sensor interface module header. + * + * @addtogroup BMP085 + * @ingroup EX_BOSCH + * @{ + */ + +#ifndef BMP085_H +#define BMP085_H + +#include "ex_barometer.h" +#include "ex_thermometer.h" + +/*==========================================================================*/ +/* Driver constants. */ +/*==========================================================================*/ + +/** + * @name Version identification + * @{ + */ + +/** + * @brief BMP085 driver version string. + */ +#define EX_BMP085_VERSION "1.0.1" + +/** + * @brief BMP085 driver version major number. + */ +#define EX_BMP085_MAJOR 1 + +/** + * @brief BMP085 driver version minor number. + */ +#define EX_BMP085_MINOR 0 + +/** + * @brief BMP085 driver version patch number. + */ +#define EX_BMP085_PATCH 1 +/** @}*/ + +/** + * @brief BMP085 barometer subsystem characteristics. + * @{ + */ +#define BMP085_BARO_NUMBER_OF_AXES 1U /**< Number of axes */ + +#define BMP085_P_RES 0.01 /**< LSB/hP */ +/** @} */ + +/** + * @brief BMP085 thermometer subsystem characteristics. + * @{ + */ +#define BMP085_THERMO_NUMBER_OF_AXES 1U /**< Number of axes */ + +#define BMP085_T_RES 0.1 /**< LSB/C° */ +/** @} */ + +/** + * @name BMP085 Registers addresses. + * @{ + */ +#define BMP085_AD_CR 0xF4 /**< Control register address. */ +#define BMP085_AD_T_DR_MSB 0xF6 /**< Temp MSB data register addr. */ +#define BMP085_AD_T_DR_LSB 0xF7 /**< Temp LSB data register addr. */ +#define BMP085_AD_P_DR_MSB 0xF6 /**< Press MSB data register addr. */ +#define BMP085_AD_P_DR_LSB 0xF7 /**< Press LSB data register addr. */ +#define BMP085_AD_P_DR_XLSB 0xF8 /**< Press XLSB data register addr.*/ +#define BMP085_AD_CC_AC1_MSB 0xAA /**< AC1 MSB calib coef reg addr. */ +#define BMP085_AD_CC_AC1_LSB 0xAB /**< AC1 LSB calib coef reg addr. */ +#define BMP085_AD_CC_AC2_MSB 0xAC /**< AC2 MSB calib coef reg addr. */ +#define BMP085_AD_CC_AC2_LSB 0xAD /**< AC2 LSB calib coef reg addr. */ +#define BMP085_AD_CC_AC3_MSB 0xAE /**< AC3 MSB calib coef reg addr. */ +#define BMP085_AD_CC_AC3_LSB 0xAF /**< AC3 LSB calib coef reg addr. */ +#define BMP085_AD_CC_AC4_MSB 0xB0 /**< AC4 MSB calib coef reg addr. */ +#define BMP085_AD_CC_AC4_LSB 0xB1 /**< AC4 LSB calib coef reg addr. */ +#define BMP085_AD_CC_AC5_MSB 0xB2 /**< AC5 MSB calib coef reg addr. */ +#define BMP085_AD_CC_AC5_LSB 0xB3 /**< AC5 LSB calib coef reg addr. */ +#define BMP085_AD_CC_AC6_MSB 0xB4 /**< AC6 MSB calib coef reg addr. */ +#define BMP085_AD_CC_AC6_LSB 0xB5 /**< AC6 LSB calib coef reg addr. */ +#define BMP085_AD_CC_B1_MSB 0xB6 /**< B1 MSB calib coef reg addr. */ +#define BMP085_AD_CC_B1_LSB 0xB7 /**< B1 LSB calib coef reg addr. */ +#define BMP085_AD_CC_B2_MSB 0xB8 /**< B2 MSB calib coef reg addr. */ +#define BMP085_AD_CC_B2_LSB 0xB9 /**< B2 LSB calib coef reg addr. */ +#define BMP085_AD_CC_MB_MSB 0xBA /**< MB MSB calib coef reg addr. */ +#define BMP085_AD_CC_MB_LSB 0xBB /**< MB LSB calib coef reg addr. */ +#define BMP085_AD_CC_MC_MSB 0xBC /**< MC MSB calib coef reg addr. */ +#define BMP085_AD_CC_MC_LSB 0xBD /**< MC LSB calib coef reg addr. */ +#define BMP085_AD_CC_MD_MSB 0xBE /**< MD MSB calib coef reg addr. */ +#define BMP085_AD_CC_MD_LSB 0xBF /**< MD LSB calib coef reg addr. */ +/** @} */ + +/*==========================================================================*/ +/* Driver pre-compile time settings. */ +/*==========================================================================*/ + +/** + * @name Configuration options + * @{ + */ + +/** + * @brief BMP085 I2C interface selector. + * @details If set to @p TRUE the support for I2C is included. + * @note The default is @p TRUE. + */ +#if !defined(BMP085_USE_I2C) || defined(__DOXYGEN__) +#define BMP085_USE_I2C TRUE +#endif + +/** + * @brief BMP085 sensor subsystem advanced configurations switch. + * @details If set to @p TRUE more configurations are available. + * @note The default is @p TRUE. + */ +#if !defined(BMP085_USE_ADVANCED) || defined(__DOXYGEN__) +#define BMP085_USE_ADVANCED TRUE +#endif + +/** + * @brief BMP085 shared I2C switch. + * @details If set to @p TRUE the device acquires I2C bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION. + */ +#if !defined(BMP085_SHARED_I2C) || defined(__DOXYGEN__) +#define BMP085_SHARED_I2C FALSE +#endif +/** @} */ + +/*==========================================================================*/ +/* Derived constants and error checks. */ +/*==========================================================================*/ + +#if !HAL_USE_I2C +#error "BMP085_USE_I2C requires HAL_USE_I2C" +#endif + +#if BMP085_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION +#error "BMP085_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" +#endif + +/*==========================================================================*/ +/* Driver data structures and types. */ +/*==========================================================================*/ + +/** + * @name BMP085 barometer subsystem data structures and types. + * @{ + */ + +/** + * @brief BMP085 barometer subsystem pressure conversion time. + */ +typedef enum { + BMP085_BARO_CT_LOW = 0x05, /**< Convers time in ultra low power mode. */ + BMP085_BARO_CT_STD = 0x18, /**< Convers time in standard mode. */ + BMP085_BARO_CT_HR = 0x0E, /**< Convers time in high resolution mode. */ + BMP085_BARO_CT_LUHR = 0x1A /**< Convers time in ultra high res. mode. */ +} bmp085_baro_ct_t; + +/** + * @brief BMP085 barometer subsystem mode. + */ +typedef enum { + BMP085_BARO_MODE_LOW = 0x00, /**< BMP085 ultra low power mode. */ + BMP085_BARO_MODE_STD = 0x01, /**< BMP085 standard mode. */ + BMP085_BARO_MODE_HR = 0x02, /**< BMP085 high resolution mode. */ + BMP085_BARO_MODE_LUHR = 0x03 /**< BMP085 ultra high res. mode. */ +} bmp085_baro_mode_t; + +/** + * @brief BMP085 barometer oversampling setting. + */ +typedef enum { + BMP085_BARO_OSS_0 = 0x00, /**< Ultra low power sampling rate. */ + BMP085_BARO_OSS_1 = 0x01, /**< Standard mode sampling rate. */ + BMP085_BARO_OSS_2 = 0x02, /**< High resolution sampling rate. */ + BMP085_BARO_OSS_3 = 0x04 /**< ultra high resolution sampling rate. */ +}bmp085_baro_oss_t; + +/** + * @brief BMP085 barometer subsystem calibration data. + */ +typedef struct { + int16_t ac1; + int16_t ac2; + int16_t ac3; + int16_t b1; + int16_t b2; + int16_t mb; + int16_t mc; + int16_t md; + uint16_t ac4; + uint16_t ac5; + uint16_t ac6; + int32_t b5; +} bmp085_cd_t; + +/** @} */ + +/** + * @name BMP085 thermometer subsystem data structures and types. + * @{ + */ + +/** + * @brief BMP085 thermometer subsystem temperature conversion time. + */ +typedef enum { + BMP085_THERMO_CT_LOW = 0x05, /**< Conv time in ultra low power mode. */ + BMP085_THERMO_CT_STD = 0x18, /**< Conv time in standard mode. */ + BMP085_THERMO_CT_HR = 0x0E, /**< Conv time in high resolution mode. */ + BMP085_THERMO_CT_LUHR = 0x1A /**< Conv time in ultra high res. mode. */ +} bmp085_thermo_ct_t; + +/** @} */ + +/** + * @name BMP085 main system data structures and types. + * @{ + */ + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + BMP085_UNINIT = 0, /**< Not initialized. */ + BMP085_STOP = 1, /**< Stopped. */ + BMP085_READY = 2 /**< Ready. */ +} bmp085_state_t; + +/** + * @brief BMP085 configuration structure. + */ +typedef struct { +#if BMP085_USE_I2C || defined(__DOXYGEN__) + /** + * @brief I2C driver associated to this BMP085. + */ + I2CDriver *i2cp; + + /** + * @brief I2C configuration associated to this BMP085 subsystem. + */ + const I2CConfig *i2ccfg; +#endif /* BMP085_USE_I2C */ + /** + * @brief HTS221 initial sensitivity. + * @note Value are respectively related to hygrometer + * and thermometer. + */ + float* sensitivity; + /** + * @brief HTS221 initial bias. + * @note Value are respectively related to hygrometer + * and thermometer. + */ + float* bias; + /** + * @brief HTS221 output data rate selection. + */ + float* outputdatarate; +#if BMP085_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief BMP085 barometer subsystem pressure conversion time. + */ + bmp085_baro_ct_t bct; + + /** + * @brief BMP085 barometer subsystem mode. + */ + bmp085_baro_mode_t mode; + + /** + * @brief BMP085 barometer subsystem oversampling setting. + */ + bmp085_baro_oss_t oss; + + /** + * @brief BMP085 thermometer subsystem temperature conversion time. + */ + bmp085_thermo_ct_t tct; +#endif /* BMP085_USE_ADVANCED */ +} BMP085Config; + +/** + * @brief Structure representing a BMP085 driver. + */ +typedef struct BMP085Driver BMP085Driver; + +/** + * @brief @p BMP085 barometer subsystem specific methods. + */ +#define _bmp085_baro_methods \ + _base_barometer_methods + +/** + * @brief @p BMP085 thermometer subsystem specific methods. + */ +#define _bmp085_thermo_methods \ + _base_thermometer_methods + +/** + * @extends BaseBarometerVMT + * + * @brief @p BMP085 barometer virtual methods table. + */ +struct BMP085BAROVMT { + _bmp085_baro_methods +}; + +/** + * @extends BaseThermometerVMT + * + * @brief @p BMP085 thermometer virtual methods table. + */ +struct BMP085THERMOVMT { + _bmp085_thermo_methods +}; + +/** + * @brief @p BMP085Driver specific data. + */ +#define _bmp085_data \ + _base_barometer_data \ + _base_thermometer_data \ + /* Driver state. */ \ + bmp085_state_t state; \ + /* Current configuration data. */ \ + const BMP085Config *config; \ + /* Current barometer sensitivity. */ \ + float barosensitivity[BMP085_BARO_NUMBER_OF_AXES]; \ + /* Barometer bias data. */ \ + int32_t barobias[BMP085_BARO_NUMBER_OF_AXES]; \ + /* Current thermometer sensitivity. */ \ + float thermosensitivity[BMP085_THERMO_NUMBER_OF_AXES]; \ + /* Thermometer bias data. */ \ + int32_t thermobias[BMP085_THERMO_NUMBER_OF_AXES]; \ + /* BMP085 calibration data. */ \ + bmp085_cd_t calibrationdata; + +/** + * @brief BMP085 driver structure. + */ +struct BMP085Driver { + /** @brief BaseSensor Virtual Methods Table. */ + const struct BaseSensorVMT *vmt_basesensor; + /** @brief BaseBarometer Virtual Methods Table. */ + const struct BaseBarometerVMT *vmt_basebarometer; + /** @brief BaseThermometer Virtual Methods Table. */ + const struct BaseThermometerVMT *vmt_basethermometer; + _bmp085_data; +}; + +/** @} */ + +/*==========================================================================*/ +/* Driver macros. */ +/*==========================================================================*/ + +/*==========================================================================*/ +/* External declarations. */ +/*==========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void bmp085ObjectInit(BMP085Driver *devp); + void bmp085Start(BMP085Driver *devp, const BMP085Config *config); + void bmp085Stop(BMP085Driver *devp); +#ifdef __cplusplus +} +#endif + +#endif /* BMP085_H */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.mk b/ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.mk new file mode 100644 index 0000000..7c868ca --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.mk @@ -0,0 +1,10 @@ +# List of all the BMP085 device files. +BMP085SRC := $(CHIBIOS)/os/ex/devices/Bosch/bmp085.c + +# Required include directories +BMP085INC := $(CHIBIOS)/os/ex/include \ + $(CHIBIOS)/os/ex/devices/Bosch + +# Shared variables +ALLCSRC += $(BMP085SRC) +ALLINC += $(BMP085INC) \ No newline at end of file diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/hts221.c b/ChibiOS_20.3.2/os/ex/devices/ST/hts221.c new file mode 100644 index 0000000..eb04ef7 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/hts221.c @@ -0,0 +1,781 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file hts221.c + * @brief HTS221 MEMS interface module code. + * + * @addtogroup HTS221 + * @ingroup EX_ST + * @{ + */ + +#include "hal.h" +#include "hts221.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define HTS221_SEL(mask, offset) (int16_t)(mask << offset) + +#define HTS221_FLAG_HYGRO_BIAS 0x01 +#define HTS221_FLAG_HYGRO_SENS 0x02 +#define HTS221_FLAG_THERMO_BIAS 0x04 +#define HTS221_FLAG_THERMO_SENS 0x08 + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if (HTS221_USE_I2C) || defined(__DOXYGEN__) +/** + * @brief Reads registers value using I2C. + * @pre The I2C interface must be initialized and the driver started. + * + * @param[in] i2cp pointer to the I2C interface + * @param[in] reg first sub-register address + * @param[out] rxbuf pointer to an output buffer + * @param[in] n number of consecutive register to read + * @return the operation status. + * + * @notapi + */ +static msg_t hts221I2CReadRegister(I2CDriver *i2cp, uint8_t reg, uint8_t* rxbuf, + size_t n) { + uint8_t txbuf = reg; + if (n > 1) + txbuf |= HTS221_SUB_MS; + + return i2cMasterTransmitTimeout(i2cp, HTS221_SAD, &txbuf, 1, rxbuf, n, + TIME_INFINITE); +} + +/** + * @brief Writes a value into a register using I2C. + * @pre The I2C interface must be initialized and the driver started. + * + * @param[in] i2cp pointer to the I2C interface + * @param[in] txbuf buffer containing sub-address value in first position + * and values to write + * @param[in] n size of txbuf less one (not considering the first + * element) + * @return the operation status. + * + * @notapi + */ +static msg_t hts221I2CWriteRegister(I2CDriver *i2cp, uint8_t* txbuf, size_t n) { + if (n > 1) + (*txbuf) |= HTS221_SUB_MS; + + return i2cMasterTransmitTimeout(i2cp, HTS221_SAD, txbuf, n + 1, NULL, 0, + TIME_INFINITE); +} +#endif /* HTS221_USE_I2C */ + +/** + * @brief Computes biases and sensitivities starting from data stored in + * calibration registers. + * @note Factory bias and sensitivity values are stored into the driver + * structure. + * + * @param[in] devp pointer to the HTS221 interface + * @return the operation status. + * + * @notapi + */ +static msg_t hts221Calibrate(HTS221Driver *devp) { + msg_t msg; + uint8_t calib[16], H0_rH_x2, H1_rH_x2, msb; + int16_t H0_T0_OUT, H1_T0_OUT, T0_degC_x8, T1_degC_x8, T0_OUT, T1_OUT; + + /* Retrieving rH values from Calibration registers */ + msg = hts221I2CReadRegister(devp->config->i2cp, + HTS221_AD_CALIB_0, calib, 16); + + H0_rH_x2 = calib[0]; + H1_rH_x2 = calib[1]; + H0_T0_OUT = calib[6]; + H0_T0_OUT += calib[7] << 8; + H1_T0_OUT = calib[10]; + H1_T0_OUT += calib[11] << 8; + + T0_degC_x8 = calib[2]; + + /* Completing T0_degC_x8 value */ + msb = (calib[5] & HTS221_SEL(0x03, 0)); + if (msb & HTS221_SEL(0x01, 1)) { + msb |= HTS221_SEL(0x3F, 2); + } + T0_degC_x8 += msb << 8; + + T1_degC_x8 = calib[3]; + /* Completing T1_degC_x8 value */ + msb = ((calib[5] & HTS221_SEL(0x03, 2)) >> 2); + if (msb & HTS221_SEL(0x01, 1)) { + msb |= HTS221_SEL(0x3F, 2); + } + T1_degC_x8 += msb << 8; + + T0_OUT = calib[12]; + T0_OUT += calib[13] << 8; + T1_OUT = calib[14]; + T1_OUT += calib[15] << 8; + + devp->hygrofactorysensitivity = ((float)H1_rH_x2 - (float)H0_rH_x2) / + (((float)H1_T0_OUT - (float)H0_T0_OUT) * 2.0f); + + + devp->hygrofactorybias = (devp->hygrofactorysensitivity * (float)H0_T0_OUT) - + ((float)H0_rH_x2 / 2.0f); + + devp->thermofactorysensitivity = ((float)T1_degC_x8 - (float)T0_degC_x8) / + (((float)T1_OUT - (float)T0_OUT) * 8.0f); + + devp->thermofactorybias = (devp->thermofactorysensitivity * (float)T0_OUT) - + ((float)T0_degC_x8 / 8.0f); + + return msg; +} + +/** + * @brief Return the number of axes of the BaseHygrometer. + * + * @param[in] ip pointer to @p BaseHygrometer interface. + * + * @return the number of axes. + */ +static size_t hygro_get_axes_number(void *ip) { + (void)ip; + + return HTS221_HYGRO_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseHygrometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseHygrometer axes number. + * + * @param[in] ip pointer to @p BaseHygrometer interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t hygro_read_raw(void *ip, int32_t axes[]) { + HTS221Driver* devp; + uint8_t buff[2]; + int16_t tmp; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(HTS221Driver*, (BaseHygrometer*)ip); + + osalDbgAssert((devp->state == HTS221_READY), + "hygro_read_raw(), invalid state"); + + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "hygro_read_raw(), channel not ready"); + +#if HTS221_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* HTS221_SHARED_I2C */ + + msg = hts221I2CReadRegister(devp->config->i2cp, HTS221_AD_HUMIDITY_OUT_L, + buff, 2); + +#if HTS221_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* HTS221_SHARED_I2C */ + + if (msg == MSG_OK) { + tmp = buff[0] + (buff[1] << 8); + *axes = (int32_t)tmp; + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseHygrometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as %rH. + * @note The axes array must be at least the same size of the + * BaseHygrometer axes number. + * + * @param[in] ip pointer to @p BaseHygrometer interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t hygro_read_cooked(void *ip, float axes[]) { + HTS221Driver* devp; + int32_t raw; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(HTS221Driver*, (BaseHygrometer*)ip); + + osalDbgAssert((devp->state == HTS221_READY), + "hygro_read_cooked(), invalid state"); + + msg = hygro_read_raw(ip, &raw); + + *axes = (raw * devp->hygrosensitivity) - devp->hygrobias; + + return msg; +} + +/** + * @brief Set bias values for the BaseHygrometer. + * @note Bias must be expressed as %rH. + * @note The bias buffer must be at least the same size of the + * BaseHygrometer axes number. + * + * @param[in] ip pointer to @p BaseHygrometer interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t hygro_set_bias(void *ip, float *bp) { + HTS221Driver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(HTS221Driver*, (BaseHygrometer*)ip); + + osalDbgAssert((devp->state == HTS221_READY), + "hygro_set_bias(), invalid state"); + + devp->hygrobias = *bp; + return msg; +} + +/** + * @brief Reset bias values for the BaseHygrometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseHygrometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t hygro_reset_bias(void *ip) { + HTS221Driver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(HTS221Driver*, (BaseHygrometer*)ip); + + osalDbgAssert((devp->state == HTS221_READY), + "hygro_reset_bias(), invalid state"); + + devp->hygrobias = devp->hygrofactorybias; + return msg; +} + +/** + * @brief Set sensitivity values for the BaseHygrometer. + * @note Sensitivity must be expressed as %rH/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseHygrometer axes number. + * + * @param[in] ip pointer to @p BaseHygrometer interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t hygro_set_sensitivity(void *ip, float *sp) { + HTS221Driver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (sp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(HTS221Driver*, (BaseHygrometer*)ip); + + osalDbgAssert((devp->state == HTS221_READY), + "hygro_set_sensitivity(), invalid state"); + + devp->hygrosensitivity = *sp; + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseHygrometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseHygrometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t hygro_reset_sensitivity(void *ip) { + HTS221Driver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(HTS221Driver*, (BaseHygrometer*)ip); + + osalDbgAssert((devp->state == HTS221_READY), + "hygro_reset_sensitivity(), invalid state"); + + devp->hygrosensitivity = devp->hygrofactorysensitivity; + return msg; +} + +/** + * @brief Return the number of axes of the BaseThermometer. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * + * @return the number of axes. + */ +static size_t thermo_get_axes_number(void *ip) { + (void)ip; + + return HTS221_THERMO_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseThermometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t thermo_read_raw(void *ip, int32_t axes[]) { + HTS221Driver* devp; + int16_t tmp; + uint8_t buff[2]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(HTS221Driver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == HTS221_READY), + "thermo_read_raw(), invalid state"); + + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "thermo_read_raw(), channel not ready"); + +#if HTS221_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* HTS221_SHARED_I2C */ + + msg = hts221I2CReadRegister(devp->config->i2cp, HTS221_AD_TEMP_OUT_L, + buff, 2); + +#if HTS221_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* HTS221_SHARED_I2C */ + + if (msg == MSG_OK) { + tmp = buff[0] + (buff[1] << 8); + *axes = (int32_t)tmp; + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseThermometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as °C. + * @note The axes array must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * @param[out] axis a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t thermo_read_cooked(void *ip, float* axis) { + HTS221Driver* devp; + int32_t raw; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axis != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(HTS221Driver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == HTS221_READY), + "thermo_read_cooked(), invalid state"); + + msg = thermo_read_raw(devp, &raw); + + *axis = (raw * devp->thermosensitivity) - devp->thermobias; + + return msg; +} + +/** + * @brief Set bias values for the BaseThermometer. + * @note Bias must be expressed as °C. + * @note The bias buffer must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t thermo_set_bias(void *ip, float *bp) { + HTS221Driver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(HTS221Driver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == HTS221_READY), + "thermo_set_bias(), invalid state"); + + devp->thermobias = *bp; + + return msg; +} + +/** + * @brief Reset bias values for the BaseThermometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t thermo_reset_bias(void *ip) { + HTS221Driver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(HTS221Driver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == HTS221_READY), + "thermo_reset_bias(), invalid state"); + + devp->thermobias = devp->thermofactorybias; + + return msg; +} + +/** + * @brief Set sensitivity values for the BaseThermometer. + * @note Sensitivity must be expressed as °C/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t thermo_set_sensitivity(void *ip, float *sp) { + HTS221Driver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (sp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(HTS221Driver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == HTS221_READY), + "thermo_set_sensitivity(), invalid state"); + + devp->thermosensitivity = *sp; + + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseThermometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t thermo_reset_sensitivity(void *ip) { + HTS221Driver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(HTS221Driver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == HTS221_READY), + "thermo_reset_sensitivity(), invalid state"); + + devp->thermosensitivity = devp->thermofactorysensitivity; + + return msg; +} + +static const struct HTS221VMT vmt_device = { + (size_t)0 +}; + +static const struct BaseHygrometerVMT vmt_hygrometer = { + sizeof(struct HTS221VMT*), + hygro_get_axes_number, hygro_read_raw, hygro_read_cooked, + hygro_set_bias, hygro_reset_bias, hygro_set_sensitivity, + hygro_reset_sensitivity +}; + +static const struct BaseThermometerVMT vmt_thermometer = { + sizeof(struct HTS221VMT*) + sizeof(BaseHygrometer), + thermo_get_axes_number, thermo_read_raw, thermo_read_cooked, + thermo_set_bias, thermo_reset_bias, thermo_set_sensitivity, + thermo_reset_sensitivity +}; + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes an instance. + * + * @param[out] devp pointer to the @p HTS221Driver object + * + * @init + */ +void hts221ObjectInit(HTS221Driver *devp) { + + devp->vmt = &vmt_device; + devp->hygro_if.vmt = &vmt_hygrometer; + devp->thermo_if.vmt = &vmt_thermometer; + + devp->config = NULL; + + devp->hygroaxes = HTS221_HYGRO_NUMBER_OF_AXES; + devp->thermoaxes = HTS221_THERMO_NUMBER_OF_AXES; + + devp->hygrobias = 0.0f; + devp->thermobias = 0.0f; + + devp->state = HTS221_STOP; +} + +/** + * @brief Configures and activates HTS221 Complex Driver peripheral. + * + * @param[in] devp pointer to the @p HTS221Driver object + * @param[in] config pointer to the @p HTS221Config object + * + * @api + */ +void hts221Start(HTS221Driver *devp, const HTS221Config *config) { + uint8_t cr[2]; + osalDbgCheck((devp != NULL) && (config != NULL)); + + osalDbgAssert((devp->state == HTS221_STOP) || (devp->state == HTS221_READY), + "hts221Start(), invalid state"); + + devp->config = config; + +#if HTS221_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); +#endif /* HTS221_SHARED_I2C */ + + /* Intializing the I2C. */ + i2cStart(devp->config->i2cp, devp->config->i2ccfg); + + hts221Calibrate(devp); + +#if HTS221_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* HTS221_SHARED_I2C */ + + + if(devp->config->hygrosensitivity == NULL) { + devp->hygrosensitivity = devp->hygrofactorysensitivity; + } + else{ + /* Taking hygrometer sensitivity from user configurations */ + devp->hygrosensitivity = *(devp->config->hygrosensitivity); + } + + if(devp->config->hygrobias == NULL) { + devp->hygrobias = devp->hygrofactorybias; + } + else{ + /* Taking hygrometer bias from user configurations */ + devp->hygrobias = *(devp->config->hygrobias); + } + + if(devp->config->thermosensitivity == NULL) { + devp->thermosensitivity = devp->thermofactorysensitivity; + } + else{ + /* Taking thermometer sensitivity from user configurations */ + devp->thermosensitivity = *(devp->config->thermosensitivity); + } + + if(devp->config->thermobias == NULL) { + devp->thermobias = devp->thermofactorybias; + } + else{ + /* Taking thermometer bias from user configurations */ + devp->thermobias = *(devp->config->thermobias); + } + + /* Control register 1 configuration block.*/ + { + cr[0] = HTS221_AD_CTRL_REG1; + cr[1] = devp->config->outputdatarate | HTS221_CTRL_REG1_PD; +#if HTS221_USE_ADVANCED || defined(__DOXYGEN__) + cr[1] |= devp->config->blockdataupdate; +#endif + +#if HTS221_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* HTS221_SHARED_I2C */ + + hts221I2CWriteRegister(devp->config->i2cp, cr, 1); + +#if HTS221_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* HTS221_SHARED_I2C */ + } + + /* Average register configuration block.*/ + { + cr[0] = HTS221_AD_AV_CONF; + cr[1] = 0x05; +#if HTS221_USE_ADVANCED || defined(__DOXYGEN__) + cr[1] = devp->config->hygroresolution | devp->config->thermoresolution; +#endif + +#if HTS221_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* HTS221_SHARED_I2C */ + + hts221I2CWriteRegister(devp->config->i2cp, cr, 1); + +#if HTS221_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* HTS221_SHARED_I2C */ + } + + /* This is the MEMS transient recovery time */ + osalThreadSleepMilliseconds(5); + + devp->state = HTS221_READY; +} + +/** + * @brief Deactivates the HTS221 Complex Driver peripheral. + * + * @param[in] devp pointer to the @p HTS221Driver object + * + * @api + */ +void hts221Stop(HTS221Driver *devp) { + uint8_t cr[2]; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == HTS221_STOP) || (devp->state == HTS221_READY), + "hts221Stop(), invalid state"); + + if (devp->state == HTS221_READY) { + +#if HTS221_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* HTS221_SHARED_I2C */ + + cr[0] = HTS221_AD_CTRL_REG1; + cr[1] = 0; + hts221I2CWriteRegister(devp->config->i2cp, cr, 1); + + i2cStop(devp->config->i2cp); +#if HTS221_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* HTS221_SHARED_I2C */ + } + devp->state = HTS221_STOP; +} +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/hts221.h b/ChibiOS_20.3.2/os/ex/devices/ST/hts221.h new file mode 100644 index 0000000..d79972d --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/hts221.h @@ -0,0 +1,707 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file hts221.h + * @brief HTS221 MEMS interface module header. + * + * + * @addtogroup HTS221 + * @ingroup EX_ST + * @{ + */ +#ifndef _HTS221_H_ +#define _HTS221_H_ + +#include "ex_hygrometer.h" +#include "ex_thermometer.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Version identification + * @{ + */ +/** + * @brief HTS221 driver version string. + */ +#define EX_HTS221_VERSION "1.1.2" + +/** + * @brief HTS221 driver version major number. + */ +#define EX_HTS221_MAJOR 1 + +/** + * @brief HTS221 driver version minor number. + */ +#define EX_HTS221_MINOR 1 + +/** + * @brief HTS221 driver version patch number. + */ +#define EX_HTS221_PATCH 2 +/** @} */ + +/** + * @brief HTS221 hygrometer subsystem characteristics. + * @note Sensitivity is expressed as %rH/LSB whereas %rH stand for percentage + * of relative humidity. + * @note Bias is expressed as %rH. + * @{ + */ +#define HTS221_HYGRO_NUMBER_OF_AXES 1U + +#define HTS221_HYGRO_SENS 0.00390625f +#define HTS221_HYGRO_BIAS 0.0f +/** @} */ + +/** + * @brief HTS221 thermometer subsystem characteristics. + * @note Sensitivity is expressed as �C/LSB. + * @note Bias is expressed as �C. + * + * @{ + */ +#define HTS221_THERMO_NUMBER_OF_AXES 1U + +#define HTS221_THERMO_SENS 0.0015625f +#define HTS221_THERMO_BIAS 0.0f +/** @} */ + +/** + * @name HTS221 communication interfaces related bit masks + * @{ + */ +#define HTS221_DI_MASK 0xFF +#define HTS221_DI(n) (1 << n) +#define HTS221_AD_MASK 0x3F +#define HTS221_AD(n) (1 << n) +#define HTS221_MS (1 << 6) +#define HTS221_RW (1 << 7) + +#define HTS221_SUB_MS (1 << 7) + +#define HTS221_SAD 0x5F +/** @} */ + +/** + * @name HTS221 register addresses + * @{ + */ +#define HTS221_AD_WHO_AM_I 0x0F +#define HTS221_AD_AV_CONF 0x10 +#define HTS221_AD_CTRL_REG1 0x20 +#define HTS221_AD_CTRL_REG2 0x21 +#define HTS221_AD_CTRL_REG3 0x22 +#define HTS221_AD_STATUS_REG 0x27 +#define HTS221_AD_HUMIDITY_OUT_L 0x28 +#define HTS221_AD_HUMIDITY_OUT_H 0x29 +#define HTS221_AD_TEMP_OUT_L 0x2A +#define HTS221_AD_TEMP_OUT_H 0x2B +#define HTS221_AD_CALIB_0 0x30 +#define HTS221_AD_CALIB_1 0x31 +#define HTS221_AD_CALIB_2 0x32 +#define HTS221_AD_CALIB_3 0x33 +#define HTS221_AD_CALIB_4 0x34 +#define HTS221_AD_CALIB_5 0x35 +#define HTS221_AD_CALIB_6 0x36 +#define HTS221_AD_CALIB_7 0x37 +#define HTS221_AD_CALIB_8 0x38 +#define HTS221_AD_CALIB_9 0x39 +#define HTS221_AD_CALIB_A 0x3A +#define HTS221_AD_CALIB_B 0x3B +#define HTS221_AD_CALIB_C 0x3C +#define HTS221_AD_CALIB_D 0x3D +#define HTS221_AD_CALIB_E 0x3E +#define HTS221_AD_CALIB_F 0x3F +/** @} */ + +/** + * @name HTS221_CTRL_REG1 register bits definitions + * @{ + */ +#define HTS221_CTRL_REG1_MASK 0x87 +#define HTS221_CTRL_REG1_ODR0 (1 << 0) +#define HTS221_CTRL_REG1_ODR1 (1 << 1) +#define HTS221_CTRL_REG1_BDU (1 << 2) +#define HTS221_CTRL_REG1_PD (1 << 7) +/** @} */ + +/** + * @name HTS221_CTRL_REG2 register bits definitions + * @{ + */ +#define HTS221_CTRL_REG2_MASK 0x83 +#define HTS221_CTRL_REG2_ONE_SHOT (1 << 0) +#define HTS221_CTRL_REG2_HEATER (1 << 1) +#define HTS221_CTRL_REG2_BOOT (1 << 7) +/** @} */ + +/** + * @name HTS221_CTRL_REG3 register bits definitions + * @{ + */ +#define HTS221_CTRL_REG3_MASK 0xC4 +#define HTS221_CTRL_REG3_DRDY (1 << 2) +#define HTS221_CTRL_REG3_PP_OD (1 << 6) +#define HTS221_CTRL_REG3_INT_H_L (1 << 7) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief HTS221 SPI interface switch. + * @details If set to @p TRUE the support for SPI is included. + * @note The default is @p FALSE. + */ +#if !defined(HTS221_USE_SPI) || defined(__DOXYGEN__) +#define HTS221_USE_SPI FALSE +#endif + +/** + * @brief HTS221 shared SPI switch. + * @details If set to @p TRUE the device acquires SPI bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION + */ +#if !defined(HTS221_SHARED_SPI) || defined(__DOXYGEN__) +#define HTS221_SHARED_SPI FALSE +#endif + +/** + * @brief HTS221 I2C interface switch. + * @details If set to @p TRUE the support for I2C is included. + * @note The default is @p TRUE. + */ +#if !defined(HTS221_USE_I2C) || defined(__DOXYGEN__) +#define HTS221_USE_I2C TRUE +#endif + +/** + * @brief HTS221 shared I2C switch. + * @details If set to @p TRUE the device acquires I2C bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION + */ +#if !defined(HTS221_SHARED_I2C) || defined(__DOXYGEN__) +#define HTS221_SHARED_I2C FALSE +#endif + +/** + * @brief HTS221 advanced configurations switch. + * @details If set to @p TRUE more configurations are available. + * @note The default is @p FALSE. + */ +#if !defined(HTS221_USE_ADVANCED) || defined(__DOXYGEN__) +#define HTS221_USE_ADVANCED FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !(HTS221_USE_SPI ^ HTS221_USE_I2C) +#error "HTS221_USE_SPI and HTS221_USE_I2C cannot be both true or both false" +#endif + +#if HTS221_USE_SPI && !HAL_USE_SPI +#error "HTS221_USE_SPI requires HAL_USE_SPI" +#endif + +#if HTS221_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION +#error "HTS221_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" +#endif + +#if HTS221_USE_I2C && !HAL_USE_I2C +#error "HTS221_USE_I2C requires HAL_USE_I2C" +#endif + +#if HTS221_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION +#error "HTS221_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" +#endif + +/* + * CHTODO: Add support for HTS221 over SPI. + */ +#if HTS221_USE_SPI +#error "HTS221 over SPI still not supported." +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @name HTS221 data structures and types. + * @{ + */ +/** + * @brief Structure representing a HTS221 driver. + */ +typedef struct HTS221Driver HTS221Driver; + +/** + * @brief HTS221 output data rate and bandwidth. + */ +typedef enum { + HTS221_ODR_ONE_SHOT = 0x00, /**< One shot. */ + HTS221_ODR_1HZ = 0x01, /**< Output data rate 1 Hz. */ + HTS221_ODR_7HZ = 0x02, /**< Output data rate 7 Hz. */ + HTS221_ODR_12P5HZ = 0x03, /**< Output data rate 12.5 Hz. */ +}hts221_odr_t; + +/** + * @brief HTS221 humidity resolution. + */ +typedef enum { + HTS221_AVGH_4 = 0x00, /**< Number of internal average is 4. */ + HTS221_AVGH_8 = 0x01, /**< Number of internal average is 8. */ + HTS221_AVGH_16 = 0x02, /**< Number of internal average is 16. */ + HTS221_AVGH_32 = 0x03, /**< Number of internal average is 32. */ + HTS221_AVGH_64 = 0x04, /**< Number of internal average is 64. */ + HTS221_AVGH_128 = 0x05, /**< Number of internal average is 128. */ + HTS221_AVGH_256 = 0x06, /**< Number of internal average is 256. */ + HTS221_AVGH_512 = 0x07 /**< Number of internal average is 512. */ +}hts221_avgh_t; + +/** + * @brief HTS221 temperature resolution. + */ +typedef enum { + HTS221_AVGT_2 = 0x00, /**< Number of internal average is 2. */ + HTS221_AVGT_4 = 0x08, /**< Number of internal average is 4. */ + HTS221_AVGT_8 = 0x10, /**< Number of internal average is 8. */ + HTS221_AVGT_16 = 0x18, /**< Number of internal average is 16. */ + HTS221_AVGT_32 = 0x20, /**< Number of internal average is 32. */ + HTS221_AVGT_64 = 0x28, /**< Number of internal average is 64. */ + HTS221_AVGT_128 = 0x30, /**< Number of internal average is 128. */ + HTS221_AVGT_256 = 0x38, /**< Number of internal average is 256. */ +}hts221_avgt_t; + +/** + * @brief HTS221 block data update. + */ +typedef enum { + HTS221_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */ + HTS221_BDU_BLOCKED = 0x40 /**< Block data updated after reading. */ +}hts221_bdu_t; + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + HTS221_UNINIT = 0, /**< Not initialized. */ + HTS221_STOP = 1, /**< Stopped. */ + HTS221_READY = 2, /**< Ready. */ +} hts221_state_t; + +/** + * @brief HTS221 configuration structure. + */ +typedef struct { + +#if HTS221_USE_SPI || defined(__DOXYGEN__) + /** + * @brief SPI driver associated to this HTS221. + */ + SPIDriver *spip; + /** + * @brief SPI configuration associated to this HTS221. + */ + const SPIConfig *spicfg; +#endif /* HTS221_USE_SPI */ +#if HTS221_USE_I2C || defined(__DOXYGEN__) + /** + * @brief I2C driver associated to this HTS221. + */ + I2CDriver *i2cp; + /** + * @brief I2C configuration associated to this HTS221. + */ + const I2CConfig *i2ccfg; +#endif /* HTS221_USE_I2C */ + /** + * @brief HTS221 hygrometer subsystem initial sensitivity. + */ + float *hygrosensitivity; + /** + * @brief HTS221 hygrometer subsystem initial bias. + */ + float *hygrobias; + /** + * @brief HTS221 thermometer subsystem initial sensitivity. + */ + float *thermosensitivity; + /** + * @brief HTS221 thermometer subsystem initial bias. + */ + float *thermobias; + /** + * @brief HTS221 output data rate selection. + */ + hts221_odr_t outputdatarate; +#if HTS221_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief HTS221 block data update. + */ + hts221_bdu_t blockdataupdate; + /** + * @brief HTS221 hygrometer subsystem resolution. + */ + hts221_avgh_t hygroresolution; + /** + * @brief HTS221 thermometer subsystem resolution. + */ + hts221_avgt_t thermoresolution; +#endif +} HTS221Config; + +/** + * @brief @p HTS221 specific methods. + * @note No methods so far, just a common ancestor interface. + */ +#define _hts221_methods_alone + +/** + * @brief @p HTS221 specific methods with inherited ones. + */ +#define _hts221_methods \ + _base_object_methods \ + _hts221_methods_alone + +/** + * @extends BaseObjectVMT + * + * @brief @p HTS221 virtual methods table. + */ +struct HTS221VMT { + _hts221_methods +}; + +/** + * @brief @p HTS221Driver specific data. + */ +#define _hts221_data \ + /* Driver state.*/ \ + hts221_state_t state; \ + /* Current configuration data.*/ \ + const HTS221Config *config; \ + /* Hygrometer subsystem axes number.*/ \ + size_t hygroaxes; \ + /* Hygrometer subsystem current sensitivity.*/ \ + float hygrosensitivity; \ + /* Hygrometer subsystem current bias .*/ \ + float hygrobias; \ + /* Hygrometer subsystem factory sensitivity.*/ \ + float hygrofactorysensitivity; \ + /* Hygrometer subsystem factory bias .*/ \ + float hygrofactorybias; \ + /* Thermometer subsystem axes number.*/ \ + size_t thermoaxes; \ + /* Thermometer subsystem current sensitivity.*/ \ + float thermosensitivity; \ + /* Thermometer subsystem current bias.*/ \ + float thermobias; \ + /* Thermometer subsystem factory sensitivity.*/ \ + float thermofactorysensitivity; \ + /* Thermometer subsystem factory bias.*/ \ + float thermofactorybias; + +/** + * @brief HTS221 2-axis hygrometer/thermometer class. + */ +struct HTS221Driver { + /** @brief Virtual Methods Table.*/ + const struct HTS221VMT *vmt; + /** @brief Base hygrometer interface.*/ + BaseHygrometer hygro_if; + /** @brief Base thermometer interface.*/ + BaseThermometer thermo_if; + _hts221_data +}; +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Return the number of axes of the BaseHygrometer. + * + * @param[in] devp pointer to @p HTS221Driver. + * + * @return the number of axes. + * + * @api + */ +#define hts221HygrometerGetAxesNumber(devp) \ + hygrometerGetAxesNumber(&((devp)->hygro_if)) + +/** + * @brief Retrieves raw data from the BaseHygrometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseHygrometer axes number. + * + * @param[in] devp pointer to @p HTS221Driver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define hts221HygrometerReadRaw(devp, axes) \ + hygrometerReadRaw(&((devp)->hygro_if), axes) + +/** + * @brief Retrieves cooked data from the BaseHygrometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as %rH. + * @note The axes array must be at least the same size of the + * BaseHygrometer axes number. + * + * @param[in] devp pointer to @p HTS221Driver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define hts221HygrometerReadCooked(devp, axes) \ + hygrometerReadCooked(&((devp)->hygro_if), axes) + +/** + * @brief Set bias values for the BaseHygrometer. + * @note Bias must be expressed as %rH. + * @note The bias buffer must be at least the same size of the + * BaseHygrometer axes number. + * + * @param[in] devp pointer to @p HTS221Driver. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define hts221HygrometerSetBias(devp, bp) \ + hygrometerSetBias(&((devp)->hygro_if), bp) + +/** + * @brief Reset bias values for the BaseHygrometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p HTS221Driver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define hts221HygrometerResetBias(devp) \ + hygrometerResetBias(&((devp)->hygro_if)) + +/** + * @brief Set sensitivity values for the BaseHygrometer. + * @note Sensitivity must be expressed as %rH/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseHygrometer axes number. + * + * @param[in] devp pointer to @p HTS221Driver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define hts221HygrometerSetSensitivity(devp, sp) \ + hygrometerSetSensitivity(&((devp)->hygro_if), sp) + +/** + * @brief Reset sensitivity values for the BaseHygrometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p HTS221Driver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define hts221HygrometerResetSensitivity(devp) \ + hygrometerResetSensitivity(&((devp)->hygro_if)) + +/** + * @brief Return the number of axes of the BaseThermometer. + * + * @param[in] devp pointer to @p HTS221Driver. + * + * @return the number of axes. + * + * @api + */ +#define hts221ThermometerGetAxesNumber(devp) \ + thermometerGetAxesNumber(&((devp)->thermo_if)) + +/** + * @brief Retrieves raw data from the BaseThermometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] devp pointer to @p HTS221Driver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define hts221ThermometerReadRaw(devp, axes) \ + thermometerReadRaw(&((devp)->thermo_if), axes) + +/** + * @brief Retrieves cooked data from the BaseThermometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as �C. + * @note The axes array must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] devp pointer to @p HTS221Driver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define hts221ThermometerReadCooked(devp, axes) \ + thermometerReadCooked(&((devp)->thermo_if), axes) + +/** + * @brief Set bias values for the BaseThermometer. + * @note Bias must be expressed as �C. + * @note The bias buffer must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] devp pointer to @p HTS221Driver. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define hts221ThermometerSetBias(devp, bp) \ + thermometerSetBias(&((devp)->thermo_if), bp) + +/** + * @brief Reset bias values for the BaseThermometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p HTS221Driver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define hts221ThermometerResetBias(devp) \ + thermometerResetBias(&((devp)->thermo_if)) + +/** + * @brief Set sensitivity values for the BaseThermometer. + * @note Sensitivity must be expressed as �C/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] devp pointer to @p HTS221Driver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define hts221ThermometerSetSensitivity(devp, sp) \ + thermometerSetSensitivity(&((devp)->thermo_if), sp) + +/** + * @brief Reset sensitivity values for the BaseThermometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p HTS221Driver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define hts221ThermometerResetSensitivity(devp) \ + thermometerResetSensitivity(&((devp)->thermo_if)) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void hts221ObjectInit(HTS221Driver *devp); + void hts221Start(HTS221Driver *devp, const HTS221Config *config); + void hts221Stop(HTS221Driver *devp); +#ifdef __cplusplus +} +#endif + +#endif /* _HTS221_H_ */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/hts221.mk b/ChibiOS_20.3.2/os/ex/devices/ST/hts221.mk new file mode 100644 index 0000000..1b9223a --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/hts221.mk @@ -0,0 +1,10 @@ +# List of all the HTS221 device files. +HTS221SRC := $(CHIBIOS)/os/ex/devices/ST/hts221.c + +# Required include directories +HTS221INC := $(CHIBIOS)/os/ex/include \ + $(CHIBIOS)/os/ex/devices/ST + +# Shared variables +ALLCSRC += $(HTS221SRC) +ALLINC += $(HTS221INC) \ No newline at end of file diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.c b/ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.c new file mode 100644 index 0000000..7ac57aa --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.c @@ -0,0 +1,642 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file l3gd20.c + * @brief L3GD20 MEMS interface module code. + * + * @addtogroup L3GD20 + * @ingroup EX_ST + * @{ + */ + +#include "hal.h" +#include "l3gd20.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if (L3GD20_USE_SPI) || defined(__DOXYGEN__) +/** + * @brief Reads a generic register value using SPI. + * @pre The SPI interface must be initialized and the driver started. + * + * @param[in] spip pointer to the SPI interface + * @param[in] reg starting register address + * @param[in] n number of consecutive registers to read + * @param[in] b pointer to an output buffer. + */ +static void l3gd20SPIReadRegister(SPIDriver *spip, uint8_t reg, size_t n, + uint8_t* b) { + uint8_t cmd; + (n == 1) ? (cmd = reg | L3GD20_RW) : (cmd = reg | L3GD20_RW | L3GD20_MS); + spiSelect(spip); + spiSend(spip, 1, &cmd); + spiReceive(spip, n, b); + spiUnselect(spip); +} + +/** + * @brief Writes a value into a generic register using SPI. + * @pre The SPI interface must be initialized and the driver started. + * + * @param[in] spip pointer to the SPI interface + * @param[in] reg starting register address + * @param[in] n number of adjacent registers to write + * @param[in] b pointer to a buffer of values. + */ +static void l3gd20SPIWriteRegister(SPIDriver *spip, uint8_t reg, size_t n, + uint8_t* b) { + uint8_t cmd; + (n == 1) ? (cmd = reg) : (cmd = reg | L3GD20_MS); + spiSelect(spip); + spiSend(spip, 1, &cmd); + spiSend(spip, n, b); + spiUnselect(spip); +} +#endif /* L3GD20_USE_SPI */ + +/** + * @brief Return the number of axes of the BaseGyroscope. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * + * @return the number of axes. + */ +static size_t gyro_get_axes_number(void *ip) { + (void)ip; + + return L3GD20_GYRO_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseGyroscope. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t gyro_read_raw(void *ip, int32_t axes[L3GD20_GYRO_NUMBER_OF_AXES]) { + L3GD20Driver* devp; + int16_t tmp; + uint8_t i, buff [2 * L3GD20_GYRO_NUMBER_OF_AXES]; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(L3GD20Driver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == L3GD20_READY), + "gyro_read_raw(), invalid state"); +#if L3GD20_USE_SPI + osalDbgAssert((devp->config->spip->state == SPI_READY), + "gyro_read_raw(), channel not ready"); + +#if L3GD20_SHARED_SPI + spiAcquireBus(devp->config->spip); + spiStart(devp->config->spip, + devp->config->spicfg); +#endif /* L3GD20_SHARED_SPI */ + + l3gd20SPIReadRegister(devp->config->spip, L3GD20_AD_OUT_X_L, + L3GD20_GYRO_NUMBER_OF_AXES * 2, buff); + +#if L3GD20_SHARED_SPI + spiReleaseBus(devp->config->spip); +#endif /* L3GD20_SHARED_SPI */ +#endif /* L3GD20_USE_SPI */ + + for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) { + tmp = buff[2 * i] + (buff[2 * i + 1] << 8); + axes[i] = (int32_t)tmp; + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseGyroscope. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as DPS. + * @note The axes array must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t gyro_read_cooked(void *ip, float axes[]) { + L3GD20Driver* devp; + uint32_t i; + int32_t raw[L3GD20_GYRO_NUMBER_OF_AXES]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(L3GD20Driver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == L3GD20_READY), + "gyro_read_cooked(), invalid state"); + + msg = gyro_read_raw(ip, raw); + for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++){ + axes[i] = (raw[i] * devp->gyrosensitivity[i]) - devp->gyrobias[i]; + } + return msg; +} + +/** + * @brief Samples bias values for the BaseGyroscope. + * @note The L3GD20 shall not be moved during the whole procedure. + * @note After this function internal bias is automatically updated. + * @note The behavior of this function depends on @p L3GD20_BIAS_ACQ_TIMES + * and @p L3GD20_BIAS_SETTLING_US. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t gyro_sample_bias(void *ip) { + L3GD20Driver* devp; + uint32_t i, j; + int32_t raw[L3GD20_GYRO_NUMBER_OF_AXES]; + int32_t buff[L3GD20_GYRO_NUMBER_OF_AXES] = {0, 0, 0}; + msg_t msg; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(L3GD20Driver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == L3GD20_READY), + "gyro_sample_bias(), invalid state"); +#if L3GD20_USE_SPI + osalDbgAssert((devp->config->spip->state == SPI_READY), + "gyro_sample_bias(), channel not ready"); +#endif + + for(i = 0; i < L3GD20_BIAS_ACQ_TIMES; i++){ + msg = gyro_read_raw(ip, raw); + if(msg != MSG_OK) + return msg; + for(j = 0; j < L3GD20_GYRO_NUMBER_OF_AXES; j++){ + buff[j] += raw[j]; + } + osalThreadSleepMicroseconds(L3GD20_BIAS_SETTLING_US); + } + + for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++){ + devp->gyrobias[i] = (buff[i] / L3GD20_BIAS_ACQ_TIMES); + devp->gyrobias[i] *= devp->gyrosensitivity[i]; + } + return msg; +} + +/** + * @brief Set bias values for the BaseGyroscope. + * @note Bias must be expressed as DPS. + * @note The bias buffer must be at least the same size of the BaseGyroscope + * axes number. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t gyro_set_bias(void *ip, float *bp) { + L3GD20Driver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(L3GD20Driver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == L3GD20_READY), + "gyro_set_bias(), invalid state"); + + for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) { + devp->gyrobias[i] = bp[i]; + } + return msg; +} + +/** + * @brief Reset bias values for the BaseGyroscope. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t gyro_reset_bias(void *ip) { + L3GD20Driver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(L3GD20Driver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == L3GD20_READY), + "gyro_reset_bias(), invalid state"); + + for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) + devp->gyrobias[i] = L3GD20_GYRO_BIAS; + return msg; +} + +/** + * @brief Set sensitivity values for the BaseGyroscope. + * @note Sensitivity must be expressed as DPS/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t gyro_set_sensivity(void *ip, float *sp) { + L3GD20Driver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (sp !=NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(L3GD20Driver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == L3GD20_READY), + "gyro_set_sensivity(), invalid state"); + + for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) { + devp->gyrosensitivity[i] = sp[i]; + } + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseGyroscope. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t gyro_reset_sensivity(void *ip) { + L3GD20Driver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(L3GD20Driver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == L3GD20_READY), + "gyro_reset_sensivity(), invalid state"); + + if(devp->config->gyrofullscale == L3GD20_FS_250DPS) + for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) + devp->gyrosensitivity[i] = L3GD20_GYRO_SENS_250DPS; + else if(devp->config->gyrofullscale == L3GD20_FS_500DPS) + for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) + devp->gyrosensitivity[i] = L3GD20_GYRO_SENS_500DPS; + else if(devp->config->gyrofullscale == L3GD20_FS_2000DPS) + for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) + devp->gyrosensitivity[i] = L3GD20_GYRO_SENS_2000DPS; + else { + osalDbgAssert(FALSE, "gyro_reset_sensivity(), full scale issue"); + return MSG_RESET; + } + return msg; +} + +/** + * @brief Changes the L3GD20Driver gyroscope fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p BaseGyroscope interface. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t gyro_set_full_scale(L3GD20Driver *devp, l3gd20_fs_t fs) { + float newfs, scale; + uint8_t i, cr; + msg_t msg = MSG_OK; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == L3GD20_READY), + "gyro_set_full_scale(), invalid state"); +#if L3GD20_USE_SPI + osalDbgAssert((devp->config->spip->state == SPI_READY), + "gyro_set_full_scale(), channel not ready"); +#endif + + if(fs == L3GD20_FS_250DPS) { + newfs = L3GD20_250DPS; + } + else if(fs == L3GD20_FS_500DPS) { + newfs = L3GD20_500DPS; + } + else if(fs == L3GD20_FS_2000DPS) { + newfs = L3GD20_2000DPS; + } + else { + return MSG_RESET; + } + + if(newfs != devp->gyrofullscale) { + scale = newfs / devp->gyrofullscale; + devp->gyrofullscale = newfs; + +#if L3GD20_USE_SPI +#if L3GD20_SHARED_SPI + spiAcquireBus(devp->config->spip); + spiStart(devp->config->spip, + devp->config->spicfg); +#endif /* L3GD20_SHARED_SPI */ + + /* Updating register.*/ + l3gd20SPIReadRegister(devp->config->spip, + L3GD20_AD_CTRL_REG4, 1, &cr); + +#if L3GD20_SHARED_SPI + spiReleaseBus(devp->config->spip); +#endif /* L3GD20_SHARED_SPI */ +#endif /* L3GD20_USE_SPI */ + cr &= ~(L3GD20_CTRL_REG4_FS_MASK); + cr |= fs; + +#if L3GD20_USE_SPI +#if L3GD20_SHARED_SPI + spiAcquireBus(devp->config->spip); + spiStart(devp->config->spip, + devp->config->spicfg); +#endif /* L3GD20_SHARED_SPI */ + + l3gd20SPIWriteRegister(devp->config->spip, + L3GD20_AD_CTRL_REG4, 1, &cr); +#if L3GD20_SHARED_SPI + spiReleaseBus(devp->config->spip); +#endif /* L3GD20_SHARED_SPI */ +#endif /* L3GD20_USE_SPI */ + + /* Scaling sensitivity and bias. Re-calibration is suggested anyway. */ + for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) { + devp->gyrosensitivity[i] *= scale; + devp->gyrobias[i] *= scale; + } + } + return msg; +} + +static const struct L3GD20VMT vmt_device = { + (size_t)0, + gyro_set_full_scale +}; + +static const struct BaseGyroscopeVMT vmt_gyroscope = { + sizeof(struct L3GD20VMT*), + gyro_get_axes_number, gyro_read_raw, gyro_read_cooked, + gyro_sample_bias, gyro_set_bias, gyro_reset_bias, + gyro_set_sensivity, gyro_reset_sensivity +}; + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes an instance. + * + * @param[out] devp pointer to the @p L3GD20Driver object + * + * @init + */ +void l3gd20ObjectInit(L3GD20Driver *devp) { + devp->vmt = &vmt_device; + devp->gyro_if.vmt = &vmt_gyroscope; + + devp->config = NULL; + + devp->state = L3GD20_STOP; +} + +/** + * @brief Configures and activates L3GD20 Complex Driver peripheral. + * + * @param[in] devp pointer to the @p L3GD20Driver object + * @param[in] config pointer to the @p L3GD20Config object + * + * @api + */ +void l3gd20Start(L3GD20Driver *devp, const L3GD20Config *config) { + uint32_t i; + uint8_t cr[5] = {0, 0, 0, 0, 0}; + osalDbgCheck((devp != NULL) && (config != NULL)); + + osalDbgAssert((devp->state == L3GD20_STOP) || (devp->state == L3GD20_READY), + "l3gd20Start(), invalid state"); + + devp->config = config; + + /* Control register 1 configuration block.*/ + { + cr[0] = L3GD20_CTRL_REG1_XEN | L3GD20_CTRL_REG1_YEN | + L3GD20_CTRL_REG1_ZEN | L3GD20_CTRL_REG1_PD | + devp->config->gyrooutputdatarate; +#if L3GD20_USE_ADVANCED || defined(__DOXYGEN__) + cr[0] |= devp->config->gyrobandwidth; +#endif + } + + /* Control register 2 configuration block.*/ + { +#if L3GD20_USE_ADVANCED || defined(__DOXYGEN__) + if(devp->config->gyrohpmode != L3GD20_HPM_BYPASSED) + cr[1] = devp->config->gyrohpmode | devp->config->gyrohpconfiguration; +#endif + } + + /* Control register 4 configuration block.*/ + { + cr[3] = devp->config->gyrofullscale; +#if L3GD20_USE_ADVANCED || defined(__DOXYGEN__) + cr[3] |= devp->config->gyroblockdataupdate | + devp->config->gyroendianness; +#endif + } + + /* Control register 5 configuration block.*/ + { +#if L3GD20_USE_ADVANCED || defined(__DOXYGEN__) + if((devp->config->gyrohpmode != L3GD20_HPM_BYPASSED)) { + cr[4] = L3GD20_CTRL_REG5_HPEN; + if(devp->config->gyrolp2mode != L3GD20_LP2M_BYPASSED) { + cr[4] |= L3GD20_CTRL_REG5_INT1_SEL1 | + L3GD20_CTRL_REG5_OUT_SEL1; + } + else { + cr[4] |= L3GD20_CTRL_REG5_INT1_SEL0 | + L3GD20_CTRL_REG5_OUT_SEL0; + } + } +#endif + } + +#if L3GD20_USE_SPI +#if L3GD20_SHARED_SPI + spiAcquireBus(devp->config->spip); +#endif /* L3GD20_SHARED_SPI */ + spiStart(devp->config->spip, + devp->config->spicfg); + + l3gd20SPIWriteRegister(devp->config->spip, L3GD20_AD_CTRL_REG1, + 5, cr); +#if L3GD20_SHARED_SPI + spiReleaseBus(devp->config->spip); +#endif /* L3GD20_SHARED_SPI */ +#endif /* L3GD20_USE_SPI */ + + /* Storing sensitivity information according to full scale.*/ + if(devp->config->gyrofullscale == L3GD20_FS_250DPS) { + devp->gyrofullscale = L3GD20_250DPS; + for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) { + if (devp->config->gyrosensitivity == NULL) + devp->gyrosensitivity[i] = L3GD20_GYRO_SENS_250DPS; + else + devp->gyrosensitivity[i] = devp->config->gyrosensitivity[i]; + } + } + else if(devp->config->gyrofullscale == L3GD20_FS_500DPS) { + devp->gyrofullscale = L3GD20_500DPS; + for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) { + if (devp->config->gyrosensitivity == NULL) + devp->gyrosensitivity[i] = L3GD20_GYRO_SENS_500DPS; + else + devp->gyrosensitivity[i] = devp->config->gyrosensitivity[i]; + } + } + else if(devp->config->gyrofullscale == L3GD20_FS_2000DPS) { + devp->gyrofullscale = L3GD20_2000DPS; + for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) { + if (devp->config->gyrosensitivity == NULL) + devp->gyrosensitivity[i] = L3GD20_GYRO_SENS_2000DPS; + else + devp->gyrosensitivity[i] = devp->config->gyrosensitivity[i]; + } + } + else + osalDbgAssert(FALSE, "l3gd20Start(), full scale issue"); + + /* Storing bias information.*/ + if(devp->config->gyrobias != NULL) { + for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) { + devp->gyrobias[i] = devp->config->gyrobias[i]; + } + } + else { + for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) + devp->gyrobias[i] = L3GD20_GYRO_BIAS; + } + + /* This is the Gyroscope transient recovery time.*/ + osalThreadSleepMilliseconds(10); + + devp->state = L3GD20_READY; +} + +/** + * @brief Deactivates the L3GD20 Complex Driver peripheral. + * + * @param[in] devp pointer to the @p L3GD20Driver object + * + * @api + */ +void l3gd20Stop(L3GD20Driver *devp) { + uint8_t cr1; + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == L3GD20_STOP) || (devp->state == L3GD20_READY), + "l3gd20Stop(), invalid state"); + + if (devp->state == L3GD20_READY) { + /* Disabling all axes and enabling power down mode.*/ + cr1 = 0; + +#if L3GD20_USE_SPI +#if L3GD20_SHARED_SPI + spiAcquireBus(devp->config->spip); + spiStart(devp->config->spip, + devp->config->spicfg); +#endif /* L3GD20_SHARED_SPI */ + + l3gd20SPIWriteRegister(devp->config->spip, L3GD20_AD_CTRL_REG1, + 1, &cr1); + spiStop(devp->config->spip); + +#if L3GD20_SHARED_SPI + spiReleaseBus(devp->config->spip); +#endif /* L3GD20_SHARED_SPI */ +#endif /* L3GD20_USE_SPI */ + } + devp->state = L3GD20_STOP; +} +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.h b/ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.h new file mode 100644 index 0000000..5528ecc --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.h @@ -0,0 +1,725 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file l3gd20.h + * @brief L3GD20 MEMS interface module header. + * + * @addtogroup L3GD20 + * @ingroup EX_ST + * @{ + */ +#ifndef _L3GD20_H_ +#define _L3GD20_H_ + +#include "ex_gyroscope.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Version identification + * @{ + */ +/** + * @brief L3GD20 driver version string. + */ +#define EX_L3GD20_VERSION "1.1.2" + +/** + * @brief L3GD20 driver version major number. + */ +#define EX_L3GD20_MAJOR 1 + +/** + * @brief L3GD20 driver version minor number. + */ +#define EX_L3GD20_MINOR 1 + +/** + * @brief L3GD20 driver version patch number. + */ +#define EX_L3GD20_PATCH 2 +/** @} */ + +/** + * @brief L3GD20 gyroscope system characteristics. + * @note Sensitivity is expressed as DPS/LSB whereas DPS stand for Degree + * per second [°/s]. + * @note Bias is expressed as DPS. + * + * @{ + */ +#define L3GD20_GYRO_NUMBER_OF_AXES 3U + +#define L3GD20_250DPS 250.0f +#define L3GD20_500DPS 500.0f +#define L3GD20_2000DPS 2000.0f + +#define L3GD20_GYRO_SENS_250DPS 0.00875f +#define L3GD20_GYRO_SENS_500DPS 0.01750f +#define L3GD20_GYRO_SENS_2000DPS 0.07000f + +#define L3GD20_GYRO_BIAS 0.0f +/** @} */ + +/** + * @name L3GD20 communication interfaces related bit masks + * @{ + */ +#define L3GD20_DI_MASK 0xFF +#define L3GD20_DI(n) (1 << n) +#define L3GD20_AD_MASK 0x3F +#define L3GD20_AD(n) (1 << n) +#define L3GD20_MS (1 << 6) +#define L3GD20_RW (1 << 7) +/** @} */ + +/** + * @name L3GD20 register addresses + * @{ + */ +#define L3GD20_AD_WHO_AM_I 0x0F +#define L3GD20_AD_CTRL_REG1 0x20 +#define L3GD20_AD_CTRL_REG2 0x21 +#define L3GD20_AD_CTRL_REG3 0x22 +#define L3GD20_AD_CTRL_REG4 0x23 +#define L3GD20_AD_CTRL_REG5 0x24 +#define L3GD20_AD_REFERENCE 0x25 +#define L3GD20_AD_OUT_TEMP 0x26 +#define L3GD20_AD_STATUS_REG 0x27 +#define L3GD20_AD_OUT_X_L 0x28 +#define L3GD20_AD_OUT_X_H 0x29 +#define L3GD20_AD_OUT_Y_L 0x2A +#define L3GD20_AD_OUT_Y_H 0x2B +#define L3GD20_AD_OUT_Z_L 0x2C +#define L3GD20_AD_OUT_Z_H 0x2D +#define L3GD20_AD_FIFO_CTRL_REG 0x2E +#define L3GD20_AD_FIFO_SRC_REG 0x2F +#define L3GD20_AD_INT1_CFG 0x30 +#define L3GD20_AD_INT1_SRC 0x31 +#define L3GD20_AD_INT1_THS_XH 0x32 +#define L3GD20_AD_INT1_THS_XL 0x33 +#define L3GD20_AD_INT1_THS_YH 0x34 +#define L3GD20_AD_INT1_THS_YL 0x35 +#define L3GD20_AD_INT1_THS_ZH 0x36 +#define L3GD20_AD_INT1_THS_ZL 0x37 +#define L3GD20_AD_INT1_DURATION 0x38 +/** @} */ + +/** + * @name L3GD20_CTRL_REG1 register bits definitions + * @{ + */ +#define L3GD20_CTRL_REG1_MASK 0xFF +#define L3GD20_CTRL_REG1_XEN (1 << 0) +#define L3GD20_CTRL_REG1_YEN (1 << 1) +#define L3GD20_CTRL_REG1_ZEN (1 << 2) +#define L3GD20_CTRL_REG1_PD (1 << 3) +#define L3GD20_CTRL_REG1_BW0 (1 << 4) +#define L3GD20_CTRL_REG1_BW1 (1 << 5) +#define L3GD20_CTRL_REG1_DR0 (1 << 6) +#define L3GD20_CTRL_REG1_DR1 (1 << 7) +/** @} */ + +/** + * @name L3GD20_CTRL_REG2 register bits definitions + * @{ + */ +#define L3GD20_CTRL_REG2_MASK 0x3F +#define L3GD20_CTRL_REG2_HPCF0 (1 << 0) +#define L3GD20_CTRL_REG2_HPCF1 (1 << 1) +#define L3GD20_CTRL_REG2_HPCF2 (1 << 2) +#define L3GD20_CTRL_REG2_HPCF3 (1 << 3) +#define L3GD20_CTRL_REG2_HPM0 (1 << 4) +#define L3GD20_CTRL_REG2_HPM1 (1 << 5) +/** @} */ + +/** + * @name L3GD20_CTRL_REG3 register bits definitions + * @{ + */ +#define L3GD20_CTRL_REG3_MASK 0xFF +#define L3GD20_CTRL_REG3_I2_EMPTY (1 << 0) +#define L3GD20_CTRL_REG3_I2_ORUN (1 << 1) +#define L3GD20_CTRL_REG3_I2_WTM (1 << 2) +#define L3GD20_CTRL_REG3_I2_DRDY (1 << 3) +#define L3GD20_CTRL_REG3_PP_OD (1 << 4) +#define L3GD20_CTRL_REG3_H_LACTIVE (1 << 5) +#define L3GD20_CTRL_REG3_I1_BOOT (1 << 6) +#define L3GD20_CTRL_REG3_I1_INT1 (1 << 7) +/** @} */ + +/** + * @name L3GD20_CTRL_REG4 register bits definitions + * @{ + */ +#define L3GD20_CTRL_REG4_MASK 0xF1 +#define L3GD20_CTRL_REG4_SIM (1 << 0) +#define L3GD20_CTRL_REG4_FS_MASK 0x30 +#define L3GD20_CTRL_REG4_FS0 (1 << 4) +#define L3GD20_CTRL_REG4_FS1 (1 << 5) +#define L3GD20_CTRL_REG4_BLE (1 << 6) +#define L3GD20_CTRL_REG4_BDU (1 << 7) +/** @} */ + +/** + * @name L3GD20_CTRL_REG5 register bits definitions + * @{ + */ +#define L3GD20_CTRL_REG5_MASK 0xDF +#define L3GD20_CTRL_REG5_OUT_SEL0 (1 << 0) +#define L3GD20_CTRL_REG5_OUT_SEL1 (1 << 1) +#define L3GD20_CTRL_REG5_INT1_SEL0 (1 << 2) +#define L3GD20_CTRL_REG5_INT1_SEL1 (1 << 3) +#define L3GD20_CTRL_REG5_HPEN (1 << 4) +#define L3GD20_CTRL_REG5_FIFO_EN (1 << 6) +#define L3GD20_CTRL_REG5_BOOT (1 << 7) +/** @} */ + +/** + * @name L3GD20_INT1_CFG register bits definitions + * @{ + */ +#define L3GD20_INT1_CFG_MASK 0xFF +#define L3GD20_INT1_CFG_XLIE (1 << 0) +#define L3GD20_INT1_CFG_XHIE (1 << 1) +#define L3GD20_INT1_CFG_YLIE (1 << 2) +#define L3GD20_INT1_CFG_YHIE (1 << 3) +#define L3GD20_INT1_CFG_ZLIE (1 << 4) +#define L3GD20_INT1_CFG_ZHIE (1 << 5) +#define L3GD20_INT1_CFG_LIR (1 << 6) +#define L3GD20_INT1_CFG_AND_OR (1 << 7) +/** @} */ + +/** + * @name L3GD20_INT1_SRC register bits definitions + * @{ + */ +#define L3GD20_INT1_SRC_MASK 0x7F +#define L3GD20_INT1_SRC_XL (1 << 0) +#define L3GD20_INT1_SRC_XH (1 << 1) +#define L3GD20_INT1_SRC_YL (1 << 2) +#define L3GD20_INT1_SRC_YH (1 << 3) +#define L3GD20_INT1_SRC_ZL (1 << 4) +#define L3GD20_INT1_SRC_ZH (1 << 5) +#define L3GD20_INT1_SRC_IA (1 << 6) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief L3GD20 SPI interface switch. + * @details If set to @p TRUE the support for SPI is included. + * @note The default is @p TRUE. + */ +#if !defined(L3GD20_USE_SPI) || defined(__DOXYGEN__) +#define L3GD20_USE_SPI TRUE +#endif + +/** + * @brief L3GD20 shared SPI switch. + * @details If set to @p TRUE the device acquires SPI bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION. + */ +#if !defined(L3GD20_SHARED_SPI) || defined(__DOXYGEN__) +#define L3GD20_SHARED_SPI FALSE +#endif + +/** + * @brief L3GD20 I2C interface switch. + * @details If set to @p TRUE the support for I2C is included. + * @note The default is @p FALSE. + */ +#if !defined(L3GD20_USE_I2C) || defined(__DOXYGEN__) +#define L3GD20_USE_I2C FALSE +#endif + +/** + * @brief L3GD20 shared I2C switch. + * @details If set to @p TRUE the device acquires I2C bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION. + */ +#if !defined(L3GD20_SHARED_I2C) || defined(__DOXYGEN__) +#define L3GD20_SHARED_I2C FALSE +#endif + +/** + * @brief L3GD20 advanced configurations switch. + * @details If set to @p TRUE more configurations are available. + * @note The default is @p FALSE. + */ +#if !defined(L3GD20_USE_ADVANCED) || defined(__DOXYGEN__) +#define L3GD20_USE_ADVANCED FALSE +#endif + +/** + * @brief Number of acquisitions for bias removal + * @details This is the number of acquisitions performed to compute the + * bias. A repetition is required in order to remove noise. + */ +#if !defined(L3GD20_BIAS_ACQ_TIMES) || defined(__DOXYGEN__) +#define L3GD20_BIAS_ACQ_TIMES 50 +#endif + +/** + * @brief Settling time for bias removal + * @details This is the time between each bias acquisition. + */ +#if !defined(L3GD20_BIAS_SETTLING_US) || defined(__DOXYGEN__) +#define L3GD20_BIAS_SETTLING_US 5000 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !(L3GD20_USE_SPI ^ L3GD20_USE_I2C) +#error "L3GD20_USE_SPI and L3GD20_USE_I2C cannot be both true or both false" +#endif + +#if L3GD20_USE_SPI && !HAL_USE_SPI +#error "L3GD20_USE_SPI requires HAL_USE_SPI" +#endif + +#if L3GD20_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION +#error "L3GD20_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" +#endif + +#if L3GD20_USE_I2C && !HAL_USE_I2C +#error "L3GD20_USE_I2C requires HAL_USE_I2C" +#endif + +#if L3GD20_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION +#error "L3GD20_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" +#endif + +/* + * CHTODO: Add support for L3GD20 over I2C. + */ +#if L3GD20_USE_I2C +#error "L3GD20 over I2C still not supported" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @name L3GD20 data structures and types. + * @{ + */ +/** + * @brief Structure representing a L3GD20 driver. + */ +typedef struct L3GD20Driver L3GD20Driver; + +/** + * @brief L3GD20 full scale. + */ +typedef enum { + L3GD20_FS_250DPS = 0x00, /**< Full scale 250 degree per second. */ + L3GD20_FS_500DPS = 0x10, /**< Full scale 500 degree per second. */ + L3GD20_FS_2000DPS = 0x20 /**< Full scale 2000 degree per second. */ +} l3gd20_fs_t; + +/** + * @brief L3GD20 output data rate and bandwidth. + */ +typedef enum { + L3GD20_ODR_95HZ = 0x00, /**< Output data rate 95 Hz. */ + L3GD20_ODR_190HZ = 0x40, /**< Output data rate 190 Hz. */ + L3GD20_ODR_380HZ = 0x80, /**< Output data rate 380 Hz. */ + L3GD20_ODR_760HZ = 0xC0 /**< Output data rate 760 Hz. */ +} l3gd20_odr_t; + +/** + * @brief L3GD20 low pass filter 1 bandwidth. + */ +typedef enum { + L3GD20_BW0 = 0x00, /**< LPF1 bandwidth. Depends on ODR. */ + L3GD20_BW1 = 0x40, /**< LPF1 bandwidth. Depends on ODR. */ + L3GD20_BW2 = 0x80, /**< LPF1 bandwidth. Depends on ODR. */ + L3GD20_BW3 = 0xC0 /**< LPF1 bandwidth. Depends on ODR. */ +} l3gd20_bw_t; + +/** + * @brief L3GD20 block data update. + */ +typedef enum { + L3GD20_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */ + L3GD20_BDU_BLOCKED = 0x80 /**< Block data updated after reading. */ +} l3gd20_bdu_t; + +/** + * @brief L3GD20 HP filter mode. + */ +typedef enum { + L3GD20_HPM_NORMAL = 0x00, /**< Normal mode. */ + L3GD20_HPM_REFERENCE = 0x10, /**< Reference signal for filtering. */ + L3GD20_HPM_AUTORESET = 0x30, /**< Autoreset on interrupt event. */ + L3GD20_HPM_BYPASSED = 0xFF /**< HP filter bypassed */ +} l3gd20_hpm_t; + +/** + * @brief L3GD20 HP configuration. + */ +typedef enum { + L3GD20_HPCF_0 = 0x00, /**< Depends on ODR (Table 26 for more).*/ + L3GD20_HPCF_1 = 0x01, /**< Depends on ODR (Table 26 for more).*/ + L3GD20_HPCF_2 = 0x02, /**< Depends on ODR (Table 26 for more).*/ + L3GD20_HPCF_3 = 0x03, /**< Depends on ODR (Table 26 for more).*/ + L3GD20_HPCF_4 = 0x04, /**< Depends on ODR (Table 26 for more).*/ + L3GD20_HPCF_5 = 0x05, /**< Depends on ODR (Table 26 for more).*/ + L3GD20_HPCF_6 = 0x06, /**< Depends on ODR (Table 26 for more).*/ + L3GD20_HPCF_7 = 0x07, /**< Depends on ODR (Table 26 for more).*/ + L3GD20_HPCF_8 = 0x08, /**< Depends on ODR (Table 26 for more).*/ + L3GD20_HPCF_9 = 0x09 /**< Depends on ODR (Table 26 for more).*/ +} l3gd20_hpcf_t; + +/** + * @brief L3GD20 LP2 filter mode. + * @details To activate LP2 HP should be active + */ +typedef enum { + L3GD20_LP2M_ON = 0x00, /**< LP2 filter activated. */ + L3GD20_LP2M_BYPASSED = 0xFF, /**< LP2 filter bypassed. */ +} l3gd20_lp2m_t; + +/** + * @brief L3GD20 endianness. + */ +typedef enum { + L3GD20_END_LITTLE = 0x00, /**< Little endian. */ + L3GD20_END_BIG = 0x40 /**< Big endian. */ +} l3gd20_end_t; + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + L3GD20_UNINIT = 0, /**< Not initialized. */ + L3GD20_STOP = 1, /**< Stopped. */ + L3GD20_READY = 2 /**< Ready. */ +} l3gd20_state_t; + +/** + * @brief L3GD20 configuration structure. + */ +typedef struct { + +#if L3GD20_USE_SPI || defined(__DOXYGEN__) + /** + * @brief SPI driver associated to this L3GD20. + */ + SPIDriver *spip; + /** + * @brief SPI configuration associated to this L3GD20. + */ + const SPIConfig *spicfg; +#endif /* L3GD20_USE_SPI */ +#if L3GD20_USE_I2C || defined(__DOXYGEN__) + /** + * @brief I2C driver associated to this L3GD20. + */ + I2CDriver *i2cp; + /** + * @brief I2C configuration associated to this L3GD20. + */ + const I2CConfig *i2ccfg; +#endif /* L3GD20_USE_I2C */ + /** + * @brief L3GD20 gyroscope system initial sensitivity. + */ + float *gyrosensitivity; + /** + * @brief L3GD20 gyroscope system initial bias. + */ + float *gyrobias; + /** + * @brief L3GD20 gyroscope system initial full scale value. + */ + l3gd20_fs_t gyrofullscale; + /** + * @brief L3GD20 gyroscope system output data rate selection. + */ + l3gd20_odr_t gyrooutputdatarate; +#if L3GD20_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief L3GD20 gyroscope system block data update. + */ + l3gd20_bdu_t gyroblockdataupdate; + /** + * @brief L3GD20 gyroscope system endianness. + */ + l3gd20_end_t gyroendianness; + /** + * @brief L3GD20 gyroscope system LP1 filter bandwidth. + */ + l3gd20_bw_t gyrobandwidth; + /** + * @brief L3GD20 gyroscope system HP filter mode. + */ + l3gd20_hpm_t gyrohpmode; + /** + * @brief L3GD20 gyroscope system HP configuration. + */ + l3gd20_hpcf_t gyrohpconfiguration; + /** + * @brief L3GD20 gyroscope system LP2 filter mode. + * @details To activate LP2 HP should be active + */ + l3gd20_lp2m_t gyrolp2mode; +#endif +} L3GD20Config; + +/** + * @brief @p L3GD20 specific methods. + */ +#define _l3gd20_methods_alone \ + /* Change full scale value of L3GD20.*/ \ + msg_t (*gyro_set_full_scale)(L3GD20Driver *devp, l3gd20_fs_t fs); + +/** + * @brief @p L3GD20 specific methods with inherited ones. + */ +#define _l3gd20_methods \ + _base_object_methods \ + _l3gd20_methods_alone + +/** + * @extends BaseObjectVMT + * + * @brief @p L3GD20 virtual methods table. + */ +struct L3GD20VMT { + _l3gd20_methods +}; + +/** + * @brief @p L3GD20Driver specific data. + */ +#define _l3gd20_data \ + _base_sensor_data \ + /* Driver state.*/ \ + l3gd20_state_t state; \ + /* Current configuration data.*/ \ + const L3GD20Config *config; \ + /* Gyroscope subsystem axes number.*/ \ + size_t gyroaxes; \ + /* Gyroscope subsystem current sensitivity.*/ \ + float gyrosensitivity[L3GD20_GYRO_NUMBER_OF_AXES]; \ + /* Gyroscope subsystem current Bias.*/ \ + float gyrobias[L3GD20_GYRO_NUMBER_OF_AXES]; \ + /* Gyroscope subsystem current full scale value.*/ \ + float gyrofullscale; + +/** + * @brief L3GD20 3-axis gyroscope class. + */ +struct L3GD20Driver { + /** @brief Virtual Methods Table. */ + const struct L3GD20VMT *vmt; + /** @brief Base gyroscope interface.*/ + BaseGyroscope gyro_if; + _l3gd20_data +}; +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Return the number of axes of the BaseGyroscope. + * + * @param[in] devp pointer to @p L3GD20Driver. + * + * @return the number of axes. + * + * @api + */ +#define l3gd20GyroscopeGetAxesNumber(devp) \ + gyroscopeGetAxesNumber(&((devp)->gyro_if)) + +/** + * @brief Retrieves raw data from the BaseGyroscope. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] devp pointer to @p L3GD20Driver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define l3gd20GyroscopeReadRaw(devp, axes) \ + gyroscopeReadRaw(&((devp)->gyro_if), axes) + +/** + * @brief Retrieves cooked data from the BaseGyroscope. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as DPS. + * @note The axes array must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] devp pointer to @p L3GD20Driver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define l3gd20GyroscopeReadCooked(devp, axes) \ + gyroscopeReadCooked(&((devp)->gyro_if), axes) + +/** + * @brief Samples bias values for the BaseGyroscope. + * @note The L3GD20 shall not be moved during the whole procedure. + * @note After this function internal bias is automatically updated. + * @note The behavior of this function depends on @p L3GD20_BIAS_ACQ_TIMES + * and @p L3GD20_BIAS_SETTLING_US. + * + * @param[in] devp pointer to @p L3GD20Driver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define l3gd20GyroscopeSampleBias(devp) \ + gyroscopeSampleBias(&((devp)->gyro_if)) + +/** + * @brief Set bias values for the BaseGyroscope. + * @note Bias must be expressed as DPS. + * @note The bias buffer must be at least the same size of the BaseGyroscope + * axes number. + * + * @param[in] devp pointer to @p L3GD20Driver. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define l3gd20GyroscopeSetBias(devp, bp) \ + gyroscopeSetBias(&((devp)->gyro_if), bp) + +/** + * @brief Reset bias values for the BaseGyroscope. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p L3GD20Driver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define l3gd20GyroscopeResetBias(devp) \ + gyroscopeResetBias(&((devp)->gyro_if)) + +/** + * @brief Set sensitivity values for the BaseGyroscope. + * @note Sensitivity must be expressed as DPS/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] devp pointer to @p L3GD20Driver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define l3gd20GyroscopeSetSensitivity(devp, sp) \ + gyroscopeSetSensitivity(&((devp)->gyro_if), sp) + +/** + * @brief Reset sensitivity values for the BaseGyroscope. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p L3GD20Driver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define l3gd20GyroscopeResetSensitivity(devp) \ + gyroscopeResetSensitivity(&((devp)->gyro_if)) + +/** + * @brief Changes the L3GD20Driver gyroscope fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p L3GD20Driver. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define l3gd20GyroscopeSetFullScale(devp, fs) \ + (devp)->vmt->acc_set_full_scale(devp, fs) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void l3gd20ObjectInit(L3GD20Driver *devp); + void l3gd20Start(L3GD20Driver *devp, const L3GD20Config *config); + void l3gd20Stop(L3GD20Driver *devp); +#ifdef __cplusplus +} +#endif + +#endif /* _L3GD20_H_ */ + +/** @} */ + diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.mk b/ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.mk new file mode 100644 index 0000000..94a4ec6 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.mk @@ -0,0 +1,10 @@ +# List of all the L3GD20 device files. +L3GD20SRC := $(CHIBIOS)/os/ex/devices/ST/l3gd20.c + +# Required include directories +L3GD20INC := $(CHIBIOS)/os/ex/include \ + $(CHIBIOS)/os/ex/devices/ST + +# Shared variables +ALLCSRC += $(L3GD20SRC) +ALLINC += $(L3GD20INC) \ No newline at end of file diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.c b/ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.c new file mode 100644 index 0000000..099698d --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.c @@ -0,0 +1,554 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lis302dl.c + * @brief LIS302DL MEMS interface module code. + * + * @addtogroup LIS302DL + * @ingroup EX_ST + * @{ + */ + +#include "hal.h" +#include "lis302dl.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if (LIS302DL_USE_SPI) || defined(__DOXYGEN__) +/** + * @brief Reads a generic register value using SPI. + * @pre The SPI interface must be initialized and the driver started. + * + * @param[in] spip pointer to the SPI interface + * @param[in] reg starting register address + * @param[in] n number of adjacent registers to write + * @param[in] b pointer to a buffer. + */ +static void lis302dlSPIReadRegister(SPIDriver *spip, uint8_t reg, size_t n, + uint8_t* b) { + uint8_t cmd; + (n == 1) ? (cmd = reg | LIS302DL_RW) : (cmd = reg | LIS302DL_RW | LIS302DL_MS); + spiSelect(spip); + spiSend(spip, 1, &cmd); + spiReceive(spip, n, b); + spiUnselect(spip); +} + +/** + * @brief Writes a value into a generic register using SPI. + * @pre The SPI interface must be initialized and the driver started. + * + * @param[in] spip pointer to the SPI interface + * @param[in] reg starting register address + * @param[in] n number of adjacent registers to write + * @param[in] b pointer to a buffer of values. + */ +static void lis302dlSPIWriteRegister(SPIDriver *spip, uint8_t reg, size_t n, + uint8_t* b) { + uint8_t cmd; + (n == 1) ? (cmd = reg) : (cmd = reg | LIS302DL_MS); + spiSelect(spip); + spiSend(spip, 1, &cmd); + spiSend(spip, n, b); + spiUnselect(spip); +} +#endif /* LIS302DL_USE_SPI */ + +/** + * @brief Return the number of axes of the BaseAccelerometer. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return the number of axes. + */ +static size_t acc_get_axes_number(void *ip) { + (void)ip; + + return LIS302DL_ACC_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseAccelerometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t acc_read_raw(void *ip, int32_t axes[]) { + LIS302DLDriver* devp; + uint8_t i, tmp; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS302DLDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LIS302DL_READY), + "acc_read_raw(), invalid state"); + +#if LIS302DL_USE_SPI +#if LIS302DL_SHARED_SPI + osalDbgAssert((devp->config->spip->state == SPI_READY), + "acc_read_raw(), channel not ready"); + + spiAcquireBus(devp->config->spip); + spiStart(devp->config->spip, + devp->config->spicfg); +#endif /* LIS302DL_SHARED_SPI */ + + for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) { + lis302dlSPIReadRegister(devp->config->spip, + LIS302DL_AD_OUT_X + (i * 2), 1, &tmp); + axes[i] = (int32_t)((int8_t)tmp); + } + +#if LIS302DL_SHARED_SPI + spiReleaseBus(devp->config->spip); +#endif /* LIS302DL_SHARED_SPI */ +#endif /* LIS302DL_USE_SPI */ + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseAccelerometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as milli-G. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t acc_read_cooked(void *ip, float axes[]) { + LIS302DLDriver* devp; + uint32_t i; + int32_t raw[LIS302DL_ACC_NUMBER_OF_AXES]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS302DLDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LIS302DL_READY), + "acc_read_cooked(), invalid state"); + + msg = acc_read_raw(ip, raw); + for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) { + axes[i] = (raw[i] * devp->accsensitivity[i]) - devp->accbias[i]; + } + return msg; +} + +/** + * @brief Set bias values for the BaseAccelerometer. + * @note Bias must be expressed as milli-G. + * @note The bias buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_set_bias(void *ip, float *bp) { + LIS302DLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS302DLDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LIS302DL_READY), + "acc_set_bias(), invalid state"); + + for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) { + devp->accbias[i] = bp[i]; + } + return msg; +} + +/** + * @brief Reset bias values for the BaseAccelerometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_reset_bias(void *ip) { + LIS302DLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS302DLDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LIS302DL_READY), + "acc_reset_bias(), invalid state"); + + for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = LIS302DL_ACC_BIAS; + return msg; +} + +/** + * @brief Set sensitivity values for the BaseAccelerometer. + * @note Sensitivity must be expressed as milli-G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_set_sensivity(void *ip, float *sp) { + LIS302DLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS302DLDriver*, (BaseAccelerometer*)ip); + + osalDbgCheck((ip != NULL) && (sp != NULL)); + + osalDbgAssert((devp->state == LIS302DL_READY), + "acc_set_sensivity(), invalid state"); + + for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] = sp[i]; + } + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseAccelerometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t acc_reset_sensivity(void *ip) { + LIS302DLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS302DLDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LIS302DL_READY), + "acc_reset_sensivity(), invalid state"); + + if(devp->config->accfullscale == LIS302DL_ACC_FS_2G) + for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LIS302DL_ACC_SENS_2G; + else if(devp->config->accfullscale == LIS302DL_ACC_FS_8G) + for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LIS302DL_ACC_SENS_8G; + else { + osalDbgAssert(FALSE, + "acc_reset_sensivity(), accelerometer full scale issue"); + return MSG_RESET; + } + return msg; +} + +/** + * @brief Changes the LIS302DLDriver accelerometer fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LIS302DLDriver interface. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t acc_set_full_scale(LIS302DLDriver *devp, lis302dl_acc_fs_t fs) { + float newfs, scale; + uint8_t i, cr; + msg_t msg; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LIS302DL_READY), + "acc_set_full_scale(), invalid state"); + osalDbgAssert((devp->config->spip->state == SPI_READY), + "acc_set_full_scale(), channel not ready"); + + /* Computing new fullscale value.*/ + if(fs == LIS302DL_ACC_FS_2G) { + newfs = LIS302DL_ACC_2G; + } + else if(fs == LIS302DL_ACC_FS_8G) { + newfs = LIS302DL_ACC_8G; + } + else { + msg = MSG_RESET; + return msg; + } + + if(newfs != devp->accfullscale) { + /* Computing scale value.*/ + scale = newfs / devp->accfullscale; + devp->accfullscale = newfs; + +#if LIS302DL_USE_SPI +#if LIS302DL_SHARED_SPI + spiAcquireBus(devp->config->spip); + spiStart(devp->config->spip, + devp->config->spicfg); +#endif /* LIS302DL_SHARED_SPI */ + + /* Getting data from register.*/ + lis302dlSPIReadRegister(devp->config->spip, LIS302DL_AD_CTRL_REG1, 1, &cr); + +#if LIS302DL_SHARED_SPI + spiReleaseBus(devp->config->spip); +#endif /* LIS302DL_SHARED_SPI */ +#endif /* LIS302DL_USE_SPI */ + + cr &= ~(LIS302DL_CTRL_REG1_FS_MASK); + cr |= fs; + +#if LIS302DL_USE_SPI +#if LIS302DL_SHARED_SPI + spiAcquireBus(devp->config->spip); + spiStart(devp->config->spip, + devp->config->spicfg); +#endif /* LIS302DL_SHARED_SPI */ + + /* Getting data from register.*/ + lis302dlSPIWriteRegister(devp->config->spip, LIS302DL_AD_CTRL_REG1, 1, &cr); + +#if LIS302DL_SHARED_SPI + spiReleaseBus(devp->config->spip); +#endif /* LIS302DL_SHARED_SPI */ +#endif /* LIS302DL_USE_SPI */ + + /* Scaling sensitivity and bias. Re-calibration is suggested anyway. */ + for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] *= scale; + devp->accbias[i] *= scale; + } + } + return msg; +} + +static const struct LIS302DLVMT vmt_device = { + (size_t)0, + acc_set_full_scale +}; + +static const struct BaseAccelerometerVMT vmt_accelerometer = { + sizeof(struct LIS302DLVMT*), + acc_get_axes_number, acc_read_raw, acc_read_cooked, + acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity +}; + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes an instance. + * + * @param[out] devp pointer to the @p LIS302DLDriver object + * + * @init + */ +void lis302dlObjectInit(LIS302DLDriver *devp) { + devp->vmt = &vmt_device; + devp->acc_if.vmt = &vmt_accelerometer; + + devp->config = NULL; + + devp->accaxes = LIS302DL_ACC_NUMBER_OF_AXES; + + devp->state = LIS302DL_STOP; +} + +/** + * @brief Configures and activates LIS302DL Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LIS302DLDriver object + * @param[in] config pointer to the @p LIS302DLConfig object + * + * @api + */ +void lis302dlStart(LIS302DLDriver *devp, const LIS302DLConfig *config) { + uint32_t i; + uint8_t cr[2] = {0, 0}; + osalDbgCheck((devp != NULL) && (config != NULL)); + + osalDbgAssert((devp->state == LIS302DL_STOP) || (devp->state == LIS302DL_READY), + "lis302dlStart(), invalid state"); + + devp->config = config; + + /* Control register 1 configuration block.*/ + { + cr[0] = LIS302DL_CTRL_REG1_XEN | LIS302DL_CTRL_REG1_YEN | + LIS302DL_CTRL_REG1_ZEN | LIS302DL_CTRL_REG1_PD | + devp->config->accoutputdatarate | + devp->config->accfullscale; + } + + /* Control register 2 configuration block.*/ + { +#if LIS302DL_USE_ADVANCED || defined(__DOXYGEN__) + if(devp->config->hpmode != LIS302DL_HPM_BYPASSED) + cr[1] = devp->config->acchighpass; +#endif + } + +#if LIS302DL_USE_SPI +#if LIS302DL_SHARED_SPI + spiAcquireBus((devp)->config->spip); +#endif /* LIS302DL_SHARED_SPI */ + spiStart((devp)->config->spip, (devp)->config->spicfg); + + lis302dlSPIWriteRegister(devp->config->spip, LIS302DL_AD_CTRL_REG1, + 2, cr); + +#if LIS302DL_SHARED_SPI + spiReleaseBus((devp)->config->spip); +#endif /* LIS302DL_SHARED_SPI */ +#endif /* LIS302DL_USE_SPI */ + + /* Storing sensitivity information according to full scale value */ + if(devp->config->accfullscale == LIS302DL_ACC_FS_2G) { + devp->accfullscale = LIS302DL_ACC_2G; + if(devp->config->accsensitivity == NULL) + for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LIS302DL_ACC_SENS_2G; + else + for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + else if(devp->config->accfullscale == LIS302DL_ACC_FS_8G) { + devp->accfullscale = LIS302DL_ACC_8G; + if(devp->config->accsensitivity == NULL) + for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LIS302DL_ACC_SENS_8G; + else + for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + else { + osalDbgAssert(FALSE, "lis302dlStart(), accelerometer full scale issue"); + } + + /* Storing bias information according to user setting */ + if(devp->config->accbias != NULL) + for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = devp->config->accbias[i]; + else + for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = LIS302DL_ACC_BIAS; + + /* This is the Accelerometer transient recovery time */ + osalThreadSleepMilliseconds(10); + + devp->state = LIS302DL_READY; +} + +/** + * @brief Deactivates the LIS302DL Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LIS302DLDriver object + * + * @api + */ +void lis302dlStop(LIS302DLDriver *devp) { + uint8_t cr1; + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LIS302DL_STOP) || + (devp->state == LIS302DL_READY), + "lis302dlStop(), invalid state"); + + if (devp->state == LIS302DL_READY) { +#if LIS302DL_USE_SPI +#if LIS302DL_SHARED_SPI + spiAcquireBus((devp)->config->spip); + spiStart((devp)->config->spip, + (devp)->config->spicfg); +#endif /* LIS302DL_SHARED_SPI */ + /* Disabling all axes and enabling power down mode.*/ + cr1 = 0; + lis302dlSPIWriteRegister(devp->config->spip, LIS302DL_AD_CTRL_REG1, 1, &cr1); + spiStop((devp)->config->spip); +#if LIS302DL_SHARED_SPI + spiReleaseBus((devp)->config->spip); +#endif /* LIS302DL_SHARED_SPI */ +#endif /* LIS302DL_USE_SPI */ + } + devp->state = LIS302DL_STOP; +} +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.h b/ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.h new file mode 100644 index 0000000..3c662f4 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.h @@ -0,0 +1,566 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lis302dl.h + * @brief LIS302DL MEMS interface module header. + * + * @addtogroup LIS302DL + * @ingroup EX_ST + * @{ + */ + +#ifndef _LIS302DL_H_ +#define _LIS302DL_H_ + +#include "ex_accelerometer.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Version identification + * @{ + */ +/** + * @brief LIS302DL driver version string. + */ +#define EX_LIS302DL_VERSION "1.1.1" + +/** + * @brief LIS302DL driver version major number. + */ +#define EX_LIS302DL_MAJOR 1 + +/** + * @brief LIS302DL driver version minor number. + */ +#define EX_LIS302DL_MINOR 1 + +/** + * @brief LIS302DL driver version patch number. + */ +#define EX_LIS302DL_PATCH 1 +/** @} */ + +/** + * @brief LIS302DL accelerometer subsystem characteristics. + * @note Sensitivity is expressed as milli-G/LSB whereas + * 1 milli-G = 0.00980665 m/s^2. + * @note Bias is expressed as milli-G. + * + * @{ + */ +#define LIS302DL_ACC_NUMBER_OF_AXES 3U + +#define LIS302DL_ACC_2G 2.0f +#define LIS302DL_ACC_8G 8.0f + +#define LIS302DL_ACC_SENS_2G 18.0f +#define LIS302DL_ACC_SENS_8G 72.0f + +#define LIS302DL_ACC_BIAS 0.0f +/** @} */ + +/** + * @name LIS302DL communication interfaces related bit masks + * @{ + */ +#define LIS302DL_DI_MASK 0xFF +#define LIS302DL_DI(n) (1 << n) +#define LIS302DL_AD_MASK 0x3F +#define LIS302DL_AD(n) (1 << n) +#define LIS302DL_MS (1 << 6) +#define LIS302DL_RW (1 << 7) +/** @} */ + +/** + * @name LIS302DL register addresses + * @{ + */ +#define LIS302DL_AD_WHO_AM_I 0x0F +#define LIS302DL_AD_CTRL_REG1 0x20 +#define LIS302DL_AD_CTRL_REG2 0x21 +#define LIS302DL_AD_CTRL_REG3 0x22 +#define LIS302DL_AD_HP_FILER_RESET 0x23 +#define LIS302DL_AD_STATUS_REG 0x27 +#define LIS302DL_AD_OUT_X 0x29 +#define LIS302DL_AD_OUT_Y 0x2B +#define LIS302DL_AD_OUT_Z 0x2D +#define LIS302DL_AD_FF_WU_CFG_1 0x30 +#define LIS302DL_AD_FF_WU_SRC_1 0x31 +#define LIS302DL_AD_FF_WU_THS_1 0x32 +#define LIS302DL_AD_FF_WU_DURATION_1 0x33 +#define LIS302DL_AD_FF_WU_CFG_2 0x34 +#define LIS302DL_AD_FF_WU_SRC_2 0x35 +#define LIS302DL_AD_FF_WU_THS_2 0x36 +#define LIS302DL_AD_FF_WU_DURATION_2 0x37 +#define LIS302DL_AD_CLICK_CFG 0x38 +#define LIS302DL_AD_CLICK_SRC 0x39 +#define LIS302DL_AD_CLICK_THSY_X 0x3B +#define LIS302DL_AD_CLICK_THSZ 0x3C +#define LIS302DL_AD_CLICK_TIME_LIMIT 0x3D +#define LIS302DL_AD_CLICK_LATENCY 0x3E +#define LIS302DL_AD_CLICK_WINDOW 0x3F +/** @} */ + +/** + * @name LIS302DL_CTRL_REG1 register bits definitions + * @{ + */ +#define LIS302DL_CTRL_REG1_MASK 0xFF +#define LIS302DL_CTRL_REG1_XEN (1 << 0) +#define LIS302DL_CTRL_REG1_YEN (1 << 1) +#define LIS302DL_CTRL_REG1_ZEN (1 << 2) +#define LIS302DL_CTRL_REG1_STM (1 << 3) +#define LIS302DL_CTRL_REG1_STP (1 << 4) +#define LIS302DL_CTRL_REG1_FS_MASK 0x20 +#define LIS302DL_CTRL_REG1_FS (1 << 5) +#define LIS302DL_CTRL_REG1_PD (1 << 6) +#define LIS302DL_CTRL_REG1_DR (1 << 7) +/** @} */ + +/** + * @name LIS302DL_CTRL_REG2 register bits definitions + * @{ + */ +#define LIS302DL_CTRL_REG2_MASK 0xDF +#define LIS302DL_CTRL_REG2_HPCF1 (1 << 0) +#define LIS302DL_CTRL_REG2_HPCF2 (1 << 1) +#define LIS302DL_CTRL_REG2_HPFFWU1 (1 << 2) +#define LIS302DL_CTRL_REG2_HPFFWU2 (1 << 3) +#define LIS302DL_CTRL_REG2_FDS (1 << 4) +#define LIS302DL_CTRL_REG2_BOOT (1 << 6) +#define LIS302DL_CTRL_REG2_SIM (1 << 7) +/** @} */ + +/** + * @name LIS302DL_CTRL_REG3 register bits definitions + * @{ + */ +#define LIS302DL_CTRL_REG3_MASK 0xFF +#define LIS302DL_CTRL_REG3_I1CFG0 (1 << 0) +#define LIS302DL_CTRL_REG3_I1CFG1 (1 << 1) +#define LIS302DL_CTRL_REG3_I1CFG2 (1 << 2) +#define LIS302DL_CTRL_REG3_I2CFG0 (1 << 3) +#define LIS302DL_CTRL_REG3_I2CFG1 (1 << 4) +#define LIS302DL_CTRL_REG3_I2CFG2 (1 << 5) +#define LIS302DL_CTRL_REG3_PP_OD (1 << 6) +#define LIS302DL_CTRL_REG3_IHL (1 << 7) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief LIS302DL SPI interface switch. + * @details If set to @p TRUE the support for SPI is included. + * @note The default is @p TRUE. + */ +#if !defined(LIS302DL_USE_SPI) || defined(__DOXYGEN__) +#define LIS302DL_USE_SPI TRUE +#endif + +/** + * @brief LIS302DL shared SPI switch. + * @details If set to @p TRUE the device acquires SPI bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LIS302DL_SHARED_SPI) || defined(__DOXYGEN__) +#define LIS302DL_SHARED_SPI FALSE +#endif + +/** + * @brief LIS302DL I2C interface switch. + * @details If set to @p TRUE the support for I2C is included. + * @note The default is @p FALSE. + */ +#if !defined(LIS302DL_USE_I2C) || defined(__DOXYGEN__) +#define LIS302DL_USE_I2C FALSE +#endif + +/** + * @brief LIS302DL shared I2C switch. + * @details If set to @p TRUE the device acquires I2C bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LIS302DL_SHARED_I2C) || defined(__DOXYGEN__) +#define LIS302DL_SHARED_I2C FALSE +#endif + +/** + * @brief LIS302DL advanced configurations switch. + * @details If set to @p TRUE more configurations are available. + * @note The default is @p FALSE. + */ +#if !defined(LIS302DL_USE_ADVANCED) || defined(__DOXYGEN__) +#define LIS302DL_USE_ADVANCED FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !(LIS302DL_USE_SPI ^ LIS302DL_USE_I2C) +#error "LIS302DL_USE_SPI and LIS302DL_USE_I2C cannot be both true or both false" +#endif + +#if LIS302DL_USE_SPI && !HAL_USE_SPI +#error "LIS302DL_USE_SPI requires HAL_USE_SPI" +#endif + +#if LIS302DL_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION +#error "LIS302DL_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" +#endif + +#if LIS302DL_USE_I2C && !HAL_USE_I2C +#error "LIS302DL_USE_I2C requires HAL_USE_I2C" +#endif + +#if LIS302DL_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION +#error "LIS302DL_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" +#endif + +/* + * CHTODO: Add support for LIS302DL over I2C. + */ +#if LIS302DL_USE_I2C +#error "LIS302DL over I2C still not supported" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @name LIS302DL data structures and types + * @{ + */ +/** + * @brief Structure representing a LIS302DL driver. + */ +typedef struct LIS302DLDriver LIS302DLDriver; + +/** + * @brief LIS302DL full scale. + */ +typedef enum { + LIS302DL_ACC_FS_2G = 0x00, /**< Full scale �2g. */ + LIS302DL_ACC_FS_8G = 0x20 /**< Full scale �8g. */ +}lis302dl_acc_fs_t; + +/** + * @brief LIS302DL output data rate and bandwidth. + */ +typedef enum { + LIS302DL_ACC_ODR_100HZ = 0x00, /**< ODR 100 Hz. */ + LIS302DL_ACC_ODR_400HZ = 0x80 /**< ODR 400 Hz. */ +}lis302dl_acc_odr_t; + +/** + * @brief LIS302DL high pass filtering. + */ +typedef enum { + LIS302DL_ACC_HP_DISABLED = 0x00, /**< HP bypassed. */ + LIS302DL_ACC_HP_0 = 0x10, /**< HP cutoff 2Hz (ODR 100Hz) or 8Hz */ + LIS302DL_ACC_HP_1 = 0x11, /**< HP cutoff 1Hz or 4Hz */ + LIS302DL_ACC_HP_2 = 0x12, /**< HP cutoff 0.5Hz or 2Hz */ + LIS302DL_ACC_HP_3 = 0x13 /**< HP cutoff 0.25Hz or 1Hz */ +}lis302dl_acc_hp_t; + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + LIS302DL_UNINIT = 0, /**< Not initialized. */ + LIS302DL_STOP = 1, /**< Stopped. */ + LIS302DL_READY = 2, /**< Ready. */ +} lis302dl_state_t; + +/** + * @brief LIS302DL configuration structure. + */ +typedef struct { + +#if (LIS302DL_USE_SPI) || defined(__DOXYGEN__) + /** + * @brief SPI driver associated to this LIS302DL. + */ + SPIDriver *spip; + /** + * @brief SPI configuration associated to this LIS302DL. + */ + const SPIConfig *spicfg; +#endif /* LIS302DL_USE_SPI */ +#if (LIS302DL_USE_I2C) || defined(__DOXYGEN__) + /** + * @brief I2C driver associated to this LIS302DL. + */ + I2CDriver *i2cp; + /** + * @brief I2C configuration associated to this LIS302DL. + */ + const I2CConfig *i2ccfg; +#endif /* LIS302DL_USE_I2C */ + /** + * @brief LIS302DL accelerometer subsystem initial sensitivity. + */ + float *accsensitivity; + /** + * @brief LIS302DL accelerometer subsystem initial bias. + */ + float *accbias; + /** + * @brief LIS302DL accelerometer subsystem initial full scale. + */ + lis302dl_acc_fs_t accfullscale; + /** + * @brief LIS302DL output data rate selection. + */ + lis302dl_acc_odr_t accoutputdatarate; +#if LIS302DL_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief LIS302DL high pass filtering. + */ + lis302dl_acc_hp_t acchighpass; +#endif +} LIS302DLConfig; + +/** + * @brief @p LIS302DL specific methods. + */ +#define _lis302dl_methods_alone \ + /* Change full scale value of LIS302DL .*/ \ + msg_t (*set_full_scale)(LIS302DLDriver *devp, lis302dl_acc_fs_t fs); + + +/** + * @brief @p LIS302DL specific methods with inherited ones. + */ +#define _lis302dl_methods \ + _base_object_methods \ + _lis302dl_methods_alone + +/** + * @extends BaseObjectVMT + * + * @brief @p LIS302DL accelerometer virtual methods table. + */ +struct LIS302DLVMT { + _lis302dl_methods +}; + +/** + * @brief @p LIS302DLDriver specific data. + */ +#define _lis302dl_data \ + /* Driver state.*/ \ + lis302dl_state_t state; \ + /* Current configuration data.*/ \ + const LIS302DLConfig *config; \ + /* Accelerometer subsystem axes number.*/ \ + size_t accaxes; \ + /* Current sensitivity.*/ \ + float accsensitivity[LIS302DL_ACC_NUMBER_OF_AXES]; \ + /* Bias data.*/ \ + int32_t accbias[LIS302DL_ACC_NUMBER_OF_AXES]; \ + /* Current full scale value.*/ \ + float accfullscale; + +/** + * @brief LIS302DL 3-axis accelerometer class. + */ +struct LIS302DLDriver { + /** @brief Virtual Methods Table.*/ + const struct LIS302DLVMT *vmt; + /** @brief Base accelerometer interface.*/ + BaseAccelerometer acc_if; + _lis302dl_data +}; +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Return the number of axes of the BaseAccelerometer. + * + * @param[in] devp pointer to @p LIS302DLDriver. + * + * @return the number of axes. + * + * @api + */ +#define lis302dlAccelerometerGetAxesNumber(devp) \ + accelerometerGetAxesNumber(&((devp)->acc_if)) + +/** + * @brief Retrieves raw data from the BaseAccelerometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LIS302DLDriver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lis302dlAccelerometerReadRaw(devp, axes) \ + accelerometerReadRaw(&((devp)->acc_if), axes) + +/** + * @brief Retrieves cooked data from the BaseAccelerometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as milli-G. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LIS302DLDriver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lis302dlAccelerometerReadCooked(devp, axes) \ + accelerometerReadCooked(&((devp)->acc_if), axes) + +/** + * @brief Set bias values for the BaseAccelerometer. + * @note Bias must be expressed as milli-G. + * @note The bias buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LIS302DLDriver. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lis302dlAccelerometerSetBias(devp, bp) \ + accelerometerSetBias(&((devp)->acc_if), bp) + +/** + * @brief Reset bias values for the BaseAccelerometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p LIS302DLDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lis302dlAccelerometerResetBias(devp) \ + accelerometerResetBias(&((devp)->acc_if)) + +/** + * @brief Set sensitivity values for the BaseAccelerometer. + * @note Sensitivity must be expressed as milli-G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LIS302DLDriver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lis302dlAccelerometerSetSensitivity(devp, sp) \ + accelerometerSetSensitivity(&((devp)->acc_if), sp) + +/** + * @brief Reset sensitivity values for the BaseAccelerometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p LIS302DLDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lis302dlAccelerometerResetSensitivity(devp) \ + accelerometerResetSensitivity(&((devp)->acc_if)) + +/** + * @brief Changes the LIS302DLDriver accelerometer fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LIS302DLDriver. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lis302dlAccelerometerSetFullScale(devp, fs) \ + (devp)->vmt->acc_set_full_scale(devp, fs) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void lis302dlObjectInit(LIS302DLDriver *devp); + void lis302dlStart(LIS302DLDriver *devp, const LIS302DLConfig *config); + void lis302dlStop(LIS302DLDriver *devp); +#ifdef __cplusplus +} +#endif + +#endif /* _LIS302DL_H_ */ + +/** @} */ + diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.mk b/ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.mk new file mode 100644 index 0000000..b7850ba --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.mk @@ -0,0 +1,10 @@ +# List of all the LIS302DL device files. +LIS302DLSRC := $(CHIBIOS)/os/ex/devices/ST/lis302dl.c + +# Required include directories +LIS302DLINC := $(CHIBIOS)/os/ex/include \ + $(CHIBIOS)/os/ex/devices/ST + +# Shared variables +ALLCSRC += $(LIS302DLSRC) +ALLINC += $(LIS302DLINC) \ No newline at end of file diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.c b/ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.c new file mode 100644 index 0000000..865ff79 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.c @@ -0,0 +1,641 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lis3dsh.c + * @brief LIS3DSH MEMS interface module code. + * + * @addtogroup LIS3DSH + * @ingroup EX_ST + * @{ + */ + +#include "hal.h" +#include "lis3dsh.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if (LIS3DSH_USE_SPI) || defined(__DOXYGEN__) +/** + * @brief Reads a generic register value using SPI. + * @pre The SPI interface must be initialized and the driver started. + * @note Multiple write/read requires proper settings in CTRL_REG6. + * + * @param[in] spip pointer to the SPI interface + * @param[in] reg starting register address + * @param[in] n number of adjacent registers to write + * @param[in] b pointer to a buffer. + */ +static void lis3dshSPIReadRegister(SPIDriver *spip, uint8_t reg, size_t n, + uint8_t* b) { + uint8_t cmd; + cmd = reg | LIS3DSH_RW; + spiSelect(spip); + spiSend(spip, 1, &cmd); + spiReceive(spip, n, b); + spiUnselect(spip); +} + +/** + * @brief Writes a value into a generic register using SPI. + * @pre The SPI interface must be initialized and the driver started. + * @note Multiple write/read requires proper settings in CTRL_REG6. + * + * @param[in] spip pointer to the SPI interface + * @param[in] reg starting register address + * @param[in] n number of adjacent registers to write + * @param[in] b pointer to a buffer of values. + */ +static void lis3dshSPIWriteRegister(SPIDriver *spip, uint8_t reg, size_t n, + uint8_t* b) { + uint8_t cmd; + cmd = reg; + spiSelect(spip); + spiSend(spip, 1, &cmd); + spiSend(spip, n, b); + spiUnselect(spip); +} +#endif /* LIS3DSH_USE_SPI */ + +/** + * @brief Return the number of axes of the BaseAccelerometer. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return the number of axes. + */ +static size_t acc_get_axes_number(void *ip) { + (void)ip; + + return LIS3DSH_ACC_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseAccelerometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t acc_read_raw(void *ip, int32_t axes[]) { + LIS3DSHDriver* devp; + uint8_t buff [LIS3DSH_ACC_NUMBER_OF_AXES * 2], i; + int16_t tmp; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS3DSHDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LIS3DSH_READY), + "acc_read_raw(), invalid state"); + +#if LIS3DSH_USE_SPI +#if LIS3DSH_SHARED_SPI + osalDbgAssert((devp->config->spip->state == SPI_READY), + "acc_read_raw(), channel not ready"); + + spiAcquireBus(devp->config->spip); + spiStart(devp->config->spip, + devp->config->spicfg); +#endif /* LIS3DSH_SHARED_SPI */ + + lis3dshSPIReadRegister(devp->config->spip, LIS3DSH_AD_OUT_X_L, + LIS3DSH_ACC_NUMBER_OF_AXES * 2, buff); + +#if LIS3DSH_SHARED_SPI + spiReleaseBus(devp->config->spip); +#endif /* LIS3DSH_SHARED_SPI */ +#endif /* LIS3DSH_USE_SPI */ + + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) { + tmp = buff[2 * i] + (buff[2 * i + 1] << 8); + axes[i] = (int32_t)tmp; + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseAccelerometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as milli-G. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t acc_read_cooked(void *ip, float axes[]) { + LIS3DSHDriver* devp; + uint32_t i; + int32_t raw[LIS3DSH_ACC_NUMBER_OF_AXES]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS3DSHDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LIS3DSH_READY), + "acc_read_cooked(), invalid state"); + + msg = acc_read_raw(ip, raw); + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) { + axes[i] = (raw[i] * devp->accsensitivity[i]) - devp->accbias[i]; + } + return msg; +} + +/** + * @brief Set bias values for the BaseAccelerometer. + * @note Bias must be expressed as milli-G. + * @note The bias buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_set_bias(void *ip, float *bp) { + LIS3DSHDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS3DSHDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LIS3DSH_READY), + "acc_set_bias(), invalid state"); + + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) { + devp->accbias[i] = bp[i]; + } + return msg; +} + +/** + * @brief Reset bias values for the BaseAccelerometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_reset_bias(void *ip) { + LIS3DSHDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS3DSHDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LIS3DSH_READY), + "acc_reset_bias(), invalid state"); + + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = LIS3DSH_ACC_BIAS; + return msg; +} + +/** + * @brief Set sensitivity values for the BaseAccelerometer. + * @note Sensitivity must be expressed as milli-G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_set_sensivity(void *ip, float *sp) { + LIS3DSHDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS3DSHDriver*, (BaseAccelerometer*)ip); + + osalDbgCheck((ip != NULL) && (sp != NULL)); + + osalDbgAssert((devp->state == LIS3DSH_READY), + "acc_set_sensivity(), invalid state"); + + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] = sp[i]; + } + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseAccelerometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t acc_reset_sensivity(void *ip) { + LIS3DSHDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS3DSHDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LIS3DSH_READY), + "acc_reset_sensivity(), invalid state"); + + if(devp->config->accfullscale == LIS3DSH_ACC_FS_2G) + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LIS3DSH_ACC_SENS_2G; + else if(devp->config->accfullscale == LIS3DSH_ACC_FS_4G) + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LIS3DSH_ACC_SENS_4G; + else if(devp->config->accfullscale == LIS3DSH_ACC_FS_6G) + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LIS3DSH_ACC_SENS_6G; + else if(devp->config->accfullscale == LIS3DSH_ACC_FS_8G) + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LIS3DSH_ACC_SENS_8G; + else if(devp->config->accfullscale == LIS3DSH_ACC_FS_16G) + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LIS3DSH_ACC_SENS_16G; + else { + osalDbgAssert(FALSE, + "acc_reset_sensivity(), accelerometer full scale issue"); + return MSG_RESET; + } + return msg; +} + +/** + * @brief Changes the LIS3DSHDriver accelerometer fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LIS3DSHDriver interface. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t acc_set_full_scale(LIS3DSHDriver *devp, lis3dsh_acc_fs_t fs) { + float newfs, scale; + uint8_t i, cr; + msg_t msg; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LIS3DSH_READY), + "acc_set_full_scale(), invalid state"); + osalDbgAssert((devp->config->spip->state == SPI_READY), + "acc_set_full_scale(), channel not ready"); + + /* Computing new fullscale value.*/ + if(fs == LIS3DSH_ACC_FS_2G) { + newfs = LIS3DSH_ACC_2G; + } + else if(fs == LIS3DSH_ACC_FS_4G) { + newfs = LIS3DSH_ACC_4G; + } + else if(fs == LIS3DSH_ACC_FS_6G) { + newfs = LIS3DSH_ACC_6G; + } + else if(fs == LIS3DSH_ACC_FS_8G) { + newfs = LIS3DSH_ACC_8G; + } + else if(fs == LIS3DSH_ACC_FS_16G) { + newfs = LIS3DSH_ACC_16G; + } + else { + msg = MSG_RESET; + return msg; + } + + if(newfs != devp->accfullscale) { + /* Computing scale value.*/ + scale = newfs / devp->accfullscale; + devp->accfullscale = newfs; + +#if LIS3DSH_USE_SPI +#if LIS3DSH_SHARED_SPI + spiAcquireBus(devp->config->spip); + spiStart(devp->config->spip, + devp->config->spicfg); +#endif /* LIS3DSH_SHARED_SPI */ + + /* Getting data from register.*/ + lis3dshSPIReadRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG5, 1, &cr); + +#if LIS3DSH_SHARED_SPI + spiReleaseBus(devp->config->spip); +#endif /* LIS3DSH_SHARED_SPI */ +#endif /* LIS3DSH_USE_SPI */ + + cr &= ~(LIS3DSH_CTRL_REG5_FS_MASK); + cr |= fs; + +#if LIS3DSH_USE_SPI +#if LIS3DSH_SHARED_SPI + spiAcquireBus(devp->config->spip); + spiStart(devp->config->spip, + devp->config->spicfg); +#endif /* LIS3DSH_SHARED_SPI */ + + /* Getting data from register.*/ + lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG5, 1, &cr); + +#if LIS3DSH_SHARED_SPI + spiReleaseBus(devp->config->spip); +#endif /* LIS3DSH_SHARED_SPI */ +#endif /* LIS3DSH_USE_SPI */ + + /* Scaling sensitivity and bias. Re-calibration is suggested anyway. */ + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] *= scale; + devp->accbias[i] *= scale; + } + } + return msg; +} + +static const struct LIS3DSHVMT vmt_device = { + (size_t)0, + acc_set_full_scale +}; + +static const struct BaseAccelerometerVMT vmt_accelerometer = { + sizeof(struct LIS3DSHVMT*), + acc_get_axes_number, acc_read_raw, acc_read_cooked, + acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity +}; + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes an instance. + * + * @param[out] devp pointer to the @p LIS3DSHDriver object + * + * @init + */ +void lis3dshObjectInit(LIS3DSHDriver *devp) { + devp->vmt = &vmt_device; + devp->acc_if.vmt = &vmt_accelerometer; + + devp->config = NULL; + + devp->accaxes = LIS3DSH_ACC_NUMBER_OF_AXES; + + devp->state = LIS3DSH_STOP; +} + +/** + * @brief Configures and activates LIS3DSH Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LIS3DSHDriver object + * @param[in] config pointer to the @p LIS3DSHConfig object + * + * @api + */ +void lis3dshStart(LIS3DSHDriver *devp, const LIS3DSHConfig *config) { + uint32_t i; + uint8_t cr; + osalDbgCheck((devp != NULL) && (config != NULL)); + + osalDbgAssert((devp->state == LIS3DSH_STOP) || + (devp->state == LIS3DSH_READY), + "lis3dshStart(), invalid state"); + + devp->config = config; + + /* Control register 4 configuration block.*/ + { + cr = LIS3DSH_CTRL_REG4_XEN | LIS3DSH_CTRL_REG4_YEN | LIS3DSH_CTRL_REG4_ZEN | + devp->config->accoutputdatarate; +#if LIS3DSH_USE_ADVANCED || defined(__DOXYGEN__) + cr |= devp->config->accblockdataupdate; +#endif + } + +#if LIS3DSH_USE_SPI +#if LIS3DSH_SHARED_SPI + spiAcquireBus(devp->config->spip); +#endif /* LIS3DSH_SHARED_SPI */ + spiStart(devp->config->spip, devp->config->spicfg); + + lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG4, 1, &cr); + +#if LIS3DSH_SHARED_SPI + spiReleaseBus(devp->config->spip); +#endif /* LIS3DSH_SHARED_SPI */ +#endif /* LIS3DSH_USE_SPI */ + + /* Control register 5 configuration block.*/ + { + cr = devp->config->accfullscale; +#if LIS3DSH_USE_ADVANCED || defined(__DOXYGEN__) + cr |= devp->config->accantialiasing; +#endif + } + +#if LIS3DSH_USE_SPI +#if LIS3DSH_SHARED_SPI + spiAcquireBus(devp->config->spip); + spiStart(devp->config->spip, devp->config->spicfg); +#endif /* LIS3DSH_SHARED_SPI */ + + lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG5, 1, &cr); + +#if LIS3DSH_SHARED_SPI + spiReleaseBus(devp->config->spip); +#endif /* LIS3DSH_SHARED_SPI */ +#endif /* LIS3DSH_USE_SPI */ + + /* Control register 6 configuration block.*/ + { + cr = LIS3DSH_CTRL_REG6_ADD_INC; +#if LIS3DSH_USE_ADVANCED || defined(__DOXYGEN__) + cr |= devp->config->accblockdataupdate; +#endif + } + +#if LIS3DSH_USE_SPI +#if LIS3DSH_SHARED_SPI + spiAcquireBus(devp->config->spip); + spiStart(devp->config->spip, devp->config->spicfg); +#endif /* LIS3DSH_SHARED_SPI */ + + lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG6, 1, &cr); + +#if LIS3DSH_SHARED_SPI + spiReleaseBus(devp->config->spip); +#endif /* LIS3DSH_SHARED_SPI */ +#endif /* LIS3DSH_USE_SPI */ + + /* Storing sensitivity information according to user setting */ + if(devp->config->accfullscale == LIS3DSH_ACC_FS_2G) { + devp->accfullscale = LIS3DSH_ACC_2G; + if(devp->config->accsensitivity == NULL) + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LIS3DSH_ACC_SENS_2G; + else + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + else if(devp->config->accfullscale == LIS3DSH_ACC_FS_4G) { + devp->accfullscale = LIS3DSH_ACC_4G; + if(devp->config->accsensitivity == NULL) + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LIS3DSH_ACC_SENS_4G; + else + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + else if(devp->config->accfullscale == LIS3DSH_ACC_FS_6G) { + devp->accfullscale = LIS3DSH_ACC_6G; + if(devp->config->accsensitivity == NULL) + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LIS3DSH_ACC_SENS_6G; + else + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + else if(devp->config->accfullscale == LIS3DSH_ACC_FS_8G) { + devp->accfullscale = LIS3DSH_ACC_8G; + if(devp->config->accsensitivity == NULL) + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LIS3DSH_ACC_SENS_8G; + else + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + else if(devp->config->accfullscale == LIS3DSH_ACC_FS_16G) { + devp->accfullscale = LIS3DSH_ACC_16G; + if(devp->config->accsensitivity == NULL) + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LIS3DSH_ACC_SENS_16G; + else + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + else { + osalDbgAssert(FALSE, "lis3dshStart(), accelerometer full scale issue"); + } + + /* Storing bias information according to user setting */ + if(devp->config->accbias != NULL) + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = devp->config->accbias[i]; + else + for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = LIS3DSH_ACC_BIAS; + + /* This is the Accelerometer transient recovery time */ + osalThreadSleepMilliseconds(10); + + devp->state = LIS3DSH_READY; +} + +/** + * @brief Deactivates the LIS3DSH Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LIS3DSHDriver object + * + * @api + */ +void lis3dshStop(LIS3DSHDriver *devp) { + uint8_t cr4; + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LIS3DSH_STOP) || + (devp->state == LIS3DSH_READY), + "lis3dshStop(), invalid state"); + + if (devp->state == LIS3DSH_READY) { +#if (LIS3DSH_USE_SPI) +#if LIS3DSH_SHARED_SPI + spiAcquireBus(devp->config->spip); + spiStart(devp->config->spip, + devp->config->spicfg); +#endif /* LIS3DSH_SHARED_SPI */ + /* Disabling all axes and enabling power down mode.*/ + cr4 = 0; + lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG4, + 1, &cr4); + + spiStop(devp->config->spip); +#if LIS3DSH_SHARED_SPI + spiReleaseBus(devp->config->spip); +#endif /* LIS3DSH_SHARED_SPI */ +#endif /* LIS3DSH_USE_SPI */ + } + devp->state = LIS3DSH_STOP; +} +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.h b/ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.h new file mode 100644 index 0000000..062f7b2 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.h @@ -0,0 +1,708 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lis3dsh.h + * @brief LIS3DSH MEMS interface module header. + * + * @addtogroup LIS3DSH + * @ingroup EX_ST + * @{ + */ + +#ifndef _LIS3DSH_H_ +#define _LIS3DSH_H_ + +#include "ex_accelerometer.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Version identification + * @{ + */ +/** + * @brief LIS3DSH driver version string. + */ +#define EX_LIS3DSH_VERSION "1.1.2" + +/** + * @brief LIS3DSH driver version major number. + */ +#define EX_LIS3DSH_MAJOR 1 + +/** + * @brief LIS3DSH driver version minor number. + */ +#define EX_LIS3DSH_MINOR 1 + +/** + * @brief LIS3DSH driver version patch number. + */ +#define EX_LIS3DSH_PATCH 2 +/** @} */ + +/** + * @brief LIS3DSH accelerometer subsystem characteristics. + * @note Sensitivity is expressed as milli-G/LSB whereas + * 1 milli-G = 0.00980665 m/s^2. + * @note Bias is expressed as milli-G. + * + * @{ + */ +#define LIS3DSH_ACC_NUMBER_OF_AXES 3U + +#define LIS3DSH_ACC_2G 2.0f +#define LIS3DSH_ACC_4G 4.0f +#define LIS3DSH_ACC_6G 6.0f +#define LIS3DSH_ACC_8G 8.0f +#define LIS3DSH_ACC_16G 16.0f + +#define LIS3DSH_ACC_SENS_2G 0.06f +#define LIS3DSH_ACC_SENS_4G 0.12f +#define LIS3DSH_ACC_SENS_6G 0.18f +#define LIS3DSH_ACC_SENS_8G 0.24f +#define LIS3DSH_ACC_SENS_16G 0.73f + +#define LIS3DSH_ACC_BIAS 0.0f +/** @} */ + +/** + * @name LIS3DSH communication interfaces related bit masks + * @{ + */ +#define LIS3DSH_DI_MASK 0xFF +#define LIS3DSH_DI(n) (1 << n) +#define LIS3DSH_AD_MASK 0x3F +#define LIS3DSH_AD(n) (1 << n) +#define LIS3DSH_MS (1 << 6) +#define LIS3DSH_RW (1 << 7) +/** @} */ + +/** + * @name LIS3DSH register addresses + * @{ + */ +#define LIS3DSH_AD_OUT_T 0x0C +#define LIS3DSH_AD_INFO1 0x0D +#define LIS3DSH_AD_INFO2 0x0E +#define LIS3DSH_AD_WHO_AM_I 0x0F +#define LIS3DSH_AD_OFF_X 0x10 +#define LIS3DSH_AD_OFF_Y 0x11 +#define LIS3DSH_AD_OFF_Z 0x12 +#define LIS3DSH_AD_CS_X 0x13 +#define LIS3DSH_AD_CS_Y 0x14 +#define LIS3DSH_AD_CS_Z 0x15 +#define LIS3DSH_AD_LC_L 0x16 +#define LIS3DSH_AD_LC_H 0x17 +#define LIS3DSH_AD_STAT 0x18 +#define LIS3DSH_AD_PEAK1 0x19 +#define LIS3DSH_AD_PEAK2 0x1A +#define LIS3DSH_AD_VFC_1 0x1B +#define LIS3DSH_AD_VFC_2 0x1C +#define LIS3DSH_AD_VFC_3 0x1D +#define LIS3DSH_AD_VFC_4 0x1E +#define LIS3DSH_AD_THRS3 0x1F +#define LIS3DSH_AD_CTRL_REG4 0x20 +#define LIS3DSH_AD_CTRL_REG1 0x21 +#define LIS3DSH_AD_CTRL_REG2 0x22 +#define LIS3DSH_AD_CTRL_REG3 0x23 +#define LIS3DSH_AD_CTRL_REG5 0x24 +#define LIS3DSH_AD_CTRL_REG6 0x25 +#define LIS3DSH_AD_STATUS 0x27 +#define LIS3DSH_AD_OUT_X_L 0x28 +#define LIS3DSH_AD_OUT_X_H 0x29 +#define LIS3DSH_AD_OUT_Y_L 0x2A +#define LIS3DSH_AD_OUT_Y_H 0x2B +#define LIS3DSH_AD_OUT_Z_L 0x2C +#define LIS3DSH_AD_OUT_Z_H 0x2D +#define LIS3DSH_AD_FIFO_CTRL 0x2E +#define LIS3DSH_AD_FIFO_SRC 0x2F +#define LIS3DSH_AD_ST1_0 0x40 +#define LIS3DSH_AD_ST1_1 0x41 +#define LIS3DSH_AD_ST1_2 0x42 +#define LIS3DSH_AD_ST1_3 0x43 +#define LIS3DSH_AD_ST1_4 0x44 +#define LIS3DSH_AD_ST1_5 0x45 +#define LIS3DSH_AD_ST1_6 0x46 +#define LIS3DSH_AD_ST1_7 0x47 +#define LIS3DSH_AD_ST1_8 0x48 +#define LIS3DSH_AD_ST1_9 0x49 +#define LIS3DSH_AD_ST1_A 0x4A +#define LIS3DSH_AD_ST1_B 0x4B +#define LIS3DSH_AD_ST1_C 0x4C +#define LIS3DSH_AD_ST1_D 0x4D +#define LIS3DSH_AD_ST1_E 0x4E +#define LIS3DSH_AD_ST1_F 0x4F +#define LIS3DSH_AD_TIM4_1 0x50 +#define LIS3DSH_AD_TIM3_1 0x51 +#define LIS3DSH_AD_TIM2_1_L 0x52 +#define LIS3DSH_AD_TIM2_1_H 0x53 +#define LIS3DSH_AD_TIM1_1_L 0x54 +#define LIS3DSH_AD_TIM1_1_H 0x55 +#define LIS3DSH_AD_THRS2_1 0x56 +#define LIS3DSH_AD_THRS1_1 0x57 +#define LIS3DSH_AD_MASK1_B 0x59 +#define LIS3DSH_AD_MASK1_A 0x5A +#define LIS3DSH_AD_SETT1 0x5B +#define LIS3DSH_AD_PR1 0x5C +#define LIS3DSH_AD_TC1_L 0x5D +#define LIS3DSH_AD_TC1_H 0x5E +#define LIS3DSH_AD_OUTS1 0x5F +#define LIS3DSH_AD_ST2_0 0x60 +#define LIS3DSH_AD_ST2_1 0x61 +#define LIS3DSH_AD_ST2_2 0x62 +#define LIS3DSH_AD_ST2_3 0x63 +#define LIS3DSH_AD_ST2_4 0x64 +#define LIS3DSH_AD_ST2_5 0x65 +#define LIS3DSH_AD_ST2_6 0x66 +#define LIS3DSH_AD_ST2_7 0x67 +#define LIS3DSH_AD_ST2_8 0x68 +#define LIS3DSH_AD_ST2_9 0x69 +#define LIS3DSH_AD_ST2_A 0x6A +#define LIS3DSH_AD_ST2_B 0x6B +#define LIS3DSH_AD_ST2_C 0x6C +#define LIS3DSH_AD_ST2_D 0x6D +#define LIS3DSH_AD_ST2_E 0x6E +#define LIS3DSH_AD_ST2_F 0x6F +#define LIS3DSH_AD_TIM4_2 0x70 +#define LIS3DSH_AD_TIM3_2 0x71 +#define LIS3DSH_AD_TIM2_2_L 0x72 +#define LIS3DSH_AD_TIM2_2_H 0x73 +#define LIS3DSH_AD_TIM1_2_L 0x74 +#define LIS3DSH_AD_TIM1_2_H 0x75 +#define LIS3DSH_AD_THRS2_2 0x76 +#define LIS3DSH_AD_THRS1_2 0x77 +#define LIS3DSH_AD_DES2 0x78 +#define LIS3DSH_AD_MASK2_B 0x79 +#define LIS3DSH_AD_MASK2_A 0x7A +#define LIS3DSH_AD_SETT2 0x7B +#define LIS3DSH_AD_PR2 0x7C +#define LIS3DSH_AD_TC2_L 0x7D +#define LIS3DSH_AD_TC2_H 0x7E +#define LIS3DSH_AD_OUTS2 0x7F +/** @} */ + +/** + * @name LIS3DSH_CTRL_REG1 register bits definitions + * @{ + */ +#define LIS3DSH_CTRL_REG1_MASK 0xE9 +#define LIS3DSH_CTRL_REG1_SM1_EN (1 << 0) +#define LIS3DSH_CTRL_REG1_SM1_PIN (1 << 3) +#define LIS3DSH_CTRL_REG1_HYST0_1 (1 << 5) +#define LIS3DSH_CTRL_REG1_HYST1_1 (1 << 6) +#define LIS3DSH_CTRL_REG1_HYST2_1 (1 << 7) +/** @} */ + +/** + * @name LIS3DSH_CTRL_REG2 register bits definitions + * @{ + */ +#define LIS3DSH_CTRL_REG2_MASK 0xE9 +#define LIS3DSH_CTRL_REG2_SM2_EN (1 << 0) +#define LIS3DSH_CTRL_REG2_SM2_PIN (1 << 3) +#define LIS3DSH_CTRL_REG2_HYST0_2 (1 << 5) +#define LIS3DSH_CTRL_REG2_HYST1_2 (1 << 6) +#define LIS3DSH_CTRL_REG2_HYST2_2 (1 << 7) +/** @} */ + +/** + * @name LIS3DSH_CTRL_REG3 register bits definitions + * @{ + */ +#define LIS3DSH_CTRL_REG3_MASK 0xFF +#define LIS3DSH_CTRL_REG3_STRT (1 << 0) +#define LIS3DSH_CTRL_REG3_VFILT (1 << 2) +#define LIS3DSH_CTRL_REG3_INT1_EN (1 << 3) +#define LIS3DSH_CTRL_REG3_INT2_EN (1 << 4) +#define LIS3DSH_CTRL_REG3_IEL (1 << 5) +#define LIS3DSH_CTRL_REG3_IEA (1 << 6) +#define LIS3DSH_CTRL_REG3_DR_EN (1 << 7) +/** @} */ + +/** + * @name LIS3DSH_CTRL_REG4 register bits definitions + * @{ + */ +#define LIS3DSH_CTRL_REG4_MASK 0xFF +#define LIS3DSH_CTRL_REG4_XEN (1 << 0) +#define LIS3DSH_CTRL_REG4_YEN (1 << 1) +#define LIS3DSH_CTRL_REG4_ZEN (1 << 2) +#define LIS3DSH_CTRL_REG4_BDU (1 << 3) +#define LIS3DSH_CTRL_REG4_ODR_0 (1 << 4) +#define LIS3DSH_CTRL_REG4_ODR_1 (1 << 5) +#define LIS3DSH_CTRL_REG4_ODR_2 (1 << 6) +#define LIS3DSH_CTRL_REG4_ODR_3 (1 << 7) +/** @} */ + +/** + * @name LIS3DSH_CTRL_REG5 register bits definitions + * @{ + */ +#define LIS3DSH_CTRL_REG5_MASK 0xFF +#define LIS3DSH_CTRL_REG5_SIM (1 << 0) +#define LIS3DSH_CTRL_REG5_ST1 (1 << 1) +#define LIS3DSH_CTRL_REG5_ST2 (1 << 2) +#define LIS3DSH_CTRL_REG5_FS_MASK 0x38 +#define LIS3DSH_CTRL_REG5_FS0 (1 << 3) +#define LIS3DSH_CTRL_REG5_FS1 (1 << 4) +#define LIS3DSH_CTRL_REG5_FS2 (1 << 5) +#define LIS3DSH_CTRL_REG5_BW1 (1 << 6) +#define LIS3DSH_CTRL_REG5_BW2 (1 << 7) +/** @} */ + +/** + * @name LIS3DSH_CTRL_REG6 register bits definitions + * @{ + */ +#define LIS3DSH_CTRL_REG6_MASK 0xFF +#define LIS3DSH_CTRL_REG6_P2_BOOT (1 << 0) +#define LIS3DSH_CTRL_REG6_P1_OVRUN (1 << 1) +#define LIS3DSH_CTRL_REG6_P1_WTM (1 << 2) +#define LIS3DSH_CTRL_REG6_P1_EMPTY (1 << 3) +#define LIS3DSH_CTRL_REG6_ADD_INC (1 << 4) +#define LIS3DSH_CTRL_REG6_WTM_EN (1 << 5) +#define LIS3DSH_CTRL_REG6_FIFO_EN (1 << 6) +#define LIS3DSH_CTRL_REG6_BOOT (1 << 7) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief LIS3DSH SPI interface switch. + * @details If set to @p TRUE the support for SPI is included. + * @note The default is @p TRUE. + */ +#if !defined(LIS3DSH_USE_SPI) || defined(__DOXYGEN__) +#define LIS3DSH_USE_SPI TRUE +#endif + +/** + * @brief LIS3DSH shared SPI switch. + * @details If set to @p TRUE the device acquires SPI bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LIS3DSH_SHARED_SPI) || defined(__DOXYGEN__) +#define LIS3DSH_SHARED_SPI FALSE +#endif + +/** + * @brief LIS3DSH I2C interface switch. + * @details If set to @p TRUE the support for I2C is included. + * @note The default is @p FALSE. + */ +#if !defined(LIS3DSH_USE_I2C) || defined(__DOXYGEN__) +#define LIS3DSH_USE_I2C FALSE +#endif + +/** + * @brief LIS3DSH shared I2C switch. + * @details If set to @p TRUE the device acquires I2C bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LIS3DSH_SHARED_I2C) || defined(__DOXYGEN__) +#define LIS3DSH_SHARED_I2C FALSE +#endif + +/** + * @brief LIS3DSH advanced configurations switch. + * @details If set to @p TRUE more configurations are available. + * @note The default is @p FALSE. + */ +#if !defined(LIS3DSH_USE_ADVANCED) || defined(__DOXYGEN__) +#define LIS3DSH_USE_ADVANCED FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !(LIS3DSH_USE_SPI ^ LIS3DSH_USE_I2C) +#error "LIS3DSH_USE_SPI and LIS3DSH_USE_I2C cannot be both true or both false" +#endif + +#if LIS3DSH_USE_SPI && !HAL_USE_SPI +#error "LIS3DSH_USE_SPI requires HAL_USE_SPI" +#endif + +#if LIS3DSH_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION +#error "LIS3DSH_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" +#endif + +#if LIS3DSH_USE_I2C && !HAL_USE_I2C +#error "LIS3DSH_USE_I2C requires HAL_USE_I2C" +#endif + +#if LIS3DSH_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION +#error "LIS3DSH_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" +#endif + +/* + * CHTODO: Add support for LIS3DSH over I2C. + */ +#if LIS3DSH_USE_I2C +#error "LIS3DSH over I2C still not supported" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @name LIS3DSH data structures and types + * @{ + */ +/** + * @brief Structure representing a LIS3DSH driver. + */ +typedef struct LIS3DSHDriver LIS3DSHDriver; + +/** + * @brief LIS3DSH full scale. + */ +typedef enum { + LIS3DSH_ACC_FS_2G = 0x00, /**< Full scale �2g. */ + LIS3DSH_ACC_FS_4G = 0x08, /**< Full scale �4g. */ + LIS3DSH_ACC_FS_6G = 0x10, /**< Full scale �6g. */ + LIS3DSH_ACC_FS_8G = 0x18, /**< Full scale �8g. */ + LIS3DSH_ACC_FS_16G = 0x20 /**< Full scale �16g. */ +}lis3dsh_acc_fs_t; + +/** + * @brief LIS3DSH output data rate. + */ +typedef enum { + LIS3DSH_ACC_ODR_PD = 0x00, /**< ODR 100 Hz. */ + LIS3DSH_ACC_ODR_3_125HZ = 0x10, /**< ODR 3.125 Hz. */ + LIS3DSH_ACC_ODR_6_25HZ = 0x20, /**< ODR 6.25 Hz. */ + LIS3DSH_ACC_ODR_12_5HZ = 0x30, /**< ODR 12.5 Hz. */ + LIS3DSH_ACC_ODR_25HZ = 0x40, /**< ODR 25 Hz. */ + LIS3DSH_ACC_ODR_50HZ = 0x50, /**< ODR 50 Hz. */ + LIS3DSH_ACC_ODR_100HZ = 0x60, /**< ODR 100 Hz. */ + LIS3DSH_ACC_ODR_400HZ = 0x70, /**< ODR 400 Hz. */ + LIS3DSH_ACC_ODR_800HZ = 0x80, /**< ODR 800 Hz. */ + LIS3DSH_ACC_ODR_1600HZ = 0x90 /**< ODR 1600 Hz. */ +}lis3dsh_acc_odr_t; + +/** + * @brief LIS3DSH anti-aliasing bandwidth. + */ +typedef enum { + LIS3DSH_ACC_BW_800HZ = 0x00, /**< AA filter BW 800Hz. */ + LIS3DSH_ACC_BW_200HZ = 0x40, /**< AA filter BW 200Hz. */ + LIS3DSH_ACC_BW_400HZ = 0x80, /**< AA filter BW 400Hz. */ + LIS3DSH_ACC_BW_50HZ = 0xC0 /**< AA filter BW 50Hz. */ +}lis3dsh_acc_bw_t; + +/** + * @brief LIS3DSH block data update. + */ +typedef enum { + LIS3DSH_ACC_BDU_CONTINUOUS = 0x00,/**< Block data continuously updated. */ + LIS3DSH_ACC_BDU_BLOCKED = 0x80 /**< Block data updated after reading. */ +} lis3dsh_acc_bdu_t; + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + LIS3DSH_UNINIT = 0, /**< Not initialized. */ + LIS3DSH_STOP = 1, /**< Stopped. */ + LIS3DSH_READY = 2, /**< Ready. */ +} lis3dsh_state_t; + +/** + * @brief LIS3DSH configuration structure. + */ +typedef struct { + +#if (LIS3DSH_USE_SPI) || defined(__DOXYGEN__) + /** + * @brief SPI driver associated to this LIS3DSH. + */ + SPIDriver *spip; + /** + * @brief SPI configuration associated to this LIS3DSH. + */ + const SPIConfig *spicfg; +#endif /* LIS3DSH_USE_SPI */ +#if (LIS3DSH_USE_I2C) || defined(__DOXYGEN__) + /** + * @brief I2C driver associated to this LIS3DSH. + */ + I2CDriver *i2cp; + /** + * @brief I2C configuration associated to this LIS3DSH. + */ + const I2CConfig *i2ccfg; +#endif /* LIS3DSH_USE_I2C */ + /** + * @brief LIS3DSH accelerometer subsystem initial sensitivity. + */ + float *accsensitivity; + /** + * @brief LIS3DSH accelerometer subsystem initial bias. + */ + float *accbias; + /** + * @brief LIS3DSH accelerometer subsystem initial full scale. + */ + lis3dsh_acc_fs_t accfullscale; + /** + * @brief LIS3DSH output data rate selection. + */ + lis3dsh_acc_odr_t accoutputdatarate; +#if LIS3DSH_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief LIS3DSH anti-aliasing bandwidth. + */ + lis3dsh_acc_bw_t accantialiasing; + /** + * @brief LIS3DSH block data update. + */ + lis3dsh_acc_bdu_t accblockdataupdate; +#endif +} LIS3DSHConfig; + +/** + * @brief @p LIS3DSH specific methods. + */ +#define _lis3dsh_methods_alone \ + /* Change full scale value of LIS3DSH accelerometer subsystem.*/ \ + msg_t (*acc_set_full_scale)(LIS3DSHDriver *devp, lis3dsh_acc_fs_t fs); + + +/** + * @brief @p LIS3DSH specific methods with inherited ones. + */ +#define _lis3dsh_methods \ + _base_object_methods \ + _lis3dsh_methods_alone + +/** + * @extends BaseObjectVMT + * + * @brief @p LIS3DSH virtual methods table. + */ +struct LIS3DSHVMT { + _lis3dsh_methods +}; + +/** + * @brief @p LIS3DSHDriver specific data. + */ +#define _lis3dsh_data \ + _base_sensor_data \ + /* Driver state.*/ \ + lis3dsh_state_t state; \ + /* Current configuration data.*/ \ + const LIS3DSHConfig *config; \ + /* Accelerometer subsystem axes number.*/ \ + size_t accaxes; \ + /* Accelerometer subsystem current sensitivity.*/ \ + float accsensitivity[LIS3DSH_ACC_NUMBER_OF_AXES]; \ + /* Accelerometer subsystem current bias .*/ \ + float accbias[LIS3DSH_ACC_NUMBER_OF_AXES]; \ + /* Accelerometer subsystem current full scale value.*/ \ + float accfullscale; + +/** + * @brief LIS3DSH 3-axis accelerometer class. + */ +struct LIS3DSHDriver { + /** @brief Virtual Methods Table.*/ + const struct LIS3DSHVMT *vmt; + /** @brief Base accelerometer interface.*/ + BaseAccelerometer acc_if; + _lis3dsh_data +}; +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Return the number of axes of the BaseAccelerometer. + * + * @param[in] devp pointer to @p LIS3DSHDriver. + * + * @return the number of axes. + * + * @api + */ +#define lis3dshAccelerometerGetAxesNumber(devp) \ + accelerometerGetAxesNumber(&((devp)->acc_if)) + +/** + * @brief Retrieves raw data from the BaseAccelerometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LIS3DSHDriver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lis3dshAccelerometerReadRaw(devp, axes) \ + accelerometerReadRaw(&((devp)->acc_if), axes) + +/** + * @brief Retrieves cooked data from the BaseAccelerometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as milli-G. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LIS3DSHDriver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lis3dshAccelerometerReadCooked(devp, axes) \ + accelerometerReadCooked(&((devp)->acc_if), axes) + +/** + * @brief Set bias values for the BaseAccelerometer. + * @note Bias must be expressed as milli-G. + * @note The bias buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LIS3DSHDriver. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lis3dshAccelerometerSetBias(devp, bp) \ + accelerometerSetBias(&((devp)->acc_if), bp) + +/** + * @brief Reset bias values for the BaseAccelerometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p LIS3DSHDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lis3dshAccelerometerResetBias(devp) \ + accelerometerResetBias(&((devp)->acc_if)) + +/** + * @brief Set sensitivity values for the BaseAccelerometer. + * @note Sensitivity must be expressed as milli-G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LIS3DSHDriver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lis3dshAccelerometerSetSensitivity(devp, sp) \ + accelerometerSetSensitivity(&((devp)->acc_if), sp) + +/** + * @brief Reset sensitivity values for the BaseAccelerometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p LIS3DSHDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lis3dshAccelerometerResetSensitivity(devp) \ + accelerometerResetSensitivity(&((devp)->acc_if)) + +/** + * @brief Changes the LIS3DSHDriver accelerometer fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LIS3DSHDriver. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lis3dshAccelerometerSetFullScale(devp, fs) \ + (devp)->vmt->acc_set_full_scale(devp, fs) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void lis3dshObjectInit(LIS3DSHDriver *devp); + void lis3dshStart(LIS3DSHDriver *devp, const LIS3DSHConfig *config); + void lis3dshStop(LIS3DSHDriver *devp); +#ifdef __cplusplus +} +#endif + +#endif /* _LIS3DSH_H_ */ + +/** @} */ + diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.mk b/ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.mk new file mode 100644 index 0000000..dccac25 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.mk @@ -0,0 +1,10 @@ +# List of all the LIS3DSH device files. +LIS3DSHSRC := $(CHIBIOS)/os/ex/devices/ST/lis3dsh.c + +# Required include directories +LIS3DSHINC := $(CHIBIOS)/os/ex/include \ + $(CHIBIOS)/os/ex/devices/ST + +# Shared variables +ALLCSRC += $(LIS3DSHSRC) +ALLINC += $(LIS3DSHINC) \ No newline at end of file diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.c b/ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.c new file mode 100644 index 0000000..270ee83 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.c @@ -0,0 +1,627 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lis3mdl.c + * @brief LIS3MDL MEMS interface module code. + * + * @addtogroup LIS3MDL + * @ingroup EX_ST + * @{ + */ + +#include "hal.h" +#include "lis3mdl.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if (LIS3MDL_USE_I2C) || defined(__DOXYGEN__) +/** + * @brief Reads registers value using I2C. + * @pre The I2C interface must be initialized and the driver started. + * + * @param[in] i2cp pointer to the I2C interface + * @param[in] sad slave address without R bit + * @param[in] reg first sub-register address + * @param[out] rxbuf pointer to an output buffer + * @param[in] n number of consecutive register to read + * @return the operation status. + * @notapi + */ +msg_t lis3mdlI2CReadRegister(I2CDriver *i2cp, lis3mdl_sad_t sad, uint8_t reg, + uint8_t* rxbuf, size_t n) { + uint8_t txbuf = reg; + if(n > 1) + txbuf |= LIS3MDL_SUB_MS; + + return i2cMasterTransmitTimeout(i2cp, sad, &txbuf, 1, rxbuf, n, + TIME_INFINITE); +} + +/** + * @brief Writes a value into a register using I2C. + * @pre The I2C interface must be initialized and the driver started. + * + * @param[in] i2cp pointer to the I2C interface + * @param[in] sad slave address without R bit + * @param[in] txbuf buffer containing sub-address value in first position + * and values to write + * @param[in] n size of txbuf less one (not considering the first + * element) + * @return the operation status. + * @notapi + */ +msg_t lis3mdlI2CWriteRegister(I2CDriver *i2cp, lis3mdl_sad_t sad, uint8_t* txbuf, + uint8_t n) { + if (n > 1) + (*txbuf) |= LIS3MDL_SUB_MS; + + return i2cMasterTransmitTimeout(i2cp, sad, txbuf, n + 1, NULL, 0, + TIME_INFINITE); +} +#endif /* LIS3MDL_USE_I2C */ + +/** + * @brief Return the number of axes of the BaseCompass. + * + * @param[in] ip pointer to @p BaseCompass interface + * + * @return the number of axes. + */ +static size_t comp_get_axes_number(void *ip) { + + osalDbgCheck(ip != NULL); + return LIS3MDL_COMP_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseCompass. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] ip pointer to @p BaseCompass interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t comp_read_raw(void *ip, int32_t axes[]) { + LIS3MDLDriver* devp; + uint8_t buff [LIS3MDL_COMP_NUMBER_OF_AXES * 2], i; + int16_t tmp; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS3MDLDriver*, (BaseCompass*)ip); + + osalDbgAssert((devp->state == LIS3MDL_READY), + "comp_read_raw(), invalid state"); + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "comp_read_raw(), channel not ready"); + +#if LIS3MDL_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LIS3MDL_SHARED_I2C */ + msg = lis3mdlI2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, + LIS3MDL_AD_OUT_X_L, buff, + LIS3MDL_COMP_NUMBER_OF_AXES * 2); + +#if LIS3MDL_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LIS3MDL_SHARED_I2C */ + + if(msg == MSG_OK) + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { + tmp = buff[2 * i] + (buff[2 * i + 1] << 8); + axes[i] = (int32_t)tmp; + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseCompass. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as G. + * @note The axes array must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] ip pointer to @p BaseCompass interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t comp_read_cooked(void *ip, float axes[]) { + LIS3MDLDriver* devp; + uint32_t i; + int32_t raw[LIS3MDL_COMP_NUMBER_OF_AXES]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS3MDLDriver*, (BaseCompass*)ip); + + osalDbgAssert((devp->state == LIS3MDL_READY), + "comp_read_cooked(), invalid state"); + + msg = comp_read_raw(ip, raw); + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES ; i++) { + axes[i] = (raw[i] * devp->compsensitivity[i]) - devp->compbias[i]; + } + return msg; +} + +/** + * @brief Set bias values for the BaseCompass. + * @note Bias must be expressed as G. + * @note The bias buffer must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] ip pointer to @p BaseCompass interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t comp_set_bias(void *ip, float *bp) { + LIS3MDLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS3MDLDriver*, (BaseCompass*)ip); + + osalDbgAssert((devp->state == LIS3MDL_READY), + "comp_set_bias(), invalid state"); + + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { + devp->compbias[i] = bp[i]; + } + return msg; +} + +/** + * @brief Reset bias values for the BaseCompass. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseCompass interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t comp_reset_bias(void *ip) { + LIS3MDLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS3MDLDriver*, (BaseCompass*)ip); + + osalDbgAssert((devp->state == LIS3MDL_READY), + "comp_reset_bias(), invalid state"); + + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) + devp->compbias[i] = LIS3MDL_COMP_BIAS; + return msg; +} + +/** + * @brief Set sensitivity values for the BaseCompass. + * @note Sensitivity must be expressed as G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] ip pointer to @p BaseCompass interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t comp_set_sensivity(void *ip, float *sp) { + LIS3MDLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS3MDLDriver*, (BaseCompass*)ip); + + osalDbgCheck((ip != NULL) && (sp != NULL)); + + osalDbgAssert((devp->state == LIS3MDL_READY), + "comp_set_sensivity(), invalid state"); + + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { + devp->compsensitivity[i] = sp[i]; + } + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseCompass. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseCompass interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t comp_reset_sensivity(void *ip) { + LIS3MDLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LIS3MDLDriver*, (BaseCompass*)ip); + + osalDbgAssert((devp->state == LIS3MDL_READY), + "comp_reset_sensivity(), invalid state"); + + if(devp->config->compfullscale == LIS3MDL_COMP_FS_4GA) + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) + devp->compsensitivity[i] = LIS3MDL_COMP_SENS_4GA; + else if(devp->config->compfullscale == LIS3MDL_COMP_FS_8GA) + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) + devp->compsensitivity[i] = LIS3MDL_COMP_SENS_8GA; + else if(devp->config->compfullscale == LIS3MDL_COMP_FS_12GA) + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) + devp->compsensitivity[i] = LIS3MDL_COMP_SENS_12GA; + else if(devp->config->compfullscale == LIS3MDL_COMP_FS_16GA) + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) + devp->compsensitivity[i] = LIS3MDL_COMP_SENS_16GA; + else { + osalDbgAssert(FALSE, "comp_reset_sensivity(), compass full scale issue"); + msg = MSG_RESET; + } + return msg; +} + +/** + * @brief Changes the LIS3MDLDriver compass fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LIS3MDLDriver interface. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t comp_set_full_scale(LIS3MDLDriver *devp, lis3mdl_comp_fs_t fs) { + float newfs, scale; + uint8_t i, buff[2]; + msg_t msg; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LIS3MDL_READY), + "comp_set_full_scale(), invalid state"); + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "comp_set_full_scale(), channel not ready"); + + /* Computing new fullscale value.*/ + if(fs == LIS3MDL_COMP_FS_4GA) { + newfs = LIS3MDL_COMP_4GA; + } + else if(fs == LIS3MDL_COMP_FS_8GA) { + newfs = LIS3MDL_COMP_8GA; + } + else if(fs == LIS3MDL_COMP_FS_12GA) { + newfs = LIS3MDL_COMP_12GA; + } + else if(fs == LIS3MDL_COMP_FS_16GA) { + newfs = LIS3MDL_COMP_16GA; + } + else { + msg = MSG_RESET; + return msg; + } + + if(newfs != devp->compfullscale) { + /* Computing scale value.*/ + scale = newfs / devp->compfullscale; + devp->compfullscale = newfs; + +#if LIS3MDL_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* LIS3MDL_SHARED_I2C */ + + /* Updating register.*/ + msg = lis3mdlI2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, + LIS3MDL_AD_CTRL_REG2, &buff[1], 1); + +#if LIS3MDL_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LIS3MDL_SHARED_I2C */ + + if(msg != MSG_OK) + return msg; + buff[1] &= ~(LIS3MDL_CTRL_REG2_FS_MASK); + buff[1] |= fs; + buff[0] = LIS3MDL_AD_CTRL_REG2; + +#if LIS3MDL_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* LIS3MDL_SHARED_I2C */ + + msg = lis3mdlI2CWriteRegister(devp->config->i2cp, + devp->config->slaveaddress, + buff, 1); + +#if LIS3MDL_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LIS3MDL_SHARED_I2C */ + + if(msg != MSG_OK) + return msg; + + /* Scaling sensitivity and bias. Re-calibration is suggested anyway.*/ + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { + devp->compsensitivity[i] *= scale; + devp->compbias[i] *= scale; + } + } + return msg; +} + +static const struct LIS3MDLVMT vmt_device = { + (size_t)0, + comp_set_full_scale +}; + +static const struct BaseCompassVMT vmt_compass = { + sizeof(struct LIS3MDLVMT*), + comp_get_axes_number, comp_read_raw, comp_read_cooked, + comp_set_bias, comp_reset_bias, comp_set_sensivity, comp_reset_sensivity +}; + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes an instance. + * + * @param[out] devp pointer to the @p LIS3MDLDriver object + * + * @init + */ +void lis3mdlObjectInit(LIS3MDLDriver *devp) { + devp->vmt = &vmt_device; + devp->comp_if.vmt = &vmt_compass; + + devp->config = NULL; + + devp->compaxes = LIS3MDL_COMP_NUMBER_OF_AXES; + + devp->state = LIS3MDL_STOP; +} + +/** + * @brief Configures and activates LIS3MDL Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LIS3MDLDriver object + * @param[in] config pointer to the @p LIS3MDLConfig object + * + * @api + */ +void lis3mdlStart(LIS3MDLDriver *devp, const LIS3MDLConfig *config) { + uint32_t i; + uint8_t cr[6]; + osalDbgCheck((devp != NULL) && (config != NULL)); + + osalDbgAssert((devp->state == LIS3MDL_STOP) || (devp->state == LIS3MDL_READY), + "lis3mdlStart(), invalid state"); + + devp->config = config; + + /* Control register 1 configuration block.*/ + { + cr[0] = LIS3MDL_AD_CTRL_REG1; + cr[1] = devp->config->compoutputdatarate; +#if LIS3MDL_USE_ADVANCED || defined(__DOXYGEN__) + cr[1] |= devp->config->compoperationmodexy; +#else + cr[1] |= LIS3MDL_CTRL_REG1_OM0 | LIS3MDL_CTRL_REG1_OM1; +#endif + } + + /* Control register 2 configuration block.*/ + { + cr[2] = devp->config->compfullscale; + } + + /* Control register 3 configuration block.*/ + { + cr[3] = 0; +#if LIS3MDL_USE_ADVANCED || defined(__DOXYGEN__) + cr[3] = devp->config->compconversionmode; +#endif + } + + /* Control register 4 configuration block.*/ + { + cr[4] = 0; +#if LIS3MDL_USE_ADVANCED || defined(__DOXYGEN__) + cr[4] = devp->config->compoperationmodez | devp->config->endianness; +#endif + } + + /* Control register 5 configuration block.*/ + { + cr[5] = 0; +#if LIS3MDL_USE_ADVANCED || defined(__DOXYGEN__) + cr[5] = devp->config->blockdataupdate; +#endif + } + +#if LIS3MDL_USE_I2C +#if LIS3MDL_SHARED_I2C + i2cAcquireBus((devp)->config->i2cp); +#endif /* LIS3MDL_SHARED_I2C */ + i2cStart((devp)->config->i2cp, + (devp)->config->i2ccfg); + + lis3mdlI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + cr, 5); + +#if LIS3MDL_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* LIS3MDL_SHARED_I2C */ +#endif /* LIS3MDL_USE_I2C */ + + if(devp->config->compfullscale == LIS3MDL_COMP_FS_4GA) { + devp->compfullscale = LIS3MDL_COMP_4GA; + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { + if(devp->config->compsensitivity == NULL) { + devp->compsensitivity[i] = LIS3MDL_COMP_SENS_4GA; + } + else { + devp->compsensitivity[i] = devp->config->compsensitivity[i]; + } + } + } + else if(devp->config->compfullscale == LIS3MDL_COMP_FS_8GA) { + devp->compfullscale = LIS3MDL_COMP_8GA; + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { + if(devp->config->compsensitivity == NULL) { + devp->compsensitivity[i] = LIS3MDL_COMP_SENS_8GA; + } + else { + devp->compsensitivity[i] = devp->config->compsensitivity[i]; + } + } + } + else if(devp->config->compfullscale == LIS3MDL_COMP_FS_12GA) { + devp->compfullscale = LIS3MDL_COMP_12GA; + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { + if(devp->config->compsensitivity == NULL) { + devp->compsensitivity[i] = LIS3MDL_COMP_SENS_12GA; + } + else { + devp->compsensitivity[i] = devp->config->compsensitivity[i]; + } + } + } + else if(devp->config->compfullscale == LIS3MDL_COMP_FS_16GA) { + devp->compfullscale = LIS3MDL_COMP_16GA; + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { + if(devp->config->compsensitivity == NULL) { + devp->compsensitivity[i] = LIS3MDL_COMP_SENS_16GA; + } + else { + devp->compsensitivity[i] = devp->config->compsensitivity[i]; + } + } + } + else + osalDbgAssert(FALSE, "lis3mdlStart(), compass full scale issue"); + + /* Storing bias information */ + if(devp->config->compbias != NULL) + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) + devp->compbias[i] = devp->config->compbias[i]; + else + for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) + devp->compbias[i] = LIS3MDL_COMP_BIAS; + + /* This is the MEMS transient recovery time */ + osalThreadSleepMilliseconds(5); + + devp->state = LIS3MDL_READY; +} + +/** + * @brief Deactivates the LIS3MDL Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LIS3MDLDriver object + * + * @api + */ +void lis3mdlStop(LIS3MDLDriver *devp) { + uint8_t cr[2]; + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LIS3MDL_STOP) || (devp->state == LIS3MDL_READY), + "lis3mdlStop(), invalid state"); + + if (devp->state == LIS3MDL_READY) { +#if (LIS3MDL_USE_I2C) +#if LIS3MDL_SHARED_I2C + i2cAcquireBus((devp)->config->i2cp); + i2cStart((devp)->config->i2cp, + (devp)->config->i2ccfg); +#endif /* LIS3MDL_SHARED_I2C */ + + /* Disabling compass. */ + cr[0] = LIS3MDL_AD_CTRL_REG3; + cr[1] = LIS3MDL_CTRL_REG3_MD0 | LIS3MDL_CTRL_REG3_MD1; + lis3mdlI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + cr, 1); + + i2cStop((devp)->config->i2cp); +#if LIS3MDL_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* LIS3MDL_SHARED_I2C */ +#endif /* LIS3MDL_USE_I2C */ + } + devp->state = LIS3MDL_STOP; +} +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.h b/ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.h new file mode 100644 index 0000000..59f30f8 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.h @@ -0,0 +1,670 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lis3mdl.h + * @brief LIS3MDL MEMS interface module header. + * + * @addtogroup LIS3MDL + * @ingroup EX_ST + * @{ + */ +#ifndef _LIS3MDL_H_ +#define _LIS3MDL_H_ + +#include "ex_compass.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Version identification + * @{ + */ +/** + * @brief LIS3MDL driver version string. + */ +#define EX_LIS3MDL_VERSION "1.1.2" + +/** + * @brief LIS3MDL driver version major number. + */ +#define EX_LIS3MDL_MAJOR 1 + +/** + * @brief LIS3MDL driver version minor number. + */ +#define EX_LIS3MDL_MINOR 1 + +/** + * @brief LIS3MDL driver version patch number. + */ +#define EX_LIS3MDL_PATCH 2 +/** @} */ + +/** + * @brief LIS3MDL compass subsystem characteristics. + * @note Sensitivity is expressed as G/LSB whereas G stands for Gauss. + * @note Bias is expressed as G. + * + * @{ + */ +#define LIS3MDL_COMP_NUMBER_OF_AXES 3U + +#define LIS3MDL_COMP_4GA 4.0f +#define LIS3MDL_COMP_8GA 8.0f +#define LIS3MDL_COMP_12GA 12.0f +#define LIS3MDL_COMP_16GA 16.0f + +#define LIS3MDL_COMP_SENS_4GA 0.00014615f +#define LIS3MDL_COMP_SENS_8GA 0.00029231f +#define LIS3MDL_COMP_SENS_12GA 0.0004384f +#define LIS3MDL_COMP_SENS_16GA 0.00058445f + +#define LIS3MDL_COMP_BIAS 0.0f +/** @} */ + +/** + * @name LIS3MDL communication interfaces related bit masks + * @{ + */ +#define LIS3MDL_DI_MASK 0xFF +#define LIS3MDL_DI(n) (1 << n) +#define LIS3MDL_AD_MASK 0x3F +#define LIS3MDL_AD(n) (1 << n) +#define LIS3MDL_MS (1 << 6) +#define LIS3MDL_RW (1 << 7) + +#define LIS3MDL_SUB_MS (1 << 7) +/** @} */ + +/** + * @name LIS3MDL register addresses + * @{ + */ +#define LIS3MDL_AD_WHO_AM_I 0x0F +#define LIS3MDL_AD_CTRL_REG1 0x20 +#define LIS3MDL_AD_CTRL_REG2 0x21 +#define LIS3MDL_AD_CTRL_REG3 0x22 +#define LIS3MDL_AD_CTRL_REG4 0x23 +#define LIS3MDL_AD_CTRL_REG5 0x24 +#define LIS3MDL_AD_STATUS_REG 0x27 +#define LIS3MDL_AD_OUT_X_L 0x28 +#define LIS3MDL_AD_OUT_X_H 0x29 +#define LIS3MDL_AD_OUT_Y_L 0x2A +#define LIS3MDL_AD_OUT_Y_H 0x2B +#define LIS3MDL_AD_OUT_Z_L 0x2C +#define LIS3MDL_AD_OUT_Z_H 0x2D +#define LIS3MDL_AD_TEMP_OUT_L 0x2E +#define LIS3MDL_AD_TEMP_OUT_H 0x2F +#define LIS3MDL_AD_INT_CFG 0x30 +#define LIS3MDL_AD_INT_SOURCE 0x31 +#define LIS3MDL_AD_INT_THS_L 0x32 +#define LIS3MDL_AD_INT_THS_H 0x33 +/** @} */ + +/** + * @name LIS3MDL_CTRL_REG1 register bits definitions + * @{ + */ +#define LIS3MDL_CTRL_REG1_MASK 0xFF +#define LIS3MDL_CTRL_REG1_ST (1 << 0) +#define LIS3MDL_CTRL_REG1_FAST_ODR (1 << 1) +#define LIS3MDL_CTRL_REG1_DO0 (1 << 2) +#define LIS3MDL_CTRL_REG1_DO1 (1 << 3) +#define LIS3MDL_CTRL_REG1_DO2 (1 << 4) +#define LIS3MDL_CTRL_REG1_OM0 (1 << 5) +#define LIS3MDL_CTRL_REG1_OM1 (1 << 6) +#define LIS3MDL_CTRL_REG1_TEMP_EN (1 << 7) +/** @} */ + +/** + * @name LIS3MDL_CTRL_REG2 register bits definitions + * @{ + */ +#define LIS3MDL_CTRL_REG2_MASK 0x6C +#define LIS3MDL_CTRL_REG2_SOFT_RST (1 << 2) +#define LIS3MDL_CTRL_REG2_REBOOT (1 << 3) +#define LIS3MDL_CTRL_REG2_FS_MASK 0x60 +#define LIS3MDL_CTRL_REG2_FS0 (1 << 5) +#define LIS3MDL_CTRL_REG2_FS1 (1 << 6) +/** @} */ + +/** + * @name LIS3MDL_CTRL_REG3 register bits definitions + * @{ + */ +#define LIS3MDL_CTRL_REG3_MASK 0x27 +#define LIS3MDL_CTRL_REG3_MD0 (1 << 0) +#define LIS3MDL_CTRL_REG3_MD1 (1 << 1) +#define LIS3MDL_CTRL_REG3_SIM (1 << 2) +#define LIS3MDL_CTRL_REG3_LP (1 << 5) +/** @} */ + +/** + * @name LIS3MDL_CTRL_REG4 register bits definitions + * @{ + */ +#define LIS3MDL_CTRL_REG4_MASK 0x0E +#define LIS3MDL_CTRL_REG4_BLE (1 << 1) +#define LIS3MDL_CTRL_REG4_OMZ0 (1 << 2) +#define LIS3MDL_CTRL_REG4_OMZ1 (1 << 3) +/** @} */ + +/** + * @name LIS3MDL_CTRL_REG5 register bits definitions + * @{ + */ +#define LIS3MDL_CTRL_REG5_MASK 0xC0 +#define LIS3MDL_CTRL_REG5_BDU (1 << 6) +#define LIS3MDL_CTRL_REG5_FAST_READ (1 << 7) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief LIS3MDL SPI interface switch. + * @details If set to @p TRUE the support for SPI is included. + * @note The default is @p FALSE. + */ +#if !defined(LIS3MDL_USE_SPI) || defined(__DOXYGEN__) +#define LIS3MDL_USE_SPI FALSE +#endif + +/** + * @brief LIS3MDL shared SPI switch. + * @details If set to @p TRUE the device acquires SPI bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LIS3MDL_SHARED_SPI) || defined(__DOXYGEN__) +#define LIS3MDL_SHARED_SPI FALSE +#endif + +/** + * @brief LIS3MDL I2C interface switch. + * @details If set to @p TRUE the support for I2C is included. + * @note The default is @p TRUE. + */ +#if !defined(LIS3MDL_USE_I2C) || defined(__DOXYGEN__) +#define LIS3MDL_USE_I2C TRUE +#endif + +/** + * @brief LIS3MDL shared I2C switch. + * @details If set to @p TRUE the device acquires I2C bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION + */ +#if !defined(LIS3MDL_SHARED_I2C) || defined(__DOXYGEN__) +#define LIS3MDL_SHARED_I2C FALSE +#endif + +/** + * @brief LIS3MDL advanced configurations switch. + * @details If set to @p TRUE more configurations are available. + * @note The default is @p FALSE. + */ +#if !defined(LIS3MDL_USE_ADVANCED) || defined(__DOXYGEN__) +#define LIS3MDL_USE_ADVANCED FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !(LIS3MDL_USE_SPI ^ LIS3MDL_USE_I2C) +#error "LIS3MDL_USE_SPI and LIS3MDL_USE_I2C cannot be both true or both false" +#endif + +#if LIS3MDL_USE_SPI && !HAL_USE_SPI +#error "LIS3MDL_USE_SPI requires HAL_USE_SPI" +#endif + +#if LIS3MDL_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION +#error "LIS3MDL_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" +#endif + +#if LIS3MDL_USE_I2C && !HAL_USE_I2C +#error "LIS3MDL_USE_I2C requires HAL_USE_I2C" +#endif + +#if LIS3MDL_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION +#error "LIS3MDL_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" +#endif + +/* + * CHTODO: Add support for LIS3MDL over SPI. + */ +#if LIS3MDL_USE_SPI +#error "LIS3MDL over SPI still not supported" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @name LIS3MDL data structures and types + * @{ + */ + +/** + * @brief LIS3MDL slave address + */ +/** + * @brief Structure representing a LIS3MDL driver. + */ +typedef struct LIS3MDLDriver LIS3MDLDriver; + +/** + * @brief LIS3MDL slave address + */ +typedef enum { + LIS3MDL_SAD_GND = 0x1C, /**< Slave Address when SA1 is to GND */ + LIS3MDL_SAD_VCC = 0x1E /**< Slave Address when SA1 is to VCC */ +}lis3mdl_sad_t; + +/** + * @brief LIS3MDL full scale + */ +typedef enum { + LIS3MDL_COMP_FS_4GA = 0x00, /**< �4 Gauss */ + LIS3MDL_COMP_FS_8GA = 0x20, /**< �8 Gauss */ + LIS3MDL_COMP_FS_12GA = 0x40, /**< �12 Gauss */ + LIS3MDL_COMP_FS_16GA = 0x60 /**< �16 Gauss */ +}lis3mdl_comp_fs_t; + +/** + * @brief LIS3MDL output data rate + */ +typedef enum { + LIS3MDL_COMP_ODR_0_625HZ = 0x00, /**< Output Data Rate = 0.625 Hz */ + LIS3MDL_COMP_ODR_1_25HZ = 0x04, /**< Output Data Rate = 1.25 Hz */ + LIS3MDL_COMP_ODR_2_5HZ = 0x08, /**< Output Data Rate = 2.5 Hz */ + LIS3MDL_COMP_ODR_5HZ = 0x0C, /**< Output Data Rate = 5 Hz */ + LIS3MDL_COMP_ODR_10HZ = 0x10, /**< Output Data Rate = 10 Hz */ + LIS3MDL_COMP_ODR_20HZ = 0x14, /**< Output Data Rate = 20 Hz */ + LIS3MDL_COMP_ODR_40HZ = 0x18, /**< Output Data Rate = 40 Hz */ + LIS3MDL_COMP_ODR_80HZ = 0x1C /**< Output Data Rate = 80 Hz */ +}lis3mdl_comp_odr_t; + +/** + * @brief LIS3MDL low power mode configuration + */ +typedef enum { + LIS3MDL_COMP_LP_DISABLED = 0x00, /**< Low Power mode disabled */ + LIS3MDL_COMP_LP_ENABLED = 0x20 /**< Low Power mode enabled */ +}lis3mdl_comp_lp_t; + +/** + * @brief LIS3MDL conversion mode + */ +typedef enum { + LIS3MDL_COMP_MD_CONTINUOUS = 0x00,/**< Continuous conversion mode */ + LIS3MDL_COMP_MD_SINGLE = 0x01, /**< Single conversion mode */ + LIS3MDL_COMP_MD_POWER_DOWN = 0x02 /**< Power down mode */ +}lis3mdl_comp_md_t; + +/** + * @brief LIS3MDL operation mode for X and Y axes + */ +typedef enum { + LIS3MDL_COMP_OMXY_LP = 0x00, /**< X-Y axes low power mode */ + LIS3MDL_COMP_OMXY_MEDIUM = 0x20, /**< X-Y axes medium performance mode */ + LIS3MDL_COMP_OMXY_HIGH = 0x40, /**< X-Y axes high performance mode */ + LIS3MDL_COMP_OMXY_ULTRA = 0x60 /**< X-Y axes ultra performance mode */ +}lis3mdl_comp_omxy_t; + +/** + * @brief LIS3MDL operation mode for Z axis + */ +typedef enum { + LIS3MDL_COMP_OMZ_LP = 0x00, /**< Z axis low power mode */ + LIS3MDL_COMP_OMZ_MEDIUM = 0x04, /**< Z axis medium performance mode */ + LIS3MDL_COMP_OMZ_HIGH = 0x08, /**< Z axis high performance mode */ + LIS3MDL_COMP_OMZ_ULTRA = 0x0C /**< Z axis ultra performance mode */ +}lis3mdl_comp_omz_t; + +/** + * @brief LIS3MDL temperature sensor enabling + */ +typedef enum { + LIS3MDL_TEMP_DISABLED = 0x00, /**< Temperature sensor disabled. */ + LIS3MDL_TEMP_ENABLED = 0x80 /**< Temperature sensor enabled. */ +}lis3mdl_temp_t; + +/** + * @brief LIS3MDL block data update + */ +typedef enum { + LIS3MDL_BDU_CONTINUOUS = 0x00, /**< Continuous Update */ + LIS3MDL_BDU_BLOCKED = 0x40 /**< Block data updated after reading. */ +}lis3mdl_bdu_t; + +/** + * @brief LIS3MDL endianness + */ +typedef enum { + LIS3MDL_END_LITTLE = 0x00, /**< Little endian. */ + LIS3MDL_END_BIG = 0x02 /**< Big endian. */ +}lis3mdl_end_t; + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + LIS3MDL_UNINIT = 0, /**< Not initialized. */ + LIS3MDL_STOP = 1, /**< Stopped. */ + LIS3MDL_READY = 2, /**< Ready. */ +} lis3mdl_state_t; + +/** + * @brief LIS3MDL configuration structure. + */ +typedef struct { +#if (LIS3MDL_USE_SPI) || defined(__DOXYGEN__) + /** + * @brief SPI driver associated to this LIS3MDL. + */ + SPIDriver *spip; + /** + * @brief SPI configuration associated to this LIS3MDL. + */ + const SPIConfig *spicfg; +#endif /* LIS3MDL_USE_SPI */ +#if (LIS3MDL_USE_I2C) || defined(__DOXYGEN__) + /** + * @brief I2C driver associated to this LIS3MDL. + */ + I2CDriver *i2cp; + /** + * @brief I2C configuration associated to this LIS3MDL. + */ + const I2CConfig *i2ccfg; + /** + * @brief LIS3MDL slave address + */ + lis3mdl_sad_t slaveaddress; +#endif /* LIS3MDL_USE_I2C */ + /** + * @brief LIS3MDL compass subsystem initial sensitivity. + */ + float *compsensitivity; + /** + * @brief LIS3MDL compass subsystem initial bias. + */ + float *compbias; + /** + * @brief LIS3MDL compass subsystem full scale. + */ + lis3mdl_comp_fs_t compfullscale; + /** + * @brief LIS3MDL compass subsystem output data rate. + */ + lis3mdl_comp_odr_t compoutputdatarate; +#if LIS3MDL_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief LIS3MDL compass subsystem low power mode configuration. + */ + lis3mdl_comp_lp_t complowpowermode; + /** + * @brief LIS3MDL compass subsystem conversion mode. + */ + lis3mdl_comp_md_t compconversionmode; + /** + * @brief LIS3MDL compass subsystem operation mode for X and Y axes. + */ + lis3mdl_comp_omxy_t compoperationmodexy; + /** + * @brief LIS3MDL compass subsystem operation mode for Z axis. + */ + lis3mdl_comp_omz_t compoperationmodez; + /** + * @brief LIS3MDL block data update. + */ + lis3mdl_bdu_t blockdataupdate; + /** + * @brief LIS3MDL endianness. + */ + lis3mdl_end_t endianness; +#endif +} LIS3MDLConfig; + +/** + * @brief @p LIS3MDL specific methods. + */ +#define _lis3msl_methods_alone \ + /* Change full scale value of LIS3MDL compass subsystem.*/ \ + msg_t (*comp_set_full_scale)(LIS3MDLDriver *devp, lis3mdl_comp_fs_t fs); + +/** + * @brief @p LIS3MDL specific methods with inherited ones. + */ +#define _lis3mdl_methods \ + _base_object_methods \ + _lis3msl_methods_alone + +/** + * @extends BaseCompassVMT + * + * @brief @p LIS3MDL virtual methods table. + */ +struct LIS3MDLVMT { + _lis3mdl_methods +}; + +/** + * @brief @p LIS3MDLDriver specific data. + */ +#define _lis3mdl_data \ + _base_compass_data \ + /* Driver state.*/ \ + lis3mdl_state_t state; \ + /* Current configuration data.*/ \ + const LIS3MDLConfig *config; \ + /* Compass subsystem axes number.*/ \ + size_t compaxes; \ + /* Compass subsystem current sensitivity.*/ \ + float compsensitivity[LIS3MDL_COMP_NUMBER_OF_AXES]; \ + /* Compass subsystem current bias.*/ \ + float compbias[LIS3MDL_COMP_NUMBER_OF_AXES]; \ + /* Compass subsystem current full scale value.*/ \ + float compfullscale; + +/** + * @brief LIS3MDL 3-axis compass class. + */ +struct LIS3MDLDriver { + /** @brief Virtual Methods Table.*/ + const struct LIS3MDLVMT *vmt; + /** @brief Base compass interface.*/ + BaseCompass comp_if; + _lis3mdl_data +}; +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Return the number of axes of the BaseCompass. + * + * @param[in] devp pointer to @p LIS3MDLDriver. + * + * @return the number of axes. + * + * @api + */ +#define lis3mdlCompassGetAxesNumber(devp) \ + compassGetAxesNumber(&((devp)->comp_if)) + +/** + * @brief Retrieves raw data from the BaseCompass. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] devp pointer to @p BaseCompass interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lis3mdlCompassReadRaw(devp, axes) \ + compassReadRaw(&((devp)->comp_if), axes) + +/** + * @brief Retrieves cooked data from the BaseCompass. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as G. + * @note The axes array must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] devp pointer to @p BaseCompass interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lis3mdlCompassReadCooked(devp, axes) \ + compassReadCooked(&((devp)->comp_if), axes) + +/** + * @brief Set bias values for the BaseCompass. + * @note Bias must be expressed as G. + * @note The bias buffer must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] devp pointer to @p BaseCompass interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lis3mdlCompassSetBias(devp, bp) \ + compassSetBias(&((devp)->comp_if), bp) + +/** + * @brief Reset bias values for the BaseCompass. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p LIS3MDLDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lis3mdlCompassResetBias(devp) \ + compassResetBias(&((devp)->comp_if)) + +/** + * @brief Set sensitivity values for the BaseCompass. + * @note Sensitivity must be expressed as G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] devp pointer to @p LIS3MDLDriver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lis3mdlCompassSetSensitivity(devp, sp) \ + compassSetSensitivity(&((devp)->comp_if), sp) + +/** + * @brief Reset sensitivity values for the BaseCompass. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p LIS3MDLDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lis3mdlCompassResetSensitivity(devp) \ + compassResetSensitivity(&((devp)->comp_if)) + +/** + * @brief Changes the LIS3MDLDriver compass fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LIS3MDLDriver. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lis3mdlCompassSetFullScale(devp, fs) \ + (devp)->vmt->comp_set_full_scale(devp, fs) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void lis3mdlObjectInit(LIS3MDLDriver *devp); + void lis3mdlStart(LIS3MDLDriver *devp, const LIS3MDLConfig *config); + void lis3mdlStop(LIS3MDLDriver *devp); +#ifdef __cplusplus +} +#endif + +#endif /* _LIS3MDL_H_ */ + +/** @} */ + diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.mk b/ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.mk new file mode 100644 index 0000000..00b6b0f --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.mk @@ -0,0 +1,10 @@ +# List of all the LIS3MDL device files. +LIS3MDLSRC := $(CHIBIOS)/os/ex/devices/ST/lis3mdl.c + +# Required include directories +LIS3MDLINC := $(CHIBIOS)/os/ex/include \ + $(CHIBIOS)/os/ex/devices/ST + +# Shared variables +ALLCSRC += $(LIS3MDLSRC) +ALLINC += $(LIS3MDLINC) \ No newline at end of file diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.c b/ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.c new file mode 100644 index 0000000..9a89125 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.c @@ -0,0 +1,686 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lps22hb.c + * @brief LPS22HB MEMS interface module code. + * + * @addtogroup LPS22HB + * @ingroup EX_ST + * @{ + */ + +#include "hal.h" +#include "lps22hb.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if (LPS22HB_USE_I2C) || defined(__DOXYGEN__) +/** + * @brief Reads registers value using I2C. + * @pre The I2C interface must be initialized and the driver started. + * + * @param[in] i2cp pointer to the I2C interface + * @param[in] sad slave address without R bit + * @param[in] reg first sub-register address + * @param[out] rxbuf pointer to an output buffer + * @param[in] n number of consecutive register to read + * @return the operation status. + * + * @notapi + */ +static msg_t lps22hbI2CReadRegister(I2CDriver *i2cp, lps22hb_sad_t sad, + uint8_t reg, uint8_t* rxbuf, size_t n) { + + return i2cMasterTransmitTimeout(i2cp, sad, ®, 1, rxbuf, n, + TIME_INFINITE); +} + +/** + * @brief Writes a value into a register using I2C. + * @pre The I2C interface must be initialized and the driver started. + * + * @param[in] i2cp pointer to the I2C interface + * @param[in] sad slave address without R bit + * @param[in] txbuf buffer containing sub-address value in first position + * and values to write + * @param[in] n size of txbuf less one (not considering the first + * element) + * @return the operation status. + * + * @notapi + */ +#define lps22hbI2CWriteRegister(i2cp, sad, txbuf, n) \ + i2cMasterTransmitTimeout(i2cp, sad, txbuf, n + 1, NULL, 0, \ + TIME_INFINITE) +#endif /* LPS22HB_USE_I2C */ + +/** + * @brief Return the number of axes of the BaseBarometer. + * + * @param[in] ip pointer to @p BaseBarometer interface. + * + * @return the number of axes. + */ +static size_t baro_get_axes_number(void *ip) { + (void)ip; + + return LPS22HB_BARO_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseBarometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] ip pointer to @p BaseBarometer interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t baro_read_raw(void *ip, int32_t axes[]) { + LPS22HBDriver* devp; + uint8_t buff[3]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS22HBDriver*, (BaseBarometer*)ip); + + osalDbgAssert((devp->state == LPS22HB_READY), + "baro_read_raw(), invalid state"); + + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "baro_read_raw(), channel not ready"); + +#if LPS22HB_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LPS22HB_SHARED_I2C */ + + msg = lps22hbI2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, + LPS22HB_AD_PRESS_OUT_XL, buff, 3); + +#if LPS22HB_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LPS22HB_SHARED_I2C */ + + if(msg == MSG_OK) { + *axes = buff[0] + (buff[1] << 8) + (buff[2] << 16); + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseBarometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as hPa. + * @note The axes array must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] ip pointer to @p BaseBarometer interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t baro_read_cooked(void *ip, float axes[]) { + LPS22HBDriver* devp; + int32_t raw; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS22HBDriver*, (BaseBarometer*)ip); + + osalDbgAssert((devp->state == LPS22HB_READY), + "baro_read_cooked(), invalid state"); + + msg = baro_read_raw(ip, &raw); + + *axes = (raw * devp->barosensitivity) - devp->barobias; + + return msg; +} + +/** + * @brief Set bias values for the BaseBarometer. + * @note Bias must be expressed as hPa. + * @note The bias buffer must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] ip pointer to @p BaseBarometer interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t baro_set_bias(void *ip, float *bp) { + LPS22HBDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS22HBDriver*, (BaseBarometer*)ip); + + osalDbgAssert((devp->state == LPS22HB_READY), + "baro_set_bias(), invalid state"); + + devp->barobias = *bp; + return msg; +} + +/** + * @brief Reset bias values for the BaseBarometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseBarometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t baro_reset_bias(void *ip) { + LPS22HBDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS22HBDriver*, (BaseBarometer*)ip); + + osalDbgAssert((devp->state == LPS22HB_READY), + "baro_reset_bias(), invalid state"); + + devp->barobias = LPS22HB_BARO_SENS; + return msg; +} + +/** + * @brief Set sensitivity values for the BaseBarometer. + * @note Sensitivity must be expressed as hPa/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] ip pointer to @p BaseBarometer interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t baro_set_sensitivity(void *ip, float *sp) { + LPS22HBDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (sp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS22HBDriver*, (BaseBarometer*)ip); + + osalDbgAssert((devp->state == LPS22HB_READY), + "baro_set_sensitivity(), invalid state"); + + devp->barosensitivity = *sp; + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseBarometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseBarometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t baro_reset_sensitivity(void *ip) { + LPS22HBDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS22HBDriver*, (BaseBarometer*)ip); + + osalDbgAssert((devp->state == LPS22HB_READY), + "baro_reset_sensitivity(), invalid state"); + + devp->barosensitivity = LPS22HB_BARO_SENS; + return msg; +} + +/** + * @brief Return the number of axes of the BaseThermometer. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * + * @return the number of axes. + */ +static size_t thermo_get_axes_number(void *ip) { + (void)ip; + + return LPS22HB_THERMO_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseThermometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t thermo_read_raw(void *ip, int32_t axes[]) { + LPS22HBDriver* devp; + int16_t tmp; + uint8_t buff[2]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS22HBDriver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == LPS22HB_READY), + "thermo_read_raw(), invalid state"); + + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "thermo_read_raw(), channel not ready"); + +#if LPS22HB_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LPS22HB_SHARED_I2C */ + + msg = lps22hbI2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, + LPS22HB_AD_TEMP_OUT_L, buff, 2); + +#if LPS22HB_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LPS22HB_SHARED_I2C */ + + if (msg == MSG_OK) { + tmp = buff[0] + (buff[1] << 8); + *axes = (int32_t)tmp; + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseThermometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as °C. + * @note The axes array must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * @param[out] axis a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t thermo_read_cooked(void *ip, float* axis) { + LPS22HBDriver* devp; + int32_t raw; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axis != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS22HBDriver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == LPS22HB_READY), + "thermo_read_cooked(), invalid state"); + + msg = thermo_read_raw(devp, &raw); + + *axis = (raw * devp->thermosensitivity) - devp->thermobias; + + return msg; +} + +/** + * @brief Set bias values for the BaseThermometer. + * @note Bias must be expressed as °C. + * @note The bias buffer must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t thermo_set_bias(void *ip, float *bp) { + LPS22HBDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS22HBDriver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == LPS22HB_READY), + "thermo_set_bias(), invalid state"); + + devp->thermobias = *bp; + + return msg; +} + +/** + * @brief Reset bias values for the BaseThermometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t thermo_reset_bias(void *ip) { + LPS22HBDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS22HBDriver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == LPS22HB_READY), + "thermo_reset_bias(), invalid state"); + + devp->thermobias = LPS22HB_THERMO_BIAS; + + return msg; +} + +/** + * @brief Set sensitivity values for the BaseThermometer. + * @note Sensitivity must be expressed as °C/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t thermo_set_sensitivity(void *ip, float *sp) { + LPS22HBDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (sp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS22HBDriver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == LPS22HB_READY), + "thermo_set_sensitivity(), invalid state"); + + devp->thermosensitivity = *sp; + + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseThermometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t thermo_reset_sensitivity(void *ip) { + LPS22HBDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS22HBDriver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == LPS22HB_READY), + "thermo_reset_sensitivity(), invalid state"); + + devp->thermosensitivity = LPS22HB_THERMO_SENS; + + return msg; +} + +static const struct LPS22HBVMT vmt_device = { + (size_t)0 +}; + +static const struct BaseBarometerVMT vmt_barometer = { + sizeof(struct LPS22HBVMT*), + baro_get_axes_number, baro_read_raw, baro_read_cooked, + baro_set_bias, baro_reset_bias, baro_set_sensitivity, + baro_reset_sensitivity +}; + +static const struct BaseThermometerVMT vmt_thermometer = { + sizeof(struct LPS22HBVMT*) + sizeof(BaseBarometer), + thermo_get_axes_number, thermo_read_raw, thermo_read_cooked, + thermo_set_bias, thermo_reset_bias, thermo_set_sensitivity, + thermo_reset_sensitivity +}; + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes an instance. + * + * @param[out] devp pointer to the @p LPS22HBDriver object + * + * @init + */ +void lps22hbObjectInit(LPS22HBDriver *devp) { + + devp->vmt = &vmt_device; + devp->baro_if.vmt = &vmt_barometer; + devp->thermo_if.vmt = &vmt_thermometer; + + devp->config = NULL; + + devp->baroaxes = LPS22HB_BARO_NUMBER_OF_AXES; + devp->thermoaxes = LPS22HB_THERMO_NUMBER_OF_AXES; + + devp->state = LPS22HB_STOP; +} + +/** + * @brief Configures and activates LPS22HB Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LPS22HBDriver object + * @param[in] config pointer to the @p LPS22HBConfig object + * + * @api + */ +void lps22hbStart(LPS22HBDriver *devp, const LPS22HBConfig *config) { + uint8_t cr[2]; + osalDbgCheck((devp != NULL) && (config != NULL)); + + osalDbgAssert((devp->state == LPS22HB_STOP) || (devp->state == LPS22HB_READY), + "lps22hbStart(), invalid state"); + + devp->config = config; + + /* Enabling register auto-increment.*/ + /* Control register 1 configuration block.*/ + { + cr[0] = LPS22HB_AD_CTRL_REG2; + cr[1] = LPS22HB_CTRL_REG2_IF_ADD_INC; + } +#if LPS22HB_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); +#endif /* LPS22HB_SHARED_I2C */ + + i2cStart(devp->config->i2cp, devp->config->i2ccfg); + lps22hbI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + cr, 1); + +#if LPS22HB_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* LPS22HB_SHARED_I2C */ + + /* Control register 1 configuration block.*/ + { + cr[0] = LPS22HB_AD_CTRL_REG1; + cr[1] = devp->config->outputdatarate; +#if LPS22HB_USE_ADVANCED || defined(__DOXYGEN__) + cr[1] |= devp->config->blockdataupdate; + cr[1] |= devp->config->lowpass_filter; +#endif + } + +#if LPS22HB_SHARED_I2C + i2cAcquireBus((devp)->config->i2cp); + i2cStart((devp)->config->i2cp, + (devp)->config->i2ccfg); +#endif /* LPS22HB_SHARED_I2C */ + + lps22hbI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, cr, 1); + +#if LPS22HB_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* LPS22HB_SHARED_I2C */ + + if(devp->config->barosensitivity == NULL) { + devp->barosensitivity = LPS22HB_BARO_SENS; + } + else{ + /* Taking barometer sensitivity from user configurations */ + devp->barosensitivity = *(devp->config->barosensitivity); + } + + if(devp->config->barobias == NULL) { + devp->barobias = LPS22HB_BARO_BIAS; + } + else{ + /* Taking barometer bias from user configurations */ + devp->barobias = *(devp->config->barobias); + } + + if(devp->config->thermosensitivity == NULL) { + devp->thermosensitivity = LPS22HB_THERMO_SENS; + } + else{ + /* Taking thermometer sensitivity from user configurations */ + devp->thermosensitivity = *(devp->config->thermosensitivity); + } + + if(devp->config->thermobias == NULL) { + devp->thermobias = LPS22HB_THERMO_BIAS; + } + else{ + /* Taking thermometer bias from user configurations */ + devp->thermobias = *(devp->config->thermobias); + } + + /* This is the Barometer transient recovery time */ + osalThreadSleepMilliseconds(5); + + devp->state = LPS22HB_READY; +} + +/** + * @brief Deactivates the LPS22HB Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LPS22HBDriver object + * + * @api + */ +void lps22hbStop(LPS22HBDriver *devp) { + uint8_t cr[2]; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LPS22HB_STOP) || (devp->state == LPS22HB_READY), + "lps22hbStop(), invalid state"); + + if (devp->state == LPS22HB_READY) { +#if LPS22HB_SHARED_I2C + i2cAcquireBus((devp)->config->i2cp); + i2cStart((devp)->config->i2cp, + (devp)->config->i2ccfg); +#endif /* LPS22HB_SHARED_I2C */ + + cr[0] = LPS22HB_AD_CTRL_REG1; + cr[1] = 0; + lps22hbI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + cr, 1); + + i2cStop((devp)->config->i2cp); +#if LPS22HB_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* LPS22HB_SHARED_I2C */ + } + devp->state = LPS22HB_STOP; +} +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.h b/ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.h new file mode 100644 index 0000000..12c9ddc --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.h @@ -0,0 +1,724 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lps22hb.h + * @brief LPS22HB MEMS interface module header. + * + * @addtogroup LPS22HB + * @ingroup EX_ST + * @{ + */ +#ifndef _LPS22HB_H_ +#define _LPS22HB_H_ + +#include "ex_barometer.h" +#include "ex_thermometer.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Version identification + * @{ + */ +/** + * @brief LPS22HB driver version string. + */ +#define EX_LPS22HB_VERSION "1.0.2" + +/** + * @brief LPS22HB driver version major number. + */ +#define EX_LPS22HB_MAJOR 1 + +/** + * @brief LPS22HB driver version minor number. + */ +#define EX_LPS22HB_MINOR 0 + +/** + * @brief LPS22HB driver version patch number. + */ +#define EX_LPS22HB_PATCH 2 +/** @} */ + +/** + * @brief LPS22HB barometer subsystem characteristics. + * @note Sensitivity is expressed as hPa/LSB whereas hPa stand for + * hectopascal. + * @note Bias is expressed as hPa. + * + * @{ + */ +#define LPS22HB_BARO_NUMBER_OF_AXES 1U + +#define LPS22HB_BARO_SENS 0.00024414f +#define LPS22HB_BARO_BIAS 0.0f +/** @} */ + +/** + * @brief LPS22HB thermometer subsystem characteristics. + * @note Sensitivity is expressed as �C/LSB. + * @note Bias is expressed as �C. + * + * @{ + */ +#define LPS22HB_THERMO_NUMBER_OF_AXES 1U + +#define LPS22HB_THERMO_SENS 0.01f +#define LPS22HB_THERMO_BIAS 0.0f +/** @} */ + +/** + * @name LPS22HB communication interfaces related bit masks + * @{ + */ +#define LPS22HB_DI_MASK 0xFF +#define LPS22HB_DI(n) (1 << n) +#define LPS22HB_AD_MASK 0x3F +#define LPS22HB_AD(n) (1 << n) +#define LPS22HB_MS (1 << 6) +#define LPS22HB_RW (1 << 7) + +#define LPS22HB_SUB_MS (1 << 7) +/** @} */ + +/** + * @name LPS22HB register addresses + * @{ + */ +#define LPS22HB_AD_INT_CFG 0x0B +#define LPS22HB_AD_THS_P_L 0x0C +#define LPS22HB_AD_THS_P_H 0x0D +#define LPS22HB_AD_WHO_AM_I 0x0F +#define LPS22HB_AD_CTRL_REG1 0x10 +#define LPS22HB_AD_CTRL_REG2 0x11 +#define LPS22HB_AD_CTRL_REG3 0x12 +#define LPS22HB_AD_FIFO_CTRL 0x14 +#define LPS22HB_AD_REF_P_XL 0x15 +#define LPS22HB_AD_REF_P_L 0x16 +#define LPS22HB_AD_REF_P_H 0x17 +#define LPS22HB_AD_RPDS_L 0x18 +#define LPS22HB_AD_RPDS_H 0x19 +#define LPS22HB_AD_RES_CONF 0x1A +#define LPS22HB_AD_INT_SRC 0x25 +#define LPS22HB_AD_FIFO_SRC 0x26 +#define LPS22HB_AD_STATUS_REG 0x27 +#define LPS22HB_AD_PRESS_OUT_XL 0x28 +#define LPS22HB_AD_PRESS_OUT_L 0x29 +#define LPS22HB_AD_PRESS_OUT_H 0x2A +#define LPS22HB_AD_TEMP_OUT_L 0x2B +#define LPS22HB_AD_TEMP_OUT_H 0x2C +#define LPS22HB_AD_LPFP_RES 0x33 +/** @} */ + +/** + * @name LPS22HB_INT_CFG register bits definitions + * @{ + */ +#define LPS22HB_INT_CFG_MASK 0xFF +#define LPS22HB_INT_CFG_PHE (1 << 0) +#define LPS22HB_INT_CFG_PLE (1 << 1) +#define LPS22HB_INT_CFG_LIR (1 << 2) +#define LPS22HB_INT_CFG_DIFF_EN (1 << 3) +#define LPS22HB_INT_CFG_RESET_AZ (1 << 4) +#define LPS22HB_INT_CFG_AUTOZERO (1 << 5) +#define LPS22HB_INT_CFG_RESET_ARP (1 << 6) +#define LPS22HB_INT_CFG_AUTORIFP (1 << 7) +/** @} */ + +/** + * @name LPS22HB_CTRL_REG1 register bits definitions + * @{ + */ +#define LPS22HB_CTRL_REG1_MASK 0x7F +#define LPS22HB_CTRL_REG1_SIM (1 << 0) +#define LPS22HB_CTRL_REG1_BDU (1 << 1) +#define LPS22HB_CTRL_REG1_LPFP_CFG (1 << 2) +#define LPS22HB_CTRL_REG1_LPFP_EN (1 << 3) +#define LPS22HB_CTRL_REG1_ODR0 (1 << 4) +#define LPS22HB_CTRL_REG1_ODR1 (1 << 5) +#define LPS22HB_CTRL_REG1_ODR2 (1 << 6) +/** @} */ + +/** + * @name LPS22HB_CTRL_REG2 register bits definitions + * @{ + */ +#define LPS22HB_CTRL_REG2_MASK 0xFD +#define LPS22HB_CTRL_REG2_ONE_SHOT (1 << 0) +#define LPS22HB_CTRL_REG2_SWRESET (1 << 2) +#define LPS22HB_CTRL_REG2_I2C_DIS (1 << 3) +#define LPS22HB_CTRL_REG2_IF_ADD_INC (1 << 4) +#define LPS22HB_CTRL_REG2_STOP_ON_FTH (1 << 5) +#define LPS22HB_CTRL_REG2_FIFO_EN (1 << 6) +#define LPS22HB_CTRL_REG2_BOOT (1 << 7) +/** @} */ + +/** + * @name LPS22HB_CTRL_REG3 register bits definitions + * @{ + */ +#define LPS22HB_CTRL_REG3_MASK 0xFF +#define LPS22HB_CTRL_REG3_INT_S1 (1 << 0) +#define LPS22HB_CTRL_REG3_INT_S2 (1 << 1) +#define LPS22HB_CTRL_REG3_DRDY (1 << 2) +#define LPS22HB_CTRL_REG3_F_OVR (1 << 3) +#define LPS22HB_CTRL_REG3_F_FTH (1 << 4) +#define LPS22HB_CTRL_REG3_F_FSS5 (1 << 5) +#define LPS22HB_CTRL_REG3_PP_OD (1 << 6) +#define LPS22HB_CTRL_REG3_INT_H_L (1 << 7) +/** @} */ + +/** + * @name LPS22HB_INT_SRC register bits definitions + * @{ + */ +#define LPS22HB_INT_SRC_MASK 0x87 +#define LPS22HB_INT_SRC_PH (1 << 0) +#define LPS22HB_INT_SRC_PL (1 << 1) +#define LPS22HB_INT_SRC_IA (1 << 2) +#define LPS22HB_INT_SRC_BOOT_STATUS (1 << 8) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief LPS22HB SPI interface switch. + * @details If set to @p TRUE the support for SPI is included. + * @note The default is @p FALSE. + */ +#if !defined(LPS22HB_USE_SPI) || defined(__DOXYGEN__) +#define LPS22HB_USE_SPI FALSE +#endif + +/** + * @brief LPS22HB shared SPI switch. + * @details If set to @p TRUE the device acquires SPI bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LPS22HB_SHARED_SPI) || defined(__DOXYGEN__) +#define LPS22HB_SHARED_SPI FALSE +#endif + +/** + * @brief LPS22HB I2C interface switch. + * @details If set to @p TRUE the support for I2C is included. + * @note The default is @p TRUE. + */ +#if !defined(LPS22HB_USE_I2C) || defined(__DOXYGEN__) +#define LPS22HB_USE_I2C TRUE +#endif + +/** + * @brief LPS22HB shared I2C switch. + * @details If set to @p TRUE the device acquires I2C bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LPS22HB_SHARED_I2C) || defined(__DOXYGEN__) +#define LPS22HB_SHARED_I2C FALSE +#endif + +/** + * @brief LPS22HB advanced configurations switch. + * @details If set to @p TRUE more configurations are available. + * @note The default is @p FALSE. + */ +#if !defined(LPS22HB_USE_ADVANCED) || defined(__DOXYGEN__) +#define LPS22HB_USE_ADVANCED FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !(LPS22HB_USE_SPI ^ LPS22HB_USE_I2C) +#error "LPS22HB_USE_SPI and LPS22HB_USE_I2C cannot be both true or both false" +#endif + +#if LPS22HB_USE_SPI && !HAL_USE_SPI +#error "LPS22HB_USE_SPI requires HAL_USE_SPI" +#endif + +#if LPS22HB_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION +#error "LPS22HB_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" +#endif + +#if LPS22HB_USE_I2C && !HAL_USE_I2C +#error "LPS22HB_USE_I2C requires HAL_USE_I2C" +#endif + +#if LPS22HB_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION +#error "LPS22HB_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" +#endif + +/* + * CHTODO: Add support for LPS22HB over SPI. + */ +#if LPS22HB_USE_SPI +#error "LPS22HB over SPI still not supported" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @name LPS22HB data structures and types. + * @{ + */ +/** + * @brief Structure representing a LPS22HB driver. + */ +typedef struct LPS22HBDriver LPS22HBDriver; + +/** + * @brief LPS22HB slave address + */ +typedef enum { + LPS22HB_SAD_GND = 0x5C, /**< Slave Address when SA0 is to GND */ + LPS22HB_SAD_VCC = 0x5D /**< Slave Address when SA0 is to VCC */ +}lps22hb_sad_t; + +/** + * @brief LPS22HB output data rate and bandwidth. + */ +typedef enum { + LPS22HB_ODR_PD = 0x00, /**< Power down. */ + LPS22HB_ODR_1HZ = 0x10, /**< Output data rate 1 Hz. */ + LPS22HB_ODR_10HZ = 0x20, /**< Output data rate 10 Hz. */ + LPS22HB_ODR_25HZ = 0x30, /**< Output data rate 25 Hz. */ + LPS22HB_ODR_50HZ = 0x40, /**< Output data rate 50 Hz. */ + LPS22HB_ODR_75HZ = 0x50 /**< Output data rate 75 Hz. */ +}lps22hb_odr_t; + +/** + * @brief LPS22HB pressure resolution. + */ +typedef enum { + LPS22HB_LP_DISABLED = 0x00, /**< LP Filter disabled. */ + LPS22HB_LP_ODR_9 = 0x08, /**< LP Filter enabled. Cut-off ORD/9. */ + LPS22HB_LP_ODR_20 = 0x0C /**< LP Filter enabled. Cut-off ORD/20. */ +}lps22hb_lp_t; + +/** + * @brief LPS22HB block data update. + */ +typedef enum { + LPS22HB_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */ + LPS22HB_BDU_BLOCKED = 0x40 /**< Block data updated after reading. */ +}lps22hb_bdu_t; + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + LPS22HB_UNINIT = 0, /**< Not initialized. */ + LPS22HB_STOP = 1, /**< Stopped. */ + LPS22HB_READY = 2, /**< Ready. */ +} lps22hb_state_t; + +/** + * @brief LPS22HB configuration structure. + */ +typedef struct { + +#if LPS22HB_USE_SPI || defined(__DOXYGEN__) + /** + * @brief SPI driver associated to this LPS22HB. + */ + SPIDriver *spip; + /** + * @brief SPI configuration associated to this LPS22HB. + */ + const SPIConfig *spicfg; +#endif /* LPS22HB_USE_SPI */ +#if LPS22HB_USE_I2C || defined(__DOXYGEN__) + /** + * @brief I2C driver associated to this LPS22HB. + */ + I2CDriver *i2cp; + /** + * @brief I2C configuration associated to this LPS22HB. + */ + const I2CConfig *i2ccfg; + /** + * @brief LPS22HB slave address + */ + lps22hb_sad_t slaveaddress; +#endif /* LPS22HB_USE_I2C */ + /** + * @brief LPS22HB barometer subsystem initial sensitivity. + */ + float *barosensitivity; + /** + * @brief LPS22HB barometer subsystem initial bias. + */ + float *barobias; + /** + * @brief LPS22HB thermometer subsystem initial sensitivity. + */ + float *thermosensitivity; + /** + * @brief LPS22HB thermometer subsystem initial bias. + */ + float *thermobias; + /** + * @brief LPS22HB output data rate selection. + */ + lps22hb_odr_t outputdatarate; +#if LPS22HB_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief LPS22HB block data update. + */ + lps22hb_bdu_t blockdataupdate; + /** + * @brief LPS22HB barometer subsystem resolution. + */ + lps22hb_lp_t lowpass_filter; +#endif +} LPS22HBConfig; + +/** + * @brief @p LPS22HB specific methods. + * @note No methods so far, just a common ancestor interface. + */ +#define _lps22hb_methods_alone + +/** + * @brief @p LPS22HB specific methods with inherited ones. + */ +#define _lps22hb_methods \ + _base_object_methods \ + _lps22hb_methods_alone + +/** + * @extends BaseObjectVMT + * + * @brief @p LPS22HB virtual methods table. + */ +struct LPS22HBVMT { + _lps22hb_methods +}; + +/** + * @brief @p LPS22HBDriver specific data. + */ +#define _lps22hb_data \ + /* Driver state.*/ \ + lps22hb_state_t state; \ + /* Current configuration data.*/ \ + const LPS22HBConfig *config; \ + /* Barometer subsystem axes number.*/ \ + size_t baroaxes; \ + /* Barometer subsystem current sensitivity.*/ \ + float barosensitivity; \ + /* Barometer subsystem current bias .*/ \ + float barobias; \ + /* Thermometer subsystem axes number.*/ \ + size_t thermoaxes; \ + /* Thermometer subsystem current sensitivity.*/ \ + float thermosensitivity; \ + /* Thermometer subsystem current bias.*/ \ + float thermobias; + +/** + * @brief LPS22HB 2-axis barometer/thermometer class. + */ +struct LPS22HBDriver { + /** @brief Virtual Methods Table.*/ + const struct LPS22HBVMT *vmt; + /** @brief Base barometer interface.*/ + BaseBarometer baro_if; + /** @brief Base thermometer interface.*/ + BaseThermometer thermo_if; + _lps22hb_data +}; +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Return the number of axes of the BaseBarometer. + * + * @param[in] devp pointer to @p LPS22HBDriver. + * + * @return the number of axes. + * + * @api + */ +#define lps22hbBarometerGetAxesNumber(devp) \ + barometerGetAxesNumber(&((devp)->baro_if)) + +/** + * @brief Retrieves raw data from the BaseBarometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] devp pointer to @p LPS22HBDriver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lps22hbBarometerReadRaw(devp, axes) \ + barometerReadRaw(&((devp)->baro_if), axes) + +/** + * @brief Retrieves cooked data from the BaseBarometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as hPa. + * @note The axes array must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] devp pointer to @p LPS22HBDriver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lps22hbBarometerReadCooked(devp, axes) \ + barometerReadCooked(&((devp)->baro_if), axes) + +/** + * @brief Set bias values for the BaseBarometer. + * @note Bias must be expressed as hPa. + * @note The bias buffer must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] devp pointer to @p LPS22HBDriver. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps22hbBarometerSetBias(devp, bp) \ + barometerSetBias(&((devp)->baro_if), bp) + +/** + * @brief Reset bias values for the BaseBarometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p LPS22HBDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps22hbBarometerResetBias(devp) \ + barometerResetBias(&((devp)->baro_if)) + +/** + * @brief Set sensitivity values for the BaseBarometer. + * @note Sensitivity must be expressed as hPa/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] devp pointer to @p LPS22HBDriver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps22hbBarometerSetSensitivity(devp, sp) \ + barometerSetSensitivity(&((devp)->baro_if), sp) + +/** + * @brief Reset sensitivity values for the BaseBarometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p LPS22HBDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps22hbBarometerResetSensitivity(devp) \ + barometerResetSensitivity(&((devp)->baro_if)) + +/** + * @brief Return the number of axes of the BaseThermometer. + * + * @param[in] devp pointer to @p LPS22HBDriver. + * + * @return the number of axes. + * + * @api + */ +#define lps22hbThermometerGetAxesNumber(devp) \ + thermometerGetAxesNumber(&((devp)->thermo_if)) + +/** + * @brief Retrieves raw data from the BaseThermometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] devp pointer to @p LPS22HBDriver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lps22hbThermometerReadRaw(devp, axes) \ + thermometerReadRaw(&((devp)->thermo_if), axes) + +/** + * @brief Retrieves cooked data from the BaseThermometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as °C. + * @note The axes array must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] devp pointer to @p LPS22HBDriver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lps22hbThermometerReadCooked(devp, axes) \ + thermometerReadCooked(&((devp)->thermo_if), axes) + +/** + * @brief Set bias values for the BaseThermometer. + * @note Bias must be expressed as °C. + * @note The bias buffer must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] devp pointer to @p LPS22HBDriver. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps22hbThermometerSetBias(devp, bp) \ + thermometerSetBias(&((devp)->thermo_if), bp) + +/** + * @brief Reset bias values for the BaseThermometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p LPS22HBDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps22hbThermometerResetBias(devp) \ + thermometerResetBias(&((devp)->thermo_if)) + +/** + * @brief Set sensitivity values for the BaseThermometer. + * @note Sensitivity must be expressed as °C/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] devp pointer to @p LPS22HBDriver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps22hbThermometerSetSensitivity(devp, sp) \ + thermometerSetSensitivity(&((devp)->thermo_if), sp) + +/** + * @brief Reset sensitivity values for the BaseThermometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p LPS22HBDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps22hbThermometerResetSensitivity(devp) \ + thermometerResetSensitivity(&((devp)->thermo_if)) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void lps22hbObjectInit(LPS22HBDriver *devp); + void lps22hbStart(LPS22HBDriver *devp, const LPS22HBConfig *config); + void lps22hbStop(LPS22HBDriver *devp); +#ifdef __cplusplus +} +#endif + +#endif /* _LPS22HB_H_ */ + +/** @} */ + diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.mk b/ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.mk new file mode 100644 index 0000000..47fe88e --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.mk @@ -0,0 +1,10 @@ +# List of all the LPS22HB device files. +LPS22HBSRC := $(CHIBIOS)/os/ex/devices/ST/lps22hb.c + +# Required include directories +LPS22HBINC := $(CHIBIOS)/os/ex/include \ + $(CHIBIOS)/os/ex/devices/ST + +# Shared variables +ALLCSRC += $(LPS22HBSRC) +ALLINC += $(LPS22HBINC) \ No newline at end of file diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lps25h.c b/ChibiOS_20.3.2/os/ex/devices/ST/lps25h.c new file mode 100644 index 0000000..3aa651f --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lps25h.c @@ -0,0 +1,696 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lps25h.c + * @brief LPS25H MEMS interface module code. + * + * @addtogroup LPS25H + * @ingroup EX_ST + * @{ + */ + +#include "hal.h" +#include "lps25h.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if (LPS25H_USE_I2C) || defined(__DOXYGEN__) +/** + * @brief Reads registers value using I2C. + * @pre The I2C interface must be initialized and the driver started. + * + * @param[in] i2cp pointer to the I2C interface + * @param[in] sad slave address without R bit + * @param[in] reg first sub-register address + * @param[out] rxbuf pointer to an output buffer + * @param[in] n number of consecutive register to read + * @return the operation status. + * + * @notapi + */ +static msg_t lps25hI2CReadRegister(I2CDriver *i2cp, lps25h_sad_t sad, + uint8_t reg, uint8_t* rxbuf, size_t n) { + uint8_t txbuf = reg; + if(n > 1) + txbuf |= LPS25H_SUB_MS; + + return i2cMasterTransmitTimeout(i2cp, sad, &txbuf, 1, rxbuf, n, + TIME_INFINITE); +} + +/** + * @brief Writes a value into a register using I2C. + * @pre The I2C interface must be initialized and the driver started. + * + * @param[in] i2cp pointer to the I2C interface + * @param[in] sad slave address without R bit + * @param[in] txbuf buffer containing sub-address value in first position + * and values to write + * @param[in] n size of txbuf less one (not considering the first + * element) + * @return the operation status. + * + * @notapi + */ +static msg_t lps25hI2CWriteRegister(I2CDriver *i2cp, lps25h_sad_t sad, + uint8_t* txbuf, size_t n) { + if (n > 1) + (*txbuf) |= LPS25H_SUB_MS; + return i2cMasterTransmitTimeout(i2cp, sad, txbuf, n + 1, NULL, 0, + TIME_INFINITE); +} +#endif /* LPS25H_USE_I2C */ + +/** + * @brief Return the number of axes of the BaseBarometer. + * + * @param[in] ip pointer to @p BaseBarometer interface. + * + * @return the number of axes. + */ +static size_t baro_get_axes_number(void *ip) { + (void)ip; + + return LPS25H_BARO_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseBarometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] ip pointer to @p BaseBarometer interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t baro_read_raw(void *ip, int32_t axes[]) { + LPS25HDriver* devp; + uint8_t buff[3]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS25HDriver*, (BaseBarometer*)ip); + + osalDbgAssert((devp->state == LPS25H_READY), + "baro_read_raw(), invalid state"); + + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "baro_read_raw(), channel not ready"); + +#if LPS25H_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LPS25H_SHARED_I2C */ + + msg = lps25hI2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, + LPS25H_AD_PRESS_OUT_XL, buff, 3); + +#if LPS25H_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LPS25H_SHARED_I2C */ + + if(msg == MSG_OK) { + *axes = buff[0] + (buff[1] << 8) + (buff[2] << 16); + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseBarometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as hPa. + * @note The axes array must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] ip pointer to @p BaseBarometer interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t baro_read_cooked(void *ip, float axes[]) { + LPS25HDriver* devp; + int32_t raw; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS25HDriver*, (BaseBarometer*)ip); + + osalDbgAssert((devp->state == LPS25H_READY), + "baro_read_cooked(), invalid state"); + + msg = baro_read_raw(ip, &raw); + + *axes = (raw * devp->barosensitivity) - devp->barobias; + + return msg; +} + +/** + * @brief Set bias values for the BaseBarometer. + * @note Bias must be expressed as hPa. + * @note The bias buffer must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] ip pointer to @p BaseBarometer interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t baro_set_bias(void *ip, float *bp) { + LPS25HDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS25HDriver*, (BaseBarometer*)ip); + + osalDbgAssert((devp->state == LPS25H_READY), + "baro_set_bias(), invalid state"); + + devp->barobias = *bp; + return msg; +} + +/** + * @brief Reset bias values for the BaseBarometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseBarometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t baro_reset_bias(void *ip) { + LPS25HDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS25HDriver*, (BaseBarometer*)ip); + + osalDbgAssert((devp->state == LPS25H_READY), + "baro_reset_bias(), invalid state"); + + devp->barobias = LPS25H_BARO_SENS; + return msg; +} + +/** + * @brief Set sensitivity values for the BaseBarometer. + * @note Sensitivity must be expressed as hPa/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] ip pointer to @p BaseBarometer interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t baro_set_sensitivity(void *ip, float *sp) { + LPS25HDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (sp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS25HDriver*, (BaseBarometer*)ip); + + osalDbgAssert((devp->state == LPS25H_READY), + "baro_set_sensitivity(), invalid state"); + + devp->barosensitivity = *sp; + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseBarometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseBarometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t baro_reset_sensitivity(void *ip) { + LPS25HDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS25HDriver*, (BaseBarometer*)ip); + + osalDbgAssert((devp->state == LPS25H_READY), + "baro_reset_sensitivity(), invalid state"); + + devp->barosensitivity = LPS25H_BARO_SENS; + return msg; +} + +/** + * @brief Return the number of axes of the BaseThermometer. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * + * @return the number of axes. + */ +static size_t thermo_get_axes_number(void *ip) { + (void)ip; + + return LPS25H_THERMO_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseThermometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t thermo_read_raw(void *ip, int32_t axes[]) { + LPS25HDriver* devp; + int16_t tmp; + uint8_t buff[2]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS25HDriver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == LPS25H_READY), + "thermo_read_raw(), invalid state"); + + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "thermo_read_raw(), channel not ready"); + +#if LPS25H_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LPS25H_SHARED_I2C */ + + msg = lps25hI2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, + LPS25H_AD_TEMP_OUT_L, buff, 2); + +#if LPS25H_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LPS25H_SHARED_I2C */ + + if (msg == MSG_OK) { + tmp = buff[0] + (buff[1] << 8); + *axes = (int32_t)tmp; + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseThermometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as °C. + * @note The axes array must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * @param[out] axis a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t thermo_read_cooked(void *ip, float* axis) { + LPS25HDriver* devp; + int32_t raw; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axis != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS25HDriver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == LPS25H_READY), + "thermo_read_cooked(), invalid state"); + + msg = thermo_read_raw(devp, &raw); + + *axis = (raw * devp->thermosensitivity) - devp->thermobias; + + return msg; +} + +/** + * @brief Set bias values for the BaseThermometer. + * @note Bias must be expressed as °C. + * @note The bias buffer must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t thermo_set_bias(void *ip, float *bp) { + LPS25HDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS25HDriver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == LPS25H_READY), + "thermo_set_bias(), invalid state"); + + devp->thermobias = *bp; + + return msg; +} + +/** + * @brief Reset bias values for the BaseThermometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t thermo_reset_bias(void *ip) { + LPS25HDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS25HDriver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == LPS25H_READY), + "thermo_reset_bias(), invalid state"); + + devp->thermobias = LPS25H_THERMO_BIAS; + + return msg; +} + +/** + * @brief Set sensitivity values for the BaseThermometer. + * @note Sensitivity must be expressed as °C/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t thermo_set_sensitivity(void *ip, float *sp) { + LPS25HDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (sp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS25HDriver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == LPS25H_READY), + "thermo_set_sensitivity(), invalid state"); + + devp->thermosensitivity = *sp; + + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseThermometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseThermometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t thermo_reset_sensitivity(void *ip) { + LPS25HDriver* devp; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LPS25HDriver*, (BaseThermometer*)ip); + + osalDbgAssert((devp->state == LPS25H_READY), + "thermo_reset_sensitivity(), invalid state"); + + devp->thermosensitivity = LPS25H_THERMO_SENS; + + return msg; +} + +static const struct LPS25HVMT vmt_device = { + (size_t)0 +}; + +static const struct BaseBarometerVMT vmt_barometer = { + sizeof(struct LPS25HVMT*), + baro_get_axes_number, baro_read_raw, baro_read_cooked, + baro_set_bias, baro_reset_bias, baro_set_sensitivity, + baro_reset_sensitivity +}; + +static const struct BaseThermometerVMT vmt_thermometer = { + sizeof(struct LPS25HVMT*) + sizeof(BaseBarometer), + thermo_get_axes_number, thermo_read_raw, thermo_read_cooked, + thermo_set_bias, thermo_reset_bias, thermo_set_sensitivity, + thermo_reset_sensitivity +}; + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes an instance. + * + * @param[out] devp pointer to the @p LPS25HDriver object + * + * @init + */ +void lps25hObjectInit(LPS25HDriver *devp) { + + devp->vmt = &vmt_device; + devp->baro_if.vmt = &vmt_barometer; + devp->thermo_if.vmt = &vmt_thermometer; + + devp->config = NULL; + + devp->baroaxes = LPS25H_BARO_NUMBER_OF_AXES; + devp->thermoaxes = LPS25H_THERMO_NUMBER_OF_AXES; + + devp->state = LPS25H_STOP; +} + +/** + * @brief Configures and activates LPS25H Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LPS25HDriver object + * @param[in] config pointer to the @p LPS25HConfig object + * + * @api + */ +void lps25hStart(LPS25HDriver *devp, const LPS25HConfig *config) { + uint8_t cr[2]; + osalDbgCheck((devp != NULL) && (config != NULL)); + + osalDbgAssert((devp->state == LPS25H_STOP) || (devp->state == LPS25H_READY), + "lps25hStart(), invalid state"); + + devp->config = config; + + /* Control register 1 configuration block.*/ + { + cr[0] = LPS25H_AD_CTRL_REG1; + cr[1] = devp->config->outputdatarate | LPS25H_CTRL_REG1_PD; +#if LPS25H_USE_ADVANCED || defined(__DOXYGEN__) + cr[1] |= devp->config->blockdataupdate; +#endif + } + +#if LPS25H_SHARED_I2C + i2cAcquireBus((devp)->config->i2cp); +#endif /* LPS25H_SHARED_I2C */ + i2cStart((devp)->config->i2cp, + (devp)->config->i2ccfg); + + lps25hI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, cr, 1); + +#if LPS25H_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* LPS25H_SHARED_I2C */ + + /* Resolution configuration block.*/ + { + cr[0] = LPS25H_AD_RES_CONF; + cr[1] = 0x05; +#if LPS25H_USE_ADVANCED || defined(__DOXYGEN__) + cr[1] = devp->config->baroresolution | devp->config->thermoresolution; +#endif + + } +#if LPS25H_SHARED_I2C + i2cAcquireBus((devp)->config->i2cp); + i2cStart((devp)->config->i2cp, + (devp)->config->i2ccfg); +#endif /* LPS25H_SHARED_I2C */ + + lps25hI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + cr, 1); + +#if LPS25H_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* LPS25H_SHARED_I2C */ + + if(devp->config->barosensitivity == NULL) { + devp->barosensitivity = LPS25H_BARO_SENS; + } + else{ + /* Taking barometer sensitivity from user configurations */ + devp->barosensitivity = *(devp->config->barosensitivity); + } + + if(devp->config->barobias == NULL) { + devp->barobias = LPS25H_BARO_BIAS; + } + else{ + /* Taking barometer bias from user configurations */ + devp->barobias = *(devp->config->barobias); + } + + if(devp->config->thermosensitivity == NULL) { + devp->thermosensitivity = LPS25H_THERMO_SENS; + } + else{ + /* Taking thermometer sensitivity from user configurations */ + devp->thermosensitivity = *(devp->config->thermosensitivity); + } + + if(devp->config->thermobias == NULL) { + devp->thermobias = LPS25H_THERMO_BIAS; + } + else{ + /* Taking thermometer bias from user configurations */ + devp->thermobias = *(devp->config->thermobias); + } + + /* This is the Barometer transient recovery time */ + osalThreadSleepMilliseconds(5); + + devp->state = LPS25H_READY; +} + +/** + * @brief Deactivates the LPS25H Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LPS25HDriver object + * + * @api + */ +void lps25hStop(LPS25HDriver *devp) { + uint8_t cr[2]; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LPS25H_STOP) || (devp->state == LPS25H_READY), + "lps25hStop(), invalid state"); + + if (devp->state == LPS25H_READY) { +#if LPS25H_SHARED_I2C + i2cAcquireBus((devp)->config->i2cp); + i2cStart((devp)->config->i2cp, + (devp)->config->i2ccfg); +#endif /* LPS25H_SHARED_I2C */ + + cr[0] = LPS25H_AD_CTRL_REG1; + cr[1] = 0; + lps25hI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + cr, 1); + + i2cStop((devp)->config->i2cp); +#if LPS25H_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* LPS25H_SHARED_I2C */ + } + devp->state = LPS25H_STOP; +} +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lps25h.h b/ChibiOS_20.3.2/os/ex/devices/ST/lps25h.h new file mode 100644 index 0000000..3f3f022 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lps25h.h @@ -0,0 +1,740 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lps25h.h + * @brief LPS25H MEMS interface module header. + * + * @addtogroup LPS25H + * @ingroup EX_ST + * @{ + */ +#ifndef _LPS25H_H_ +#define _LPS25H_H_ + +#include "ex_barometer.h" +#include "ex_thermometer.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Version identification + * @{ + */ +/** + * @brief LPS25H driver version string. + */ +#define EX_LPS25H_VERSION "1.1.2" + +/** + * @brief LPS25H driver version major number. + */ +#define EX_LPS25H_MAJOR 1 + +/** + * @brief LPS25H driver version minor number. + */ +#define EX_LPS25H_MINOR 1 + +/** + * @brief LPS25H driver version patch number. + */ +#define EX_LPS25H_PATCH 2 +/** @} */ + +/** + * @brief LPS25H barometer subsystem characteristics. + * @note Sensitivity is expressed as hPa/LSB whereas hPa stand for + * hectopascal. + * @note Bias is expressed as hPa. + * + * @{ + */ +#define LPS25H_BARO_NUMBER_OF_AXES 1U + +#define LPS25H_BARO_SENS 0.00024414f +#define LPS25H_BARO_BIAS 0.0f +/** @} */ + +/** + * @brief LPS25H thermometer subsystem characteristics. + * @note Sensitivity is expressed as �C/LSB. + * @note Bias is expressed as �C. + * + * @{ + */ +#define LPS25H_THERMO_NUMBER_OF_AXES 1U + +#define LPS25H_THERMO_SENS 0.00208333f +#define LPS25H_THERMO_BIAS -42.5f +/** @} */ + +/** + * @name LPS25H communication interfaces related bit masks + * @{ + */ +#define LPS25H_DI_MASK 0xFF +#define LPS25H_DI(n) (1 << n) +#define LPS25H_AD_MASK 0x3F +#define LPS25H_AD(n) (1 << n) +#define LPS25H_MS (1 << 6) +#define LPS25H_RW (1 << 7) + +#define LPS25H_SUB_MS (1 << 7) +/** @} */ + +/** + * @name LPS25H register addresses + * @{ + */ +#define LPS25H_AD_REF_P_XL 0x08 +#define LPS25H_AD_REF_P_L 0x09 +#define LPS25H_AD_REF_P_H 0x0A +#define LPS25H_AD_WHO_AM_I 0x0F +#define LPS25H_AD_RES_CONF 0x10 +#define LPS25H_AD_CTRL_REG1 0x20 +#define LPS25H_AD_CTRL_REG2 0x21 +#define LPS25H_AD_CTRL_REG3 0x22 +#define LPS25H_AD_CTRL_REG4 0x23 +#define LPS25H_AD_INT_CFG 0x24 +#define LPS25H_AD_INT_SRC 0x25 +#define LPS25H_AD_STATUS_REG 0x27 +#define LPS25H_AD_PRESS_OUT_XL 0x28 +#define LPS25H_AD_PRESS_OUT_L 0x29 +#define LPS25H_AD_PRESS_OUT_H 0x2A +#define LPS25H_AD_TEMP_OUT_L 0x2B +#define LPS25H_AD_TEMP_OUT_H 0x2C +#define LPS25H_AD_FIFO_CTRL 0x2E +#define LPS25H_AD_FIFO_SRC 0x2F +#define LPS25H_AD_THS_P_L 0x30 +#define LPS25H_AD_THS_P_H 0x31 +#define LPS25H_AD_RPDS_L 0x39 +#define LPS25H_AD_RPDS_H 0x3A +/** @} */ + +/** + * @name LPS25H_CTRL_REG1 register bits definitions + * @{ + */ +#define LPS25H_CTRL_REG1_MASK 0xFF +#define LPS25H_CTRL_REG1_SIM (1 << 0) +#define LPS25H_CTRL_REG1_RESET_AZ (1 << 1) +#define LPS25H_CTRL_REG1_BDU (1 << 2) +#define LPS25H_CTRL_REG1_DIFF_EN (1 << 3) +#define LPS25H_CTRL_REG1_ODR0 (1 << 4) +#define LPS25H_CTRL_REG1_ODR1 (1 << 5) +#define LPS25H_CTRL_REG1_ODR2 (1 << 6) +#define LPS25H_CTRL_REG1_PD (1 << 7) +/** @} */ + +/** + * @name LPS25H_CTRL_REG2 register bits definitions + * @{ + */ +#define LPS25H_CTRL_REG2_MASK 0xF3 +#define LPS25H_CTRL_REG2_ONE_SHOT (1 << 0) +#define LPS25H_CTRL_REG2_AUTO_ZERO (1 << 1) +#define LPS25H_CTRL_REG2_SWRESET (1 << 2) +#define LPS25H_CTRL_REG2_FIFO_MEAN_DEC (1 << 4) +#define LPS25H_CTRL_REG2_WTM_EN (1 << 5) +#define LPS25H_CTRL_REG2_FIFO_EN (1 << 6) +#define LPS25H_CTRL_REG2_BOOT (1 << 7) +/** @} */ + +/** + * @name LPS25H_CTRL_REG3 register bits definitions + * @{ + */ +#define LPS25H_CTRL_REG3_MASK 0xC3 +#define LPS25H_CTRL_REG3_INT_S1 (1 << 0) +#define LPS25H_CTRL_REG3_INT_S2 (1 << 1) +#define LPS25H_CTRL_REG3_PP_OD (1 << 6) +#define LPS25H_CTRL_REG3_INT_H_L (1 << 7) +/** @} */ + +/** + * @name LPS25H_CTRL_REG4 register bits definitions + * @{ + */ +#define LPS25H_CTRL_REG4_MASK 0x0F +#define LPS25H_CTRL_REG4_P1_DRDY (1 << 0) +#define LPS25H_CTRL_REG4_P1_OVERRUN (1 << 1) +#define LPS25H_CTRL_REG4_P1_WTM (1 << 2) +#define LPS25H_CTRL_REG4_P1_EMPTY (1 << 3) +/** @} */ + +/** + * @name LPS25H_INT1_CFG register bits definitions + * @{ + */ +#define LPS25H_INT1_CFG_MASK 0x07 +#define LPS25H_INT1_CFG_PH_E (1 << 0) +#define LPS25H_INT1_CFG_PL_E (1 << 1) +#define LPS25H_INT1_CFG_LIR (1 << 2) +/** @} */ + +/** + * @name LPS25H_INT1_SRC register bits definitions + * @{ + */ +#define LPS25H_INT1_SRC_MASK 0x07 +#define LPS25H_INT1_SRC_PH (1 << 0) +#define LPS25H_INT1_SRC_PL (1 << 1) +#define LPS25H_INT1_SRC_IA (1 << 2) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief LPS25H SPI interface switch. + * @details If set to @p TRUE the support for SPI is included. + * @note The default is @p FALSE. + */ +#if !defined(LPS25H_USE_SPI) || defined(__DOXYGEN__) +#define LPS25H_USE_SPI FALSE +#endif + +/** + * @brief LPS25H shared SPI switch. + * @details If set to @p TRUE the device acquires SPI bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LPS25H_SHARED_SPI) || defined(__DOXYGEN__) +#define LPS25H_SHARED_SPI FALSE +#endif + +/** + * @brief LPS25H I2C interface switch. + * @details If set to @p TRUE the support for I2C is included. + * @note The default is @p TRUE. + */ +#if !defined(LPS25H_USE_I2C) || defined(__DOXYGEN__) +#define LPS25H_USE_I2C TRUE +#endif + +/** + * @brief LPS25H shared I2C switch. + * @details If set to @p TRUE the device acquires I2C bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LPS25H_SHARED_I2C) || defined(__DOXYGEN__) +#define LPS25H_SHARED_I2C FALSE +#endif + +/** + * @brief LPS25H advanced configurations switch. + * @details If set to @p TRUE more configurations are available. + * @note The default is @p FALSE. + */ +#if !defined(LPS25H_USE_ADVANCED) || defined(__DOXYGEN__) +#define LPS25H_USE_ADVANCED FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !(LPS25H_USE_SPI ^ LPS25H_USE_I2C) +#error "LPS25H_USE_SPI and LPS25H_USE_I2C cannot be both true or both false" +#endif + +#if LPS25H_USE_SPI && !HAL_USE_SPI +#error "LPS25H_USE_SPI requires HAL_USE_SPI" +#endif + +#if LPS25H_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION +#error "LPS25H_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" +#endif + +#if LPS25H_USE_I2C && !HAL_USE_I2C +#error "LPS25H_USE_I2C requires HAL_USE_I2C" +#endif + +#if LPS25H_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION +#error "LPS25H_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" +#endif + +/* + * CHTODO: Add support for LPS25H over SPI. + */ +#if LPS25H_USE_SPI +#error "LPS25H over SPI still not supported" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @name LPS25H data structures and types. + * @{ + */ +/** + * @brief Structure representing a LPS25H driver. + */ +typedef struct LPS25HDriver LPS25HDriver; + +/** + * @brief LPS25H slave address + */ +typedef enum { + LPS25H_SAD_GND = 0x5C, /**< Slave Address when SA0 is to GND */ + LPS25H_SAD_VCC = 0x5D /**< Slave Address when SA0 is to VCC */ +}lps25h_sad_t; + +/** + * @brief LPS25H output data rate and bandwidth. + */ +typedef enum { + LPS25H_ODR_ONE_SHOT = 0x00, /**< One shot. */ + LPS25H_ODR_1HZ = 0x10, /**< Output data rate 1 Hz. */ + LPS25H_ODR_7HZ = 0x20, /**< Output data rate 7 Hz. */ + LPS25H_ODR_12P5HZ = 0x30, /**< Output data rate 12.5 Hz. */ + LPS25H_ODR_25HZ = 0x40 /**< Output data rate 25 Hz. */ +}lps25h_odr_t; + +/** + * @brief LPS25H pressure resolution. + */ +typedef enum { + LPS25H_AVGP_8 = 0x00, /**< Number of internal average is 8. */ + LPS25H_AVGP_32 = 0x01, /**< Number of internal average is 32. */ + LPS25H_AVGP_128 = 0x02, /**< Number of internal average is 128. */ + LPS25H_AVGP_512 = 0x03, /**< Number of internal average is 512. */ +}lps25h_avgp_t; + +/** + * @brief LPS25H temperature resolution. + */ +typedef enum { + LPS25H_AVGT_8 = 0x00, /**< Number of internal average is 8. */ + LPS25H_AVGT_32 = 0x04, /**< Number of internal average is 32. */ + LPS25H_AVGT_128 = 0x08, /**< Number of internal average is 128. */ + LPS25H_AVGT_512 = 0x0C, /**< Number of internal average is 512. */ +}lps25h_avgt_t; + +/** + * @brief LPS25H block data update. + */ +typedef enum { + LPS25H_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */ + LPS25H_BDU_BLOCKED = 0x40 /**< Block data updated after reading. */ +}lps25h_bdu_t; + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + LPS25H_UNINIT = 0, /**< Not initialized. */ + LPS25H_STOP = 1, /**< Stopped. */ + LPS25H_READY = 2, /**< Ready. */ +} lps25h_state_t; + +/** + * @brief LPS25H configuration structure. + */ +typedef struct { + +#if LPS25H_USE_SPI || defined(__DOXYGEN__) + /** + * @brief SPI driver associated to this LPS25H. + */ + SPIDriver *spip; + /** + * @brief SPI configuration associated to this LPS25H. + */ + const SPIConfig *spicfg; +#endif /* LPS25H_USE_SPI */ +#if LPS25H_USE_I2C || defined(__DOXYGEN__) + /** + * @brief I2C driver associated to this LPS25H. + */ + I2CDriver *i2cp; + /** + * @brief I2C configuration associated to this LPS25H. + */ + const I2CConfig *i2ccfg; + /** + * @brief LPS25H slave address + */ + lps25h_sad_t slaveaddress; +#endif /* LPS25H_USE_I2C */ + /** + * @brief LPS25H barometer subsystem initial sensitivity. + */ + float *barosensitivity; + /** + * @brief LPS25H barometer subsystem initial bias. + */ + float *barobias; + /** + * @brief LPS25H thermometer subsystem initial sensitivity. + */ + float *thermosensitivity; + /** + * @brief LPS25H thermometer subsystem initial bias. + */ + float *thermobias; + /** + * @brief LPS25H output data rate selection. + */ + lps25h_odr_t outputdatarate; +#if LPS25H_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief LPS25H block data update. + */ + lps25h_bdu_t blockdataupdate; + /** + * @brief LPS25H barometer subsystem resolution. + */ + lps25h_avgp_t baroresolution; + /** + * @brief LPS25H thermometer subsystem resolution. + */ + lps25h_avgt_t thermoresolution; +#endif +} LPS25HConfig; + +/** + * @brief @p LPS25H specific methods. + * @note No methods so far, just a common ancestor interface. + */ +#define _lps25h_methods_alone + +/** + * @brief @p LPS25H specific methods with inherited ones. + */ +#define _lps25h_methods \ + _base_object_methods \ + _lps25h_methods_alone + +/** + * @extends BaseObjectVMT + * + * @brief @p LPS25H virtual methods table. + */ +struct LPS25HVMT { + _lps25h_methods +}; + +/** + * @brief @p LPS25HDriver specific data. + */ +#define _lps25h_data \ + /* Driver state.*/ \ + lps25h_state_t state; \ + /* Current configuration data.*/ \ + const LPS25HConfig *config; \ + /* Barometer subsystem axes number.*/ \ + size_t baroaxes; \ + /* Barometer subsystem current sensitivity.*/ \ + float barosensitivity; \ + /* Barometer subsystem current bias .*/ \ + float barobias; \ + /* Thermometer subsystem axes number.*/ \ + size_t thermoaxes; \ + /* Thermometer subsystem current sensitivity.*/ \ + float thermosensitivity; \ + /* Thermometer subsystem current bias.*/ \ + float thermobias; + +/** + * @brief LPS25H 2-axis barometer/thermometer class. + */ +struct LPS25HDriver { + /** @brief Virtual Methods Table.*/ + const struct LPS25HVMT *vmt; + /** @brief Base barometer interface.*/ + BaseBarometer baro_if; + /** @brief Base thermometer interface.*/ + BaseThermometer thermo_if; + _lps25h_data +}; +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Return the number of axes of the BaseBarometer. + * + * @param[in] devp pointer to @p LPS25HDriver. + * + * @return the number of axes. + * + * @api + */ +#define lps25hBarometerGetAxesNumber(devp) \ + barometerGetAxesNumber(&((devp)->baro_if)) + +/** + * @brief Retrieves raw data from the BaseBarometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] devp pointer to @p LPS25HDriver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lps25hBarometerReadRaw(devp, axes) \ + barometerReadRaw(&((devp)->baro_if), axes) + +/** + * @brief Retrieves cooked data from the BaseBarometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as hPa. + * @note The axes array must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] devp pointer to @p LPS25HDriver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lps25hBarometerReadCooked(devp, axes) \ + barometerReadCooked(&((devp)->baro_if), axes) + +/** + * @brief Set bias values for the BaseBarometer. + * @note Bias must be expressed as hPa. + * @note The bias buffer must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] devp pointer to @p LPS25HDriver. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps25hBarometerSetBias(devp, bp) \ + barometerSetBias(&((devp)->baro_if), bp) + +/** + * @brief Reset bias values for the BaseBarometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p LPS25HDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps25hBarometerResetBias(devp) \ + barometerResetBias(&((devp)->baro_if)) + +/** + * @brief Set sensitivity values for the BaseBarometer. + * @note Sensitivity must be expressed as hPa/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseBarometer axes number. + * + * @param[in] devp pointer to @p LPS25HDriver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps25hBarometerSetSensitivity(devp, sp) \ + barometerSetSensitivity(&((devp)->baro_if), sp) + +/** + * @brief Reset sensitivity values for the BaseBarometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p LPS25HDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps25hBarometerResetSensitivity(devp) \ + barometerResetSensitivity(&((devp)->baro_if)) + +/** + * @brief Return the number of axes of the BaseThermometer. + * + * @param[in] devp pointer to @p LPS25HDriver. + * + * @return the number of axes. + * + * @api + */ +#define lps25hThermometerGetAxesNumber(devp) \ + thermometerGetAxesNumber(&((devp)->thermo_if)) + +/** + * @brief Retrieves raw data from the BaseThermometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] devp pointer to @p LPS25HDriver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lps25hThermometerReadRaw(devp, axes) \ + thermometerReadRaw(&((devp)->thermo_if), axes) + +/** + * @brief Retrieves cooked data from the BaseThermometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as °C. + * @note The axes array must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] devp pointer to @p LPS25HDriver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lps25hThermometerReadCooked(devp, axes) \ + thermometerReadCooked(&((devp)->thermo_if), axes) + +/** + * @brief Set bias values for the BaseThermometer. + * @note Bias must be expressed as °C. + * @note The bias buffer must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] devp pointer to @p LPS25HDriver. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps25hThermometerSetBias(devp, bp) \ + thermometerSetBias(&((devp)->thermo_if), bp) + +/** + * @brief Reset bias values for the BaseThermometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p LPS25HDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps25hThermometerResetBias(devp) \ + thermometerResetBias(&((devp)->thermo_if)) + +/** + * @brief Set sensitivity values for the BaseThermometer. + * @note Sensitivity must be expressed as °C/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseThermometer axes number. + * + * @param[in] devp pointer to @p LPS25HDriver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps25hThermometerSetSensitivity(devp, sp) \ + thermometerSetSensitivity(&((devp)->thermo_if), sp) + +/** + * @brief Reset sensitivity values for the BaseThermometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p LPS25HDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lps25hThermometerResetSensitivity(devp) \ + thermometerResetSensitivity(&((devp)->thermo_if)) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void lps25hObjectInit(LPS25HDriver *devp); + void lps25hStart(LPS25HDriver *devp, const LPS25HConfig *config); + void lps25hStop(LPS25HDriver *devp); +#ifdef __cplusplus +} +#endif + +#endif /* _LPS25H_H_ */ + +/** @} */ + diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lps25h.mk b/ChibiOS_20.3.2/os/ex/devices/ST/lps25h.mk new file mode 100644 index 0000000..2cdaf78 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lps25h.mk @@ -0,0 +1,10 @@ +# List of all the LPS25H device files. +LPS25HSRC := $(CHIBIOS)/os/ex/devices/ST/lps25h.c + +# Required include directories +LPS25HINC := $(CHIBIOS)/os/ex/include \ + $(CHIBIOS)/os/ex/devices/ST + +# Shared variables +ALLCSRC += $(LPS25HSRC) +ALLINC += $(LPS25HINC) \ No newline at end of file diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.c b/ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.c new file mode 100644 index 0000000..6a4c3cd --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.c @@ -0,0 +1,906 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lsm303agr.c + * @brief LSM303AGR MEMS interface module code. + * + * @addtogroup LSM303AGR + * @ingroup EX_ST + * @{ + */ + +#include "hal.h" +#include "lsm303agr.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief Accelerometer and Compass Slave Address. + */ +typedef enum { + LSM303AGR_SAD_ACC = 0x19, /**< SAD for accelerometer. */ + LSM303AGR_SAD_COMP = 0x1E /**< SAD for compass. */ +} lsm303agr_sad_t; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Reads registers value using I2C. + * @pre The I2C interface must be initialized and the driver started. + * @note IF_ADD_INC bit must be 1 in CTRL_REG8. + * + * @param[in] i2cp pointer to the I2C interface. + * @param[in] sad slave address without R bit. + * @param[in] reg first sub-register address. + * @param[in] rxbuf receiving buffer. + * @param[in] n size of rxbuf. + * @return the operation status. + */ +static msg_t lsm303agrI2CReadRegister(I2CDriver *i2cp, lsm303agr_sad_t sad, + uint8_t reg, uint8_t *rxbuf, size_t n) { + + uint8_t txbuf = reg | LSM303AGR_MS; + return i2cMasterTransmitTimeout(i2cp, sad, &txbuf, 1, rxbuf, n, + TIME_INFINITE); +} + +/** + * @brief Writes a value into a register using I2C. + * @pre The I2C interface must be initialized and the driver started. + * + * @param[in] i2cp pointer to the I2C interface. + * @param[in] sad slave address without R bit. + * @param[in] txbuf buffer containing sub-address value in first position + * and values to write. + * @param[in] n size of txbuf less one (not considering the first + * element). + * @return the operation status. + */ +static msg_t lsm303agrI2CWriteRegister(I2CDriver *i2cp, lsm303agr_sad_t sad, + uint8_t *txbuf, size_t n) { + if (n != 1) + *txbuf |= LSM303AGR_MS; + return i2cMasterTransmitTimeout(i2cp, sad, txbuf, n + 1, NULL, 0, + TIME_INFINITE); +} + +/** + * @brief Return the number of axes of the BaseAccelerometer. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return the number of axes. + */ +static size_t acc_get_axes_number(void *ip) { + (void)ip; + + return LSM303AGR_ACC_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseAccelerometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t acc_read_raw(void *ip, int32_t axes[]) { + LSM303AGRDriver* devp; + uint8_t buff [LSM303AGR_ACC_NUMBER_OF_AXES * 2], i; + int16_t tmp; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303AGRDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM303AGR_READY), + "acc_read_raw(), invalid state"); + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "acc_read_raw(), channel not ready"); + +#if LSM303AGR_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM303AGR_SHARED_I2C */ + + msg = lsm303agrI2CReadRegister(devp->config->i2cp, LSM303AGR_SAD_ACC, + LSM303AGR_AD_OUT_X_L_A, buff, + LSM303AGR_ACC_NUMBER_OF_AXES * 2); + +#if LSM303AGR_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM303AGR_SHARED_I2C */ + + if(msg == MSG_OK) + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { + tmp = buff[2 * i] + (buff[2 * i + 1] << 8); + axes[i] = (int32_t)tmp; + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseAccelerometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as milli-G. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t acc_read_cooked(void *ip, float axes[]) { + LSM303AGRDriver* devp; + uint32_t i; + int32_t raw[LSM303AGR_ACC_NUMBER_OF_AXES]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303AGRDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM303AGR_READY), + "acc_read_cooked(), invalid state"); + + msg = acc_read_raw(ip, raw); + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { + axes[i] = (raw[i] * devp->accsensitivity[i]) - devp->accbias[i]; + } + return msg; +} + +/** + * @brief Set bias values for the BaseAccelerometer. + * @note Bias must be expressed as milli-G. + * @note The bias buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_set_bias(void *ip, float *bp) { + LSM303AGRDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303AGRDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM303AGR_READY), + "acc_set_bias(), invalid state"); + + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { + devp->accbias[i] = bp[i]; + } + return msg; +} + +/** + * @brief Reset bias values for the BaseAccelerometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_reset_bias(void *ip) { + LSM303AGRDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303AGRDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM303AGR_READY), + "acc_reset_bias(), invalid state"); + + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = LSM303AGR_ACC_BIAS; + return msg; +} + +/** + * @brief Set sensitivity values for the BaseAccelerometer. + * @note Sensitivity must be expressed as milli-G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_set_sensivity(void *ip, float *sp) { + LSM303AGRDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303AGRDriver*, (BaseAccelerometer*)ip); + + osalDbgCheck((ip != NULL) && (sp != NULL)); + + osalDbgAssert((devp->state == LSM303AGR_READY), + "acc_set_sensivity(), invalid state"); + + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] = sp[i]; + } + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseAccelerometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t acc_reset_sensivity(void *ip) { + LSM303AGRDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303AGRDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM303AGR_READY), + "acc_reset_sensivity(), invalid state"); + + if(devp->config->accfullscale == LSM303AGR_ACC_FS_2G) { + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] = LSM303AGR_ACC_SENS_2G; + } + } + else if(devp->config->accfullscale == LSM303AGR_ACC_FS_4G) { + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] = LSM303AGR_ACC_SENS_4G; + } + } + else if(devp->config->accfullscale == LSM303AGR_ACC_FS_8G) { + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] = LSM303AGR_ACC_SENS_8G; + } + } + else if(devp->config->accfullscale == LSM303AGR_ACC_FS_16G) { + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] = LSM303AGR_ACC_SENS_16G; + } + } + else { + osalDbgAssert(FALSE, "reset_sensivity(), accelerometer full scale issue"); + msg = MSG_RESET; + } + return msg; +} + +/** + * @brief Changes the LSM303AGRDriver accelerometer fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LSM303AGRDriver interface. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t acc_set_full_scale(LSM303AGRDriver *devp, + lsm303agr_acc_fs_t fs) { + float newfs, scale; + uint8_t i, buff[2]; + msg_t msg; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LSM303AGR_READY), + "acc_set_full_scale(), invalid state"); + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "acc_set_full_scale(), channel not ready"); + + /* Computing new fullscale value.*/ + if(fs == LSM303AGR_ACC_FS_2G) { + newfs = LSM303AGR_ACC_2G; + } + else if(fs == LSM303AGR_ACC_FS_4G) { + newfs = LSM303AGR_ACC_4G; + } + else if(fs == LSM303AGR_ACC_FS_8G) { + newfs = LSM303AGR_ACC_8G; + } + else if(fs == LSM303AGR_ACC_FS_16G) { + newfs = LSM303AGR_ACC_16G; + } + else { + msg = MSG_RESET; + return msg; + } + + if(newfs != devp->accfullscale) { + /* Computing scale value.*/ + scale = newfs / devp->accfullscale; + devp->accfullscale = newfs; + +#if LSM303AGR_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM303AGR_SHARED_I2C */ + + /* Updating register.*/ + msg = lsm303agrI2CReadRegister(devp->config->i2cp, + LSM303AGR_SAD_ACC, + LSM303AGR_AD_CTRL_REG4_A, + &buff[1], 1); + +#if LSM303AGR_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM303AGR_SHARED_I2C */ + + if(msg != MSG_OK) + return msg; + + buff[1] &= ~(LSM303AGR_CTRL_REG4_A_FS_MASK); + buff[1] |= fs; + buff[0] = LSM303AGR_AD_CTRL_REG4_A; + +#if LSM303AGR_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* LSM303AGR_SHARED_I2C */ + + msg = lsm303agrI2CWriteRegister(devp->config->i2cp, + LSM303AGR_SAD_ACC, buff, 1); + +#if LSM303AGR_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM303AGR_SHARED_I2C */ + + if(msg != MSG_OK) + return msg; + + /* Scaling sensitivity and bias. Re-calibration is suggested anyway.*/ + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] *= scale; + devp->accbias[i] *= scale; + } + } + return msg; +} + +/** + * @brief Return the number of axes of the BaseCompass. + * + * @param[in] ip pointer to @p BaseCompass interface + * + * @return the number of axes. + */ +static size_t comp_get_axes_number(void *ip) { + + osalDbgCheck(ip != NULL); + return LSM303AGR_COMP_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseCompass. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] ip pointer to @p BaseCompass interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t comp_read_raw(void *ip, int32_t axes[]) { + LSM303AGRDriver* devp; + uint8_t buff [LSM303AGR_COMP_NUMBER_OF_AXES * 2], i; + int16_t tmp; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303AGRDriver*, (BaseCompass*)ip); + + osalDbgAssert((devp->state == LSM303AGR_READY), + "comp_read_raw(), invalid state"); + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "comp_read_raw(), channel not ready"); + +#if LSM303AGR_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM303AGR_SHARED_I2C */ + msg = lsm303agrI2CReadRegister(devp->config->i2cp, LSM303AGR_SAD_COMP, + LSM303AGR_AD_OUTX_L_REG_M, buff, + LSM303AGR_COMP_NUMBER_OF_AXES * 2); + +#if LSM303AGR_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM303AGR_SHARED_I2C */ + + if(msg == MSG_OK) + for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) { + tmp = buff[2 * i] + (buff[2 * i + 1] << 8); + axes[i] = (int32_t)tmp; + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseCompass. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as G. + * @note The axes array must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] ip pointer to @p BaseCompass interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t comp_read_cooked(void *ip, float axes[]) { + LSM303AGRDriver* devp; + uint32_t i; + int32_t raw[LSM303AGR_COMP_NUMBER_OF_AXES]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303AGRDriver*, (BaseCompass*)ip); + + osalDbgAssert((devp->state == LSM303AGR_READY), + "comp_read_cooked(), invalid state"); + + msg = comp_read_raw(ip, raw); + for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES ; i++) { + axes[i] = (raw[i] * devp->compsensitivity[i]) - devp->compbias[i]; + } + return msg; +} + +/** + * @brief Set bias values for the BaseCompass. + * @note Bias must be expressed as G. + * @note The bias buffer must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] ip pointer to @p BaseCompass interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t comp_set_bias(void *ip, float *bp) { + LSM303AGRDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303AGRDriver*, (BaseCompass*)ip); + + osalDbgAssert((devp->state == LSM303AGR_READY), + "comp_set_bias(), invalid state"); + + for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) { + devp->compbias[i] = bp[i]; + } + return msg; +} + +/** + * @brief Reset bias values for the BaseCompass. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseCompass interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t comp_reset_bias(void *ip) { + LSM303AGRDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303AGRDriver*, (BaseCompass*)ip); + + osalDbgAssert((devp->state == LSM303AGR_READY), + "comp_reset_bias(), invalid state"); + + for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) + devp->compbias[i] = LSM303AGR_COMP_BIAS; + return msg; +} + +/** + * @brief Set sensitivity values for the BaseCompass. + * @note Sensitivity must be expressed as G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] ip pointer to @p BaseCompass interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t comp_set_sensivity(void *ip, float *sp) { + LSM303AGRDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303AGRDriver*, (BaseCompass*)ip); + + osalDbgCheck((ip != NULL) && (sp != NULL)); + + osalDbgAssert((devp->state == LSM303AGR_READY), + "comp_set_sensivity(), invalid state"); + + for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) { + devp->compsensitivity[i] = sp[i]; + } + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseCompass. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseCompass interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t comp_reset_sensivity(void *ip) { + LSM303AGRDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303AGRDriver*, (BaseCompass*)ip); + + osalDbgAssert((devp->state == LSM303AGR_READY), + "comp_reset_sensivity(), invalid state"); + + for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) + devp->compsensitivity[i] = LSM303AGR_COMP_SENS_50GA; + + return msg; +} + +static const struct LSM303AGRVMT vmt_device = { + (size_t)0, + acc_set_full_scale +}; + +static const struct BaseAccelerometerVMT vmt_accelerometer = { + sizeof(struct LSM303AGRVMT*), + acc_get_axes_number, acc_read_raw, acc_read_cooked, + acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity +}; + +static const struct BaseCompassVMT vmt_compass = { + sizeof(struct LSM303AGRVMT*) + sizeof(BaseAccelerometer), + comp_get_axes_number, comp_read_raw, comp_read_cooked, + comp_set_bias, comp_reset_bias, comp_set_sensivity, comp_reset_sensivity +}; + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes an instance. + * + * @param[out] devp pointer to the @p LSM303AGRDriver object + * + * @init + */ +void lsm303agrObjectInit(LSM303AGRDriver *devp) { + devp->vmt = &vmt_device; + devp->acc_if.vmt = &vmt_accelerometer; + devp->comp_if.vmt = &vmt_compass; + + devp->config = NULL; + + devp->accaxes = LSM303AGR_ACC_NUMBER_OF_AXES; + devp->compaxes = LSM303AGR_COMP_NUMBER_OF_AXES; + + devp->state = LSM303AGR_STOP; +} + +/** + * @brief Configures and activates LSM303AGR Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LSM303AGRDriver object + * @param[in] config pointer to the @p LSM303AGRConfig object + * + * @api + */ +void lsm303agrStart(LSM303AGRDriver *devp, const LSM303AGRConfig *config) { + uint32_t i; + uint8_t cr[6]; + osalDbgCheck((devp != NULL) && (config != NULL)); + + osalDbgAssert((devp->state == LSM303AGR_STOP) || + (devp->state == LSM303AGR_READY), + "lsm303agrStart(), invalid state"); + + devp->config = config; + + /* Configuring Accelerometer subsystem.*/ + + /* Multiple write starting address.*/ + cr[0] = LSM303AGR_AD_CTRL_REG1_A; + + /* Control register 1 configuration block.*/ + { + cr[1] = LSM303AGR_ACC_AE_XYZ | devp->config->accoutdatarate; +#if LSM303AGR_USE_ADVANCED || defined(__DOXYGEN__) + if(devp->config->accmode == LSM303AGR_ACC_MODE_LPOW) + cr[1] |= LSM303AGR_CTRL_REG1_A_LPEN; +#endif + } + + /* Control register 2 configuration block.*/ + { + cr[2] = 0; + } + + /* Control register 3 configuration block.*/ + { + cr[3] = 0; + } + + /* Control register 4 configuration block.*/ + { + cr[4] = devp->config->accfullscale; +#if LSM303AGR_USE_ADVANCED || defined(__DOXYGEN__) + cr[4] |= devp->config->accendianess | + devp->config->accblockdataupdate; + if(devp->config->accmode == LSM303AGR_ACC_MODE_HRES) + cr[4] |= LSM303AGR_CTRL_REG4_A_HR; +#endif + } + + /* Storing sensitivity according to user settings */ + if(devp->config->accfullscale == LSM303AGR_ACC_FS_2G) { + devp->accfullscale = LSM303AGR_ACC_2G; + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM303AGR_ACC_SENS_2G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + } + else if(devp->config->accfullscale == LSM303AGR_ACC_FS_4G) { + devp->accfullscale = LSM303AGR_ACC_4G; + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM303AGR_ACC_SENS_4G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + } + else if(devp->config->accfullscale == LSM303AGR_ACC_FS_8G) { + devp->accfullscale = LSM303AGR_ACC_8G; + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM303AGR_ACC_SENS_8G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + } + else if(devp->config->accfullscale == LSM303AGR_ACC_FS_16G) { + devp->accfullscale = LSM303AGR_ACC_16G; + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM303AGR_ACC_SENS_16G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + } + else + osalDbgAssert(FALSE, "lsm303dlhcStart(), accelerometer full scale issue"); + + /* Storing bias information */ + if(devp->config->accbias != NULL) + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = devp->config->accbias[i]; + else + for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = LSM303AGR_ACC_BIAS; + +#if LSM303AGR_SHARED_I2C + i2cAcquireBus((devp)->config->i2cp); +#endif /* LSM303AGR_SHARED_I2C */ + i2cStart((devp)->config->i2cp, (devp)->config->i2ccfg); + + lsm303agrI2CWriteRegister(devp->config->i2cp, LSM303AGR_SAD_ACC, cr, 4); + +#if LSM303AGR_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* LSM303AGR_SHARED_I2C */ + + /* Configuring Compass subsystem */ + /* Multiple write starting address.*/ + cr[0] = LSM303AGR_AD_CFG_REG_A_M; + + /* Control register A configuration block.*/ + { + cr[1] = devp->config->compoutputdatarate; +#if LSM303AGR_USE_ADVANCED || defined(__DOXYGEN__) + cr[1] |= devp->config->compmode | devp->config->complp; +#endif + } + + /* Control register B configuration block.*/ + { + cr[2] = 0; + } + + /* Control register C configuration block.*/ + { + cr[3] = 0; + } + +#if LSM303AGR_SHARED_I2C + i2cAcquireBus((devp)->config->i2cp); + i2cStart((devp)->config->i2cp, (devp)->config->i2ccfg); +#endif /* LSM303AGR_SHARED_I2C */ + + lsm303agrI2CWriteRegister(devp->config->i2cp, LSM303AGR_SAD_COMP, + cr, 3); + +#if LSM303AGR_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* LSM303AGR_SHARED_I2C */ + + devp->compfullscale = LSM303AGR_COMP_50GA; + for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) { + if(devp->config->compsensitivity == NULL) { + devp->compsensitivity[i] = LSM303AGR_COMP_SENS_50GA; + } + else { + devp->compsensitivity[i] = devp->config->compsensitivity[i]; + } + } + + /* This is the MEMS transient recovery time */ + osalThreadSleepMilliseconds(5); + + devp->state = LSM303AGR_READY; +} + +/** + * @brief Deactivates the LSM303AGR Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LSM303AGRDriver object + * + * @api + */ +void lsm303agrStop(LSM303AGRDriver *devp) { + uint8_t cr[2]; + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LSM303AGR_STOP) || + (devp->state == LSM303AGR_READY), + "lsm303agrStop(), invalid state"); + + if (devp->state == LSM303AGR_READY) { +#if LSM303AGR_SHARED_I2C + i2cAcquireBus((devp)->config->i2cp); + i2cStart((devp)->config->i2cp, (devp)->config->i2ccfg); +#endif /* LSM303AGR_SHARED_I2C */ + + /* Disabling accelerometer. */ + cr[0] = LSM303AGR_AD_CTRL_REG1_A; + cr[1] = LSM303AGR_ACC_AE_DISABLED | LSM303AGR_ACC_ODR_PD; + lsm303agrI2CWriteRegister(devp->config->i2cp, LSM303AGR_SAD_ACC, + cr, 1); + + /* Disabling compass. */ + cr[0] = LSM303AGR_AD_CFG_REG_A_M; + cr[1] = LSM303AGR_COMP_MODE_IDLE; + lsm303agrI2CWriteRegister(devp->config->i2cp, LSM303AGR_SAD_COMP, + cr, 1); + + i2cStop((devp)->config->i2cp); +#if LSM303AGR_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* LSM303AGR_SHARED_I2C */ + } + devp->state = LSM303AGR_STOP; +} +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.h b/ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.h new file mode 100644 index 0000000..887e115 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.h @@ -0,0 +1,919 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lsm303agr.h + * @brief LSM303AGR MEMS interface module header. + * + * @addtogroup LSM303AGR + * @ingroup EX_ST + * @{ + */ +#ifndef _LSM303AGR_H_ +#define _LSM303AGR_H_ + +#include "ex_accelerometer.h" +#include "ex_compass.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Version identification + * @{ + */ +/** + * @brief LSM303AGR driver version string. + */ +#define EX_LSM303AGR_VERSION "1.0.1" + +/** + * @brief LSM303AGR driver version major number. + */ +#define EX_LSM303AGR_MAJOR 1 + +/** + * @brief LSM303AGR driver version minor number. + */ +#define EX_LSM303AGR_MINOR 0 + +/** + * @brief LSM303AGR driver version patch number. + */ +#define EX_LSM303AGR_PATCH 1 +/** @} */ + +/** + * @brief LSM303AGR accelerometer subsystem characteristics. + * @note Sensitivity is expressed as milli-G/LSB whereas + * 1 milli-G = 0.00980665 m/s^2. + * @note Bias is expressed as milli-G. + * + * @{ + */ +#define LSM303AGR_ACC_NUMBER_OF_AXES 3U + +#define LSM303AGR_ACC_2G 2.0f +#define LSM303AGR_ACC_4G 4.0f +#define LSM303AGR_ACC_8G 8.0f +#define LSM303AGR_ACC_16G 16.0f + +#define LSM303AGR_ACC_SENS_2G 0.060f +#define LSM303AGR_ACC_SENS_4G 0.120f +#define LSM303AGR_ACC_SENS_8G 0.240f +#define LSM303AGR_ACC_SENS_16G 0.750f + +#define LSM303AGR_ACC_BIAS 0.0f +/** @} */ + +/** + * @brief LSM303AGR compass subsystem characteristics. + * @note Sensitivity is expressed as G/LSB whereas G stands for Gauss. + * @note Bias is expressed as G. + * + * @{ + */ +#define LSM303AGR_COMP_NUMBER_OF_AXES 3U + +#define LSM303AGR_COMP_50GA 50.0f + +#define LSM303AGR_COMP_SENS_50GA 0.00015f + +#define LSM303AGR_COMP_BIAS 0.0f +/** @} */ + +/** + * @name LSM303AGR communication interfaces related bit masks + * @{ + */ +#define LSM303AGR_DI_MASK 0xFF +#define LSM303AGR_DI(n) (1 << n) +#define LSM303AGR_AD_MASK 0x7F +#define LSM303AGR_AD(n) (1 << n) +#define LSM303AGR_MS (1 << 7) +/** @} */ + +/** + * @name LSM303AGR register addresses + * @{ + */ +#define LSM303AGR_AD_STATUS_REG_AUX_A 0x07 +#define LSM303AGR_AD_OUT_TEMP_L_A 0x0C +#define LSM303AGR_AD_OUT_TEMP_H_A 0x0D +#define LSM303AGR_AD_INT_COUNTER_REG_A 0x0E +#define LSM303AGR_AD_WHO_AM_I_A 0x0F +#define LSM303AGR_AD_TEMP_CFG_REG_A 0x1F +#define LSM303AGR_AD_CTRL_REG1_A 0x20 +#define LSM303AGR_AD_CTRL_REG2_A 0x21 +#define LSM303AGR_AD_CTRL_REG3_A 0x22 +#define LSM303AGR_AD_CTRL_REG4_A 0x23 +#define LSM303AGR_AD_CTRL_REG5_A 0x24 +#define LSM303AGR_AD_CTRL_REG6_A 0x25 +#define LSM303AGR_AD_REFERENCE_A 0x26 +#define LSM303AGR_AD_STATUS_REG_A 0x27 +#define LSM303AGR_AD_OUT_X_L_A 0x28 +#define LSM303AGR_AD_OUT_X_H_A 0x29 +#define LSM303AGR_AD_OUT_Y_L_A 0x2A +#define LSM303AGR_AD_OUT_Y_H_A 0x2B +#define LSM303AGR_AD_OUT_Z_L_A 0x2C +#define LSM303AGR_AD_OUT_Z_H_A 0x2D +#define LSM303AGR_AD_FIFO_CTRL_REG_A 0x2E +#define LSM303AGR_AD_FIFO_SRC_REG_A 0x2F +#define LSM303AGR_AD_INT1_CFG_A 0x30 +#define LSM303AGR_AD_INT1_SRC_A 0x31 +#define LSM303AGR_AD_INT1_THS_A 0x32 +#define LSM303AGR_AD_INT1_DURATION_A 0x33 +#define LSM303AGR_AD_INT2_CFG_A 0x34 +#define LSM303AGR_AD_INT2_SRC_A 0x35 +#define LSM303AGR_AD_INT2_THS_A 0x36 +#define LSM303AGR_AD_INT2_DURATION_A 0x37 +#define LSM303AGR_AD_CLICK_CFG_A 0x38 +#define LSM303AGR_AD_CLICK_SRC_A 0x39 +#define LSM303AGR_AD_CLICK_THS_A 0x3A +#define LSM303AGR_AD_TIME_LIMIT_A 0x3B +#define LSM303AGR_AD_TIME_LATENCY_A 0x3C +#define LSM303AGR_AD_TIME_WINDOW_A 0x3D +#define LSM303AGR_AD_ACT_THS_A 0x3E +#define LSM303AGR_AD_ACT_DUR_A 0x3F +#define LSM303AGR_AD_OFFSET_X_REG_L_M 0x45 +#define LSM303AGR_AD_OFFSET_X_REG_H_M 0x46 +#define LSM303AGR_AD_OFFSET_Y_REG_L_M 0x47 +#define LSM303AGR_AD_OFFSET_Y_REG_H_M 0x48 +#define LSM303AGR_AD_OFFSET_Z_REG_L_M 0x49 +#define LSM303AGR_AD_OFFSET_Z_REG_H_M 0x4A +#define LSM303AGR_AD_WHO_AM_I_M 0x4F +#define LSM303AGR_AD_CFG_REG_A_M 0x60 +#define LSM303AGR_AD_CFG_REG_B_M 0x61 +#define LSM303AGR_AD_CFG_REG_C_M 0x62 +#define LSM303AGR_AD_INT_CRTL_REG_M 0x63 +#define LSM303AGR_AD_INT_SOURCE_REG_M 0x64 +#define LSM303AGR_AD_INT_THS_L_REG_M 0x65 +#define LSM303AGR_AD_INT_THS_H_REG_M 0x66 +#define LSM303AGR_AD_STATUS_REG_M 0x67 +#define LSM303AGR_AD_OUTX_L_REG_M 0x68 +#define LSM303AGR_AD_OUTX_H_REG_M 0x69 +#define LSM303AGR_AD_OUTY_L_REG_M 0x6A +#define LSM303AGR_AD_OUTY_H_REG_M 0x6B +#define LSM303AGR_AD_OUTZ_L_REG_M 0x6C +#define LSM303AGR_AD_OUTZ_H_REG_M 0x6D +/** @} */ + +/** + * @name LSM303AGR_TEMP_CFG_REG_A register bits definitions + * @{ + */ +#define LSM303AGR_TEMP_CFG_REG_A_TEMP_EN0 (1 << 0) +#define LSM303AGR_TEMP_CFG_REG_A_TEMP_EN1 (1 << 0) +/** @} */ + +/** + * @name LSM303AGR_CTRL_REG1_A register bits definitions + * @{ + */ +#define LSM303AGR_CTRL_REG1_A_XEN (1 << 0) +#define LSM303AGR_CTRL_REG1_A_YEN (1 << 1) +#define LSM303AGR_CTRL_REG1_A_ZEN (1 << 2) +#define LSM303AGR_CTRL_REG1_A_LPEN (1 << 3) +#define LSM303AGR_CTRL_REG1_A_ODR0 (1 << 4) +#define LSM303AGR_CTRL_REG1_A_ODR1 (1 << 5) +#define LSM303AGR_CTRL_REG1_A_ODR2 (1 << 6) +#define LSM303AGR_CTRL_REG1_A_ODR3 (1 << 7) +/** @} */ + +/** + * @name LSM303AGR_CTRL_REG2_A register bits definitions + * @{ + */ +#define LSM303AGR_CTRL_REG2_A_HPIS1 (1 << 0) +#define LSM303AGR_CTRL_REG2_A_HPIS2 (1 << 1) +#define LSM303AGR_CTRL_REG2_A_HPCLICK (1 << 2) +#define LSM303AGR_CTRL_REG2_A_FDS (1 << 3) +#define LSM303AGR_CTRL_REG2_A_HPCF1 (1 << 4) +#define LSM303AGR_CTRL_REG2_A_HPCF2 (1 << 5) +#define LSM303AGR_CTRL_REG2_A_HPM0 (1 << 6) +#define LSM303AGR_CTRL_REG2_A_HPM1 (1 << 7) +/** @} */ + +/** + * @name LSM303AGR_CTRL_REG3_A register bits definitions + * @{ + */ +#define LSM303AGR_CTRL_REG3_A_I1_OVERRUN (1 << 1) +#define LSM303AGR_CTRL_REG3_A_I1_WTM (1 << 2) +#define LSM303AGR_CTRL_REG3_A_I1_DRDY2 (1 << 3) +#define LSM303AGR_CTRL_REG3_A_I1_DRDY1 (1 << 4) +#define LSM303AGR_CTRL_REG3_A_I1_AOI2 (1 << 5) +#define LSM303AGR_CTRL_REG3_A_I1_AOI1 (1 << 6) +#define LSM303AGR_CTRL_REG3_A_I1_CLICK (1 << 7) +/** @} */ + +/** + * @name LSM303AGR_CTRL_REG4_A register bits definitions + * @{ + */ +#define LSM303AGR_CTRL_REG4_A_SPI_ENABLE (1 << 0) +#define LSM303AGR_CTRL_REG4_A_ST0 (1 << 1) +#define LSM303AGR_CTRL_REG4_A_ST1 (1 << 2) +#define LSM303AGR_CTRL_REG4_A_HR (1 << 3) +#define LSM303AGR_CTRL_REG4_A_FS_MASK 0x30 +#define LSM303AGR_CTRL_REG4_A_FS0 (1 << 4) +#define LSM303AGR_CTRL_REG4_A_FS1 (1 << 5) +#define LSM303AGR_CTRL_REG4_A_BLE (1 << 6) +#define LSM303AGR_CTRL_REG4_A_BDU (1 << 7) +/** @} */ + +/** + * @name LSM303AGR_CTRL_REG5_A register bits definitions + * @{ + */ +#define LSM303AGR_CTRL_REG5_A_D4D_INT2 (1 << 0) +#define LSM303AGR_CTRL_REG5_A_LIR_INT2 (1 << 1) +#define LSM303AGR_CTRL_REG5_A_D4D_INT1 (1 << 2) +#define LSM303AGR_CTRL_REG5_A_LIR_INT1 (1 << 3) +#define LSM303AGR_CTRL_REG5_A_FIFO_EN (1 << 6) +#define LSM303AGR_CTRL_REG5_A_BOOT (1 << 7) +/** @} */ + +/** + * @name LSM303AGR_CTRL_REG6_A register bits definitions + * @{ + */ +#define LSM303AGR_CTRL_REG6_A_H_LACTIVE (1 << 1) +#define LSM303AGR_CTRL_REG6_A_P2_ACT (1 << 3) +#define LSM303AGR_CTRL_REG6_A_BOOT_I2 (1 << 4) +#define LSM303AGR_CTRL_REG6_A_I2_INT2 (1 << 5) +#define LSM303AGR_CTRL_REG6_A_I2_INT1 (1 << 6) +#define LSM303AGR_CTRL_REG6_A_I2_CLICKEN (1 << 7) +/** @} */ + +/** + * @name LSM303AGR_CFG_REG_A register bits definitions + * @{ + */ +#define LSM303AGR_CFG_REG_A_M_MD0 (1 << 0) +#define LSM303AGR_CFG_REG_A_M_MD1 (1 << 1) +#define LSM303AGR_CFG_REG_A_M_ODR0 (1 << 2) +#define LSM303AGR_CFG_REG_A_M_ODR1 (1 << 3) +#define LSM303AGR_CFG_REG_A_M_LP (1 << 4) +#define LSM303AGR_CFG_REG_A_M_SOFT_RST (1 << 5) +#define LSM303AGR_CFG_REG_A_M_REBOOT (1 << 6) +#define LSM303AGR_CFG_REG_A_M_COMP_TEMP_EN (1 << 7) +/** @} */ + +/** + * @name LSM303AGR_CFG_REG_B register bits definitions + * @{ + */ +#define LSM303AGR_CFG_REG_B_M_LPF (1 << 0) +#define LSM303AGR_CFG_REG_B_M_OFF_CANC (1 << 1) +#define LSM303AGR_CFG_REG_B_M_SET_FREQ (1 << 2) +#define LSM303AGR_CFG_REG_B_M_INT_ON (1 << 3) +#define LSM303AGR_CFG_REG_B_M_OFF_CANC_OS (1 << 4) +/** @} */ + +/** + * @name LSM303AGR_CFG_REG_C register bits definitions + * @{ + */ +#define LSM303AGR_CFG_REG_C_M_INT_MAG (1 << 0) +#define LSM303AGR_CFG_REG_C_M_SELF_TEST (1 << 1) +#define LSM303AGR_CFG_REG_C_M_BLE (1 << 3) +#define LSM303AGR_CFG_REG_C_M_BDU (1 << 4) +#define LSM303AGR_CFG_REG_C_M_I2C_DIS (1 << 5) +#define LSM303AGR_CFG_REG_C_M_INT_MAG_PIN (1 << 6) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief LSM303AGR SPI interface switch. + * @details If set to @p TRUE the support for SPI is included. + * @note The default is @p FALSE. + */ +#if !defined(LSM303AGR_USE_SPI) || defined(__DOXYGEN__) +#define LSM303AGR_USE_SPI FALSE +#endif + +/** + * @brief LSM303AGR shared SPI switch. + * @details If set to @p TRUE the device acquires SPI bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LSM303AGR_SHARED_SPI) || defined(__DOXYGEN__) +#define LSM303AGR_SHARED_SPI FALSE +#endif + +/** + * @brief LSM303AGR I2C interface switch. + * @details If set to @p TRUE the support for I2C is included. + * @note The default is @p TRUE. + */ +#if !defined(LSM303AGR_USE_I2C) || defined(__DOXYGEN__) +#define LSM303AGR_USE_I2C TRUE +#endif + +/** + * @brief LSM303AGR shared I2C switch. + * @details If set to @p TRUE the device acquires I2C bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LSM303AGR_SHARED_I2C) || defined(__DOXYGEN__) +#define LSM303AGR_SHARED_I2C FALSE +#endif + +/** + * @brief LSM303AGR advanced configurations switch. + * @details If set to @p TRUE more configurations are available. + * @note The default is @p FALSE. + */ +#if !defined(LSM303AGR_USE_ADVANCED) || defined(__DOXYGEN__) +#define LSM303AGR_USE_ADVANCED FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !(LSM303AGR_USE_SPI ^ LSM303AGR_USE_I2C) +#error "LSM303AGR_USE_SPI and LSM303AGR_USE_I2C cannot be both true or both false" +#endif + +#if LSM303AGR_USE_SPI && !HAL_USE_SPI +#error "LSM303AGR_USE_SPI requires HAL_USE_SPI" +#endif + +#if LSM303AGR_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION +#error "LSM303AGR_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" +#endif + +#if LSM303AGR_USE_I2C && !HAL_USE_I2C +#error "LSM303AGR_USE_I2C requires HAL_USE_I2C" +#endif + +#if LSM303AGR_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION +#error "LSM303AGR_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" +#endif + +/* + * CHTODO: Add support for LSM303AGR over SPI. + */ +#if LSM303AGR_USE_SPI +#error "LSM303AGR over SPI still not supported" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @name LSM303AGR accelerometer subsystem data structures and types. + * @{ + */ +/** + * @brief Structure representing a LSM303AGR driver. + */ +typedef struct LSM303AGRDriver LSM303AGRDriver; + +/** + * @brief LSM303AGR accelerometer subsystem full scale. + */ +typedef enum { + LSM303AGR_ACC_FS_2G = 0x00, /**< Full scale �2g. */ + LSM303AGR_ACC_FS_4G = 0x10, /**< Full scale �4g. */ + LSM303AGR_ACC_FS_8G = 0x20, /**< Full scale �8g. */ + LSM303AGR_ACC_FS_16G = 0x30 /**< Full scale �16g. */ +} lsm303agr_acc_fs_t; + +/** + * @brief LSM303AGR accelerometer subsystem output data rate. + */ +typedef enum { + LSM303AGR_ACC_ODR_PD = 0x00, /**< Power down */ + LSM303AGR_ACC_ODR_1Hz = 0x10, /**< ODR 1 Hz */ + LSM303AGR_ACC_ODR_10Hz = 0x20, /**< ODR 10 Hz */ + LSM303AGR_ACC_ODR_25Hz = 0x30, /**< ODR 25 Hz */ + LSM303AGR_ACC_ODR_50Hz = 0x40, /**< ODR 50 Hz */ + LSM303AGR_ACC_ODR_100Hz = 0x50, /**< ODR 100 Hz */ + LSM303AGR_ACC_ODR_200Hz = 0x60, /**< ODR 200 Hz */ + LSM303AGR_ACC_ODR_400Hz = 0x70, /**< ODR 400 Hz */ + LSM303AGR_ACC_ODR_1620Hz = 0x80, /**< ODR 1620 Hz (LP only) */ + LSM303AGR_ACC_ODR_1344Hz = 0x90 /**< ODR 1344 Hz or 5376 Hz in LP */ +} lsm303agr_acc_odr_t; + +/** + * @brief LSM303AGR accelerometer subsystem axes enabling. + */ +typedef enum { + LSM303AGR_ACC_AE_DISABLED = 0x00,/**< All axes disabled. */ + LSM303AGR_ACC_AE_X = 0x01, /**< Only X-axis enabled. */ + LSM303AGR_ACC_AE_Y = 0x02, /**< Only Y-axis enabled. */ + LSM303AGR_ACC_AE_XY = 0x03, /**< X and Y axes enabled. */ + LSM303AGR_ACC_AE_Z = 0x04, /**< Only Z-axis enabled. */ + LSM303AGR_ACC_AE_XZ = 0x05, /**< X and Z axes enabled. */ + LSM303AGR_ACC_AE_YZ = 0x06, /**< Y and Z axes enabled. */ + LSM303AGR_ACC_AE_XYZ = 0x07 /**< All axes enabled. */ +} lsm303agr_acc_ae_t; + +/** + * @brief LSM303AGR accelerometer subsystem operation mode. + */ +typedef enum { + LSM303AGR_ACC_MODE_NORM = 0, /**< Normal mode. */ + LSM303AGR_ACC_MODE_LPOW = 1, /**< Low power mode. */ + LSM303AGR_ACC_MODE_HRES = 2 /**< High resolution mode. */ +} lsm303agr_acc_mode_t; + +/** + * @brief LSM303AGR accelerometer subsystem block data update. + */ +typedef enum { + LSM303AGR_ACC_BDU_CONT = 0x00, /**< Continuous update */ + LSM303AGR_ACC_BDU_BLOCK = 0x80 /**< Update blocked */ +} lsm303agr_acc_bdu_t; + +/** + * @brief LSM303AGR accelerometer endianness. + */ +typedef enum { + LSM303AGR_ACC_END_LITTLE = 0x00, /**< Little Endian */ + LSM303AGR_ACC_END_BIG = 0x40 /**< Big Endian */ +} lsm303agr_acc_end_t; + +/** + * @name LSM303AGR compass subsystem data structures and types. + * @{ + */ +/** + * @brief LSM303AGR compass subsystem output data rate. + */ +typedef enum { + LSM303AGR_COMP_ODR_10HZ = 0x00, /**< ODR 10 Hz */ + LSM303AGR_COMP_ODR_20HZ = 0x04, /**< ODR 20 Hz */ + LSM303AGR_COMP_ODR_50HZ = 0x08, /**< ODR 50 Hz */ + LSM303AGR_COMP_ODR_100HZ = 0x0C /**< ODR 100 Hz */ +} lsm303agr_comp_odr_t; + +/** + * @brief LSM303AGR compass subsystem working mode. + */ +typedef enum { + LSM303AGR_COMP_MODE_NORM = 0x00, /**< Continuous-Conversion Mode */ + LSM303AGR_COMP_MODE_SINGLE = 0x01,/**< Single-Conversion Mode */ + LSM303AGR_COMP_MODE_IDLE = 0x02 /**< Sleep Mode */ +} lsm303agr_comp_mode_t; + +/** + * @brief LSM303AGR compass subsystem working mode. + */ +typedef enum { + LSM303AGR_COMP_LPOW_DIS = 0x00, /**< High Resolution Mode */ + LSM303AGR_COMP_LPOW_EN = 0x10 /**< Low Power Mode */ +} lsm303agr_comp_lpow_t; + +/** + * @name LSM303AGR main system data structures and types. + * @{ + */ +/** + * @brief Driver state machine possible states. + */ +typedef enum { + LSM303AGR_UNINIT = 0, /**< Not initialized. */ + LSM303AGR_STOP = 1, /**< Stopped. */ + LSM303AGR_READY = 2, /**< Ready. */ +} lsm303agr_state_t; + +/** + * @brief LSM303AGR configuration structure. + */ +typedef struct { + /** + * @brief I2C driver associated to this LSM303AGR. + */ + I2CDriver *i2cp; + /** + * @brief I2C configuration associated to this LSM303AGR. + */ + const I2CConfig *i2ccfg; + /** + * @brief LSM303AGR accelerometer subsystem initial sensitivity. + */ + float *accsensitivity; + /** + * @brief LSM303AGR accelerometer subsystem initial bias. + */ + float *accbias; + /** + * @brief LSM303AGR accelerometer subsystem initial full scale. + */ + lsm303agr_acc_fs_t accfullscale; + /** + * @brief LSM303AGR accelerometer subsystem output data rate. + */ + lsm303agr_acc_odr_t accoutdatarate; +#if LSM303AGR_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief LSM303AGR accelerometer subsystem mode. + */ + lsm303agr_acc_mode_t accmode; + /** + * @brief LSM303AGR accelerometer subsystem block data update. + */ + lsm303agr_acc_bdu_t accblockdataupdate; + /** + * @brief LSM303AGR accelerometer endianness. + */ + lsm303agr_acc_end_t accendianess; +#endif + /** + * @brief LSM303AGR compass initial sensitivity. + */ + float *compsensitivity; + /** + * @brief LSM303AGR compass initial bias. + */ + float *compbias; + /** + * @brief LSM303AGR compass subsystem output data rate. + */ + lsm303agr_comp_odr_t compoutputdatarate; +#if LSM303AGR_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief LSM303AGR compass subsystem working mode. + */ + lsm303agr_comp_mode_t compmode; + /** + * @brief LSM303AGR compass subsystem lowpower mode. + */ + lsm303agr_comp_lpow_t complp; +#endif +} LSM303AGRConfig; + +/** + * @brief @p LSM303AGR specific methods. + */ +#define _lsm303agr_methods_alone \ + /* Change full scale value of LSM303AGR accelerometer subsystem.*/ \ + msg_t (*acc_set_full_scale)(LSM303AGRDriver *devp, \ + lsm303agr_acc_fs_t fs); + +/** + * @brief @p LSM303AGR specific methods with inherited ones. + */ +#define _lsm303agr_methods \ + _base_object_methods \ + _lsm303agr_methods_alone + +/** + * @extends BaseObjectVMT + * + * @brief @p LSM303AGR virtual methods table. + */ +struct LSM303AGRVMT { + _lsm303agr_methods +}; + +/** + * @brief @p LSM303AGRDriver specific data. + */ +#define _lsm303agr_data \ + _base_sensor_data \ + /* Driver state.*/ \ + lsm303agr_state_t state; \ + /* Current configuration data.*/ \ + const LSM303AGRConfig *config; \ + /* Accelerometer subsystem axes number.*/ \ + size_t accaxes; \ + /* Accelerometer subsystem current sensitivity.*/ \ + float accsensitivity[LSM303AGR_ACC_NUMBER_OF_AXES]; \ + /* Accelerometer subsystem current bias .*/ \ + float accbias[LSM303AGR_ACC_NUMBER_OF_AXES]; \ + /* Accelerometer subsystem current full scale value.*/ \ + float accfullscale; \ + /* Compass subsystem axes number.*/ \ + size_t compaxes; \ + /* Compass subsystem current sensitivity.*/ \ + float compsensitivity[LSM303AGR_COMP_NUMBER_OF_AXES]; \ + /* Compass subsystem current bias.*/ \ + float compbias[LSM303AGR_COMP_NUMBER_OF_AXES]; \ + /* Compass subsystem current full scale value.*/ \ + float compfullscale; + +/** + * @brief LSM303AGR 6-axis accelerometer/compass class. + */ +struct LSM303AGRDriver { + /** @brief Virtual Methods Table.*/ + const struct LSM303AGRVMT *vmt; + /** @brief Base accelerometer interface.*/ + BaseAccelerometer acc_if; + /** @brief Base compass interface.*/ + BaseCompass comp_if; + _lsm303agr_data +}; +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Return the number of axes of the BaseAccelerometer. + * + * @param[in] devp pointer to @p LSM303AGRDriver. + * + * @return the number of axes. + * + * @api + */ +#define lsm303agrAccelerometerGetAxesNumber(devp) \ + accelerometerGetAxesNumber(&((devp)->acc_if)) + +/** + * @brief Retrieves raw data from the BaseAccelerometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM303AGRDriver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm303agrAccelerometerReadRaw(devp, axes) \ + accelerometerReadRaw(&((devp)->acc_if), axes) + +/** + * @brief Retrieves cooked data from the BaseAccelerometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as milli-G. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM303AGRDriver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm303agrAccelerometerReadCooked(devp, axes) \ + accelerometerReadCooked(&((devp)->acc_if), axes) + +/** + * @brief Set bias values for the BaseAccelerometer. + * @note Bias must be expressed as milli-G. + * @note The bias buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM303AGRDriver. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm303agrAccelerometerSetBias(devp, bp) \ + accelerometerSetBias(&((devp)->acc_if), bp) + +/** + * @brief Reset bias values for the BaseAccelerometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p LSM303AGRDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm303agrAccelerometerResetBias(devp) \ + accelerometerResetBias(&((devp)->acc_if)) + +/** + * @brief Set sensitivity values for the BaseAccelerometer. + * @note Sensitivity must be expressed as milli-G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM303AGRDriver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm303agrAccelerometerSetSensitivity(devp, sp) \ + accelerometerSetSensitivity(&((devp)->acc_if), sp) + +/** + * @brief Reset sensitivity values for the BaseAccelerometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p LSM303AGRDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lsm303agrAccelerometerResetSensitivity(devp) \ + accelerometerResetSensitivity(&((devp)->acc_if)) + +/** + * @brief Changes the LSM303AGRDriver accelerometer fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LSM303AGRDriver. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lsm303agrAccelerometerSetFullScale(devp, fs) \ + (devp)->vmt->acc_set_full_scale(devp, fs) + +/** + * @brief Return the number of axes of the BaseCompass. + * + * @param[in] devp pointer to @p LSM303AGRDriver. + * + * @return the number of axes. + * + * @api + */ +#define lsm303agrCompassGetAxesNumber(devp) \ + compassGetAxesNumber(&((devp)->comp_if)) + +/** + * @brief Retrieves raw data from the BaseCompass. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] devp pointer to @p BaseCompass interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm303agrCompassReadRaw(devp, axes) \ + compassReadRaw(&((devp)->comp_if), axes) + +/** + * @brief Retrieves cooked data from the BaseCompass. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as G. + * @note The axes array must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] devp pointer to @p BaseCompass interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm303agrCompassReadCooked(devp, axes) \ + compassReadCooked(&((devp)->comp_if), axes) + +/** + * @brief Set bias values for the BaseCompass. + * @note Bias must be expressed as G. + * @note The bias buffer must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] devp pointer to @p BaseCompass interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm303agrCompassSetBias(devp, bp) \ + compassSetBias(&((devp)->comp_if), bp) + +/** + * @brief Reset bias values for the BaseCompass. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p LSM303AGRDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm303agrCompassResetBias(devp) \ + compassResetBias(&((devp)->comp_if)) + +/** + * @brief Set sensitivity values for the BaseCompass. + * @note Sensitivity must be expressed as G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] devp pointer to @p LSM303AGRDriver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm303agrCompassSetSensitivity(devp, sp) \ + compassSetSensitivity(&((devp)->comp_if), sp) + +/** + * @brief Reset sensitivity values for the BaseCompass. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p LSM303AGRDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lsm303agrCompassResetSensitivity(devp) \ + compassResetSensitivity(&((devp)->comp_if)) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void lsm303agrObjectInit(LSM303AGRDriver *devp); + void lsm303agrStart(LSM303AGRDriver *devp, const LSM303AGRConfig *config); + void lsm303agrStop(LSM303AGRDriver *devp); +#ifdef __cplusplus +} +#endif + +#endif /* _LSM303AGR_H_ */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.mk b/ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.mk new file mode 100644 index 0000000..ddd54eb --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.mk @@ -0,0 +1,10 @@ +# List of all the LSM303AGR device files. +LSM303AGRSRC := $(CHIBIOS)/os/ex/devices/ST/lsm303agr.c + +# Required include directories +LSM303AGRINC := $(CHIBIOS)/os/ex/include \ + $(CHIBIOS)/os/ex/devices/ST + +# Shared variables +ALLCSRC += $(LSM303AGRSRC) +ALLINC += $(LSM303AGRINC) \ No newline at end of file diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.c b/ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.c new file mode 100644 index 0000000..45e0137 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.c @@ -0,0 +1,1175 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lsm303dlhc.c + * @brief LSM303DLHC MEMS interface module code. + * + * @addtogroup LSM303DLHC + * @ingroup EX_ST + * @{ + */ + +#include "hal.h" +#include "lsm303dlhc.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief Accelerometer and Compass Slave Address. + */ +typedef enum { + LSM303DLHC_SAD_ACC = 0x19, /**< SAD for accelerometer. */ + LSM303DLHC_SAD_COMP = 0x1E /**< SAD for compass. */ +} lsm303dlhc_sad_t; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Reads registers value using I2C. + * @pre The I2C interface must be initialized and the driver started. + * @note IF_ADD_INC bit must be 1 in CTRL_REG8. + * + * @param[in] i2cp pointer to the I2C interface. + * @param[in] sad slave address without R bit. + * @param[in] reg first sub-register address. + * @param[in] rxbuf receiving buffer. + * @param[in] n size of rxbuf. + * @return the operation status. + */ +static msg_t lsm303dlhcI2CReadRegister(I2CDriver *i2cp, lsm303dlhc_sad_t sad, + uint8_t reg, uint8_t *rxbuf, size_t n) { + + uint8_t txbuf = reg | LSM303DLHC_MS; + return i2cMasterTransmitTimeout(i2cp, sad, &txbuf, 1, rxbuf, n, + TIME_INFINITE); +} + +/** + * @brief Writes a value into a register using I2C. + * @pre The I2C interface must be initialized and the driver started. + * + * @param[in] i2cp pointer to the I2C interface. + * @param[in] sad slave address without R bit. + * @param[in] txbuf buffer containing sub-address value in first position + * and values to write. + * @param[in] n size of txbuf less one (not considering the first + * element). + * @return the operation status. + */ +static msg_t lsm303dlhcI2CWriteRegister(I2CDriver *i2cp, lsm303dlhc_sad_t sad, + uint8_t *txbuf, size_t n) { + if (n != 1) + *txbuf |= LSM303DLHC_MS; + return i2cMasterTransmitTimeout(i2cp, sad, txbuf, n + 1, NULL, 0, + TIME_INFINITE); +} + +/** + * @brief Return the number of axes of the BaseAccelerometer. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return the number of axes. + */ +static size_t acc_get_axes_number(void *ip) { + (void)ip; + + return LSM303DLHC_ACC_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseAccelerometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t acc_read_raw(void *ip, int32_t axes[]) { + LSM303DLHCDriver* devp; + uint8_t buff [LSM303DLHC_ACC_NUMBER_OF_AXES * 2], i; + int16_t tmp; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303DLHCDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM303DLHC_READY), + "acc_read_raw(), invalid state"); + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "acc_read_raw(), channel not ready"); + +#if LSM303DLHC_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM303DLHC_SHARED_I2C */ + + msg = lsm303dlhcI2CReadRegister(devp->config->i2cp, LSM303DLHC_SAD_ACC, + LSM303DLHC_AD_ACC_OUT_X_L, buff, + LSM303DLHC_ACC_NUMBER_OF_AXES * 2); + +#if LSM303DLHC_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM303DLHC_SHARED_I2C */ + + if(msg == MSG_OK) + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) { + tmp = buff[2 * i] + (buff[2 * i + 1] << 8); + axes[i] = (int32_t)tmp; + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseAccelerometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as milli-G. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t acc_read_cooked(void *ip, float axes[]) { + LSM303DLHCDriver* devp; + uint32_t i; + int32_t raw[LSM303DLHC_ACC_NUMBER_OF_AXES]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303DLHCDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM303DLHC_READY), + "acc_read_cooked(), invalid state"); + + msg = acc_read_raw(ip, raw); + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) { + axes[i] = (raw[i] * devp->accsensitivity[i]) - devp->accbias[i]; + } + return msg; +} + +/** + * @brief Set bias values for the BaseAccelerometer. + * @note Bias must be expressed as milli-G. + * @note The bias buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_set_bias(void *ip, float *bp) { + LSM303DLHCDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303DLHCDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM303DLHC_READY), + "acc_set_bias(), invalid state"); + + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) { + devp->accbias[i] = bp[i]; + } + return msg; +} + +/** + * @brief Reset bias values for the BaseAccelerometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_reset_bias(void *ip) { + LSM303DLHCDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303DLHCDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM303DLHC_READY), + "acc_reset_bias(), invalid state"); + + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = LSM303DLHC_ACC_BIAS; + return msg; +} + +/** + * @brief Set sensitivity values for the BaseAccelerometer. + * @note Sensitivity must be expressed as milli-G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_set_sensivity(void *ip, float *sp) { + LSM303DLHCDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303DLHCDriver*, (BaseAccelerometer*)ip); + + osalDbgCheck((ip != NULL) && (sp != NULL)); + + osalDbgAssert((devp->state == LSM303DLHC_READY), + "acc_set_sensivity(), invalid state"); + + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] = sp[i]; + } + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseAccelerometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t acc_reset_sensivity(void *ip) { + LSM303DLHCDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303DLHCDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM303DLHC_READY), + "acc_reset_sensivity(), invalid state"); + + if(devp->config->accfullscale == LSM303DLHC_ACC_FS_2G) + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_2G; + else if(devp->config->accfullscale == LSM303DLHC_ACC_FS_4G) + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_4G; + else if(devp->config->accfullscale == LSM303DLHC_ACC_FS_8G) + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_8G; + else if(devp->config->accfullscale == LSM303DLHC_ACC_FS_16G) + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_16G; + else { + osalDbgAssert(FALSE, "acc_reset_sensivity(), accelerometer full scale issue"); + msg = MSG_RESET; + } + return msg; +} + +/** + * @brief Changes the LSM303DLHCDriver accelerometer fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LSM303DLHCDriver interface. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t acc_set_full_scale(LSM303DLHCDriver *devp, + lsm303dlhc_acc_fs_t fs) { + float newfs, scale; + uint8_t i, buff[2]; + msg_t msg; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LSM303DLHC_READY), + "acc_set_full_scale(), invalid state"); + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "acc_set_full_scale(), channel not ready"); + + /* Computing new fullscale value.*/ + if(fs == LSM303DLHC_ACC_FS_2G) { + newfs = LSM303DLHC_ACC_2G; + } + else if(fs == LSM303DLHC_ACC_FS_4G) { + newfs = LSM303DLHC_ACC_4G; + } + else if(fs == LSM303DLHC_ACC_FS_8G) { + newfs = LSM303DLHC_ACC_8G; + } + else if(fs == LSM303DLHC_ACC_FS_16G) { + newfs = LSM303DLHC_ACC_16G; + } + else { + msg = MSG_RESET; + return msg; + } + + if(newfs != devp->accfullscale) { + /* Computing scale value.*/ + scale = newfs / devp->accfullscale; + devp->accfullscale = newfs; + +#if LSM303DLHC_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM303DLHC_SHARED_I2C */ + + /* Updating register.*/ + msg = lsm303dlhcI2CReadRegister(devp->config->i2cp, + LSM303DLHC_SAD_ACC, + LSM303DLHC_AD_ACC_CTRL_REG4, + &buff[1], 1); + +#if LSM303DLHC_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM303DLHC_SHARED_I2C */ + + if(msg != MSG_OK) + return msg; + + buff[1] &= ~(LSM303DLHC_CTRL_REG4_A_FS_MASK); + buff[1] |= fs; + buff[0] = LSM303DLHC_AD_ACC_CTRL_REG4; + +#if LSM303DLHC_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* LSM303DLHC_SHARED_I2C */ + + msg = lsm303dlhcI2CWriteRegister(devp->config->i2cp, + LSM303DLHC_SAD_ACC, buff, 1); + +#if LSM303DLHC_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM303DLHC_SHARED_I2C */ + + if(msg != MSG_OK) + return msg; + + /* Scaling sensitivity and bias. Re-calibration is suggested anyway.*/ + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] *= scale; + devp->accbias[i] *= scale; + } + } + return msg; +} + +/** + * @brief Return the number of axes of the BaseCompass. + * + * @param[in] ip pointer to @p BaseCompass interface + * + * @return the number of axes. + */ +static size_t comp_get_axes_number(void *ip) { + + osalDbgCheck(ip != NULL); + return LSM303DLHC_COMP_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseCompass. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] ip pointer to @p BaseCompass interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t comp_read_raw(void *ip, int32_t axes[]) { + LSM303DLHCDriver* devp; + uint8_t buff [LSM303DLHC_COMP_NUMBER_OF_AXES * 2], i; + int16_t tmp; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303DLHCDriver*, (BaseCompass*)ip); + + osalDbgAssert((devp->state == LSM303DLHC_READY), + "comp_read_raw(), invalid state"); + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "comp_read_raw(), channel not ready"); + +#if LSM303DLHC_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM303DLHC_SHARED_I2C */ + msg = lsm303dlhcI2CReadRegister(devp->config->i2cp, LSM303DLHC_SAD_COMP, + LSM303DLHC_AD_COMP_OUT_X_L, buff, + LSM303DLHC_COMP_NUMBER_OF_AXES * 2); + +#if LSM303DLHC_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM303DLHC_SHARED_I2C */ + + if(msg == MSG_OK) + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + tmp = buff[2 * i] + (buff[2 * i + 1] << 8); + axes[i] = (int32_t)tmp; + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseCompass. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as G. + * @note The axes array must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] ip pointer to @p BaseCompass interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t comp_read_cooked(void *ip, float axes[]) { + LSM303DLHCDriver* devp; + uint32_t i; + int32_t raw[LSM303DLHC_COMP_NUMBER_OF_AXES]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303DLHCDriver*, (BaseCompass*)ip); + + osalDbgAssert((devp->state == LSM303DLHC_READY), + "comp_read_cooked(), invalid state"); + + msg = comp_read_raw(ip, raw); + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES ; i++) { + axes[i] = (raw[i] * devp->compsensitivity[i]) - devp->compbias[i]; + } + return msg; +} + +/** + * @brief Set bias values for the BaseCompass. + * @note Bias must be expressed as G. + * @note The bias buffer must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] ip pointer to @p BaseCompass interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t comp_set_bias(void *ip, float *bp) { + LSM303DLHCDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303DLHCDriver*, (BaseCompass*)ip); + + osalDbgAssert((devp->state == LSM303DLHC_READY), + "comp_set_bias(), invalid state"); + + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + devp->compbias[i] = bp[i]; + } + return msg; +} + +/** + * @brief Reset bias values for the BaseCompass. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseCompass interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t comp_reset_bias(void *ip) { + LSM303DLHCDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303DLHCDriver*, (BaseCompass*)ip); + + osalDbgAssert((devp->state == LSM303DLHC_READY), + "comp_reset_bias(), invalid state"); + + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) + devp->compbias[i] = LSM303DLHC_COMP_BIAS; + return msg; +} + +/** + * @brief Set sensitivity values for the BaseCompass. + * @note Sensitivity must be expressed as G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] ip pointer to @p BaseCompass interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t comp_set_sensivity(void *ip, float *sp) { + LSM303DLHCDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303DLHCDriver*, (BaseCompass*)ip); + + osalDbgCheck((ip != NULL) && (sp != NULL)); + + osalDbgAssert((devp->state == LSM303DLHC_READY), + "comp_set_sensivity(), invalid state"); + + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + devp->compsensitivity[i] = sp[i]; + } + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseCompass. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseCompass interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t comp_reset_sensivity(void *ip) { + LSM303DLHCDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM303DLHCDriver*, (BaseCompass*)ip); + + osalDbgAssert((devp->state == LSM303DLHC_READY), + "comp_reset_sensivity(), invalid state"); + + if(devp->config->compfullscale == LSM303DLHC_COMP_FS_1P3GA) + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + if(i != 2) { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_1P3GA; + } + else { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_1P3GA; + } + } + else if(devp->config->compfullscale == LSM303DLHC_COMP_FS_1P9GA) + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + if(i != 2) { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_1P9GA; + } + else { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_1P9GA; + } + } + else if(devp->config->compfullscale == LSM303DLHC_COMP_FS_2P5GA) + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + if(i != 2) { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_2P5GA; + } + else { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_2P5GA; + } + } + else if(devp->config->compfullscale == LSM303DLHC_COMP_FS_4P0GA) + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + if(i != 2) { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_4P0GA; + } + else { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_4P0GA; + } + } + else if(devp->config->compfullscale == LSM303DLHC_COMP_FS_4P7GA) + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + if(i != 2) { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_4P7GA; + } + else { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_4P7GA; + } + } + else if(devp->config->compfullscale == LSM303DLHC_COMP_FS_5P6GA) + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + if(i != 2) { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_5P6GA; + } + else { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_5P6GA; + } + } + else if(devp->config->compfullscale == LSM303DLHC_COMP_FS_8P1GA) + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + if(i != 2) { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_8P1GA; + } + else { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_8P1GA; + } + } + else { + osalDbgAssert(FALSE, "comp_reset_sensivity(), compass full scale issue"); + msg = MSG_RESET; + } + return msg; +} + +/** + * @brief Changes the LSM303DLHCDriver compass fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LSM303DLHCDriver interface. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t comp_set_full_scale(LSM303DLHCDriver *devp, + lsm303dlhc_comp_fs_t fs) { + float newfs, scale; + uint8_t i, buff[2]; + msg_t msg; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LSM303DLHC_READY), + "comp_set_full_scale(), invalid state"); + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "comp_set_full_scale(), channel not ready"); + + /* Computing new fullscale value.*/ + if(fs == LSM303DLHC_COMP_FS_1P3GA) { + newfs = LSM303DLHC_COMP_1P3GA; + } + else if(fs == LSM303DLHC_COMP_FS_1P9GA) { + newfs = LSM303DLHC_COMP_1P9GA; + } + else if(fs == LSM303DLHC_COMP_FS_2P5GA) { + newfs = LSM303DLHC_COMP_2P5GA; + } + else if(fs == LSM303DLHC_COMP_FS_4P0GA) { + newfs = LSM303DLHC_COMP_4P0GA; + } + else if(fs == LSM303DLHC_COMP_FS_4P7GA) { + newfs = LSM303DLHC_COMP_4P7GA; + } + else if(fs == LSM303DLHC_COMP_FS_5P6GA) { + newfs = LSM303DLHC_COMP_5P6GA; + } + else if(fs == LSM303DLHC_COMP_FS_8P1GA) { + newfs = LSM303DLHC_COMP_8P1GA; + } + else { + msg = MSG_RESET; + return msg; + } + + if(newfs != devp->compfullscale) { + /* Computing scale value.*/ + scale = newfs / devp->compfullscale; + devp->compfullscale = newfs; + +#if LSM303DLHC_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* LSM303DLHC_SHARED_I2C */ + + /* Updating register.*/ + msg = lsm303dlhcI2CReadRegister(devp->config->i2cp, LSM303DLHC_SAD_COMP, + LSM303DLHC_AD_COMP_CRB_REG, &buff[1], 1); + +#if LSM303DLHC_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM303DLHC_SHARED_I2C */ + + if(msg != MSG_OK) + return msg; + buff[1] &= ~(LSM303DLHC_CRB_REG_M_GN_MASK); + buff[1] |= fs; + buff[0] = LSM303DLHC_AD_COMP_CRB_REG; + +#if LSM303DLHC_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* LSM303DLHC_SHARED_I2C */ + + msg = lsm303dlhcI2CWriteRegister(devp->config->i2cp, LSM303DLHC_SAD_COMP, + buff, 1); + +#if LSM303DLHC_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM303DLHC_SHARED_I2C */ + + if(msg != MSG_OK) + return msg; + + /* Scaling sensitivity and bias. Re-calibration is suggested anyway.*/ + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + devp->compsensitivity[i] *= scale; + devp->compbias[i] *= scale; + } + } + return msg; +} + +static const struct LSM303DLHCVMT vmt_device = { + (size_t)0, + acc_set_full_scale, comp_set_full_scale +}; + +static const struct BaseAccelerometerVMT vmt_accelerometer = { + sizeof(struct LSM303DLHCVMT*), + acc_get_axes_number, acc_read_raw, acc_read_cooked, + acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity +}; + +static const struct BaseCompassVMT vmt_compass = { + sizeof(struct LSM303DLHCVMT*) + sizeof(BaseAccelerometer), + comp_get_axes_number, comp_read_raw, comp_read_cooked, + comp_set_bias, comp_reset_bias, comp_set_sensivity, comp_reset_sensivity +}; + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes an instance. + * + * @param[out] devp pointer to the @p LSM303DLHCDriver object + * + * @init + */ +void lsm303dlhcObjectInit(LSM303DLHCDriver *devp) { + devp->vmt = &vmt_device; + devp->acc_if.vmt = &vmt_accelerometer; + devp->comp_if.vmt = &vmt_compass; + + devp->config = NULL; + + devp->accaxes = LSM303DLHC_ACC_NUMBER_OF_AXES; + devp->compaxes = LSM303DLHC_COMP_NUMBER_OF_AXES; + + devp->state = LSM303DLHC_STOP; +} + +/** + * @brief Configures and activates LSM303DLHC Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LSM303DLHCDriver object + * @param[in] config pointer to the @p LSM303DLHCConfig object + * + * @api + */ +void lsm303dlhcStart(LSM303DLHCDriver *devp, const LSM303DLHCConfig *config) { + uint32_t i; + uint8_t cr[6]; + osalDbgCheck((devp != NULL) && (config != NULL)); + + osalDbgAssert((devp->state == LSM303DLHC_STOP) || + (devp->state == LSM303DLHC_READY), + "lsm303dlhcStart(), invalid state"); + + devp->config = config; + + /* Configuring Accelerometer subsystem.*/ + + /* Multiple write starting address.*/ + cr[0] = LSM303DLHC_AD_ACC_CTRL_REG1; + + /* Control register 1 configuration block.*/ + { + cr[1] = LSM303DLHC_CTRL_REG1_A_XEN | LSM303DLHC_CTRL_REG1_A_YEN | + LSM303DLHC_CTRL_REG1_A_ZEN | devp->config->accoutdatarate; +#if LSM303DLHC_USE_ADVANCED || defined(__DOXYGEN__) + cr[1] |= devp->config->acclowpower; +#endif + } + + /* Control register 2 configuration block.*/ + { + cr[2] = 0; + } + + /* Control register 3 configuration block.*/ + { + cr[3] = 0; + } + + /* Control register 4 configuration block.*/ + { + cr[4] = devp->config->accfullscale; +#if LSM303DLHC_USE_ADVANCED || defined(__DOXYGEN__) + cr[4] |= devp->config->accendianess | + devp->config->accblockdataupdate | + devp->config->acchighresmode; +#endif + } + +#if LSM303DLHC_SHARED_I2C + i2cAcquireBus((devp)->config->i2cp); +#endif /* LSM303DLHC_SHARED_I2C */ + i2cStart((devp)->config->i2cp, (devp)->config->i2ccfg); + + lsm303dlhcI2CWriteRegister(devp->config->i2cp, LSM303DLHC_SAD_ACC, cr, 4); + +#if LSM303DLHC_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* LSM303DLHC_SHARED_I2C */ + + /* Storing sensitivity according to user settings */ + if(devp->config->accfullscale == LSM303DLHC_ACC_FS_2G) { + devp->accfullscale = LSM303DLHC_ACC_2G; + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_2G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + } + else if(devp->config->accfullscale == LSM303DLHC_ACC_FS_4G) { + devp->accfullscale = LSM303DLHC_ACC_4G; + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_4G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + } + else if(devp->config->accfullscale == LSM303DLHC_ACC_FS_8G) { + devp->accfullscale = LSM303DLHC_ACC_8G; + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_8G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + } + else if(devp->config->accfullscale == LSM303DLHC_ACC_FS_16G) { + devp->accfullscale = LSM303DLHC_ACC_16G; + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM303DLHC_ACC_SENS_16G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + } + else + osalDbgAssert(FALSE, "lsm303dlhcStart(), accelerometer full scale issue"); + + /* Storing bias information */ + if(devp->config->accbias != NULL) + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = devp->config->accbias[i]; + else + for(i = 0; i < LSM303DLHC_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = LSM303DLHC_ACC_BIAS; + + /* Configuring Compass subsystem */ + /* Multiple write starting address.*/ + cr[0] = LSM303DLHC_AD_COMP_CRA_REG; + + /* Control register A configuration block.*/ + { + cr[1] = devp->config->compoutputdatarate; + } + + /* Control register B configuration block.*/ + { + cr[2] = devp->config->compfullscale; + } + + /* Mode register configuration block.*/ + { + cr[3] = 0; +#if LSM303DLHC_USE_ADVANCED || defined(__DOXYGEN__) + cr[3] |= devp->config->compmode; +#endif + } + +#if LSM303DLHC_SHARED_I2C + i2cAcquireBus((devp)->config->i2cp); + i2cStart((devp)->config->i2cp, (devp)->config->i2ccfg); +#endif /* LSM303DLHC_SHARED_I2C */ + + lsm303dlhcI2CWriteRegister(devp->config->i2cp, LSM303DLHC_SAD_COMP, + cr, 3); + +#if LSM303DLHC_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* LSM303DLHC_SHARED_I2C */ + + if(devp->config->compfullscale == LSM303DLHC_COMP_FS_1P3GA) { + devp->compfullscale = LSM303DLHC_COMP_1P3GA; + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + if(devp->config->compsensitivity == NULL) { + if(i != 2) { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_1P3GA; + } + else { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_1P3GA; + } + } + else { + devp->compsensitivity[i] = devp->config->compsensitivity[i]; + } + } + } + else if(devp->config->compfullscale == LSM303DLHC_COMP_FS_1P9GA) { + devp->compfullscale = LSM303DLHC_COMP_1P9GA; + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + if(devp->config->compsensitivity == NULL) { + if(i != 2) { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_1P9GA; + } + else { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_1P9GA; + } + } + else { + devp->compsensitivity[i] = devp->config->compsensitivity[i]; + } + } + } + else if(devp->config->compfullscale == LSM303DLHC_COMP_FS_2P5GA) { + devp->compfullscale = LSM303DLHC_COMP_2P5GA; + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + if(devp->config->compsensitivity == NULL) { + if(i != 2) { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_2P5GA; + } + else { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_2P5GA; + } + } + else { + devp->compsensitivity[i] = devp->config->compsensitivity[i]; + } + } + } + else if(devp->config->compfullscale == LSM303DLHC_COMP_FS_4P0GA) { + devp->compfullscale = LSM303DLHC_COMP_4P0GA; + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + if(devp->config->compsensitivity == NULL) { + if(i != 2) { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_4P0GA; + } + else { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_4P0GA; + } + } + else { + devp->compsensitivity[i] = devp->config->compsensitivity[i]; + } + } + } + else if(devp->config->compfullscale == LSM303DLHC_COMP_FS_4P7GA) { + devp->compfullscale = LSM303DLHC_COMP_4P7GA; + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + if(devp->config->compsensitivity == NULL) { + if(i != 2) { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_4P7GA; + } + else { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_4P7GA; + } + } + else { + devp->compsensitivity[i] = devp->config->compsensitivity[i]; + } + } + } + else if(devp->config->compfullscale == LSM303DLHC_COMP_FS_5P6GA) { + devp->compfullscale = LSM303DLHC_COMP_5P6GA; + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + if(devp->config->compsensitivity == NULL) { + if(i != 2) { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_5P6GA; + } + else { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_5P6GA; + } + } + else { + devp->compsensitivity[i] = devp->config->compsensitivity[i]; + } + } + } + else if(devp->config->compfullscale == LSM303DLHC_COMP_FS_8P1GA) { + devp->compfullscale = LSM303DLHC_COMP_8P1GA; + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) { + if(devp->config->compsensitivity == NULL) { + if(i != 2) { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_XY_8P1GA; + } + else { + devp->compsensitivity[i] = LSM303DLHC_COMP_SENS_Z_8P1GA; + } + } + else { + devp->compsensitivity[i] = devp->config->compsensitivity[i]; + } + } + } + else + osalDbgAssert(FALSE, "lsm303dlhcStart(), compass full scale issue"); + + /* Storing bias information */ + if(devp->config->compbias != NULL) + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) + devp->compbias[i] = devp->config->compbias[i]; + else + for(i = 0; i < LSM303DLHC_COMP_NUMBER_OF_AXES; i++) + devp->compbias[i] = LSM303DLHC_COMP_BIAS; + + /* This is the MEMS transient recovery time */ + osalThreadSleepMilliseconds(5); + + devp->state = LSM303DLHC_READY; +} + +/** + * @brief Deactivates the LSM303DLHC Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LSM303DLHCDriver object + * + * @api + */ +void lsm303dlhcStop(LSM303DLHCDriver *devp) { + uint8_t cr[2]; + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LSM303DLHC_STOP) || + (devp->state == LSM303DLHC_READY), + "lsm303dlhcStop(), invalid state"); + + if (devp->state == LSM303DLHC_READY) { +#if LSM303DLHC_SHARED_I2C + i2cAcquireBus((devp)->config->i2cp); + i2cStart((devp)->config->i2cp, (devp)->config->i2ccfg); +#endif /* LSM303DLHC_SHARED_I2C */ + + /* Disabling accelerometer. */ + cr[0] = LSM303DLHC_AD_ACC_CTRL_REG1; + cr[1] = LSM303DLHC_ACC_AE_DISABLED | LSM303DLHC_ACC_ODR_PD; + lsm303dlhcI2CWriteRegister(devp->config->i2cp, LSM303DLHC_SAD_ACC, + cr, 1); + + /* Disabling compass. */ + cr[0] = LSM303DLHC_AD_COMP_MR_REG; + cr[1] = LSM303DLHC_COMP_MD_SLEEP; + lsm303dlhcI2CWriteRegister(devp->config->i2cp, LSM303DLHC_SAD_COMP, + cr, 1); + + i2cStop((devp)->config->i2cp); +#if LSM303DLHC_SHARED_I2C + i2cReleaseBus((devp)->config->i2cp); +#endif /* LSM303DLHC_SHARED_I2C */ + } + devp->state = LSM303DLHC_STOP; +} +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.h b/ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.h new file mode 100644 index 0000000..98bc43a --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.h @@ -0,0 +1,955 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lsm303dlhc.h + * @brief LSM303DLHC MEMS interface module header. + * + * @addtogroup LSM303DLHC + * @ingroup EX_ST + * @{ + */ +#ifndef _LSM303DLHC_H_ +#define _LSM303DLHC_H_ + +#include "ex_accelerometer.h" +#include "ex_compass.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Version identification + * @{ + */ +/** + * @brief LSM303DLHC driver version string. + */ +#define EX_LSM303DLHC_VERSION "1.1.2" + +/** + * @brief LSM303DLHC driver version major number. + */ +#define EX_LSM303DLHC_MAJOR 1 + +/** + * @brief LSM303DLHC driver version minor number. + */ +#define EX_LSM303DLHC_MINOR 1 + +/** + * @brief LSM303DLHC driver version patch number. + */ +#define EX_LSM303DLHC_PATCH 2 +/** @} */ + +/** + * @brief LSM303DLHC accelerometer subsystem characteristics. + * @note Sensitivity is expressed as milli-G/LSB whereas + * 1 milli-G = 0.00980665 m/s^2. + * @note Bias is expressed as milli-G. + * + * @{ + */ +#define LSM303DLHC_ACC_NUMBER_OF_AXES 3U + +#define LSM303DLHC_ACC_2G 2.0f +#define LSM303DLHC_ACC_4G 4.0f +#define LSM303DLHC_ACC_8G 8.0f +#define LSM303DLHC_ACC_16G 16.0f + +#define LSM303DLHC_ACC_SENS_2G 0.0610f +#define LSM303DLHC_ACC_SENS_4G 0.1221f +#define LSM303DLHC_ACC_SENS_8G 0.2442f +#define LSM303DLHC_ACC_SENS_16G 0.4884f + +#define LSM303DLHC_ACC_BIAS 0.0f +/** @} */ + +/** + * @brief LSM303DLHC compass subsystem characteristics. + * @note Sensitivity is expressed as G/LSB whereas G stands for Gauss. + * @note Bias is expressed as G. + * + * @{ + */ +#define LSM303DLHC_COMP_NUMBER_OF_AXES 3U + +#define LSM303DLHC_COMP_1P3GA 1.3f +#define LSM303DLHC_COMP_1P9GA 1.9f +#define LSM303DLHC_COMP_2P5GA 2.5f +#define LSM303DLHC_COMP_4P0GA 4.0f +#define LSM303DLHC_COMP_4P7GA 4.7f +#define LSM303DLHC_COMP_5P6GA 5.6f +#define LSM303DLHC_COMP_8P1GA 8.1f + +#define LSM303DLHC_COMP_SENS_XY_1P3GA 0.000909f +#define LSM303DLHC_COMP_SENS_XY_1P9GA 0.001169f +#define LSM303DLHC_COMP_SENS_XY_2P5GA 0.0014925f +#define LSM303DLHC_COMP_SENS_XY_4P0GA 0.0022222f +#define LSM303DLHC_COMP_SENS_XY_4P7GA 0.0025000f +#define LSM303DLHC_COMP_SENS_XY_5P6GA 0.0030303f +#define LSM303DLHC_COMP_SENS_XY_8P1GA 0.0043478f + +#define LSM303DLHC_COMP_SENS_Z_1P3GA 0.0010204f +#define LSM303DLHC_COMP_SENS_Z_1P9GA 0.0013071f +#define LSM303DLHC_COMP_SENS_Z_2P5GA 0.0016666f +#define LSM303DLHC_COMP_SENS_Z_4P0GA 0.0025000f +#define LSM303DLHC_COMP_SENS_Z_4P7GA 0.0028169f +#define LSM303DLHC_COMP_SENS_Z_5P6GA 0.0033898f +#define LSM303DLHC_COMP_SENS_Z_8P1GA 0.0048780f + +#define LSM303DLHC_COMP_BIAS 0.0f +/** @} */ + +/** + * @name LSM303DLHC communication interfaces related bit masks + * @{ + */ +#define LSM303DLHC_DI_MASK 0xFF +#define LSM303DLHC_DI(n) (1 << n) +#define LSM303DLHC_AD_MASK 0x7F +#define LSM303DLHC_AD(n) (1 << n) +#define LSM303DLHC_MS (1 << 7) +/** @} */ + +/** + * @name LSM303DLHC register addresses + * @{ + */ +#define LSM303DLHC_AD_ACC_CTRL_REG1 0x20 +#define LSM303DLHC_AD_ACC_CTRL_REG2 0x21 +#define LSM303DLHC_AD_ACC_CTRL_REG3 0x22 +#define LSM303DLHC_AD_ACC_CTRL_REG4 0x23 +#define LSM303DLHC_AD_ACC_CTRL_REG5 0x24 +#define LSM303DLHC_AD_ACC_CTRL_REG6 0x25 +#define LSM303DLHC_AD_ACC_REFERENCE 0x26 +#define LSM303DLHC_AD_ACC_STATUS_REG 0x27 +#define LSM303DLHC_AD_ACC_OUT_X_L 0x28 +#define LSM303DLHC_AD_ACC_OUT_X_H 0x29 +#define LSM303DLHC_AD_ACC_OUT_Y_L 0x2A +#define LSM303DLHC_AD_ACC_OUT_Y_H 0x2B +#define LSM303DLHC_AD_ACC_OUT_Z_L 0x2C +#define LSM303DLHC_AD_ACC_OUT_Z_H 0x2D +#define LSM303DLHC_AD_ACC_FIFO_CTRL_REG 0x2E +#define LSM303DLHC_AD_ACC_FIFO_SRC_REG 0x2F +#define LSM303DLHC_AD_ACC_INT1_CFG 0x30 +#define LSM303DLHC_AD_ACC_INT1_SRC 0x31 +#define LSM303DLHC_AD_ACC_INT1_THS 0x32 +#define LSM303DLHC_AD_ACC_INT1_DURATION 0x33 +#define LSM303DLHC_AD_ACC_INT2_CFG 0x34 +#define LSM303DLHC_AD_ACC_INT2_SRC 0x35 +#define LSM303DLHC_AD_ACC_INT2_THS 0x36 +#define LSM303DLHC_AD_ACC_INT2_DURATION 0x37 +#define LSM303DLHC_AD_ACC_CLICK_CFG 0x38 +#define LSM303DLHC_AD_ACC_CLICK_SRC 0x39 +#define LSM303DLHC_AD_ACC_CLICK_THS 0x3A +#define LSM303DLHC_AD_ACC_TIME_LIMIT 0x3B +#define LSM303DLHC_AD_ACC_TIME_LATENCY 0x3C +#define LSM303DLHC_AD_ACC_TIME_WINDOW 0x3D +#define LSM303DLHC_AD_COMP_CRA_REG 0x00 +#define LSM303DLHC_AD_COMP_CRB_REG 0x01 +#define LSM303DLHC_AD_COMP_MR_REG 0x02 +#define LSM303DLHC_AD_COMP_OUT_X_H 0x03 +#define LSM303DLHC_AD_COMP_OUT_X_L 0x04 +#define LSM303DLHC_AD_COMP_OUT_Z_H 0x05 +#define LSM303DLHC_AD_COMP_OUT_Z_L 0x06 +#define LSM303DLHC_AD_COMP_OUT_Y_H 0x07 +#define LSM303DLHC_AD_COMP_OUT_Y_L 0x08 +#define LSM303DLHC_AD_COMP_SR_REG 0x09 +#define LSM303DLHC_AD_COMP_IRA_REG 0x0A +#define LSM303DLHC_AD_COMP_IRB_REG 0x0B +#define LSM303DLHC_AD_COMP_IRC_REG 0x0C +#define LSM303DLHC_AD_COMP_TEMP_OUT_H 0x31 +#define LSM303DLHC_AD_COMP_TEMP_OUT_L 0x32 +/** @} */ + +/** + * @name LSM303DLHC_CTRL_REG1_A register bits definitions + * @{ + */ +#define LSM303DLHC_CTRL_REG1_A_MASK 0xFF +#define LSM303DLHC_CTRL_REG1_A_XEN (1 << 0) +#define LSM303DLHC_CTRL_REG1_A_YEN (1 << 1) +#define LSM303DLHC_CTRL_REG1_A_ZEN (1 << 2) +#define LSM303DLHC_CTRL_REG1_A_LPEN (1 << 3) +#define LSM303DLHC_CTRL_REG1_A_ODR0 (1 << 4) +#define LSM303DLHC_CTRL_REG1_A_ODR1 (1 << 5) +#define LSM303DLHC_CTRL_REG1_A_ODR2 (1 << 6) +#define LSM303DLHC_CTRL_REG1_A_ODR3 (1 << 7) +/** @} */ + +/** + * @name LSM303DLHC_CTRL_REG2_A register bits definitions + * @{ + */ +#define LSM303DLHC_CTRL_REG2_A_MASK 0xFF +#define LSM303DLHC_CTRL_REG2_A_HPIS1 (1 << 0) +#define LSM303DLHC_CTRL_REG2_A_HPIS2 (1 << 1) +#define LSM303DLHC_CTRL_REG2_A_HPCLICK (1 << 2) +#define LSM303DLHC_CTRL_REG2_A_FDS (1 << 3) +#define LSM303DLHC_CTRL_REG2_A_HPCF1 (1 << 4) +#define LSM303DLHC_CTRL_REG2_A_HPCF2 (1 << 5) +#define LSM303DLHC_CTRL_REG2_A_HPM0 (1 << 6) +#define LSM303DLHC_CTRL_REG2_A_HPM1 (1 << 7) +/** @} */ + +/** + * @name LSM303DLHC_CTRL_REG3_A register bits definitions + * @{ + */ +#define LSM303DLHC_CTRL_REG3_A_MASK 0xFD +#define LSM303DLHC_CTRL_REG3_A_I1_OVERRUN (1 << 1) +#define LSM303DLHC_CTRL_REG3_A_I1_WTM (1 << 2) +#define LSM303DLHC_CTRL_REG3_A_I1_DRDY2 (1 << 3) +#define LSM303DLHC_CTRL_REG3_A_I1_DRDY1 (1 << 4) +#define LSM303DLHC_CTRL_REG3_A_I1_AOI2 (1 << 5) +#define LSM303DLHC_CTRL_REG3_A_I1_AOI1 (1 << 6) +#define LSM303DLHC_CTRL_REG3_A_I1_CLICK (1 << 7) +/** @} */ + +/** + * @name LSM303DLHC_CTRL_REG4_A register bits definitions + * @{ + */ +#define LSM303DLHC_CTRL_REG4_A_MASK 0xF9 +#define LSM303DLHC_CTRL_REG4_A_SIM (1 << 0) +#define LSM303DLHC_CTRL_REG4_A_HR (1 << 3) +#define LSM303DLHC_CTRL_REG4_A_FS_MASK 0x30 +#define LSM303DLHC_CTRL_REG4_A_FS0 (1 << 4) +#define LSM303DLHC_CTRL_REG4_A_FS1 (1 << 5) +#define LSM303DLHC_CTRL_REG4_A_BLE (1 << 6) +#define LSM303DLHC_CTRL_REG4_A_BDU (1 << 7) +/** @} */ + +/** + * @name LSM303DLHC_CTRL_REG5_A register bits definitions + * @{ + */ +#define LSM303DLHC_CTRL_REG5_A_MASK 0xCF +#define LSM303DLHC_CTRL_REG5_A_D4D_INT2 (1 << 0) +#define LSM303DLHC_CTRL_REG5_A_LIR_INT2 (1 << 1) +#define LSM303DLHC_CTRL_REG5_A_D4D_INT1 (1 << 2) +#define LSM303DLHC_CTRL_REG5_A_LIR_INT1 (1 << 3) +#define LSM303DLHC_CTRL_REG5_A_FIFO_EN (1 << 6) +#define LSM303DLHC_CTRL_REG5_A_BOOT (1 << 7) +/** @} */ + +/** + * @name LSM303DLHC_CTRL_REG6_A register bits definitions + * @{ + */ +#define LSM303DLHC_CTRL_REG6_A_MASK 0xFA +#define LSM303DLHC_CTRL_REG6_A_H_LACTIVE (1 << 1) +#define LSM303DLHC_CTRL_REG6_A_P2_ACT (1 << 3) +#define LSM303DLHC_CTRL_REG6_A_BOOT_I1 (1 << 4) +#define LSM303DLHC_CTRL_REG6_A_I2_INT2 (1 << 5) +#define LSM303DLHC_CTRL_REG6_A_I2_INT1 (1 << 6) +#define LSM303DLHC_CTRL_REG6_A_I2_CLICKEN (1 << 7) +/** @} */ + +/** + * @name LSM303DLHC_CRA_REG_M register bits definitions + * @{ + */ +#define LSM303DLHC_CRA_REG_M_MASK 0x9C +#define LSM303DLHC_CRA_REG_M_DO0 (1 << 2) +#define LSM303DLHC_CRA_REG_M_DO1 (1 << 3) +#define LSM303DLHC_CRA_REG_M_DO2 (1 << 4) +#define LSM303DLHC_CRA_REG_M_TEMP_EN (1 << 7) +/** @} */ + +/** + * @name LSM303DLHC_CRB_REG_M register bits definitions + * @{ + */ +#define LSM303DLHC_CRB_REG_M_MASK 0xE0 +#define LSM303DLHC_CRB_REG_M_GN_MASK 0xE0 +#define LSM303DLHC_CRB_REG_M_GN0 (1 << 5) +#define LSM303DLHC_CRB_REG_M_GN1 (1 << 6) +#define LSM303DLHC_CRB_REG_M_GN2 (1 << 7) + +/** + * @name LSM303DLHC_CRB_REG_M register bits definitions + * @{ + */ +#define LSM303DLHC_MR_REG_M_MASK 0x03 +#define LSM303DLHC_MR_REG_M_MD0 (1 << 0) +#define LSM303DLHC_MR_REG_M_MD1 (1 << 1) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief LSM303DLHC SPI interface switch. + * @details If set to @p TRUE the support for SPI is included. + * @note The default is @p FALSE. + */ +#if !defined(LSM303DLHC_USE_SPI) || defined(__DOXYGEN__) +#define LSM303DLHC_USE_SPI FALSE +#endif + +/** + * @brief LSM303DLHC shared SPI switch. + * @details If set to @p TRUE the device acquires SPI bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LSM303DLHC_SHARED_SPI) || defined(__DOXYGEN__) +#define LSM303DLHC_SHARED_SPI FALSE +#endif + +/** + * @brief LSM303DLHC I2C interface switch. + * @details If set to @p TRUE the support for I2C is included. + * @note The default is @p TRUE. + */ +#if !defined(LSM303DLHC_USE_I2C) || defined(__DOXYGEN__) +#define LSM303DLHC_USE_I2C TRUE +#endif + +/** + * @brief LSM303DLHC shared I2C switch. + * @details If set to @p TRUE the device acquires I2C bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LSM303DLHC_SHARED_I2C) || defined(__DOXYGEN__) +#define LSM303DLHC_SHARED_I2C FALSE +#endif + +/** + * @brief LSM303DLHC advanced configurations switch. + * @details If set to @p TRUE more configurations are available. + * @note The default is @p FALSE. + */ +#if !defined(LSM303DLHC_USE_ADVANCED) || defined(__DOXYGEN__) +#define LSM303DLHC_USE_ADVANCED FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !(LSM303DLHC_USE_SPI ^ LSM303DLHC_USE_I2C) +#error "LSM303DLHC_USE_SPI and LSM303DLHC_USE_I2C cannot be both true or both false" +#endif + +#if LSM303DLHC_USE_SPI && !HAL_USE_SPI +#error "LSM303DLHC_USE_SPI requires HAL_USE_SPI" +#endif + +#if LSM303DLHC_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION +#error "LSM303DLHC_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" +#endif + +#if LSM303DLHC_USE_I2C && !HAL_USE_I2C +#error "LSM303DLHC_USE_I2C requires HAL_USE_I2C" +#endif + +#if LSM303DLHC_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION +#error "LSM303DLHC_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" +#endif + +/* + * CHTODO: Add support for LSM303DLHC over SPI. + */ +#if LSM303DLHC_USE_SPI +#error "LSM303DLHC over SPI still not supported" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @name LSM303DLHC accelerometer subsystem data structures and types. + * @{ + */ +/** + * @brief Structure representing a LSM303DLHC driver. + */ +typedef struct LSM303DLHCDriver LSM303DLHCDriver; + +/** + * @brief LSM303DLHC accelerometer subsystem full scale. + */ +typedef enum { + LSM303DLHC_ACC_FS_2G = 0x00, /**< Full scale �2g. */ + LSM303DLHC_ACC_FS_4G = 0x10, /**< Full scale �4g. */ + LSM303DLHC_ACC_FS_8G = 0x20, /**< Full scale �8g. */ + LSM303DLHC_ACC_FS_16G = 0x30 /**< Full scale �16g. */ +} lsm303dlhc_acc_fs_t; + +/** + * @brief LSM303DLHC accelerometer subsystem output data rate. + */ +typedef enum { + LSM303DLHC_ACC_ODR_PD = 0x00, /**< Power down */ + LSM303DLHC_ACC_ODR_1Hz = 0x10, /**< ODR 1 Hz */ + LSM303DLHC_ACC_ODR_10Hz = 0x20, /**< ODR 10 Hz */ + LSM303DLHC_ACC_ODR_25Hz = 0x30, /**< ODR 25 Hz */ + LSM303DLHC_ACC_ODR_50Hz = 0x40, /**< ODR 50 Hz */ + LSM303DLHC_ACC_ODR_100Hz = 0x50, /**< ODR 100 Hz */ + LSM303DLHC_ACC_ODR_200Hz = 0x60, /**< ODR 200 Hz */ + LSM303DLHC_ACC_ODR_400Hz = 0x70, /**< ODR 400 Hz */ + LSM303DLHC_ACC_ODR_1620Hz = 0x80, /**< ODR 1620 Hz (LP only) */ + LSM303DLHC_ACC_ODR_1344Hz = 0x90 /**< ODR 1344 Hz or 5376 Hz in LP */ +} lsm303dlhc_acc_odr_t; + +/** + * @brief LSM303DLHC accelerometer subsystem axes enabling. + */ +typedef enum { + LSM303DLHC_ACC_AE_DISABLED = 0x00,/**< All axes disabled. */ + LSM303DLHC_ACC_AE_X = 0x01, /**< Only X-axis enabled. */ + LSM303DLHC_ACC_AE_Y = 0x02, /**< Only Y-axis enabled. */ + LSM303DLHC_ACC_AE_XY = 0x03, /**< X and Y axes enabled. */ + LSM303DLHC_ACC_AE_Z = 0x04, /**< Only Z-axis enabled. */ + LSM303DLHC_ACC_AE_XZ = 0x05, /**< X and Z axes enabled. */ + LSM303DLHC_ACC_AE_YZ = 0x06, /**< Y and Z axes enabled. */ + LSM303DLHC_ACC_AE_XYZ = 0x07 /**< All axes enabled. */ +} lsm303dlhc_acc_ae_t; + +/** + * @brief LSM303DLHC accelerometer subsystem low power mode. + */ +typedef enum { + LSM303DLHC_ACC_LP_DISABLED = 0x00,/**< Low power mode disabled. */ + LSM303DLHC_ACC_LP_ENABLED = 0x40 /**< Low power mode enabled. */ +} lsm303dlhc_acc_lp_t; + +/** + * @brief LSM303DLHC accelerometer subsystem high resolution mode. + */ +typedef enum { + LSM303DLHC_ACC_HR_DISABLED = 0x00,/**< High resolution mode disabled. */ + LSM303DLHC_ACC_HR_ENABLED = 0x08 /**< High resolution mode enabled. */ +} lsm303dlhc_acc_hr_t; + +/** + * @brief LSM303DLHC accelerometer subsystem block data update. + */ +typedef enum { + LSM303DLHC_ACC_BDU_CONT = 0x00, /**< Continuous update */ + LSM303DLHC_ACC_BDU_BLOCK = 0x80 /**< Update blocked */ +} lsm303dlhc_acc_bdu_t; + +/** + * @brief LSM303DLHC accelerometer endianness. + */ +typedef enum { + LSM303DLHC_ACC_END_LITTLE = 0x00, /**< Little Endian */ + LSM303DLHC_ACC_END_BIG = 0x40 /**< Big Endian */ +} lsm303dlhc_acc_end_t; + +/** + * @name LSM303DLHC compass subsystem data structures and types. + * @{ + */ +/** + * @brief LSM303DLHC compass subsystem full scale. + */ +typedef enum { + LSM303DLHC_COMP_FS_1P3GA = 0x20, /**< Full scale �1.3 Gauss */ + LSM303DLHC_COMP_FS_1P9GA = 0x40, /**< Full scale �1.9 Gauss */ + LSM303DLHC_COMP_FS_2P5GA = 0x60, /**< Full scale �2.5 Gauss */ + LSM303DLHC_COMP_FS_4P0GA = 0x80, /**< Full scale �4.0 Gauss */ + LSM303DLHC_COMP_FS_4P7GA = 0xA0, /**< Full scale �4.7 Gauss */ + LSM303DLHC_COMP_FS_5P6GA = 0xC0, /**< Full scale �5.6 Gauss */ + LSM303DLHC_COMP_FS_8P1GA = 0xE0 /**< Full scale �8.1 Gauss */ +} lsm303dlhc_comp_fs_t; + +/** + * @brief LSM303DLHC compass subsystem output data rate. + */ +typedef enum { + LSM303DLHC_COMP_ODR_0P75HZ = 0x00,/**< ODR 0.75 Hz */ + LSM303DLHC_COMP_ODR_1P5HZ = 0x04, /**< ODR 1.5 Hz */ + LSM303DLHC_COMP_ODR_3P0HZ = 0x08, /**< ODR 3 Hz */ + LSM303DLHC_COMP_ODR_7P5HZ = 0x0C, /**< ODR 7.5 Hz */ + LSM303DLHC_COMP_ODR_15HZ = 0x10, /**< ODR 15 Hz */ + LSM303DLHC_COMP_ODR_30HZ = 0x14, /**< ODR 30 Hz */ + LSM303DLHC_COMP_ODR_75HZ = 0x18, /**< ODR 75 Hz */ + LSM303DLHC_COMP_ODR_220HZ = 0x1C /**< ODR 220 Hz */ +} lsm303dlhc_comp_odr_t; + +/** + * @brief LSM303DLHC compass subsystem working mode. + */ +typedef enum { + LSM303DLHC_COMP_MD_CONT = 0x00, /**< Continuous-Conversion Mode */ + LSM303DLHC_COMP_MD_BLOCK = 0x01, /**< Single-Conversion Mode */ + LSM303DLHC_COMP_MD_SLEEP = 0x02 /**< Sleep Mode */ +} lsm303dlhc_comp_md_t; + +/** + * @name LSM303DLHC main system data structures and types. + * @{ + */ +/** + * @brief Driver state machine possible states. + */ +typedef enum { + LSM303DLHC_UNINIT = 0, /**< Not initialized. */ + LSM303DLHC_STOP = 1, /**< Stopped. */ + LSM303DLHC_READY = 2, /**< Ready. */ +} lsm303dlhc_state_t; + +/** + * @brief LSM303DLHC configuration structure. + */ +typedef struct { + /** + * @brief I2C driver associated to this LSM303DLHC. + */ + I2CDriver *i2cp; + /** + * @brief I2C configuration associated to this LSM303DLHC. + */ + const I2CConfig *i2ccfg; + /** + * @brief LSM303DLHC accelerometer subsystem initial sensitivity. + */ + float *accsensitivity; + /** + * @brief LSM303DLHC accelerometer subsystem initial bias. + */ + float *accbias; + /** + * @brief LSM303DLHC accelerometer subsystem initial full scale. + */ + lsm303dlhc_acc_fs_t accfullscale; + /** + * @brief LSM303DLHC accelerometer subsystem output data rate. + */ + lsm303dlhc_acc_odr_t accoutdatarate; +#if LSM303DLHC_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief LSM303DLHC accelerometer subsystem low power mode. + */ + lsm303dlhc_acc_lp_t acclowpower; + /** + * @brief LSM303DLHC accelerometer subsystem high resolution mode. + */ + lsm303dlhc_acc_hr_t acchighresmode; + /** + * @brief LSM303DLHC accelerometer subsystem block data update. + */ + lsm303dlhc_acc_bdu_t accblockdataupdate; + /** + * @brief LSM303DLHC accelerometer endianness. + */ + lsm303dlhc_acc_end_t accendianess; +#endif + /** + * @brief LSM303DLHC compass initial sensitivity. + */ + float *compsensitivity; + /** + * @brief LSM303DLHC compass initial bias. + */ + float *compbias; + /** + * @brief LSM303DLHC compass subsystem initial full scale. + */ + lsm303dlhc_comp_fs_t compfullscale; + /** + * @brief LSM303DLHC compass subsystem output data rate. + */ + lsm303dlhc_comp_odr_t compoutputdatarate; +#if LSM303DLHC_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief LSM303DLHC compass subsystem working mode. + */ + lsm303dlhc_comp_md_t compmode; +#endif +} LSM303DLHCConfig; + +/** + * @brief @p LSM303DLHC specific methods. + */ +#define _lsm303dlhc_methods_alone \ + /* Change full scale value of LSM303DLHC accelerometer subsystem.*/ \ + msg_t (*acc_set_full_scale)(LSM303DLHCDriver *devp, \ + lsm303dlhc_acc_fs_t fs); \ + /* Change full scale value of LSM303DLHC compass subsystem.*/ \ + msg_t (*comp_set_full_scale)(LSM303DLHCDriver *devp, \ + lsm303dlhc_comp_fs_t fs); \ + +/** + * @brief @p LSM303DLHC specific methods with inherited ones. + */ +#define _lsm303dlhc_methods \ + _base_object_methods \ + _lsm303dlhc_methods_alone + +/** + * @extends BaseObjectVMT + * + * @brief @p LSM303DLHC virtual methods table. + */ +struct LSM303DLHCVMT { + _lsm303dlhc_methods +}; + +/** + * @brief @p LSM303DLHCDriver specific data. + */ +#define _lsm303dlhc_data \ + _base_sensor_data \ + /* Driver state.*/ \ + lsm303dlhc_state_t state; \ + /* Current configuration data.*/ \ + const LSM303DLHCConfig *config; \ + /* Accelerometer subsystem axes number.*/ \ + size_t accaxes; \ + /* Accelerometer subsystem current sensitivity.*/ \ + float accsensitivity[LSM303DLHC_ACC_NUMBER_OF_AXES]; \ + /* Accelerometer subsystem current bias .*/ \ + float accbias[LSM303DLHC_ACC_NUMBER_OF_AXES]; \ + /* Accelerometer subsystem current full scale value.*/ \ + float accfullscale; \ + /* Compass subsystem axes number.*/ \ + size_t compaxes; \ + /* Compass subsystem current sensitivity.*/ \ + float compsensitivity[LSM303DLHC_COMP_NUMBER_OF_AXES];\ + /* Compass subsystem current bias.*/ \ + float compbias[LSM303DLHC_COMP_NUMBER_OF_AXES]; \ + /* Compass subsystem current full scale value.*/ \ + float compfullscale; + +/** + * @brief LSM303DLHC 6-axis accelerometer/compass class. + */ +struct LSM303DLHCDriver { + /** @brief Virtual Methods Table.*/ + const struct LSM303DLHCVMT *vmt; + /** @brief Base accelerometer interface.*/ + BaseAccelerometer acc_if; + /** @brief Base compass interface.*/ + BaseCompass comp_if; + _lsm303dlhc_data +}; +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Return the number of axes of the BaseAccelerometer. + * + * @param[in] devp pointer to @p LSM303DLHCDriver. + * + * @return the number of axes. + * + * @api + */ +#define lsm303dlhcAccelerometerGetAxesNumber(devp) \ + accelerometerGetAxesNumber(&((devp)->acc_if)) + +/** + * @brief Retrieves raw data from the BaseAccelerometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM303DLHCDriver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm303dlhcAccelerometerReadRaw(devp, axes) \ + accelerometerReadRaw(&((devp)->acc_if), axes) + +/** + * @brief Retrieves cooked data from the BaseAccelerometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as milli-G. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM303DLHCDriver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm303dlhcAccelerometerReadCooked(devp, axes) \ + accelerometerReadCooked(&((devp)->acc_if), axes) + +/** + * @brief Set bias values for the BaseAccelerometer. + * @note Bias must be expressed as milli-G. + * @note The bias buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM303DLHCDriver. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm303dlhcAccelerometerSetBias(devp, bp) \ + accelerometerSetBias(&((devp)->acc_if), bp) + +/** + * @brief Reset bias values for the BaseAccelerometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p LSM303DLHCDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm303dlhcAccelerometerResetBias(devp) \ + accelerometerResetBias(&((devp)->acc_if)) + +/** + * @brief Set sensitivity values for the BaseAccelerometer. + * @note Sensitivity must be expressed as milli-G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM303DLHCDriver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm303dlhcAccelerometerSetSensitivity(devp, sp) \ + accelerometerSetSensitivity(&((devp)->acc_if), sp) + +/** + * @brief Reset sensitivity values for the BaseAccelerometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p LSM303DLHCDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lsm303dlhcAccelerometerResetSensitivity(devp) \ + accelerometerResetSensitivity(&((devp)->acc_if)) + +/** + * @brief Changes the LSM303DLHCDriver accelerometer fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LSM303DLHCDriver. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lsm303dlhcAccelerometerSetFullScale(devp, fs) \ + (devp)->vmt->acc_set_full_scale(devp, fs) + +/** + * @brief Return the number of axes of the BaseCompass. + * + * @param[in] devp pointer to @p LSM303DLHCDriver. + * + * @return the number of axes. + * + * @api + */ +#define lsm303dlhcCompassGetAxesNumber(devp) \ + compassGetAxesNumber(&((devp)->comp_if)) + +/** + * @brief Retrieves raw data from the BaseCompass. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] devp pointer to @p BaseCompass interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm303dlhcCompassReadRaw(devp, axes) \ + compassReadRaw(&((devp)->comp_if), axes) + +/** + * @brief Retrieves cooked data from the BaseCompass. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as G. + * @note The axes array must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] devp pointer to @p BaseCompass interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm303dlhcCompassReadCooked(devp, axes) \ + compassReadCooked(&((devp)->comp_if), axes) + +/** + * @brief Set bias values for the BaseCompass. + * @note Bias must be expressed as G. + * @note The bias buffer must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] devp pointer to @p BaseCompass interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm303dlhcCompassSetBias(devp, bp) \ + compassSetBias(&((devp)->comp_if), bp) + +/** + * @brief Reset bias values for the BaseCompass. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p LSM303DLHCDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm303dlhcCompassResetBias(devp) \ + compassResetBias(&((devp)->comp_if)) + +/** + * @brief Set sensitivity values for the BaseCompass. + * @note Sensitivity must be expressed as G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseCompass axes number. + * + * @param[in] devp pointer to @p LSM303DLHCDriver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm303dlhcCompassSetSensitivity(devp, sp) \ + compassSetSensitivity(&((devp)->comp_if), sp) + +/** + * @brief Reset sensitivity values for the BaseCompass. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p LSM303DLHCDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lsm303dlhcCompassResetSensitivity(devp) \ + compassResetSensitivity(&((devp)->comp_if)) + +/** + * @brief Changes the LSM303DLHCDriver compass fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LSM303DLHCDriver. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lsm303dlhcCompassSetFullScale(devp, fs) \ + (devp)->vmt->comp_set_full_scale(devp, fs) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void lsm303dlhcObjectInit(LSM303DLHCDriver *devp); + void lsm303dlhcStart(LSM303DLHCDriver *devp, const LSM303DLHCConfig *config); + void lsm303dlhcStop(LSM303DLHCDriver *devp); +#ifdef __cplusplus +} +#endif + +#endif /* _LSM303DLHC_H_ */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.mk b/ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.mk new file mode 100644 index 0000000..4e192aa --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.mk @@ -0,0 +1,10 @@ +# List of all the LSM303DLHC device files. +LSM303DLHCSRC := $(CHIBIOS)/os/ex/devices/ST/lsm303dlhc.c + +# Required include directories +LSM303DLHCINC := $(CHIBIOS)/os/ex/include \ + $(CHIBIOS)/os/ex/devices/ST + +# Shared variables +ALLCSRC += $(LSM303DLHCSRC) +ALLINC += $(LSM303DLHCINC) \ No newline at end of file diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.c b/ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.c new file mode 100644 index 0000000..4f1b9ec --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.c @@ -0,0 +1,1109 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lsm6ds0.c + * @brief LSM6DS0 MEMS interface module code. + * + * @addtogroup LSM6DS0 + * @ingroup EX_ST + * @{ + */ + +#include "hal.h" +#include "lsm6ds0.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if (LSM6DS0_USE_I2C) || defined(__DOXYGEN__) +/** + * @brief Reads registers value using I2C. + * @pre The I2C interface must be initialized and the driver started. + * @note IF_ADD_INC bit must be 1 in CTRL_REG8 + * + * @param[in] i2cp pointer to the I2C interface + * @param[in] sad slave address without R bit + * @param[in] reg first sub-register address + * @param[out] rxbuf pointer to an output buffer + * @param[in] n number of consecutive register to read + * @return the operation status. + * @notapi + */ +msg_t lsm6ds0I2CReadRegister(I2CDriver *i2cp, lsm6ds0_sad_t sad, uint8_t reg, + uint8_t* rxbuf, size_t n) { + + return i2cMasterTransmitTimeout(i2cp, sad, ®, 1, rxbuf, n, + TIME_INFINITE); +} + +/** + * @brief Writes a value into a register using I2C. + * @pre The I2C interface must be initialized and the driver started. + * + * @param[in] i2cp pointer to the I2C interface + * @param[in] sad slave address without R bit + * @param[in] txbuf buffer containing sub-address value in first position + * and values to write + * @param[in] n size of txbuf less one (not considering the first + * element) + * @return the operation status. + * @notapi + */ +#define lsm6ds0I2CWriteRegister(i2cp, sad, txbuf, n) \ + i2cMasterTransmitTimeout(i2cp, sad, txbuf, n + 1, NULL, 0, \ + TIME_INFINITE) +#endif /* LSM6DS0_USE_I2C */ + +/** + * @brief Return the number of axes of the BaseAccelerometer. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return the number of axes. + */ +static size_t acc_get_axes_number(void *ip) { + (void)ip; + + return LSM6DS0_ACC_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseAccelerometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t acc_read_raw(void *ip, int32_t axes[]) { + LSM6DS0Driver* devp; + uint8_t buff [LSM6DS0_ACC_NUMBER_OF_AXES * 2], i; + int16_t tmp; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DS0Driver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM6DS0_READY), + "acc_read_raw(), invalid state"); +#if LSM6DS0_USE_I2C + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "acc_read_raw(), channel not ready"); + +#if LSM6DS0_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM6DS0_SHARED_I2C */ + + msg = lsm6ds0I2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, + LSM6DS0_AD_OUT_X_L_XL, buff, + LSM6DS0_ACC_NUMBER_OF_AXES * 2); + +#if LSM6DS0_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DS0_SHARED_I2C */ +#endif /* LSM6DS0_USE_I2C */ + if(msg == MSG_OK) + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) { + tmp = buff[2 * i] + (buff[2 * i + 1] << 8); + axes[i] = (int32_t)tmp; + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseAccelerometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as milli-G. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t acc_read_cooked(void *ip, float axes[]) { + LSM6DS0Driver* devp; + uint32_t i; + int32_t raw[LSM6DS0_ACC_NUMBER_OF_AXES]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DS0Driver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM6DS0_READY), + "acc_read_cooked(), invalid state"); + + msg = acc_read_raw(ip, raw); + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) { + axes[i] = (raw[i] * devp->accsensitivity[i]) - devp->accbias[i]; + } + return msg; +} + +/** + * @brief Set bias values for the BaseAccelerometer. + * @note Bias must be expressed as milli-G. + * @note The bias buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_set_bias(void *ip, float *bp) { + LSM6DS0Driver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DS0Driver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM6DS0_READY), + "acc_set_bias(), invalid state"); + + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) { + devp->accbias[i] = bp[i]; + } + return msg; +} + +/** + * @brief Reset bias values for the BaseAccelerometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_reset_bias(void *ip) { + LSM6DS0Driver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DS0Driver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM6DS0_READY), + "acc_reset_bias(), invalid state"); + + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = LSM6DS0_ACC_BIAS; + return msg; +} + +/** + * @brief Set sensitivity values for the BaseAccelerometer. + * @note Sensitivity must be expressed as milli-G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_set_sensivity(void *ip, float *sp) { + LSM6DS0Driver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DS0Driver*, (BaseAccelerometer*)ip); + + osalDbgCheck((ip != NULL) && (sp != NULL)); + + osalDbgAssert((devp->state == LSM6DS0_READY), + "acc_set_sensivity(), invalid state"); + + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] = sp[i]; + } + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseAccelerometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t acc_reset_sensivity(void *ip) { + LSM6DS0Driver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DS0Driver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM6DS0_READY), + "acc_reset_sensivity(), invalid state"); + + if(devp->config->accfullscale == LSM6DS0_ACC_FS_2G) + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LSM6DS0_ACC_SENS_2G; + else if(devp->config->accfullscale == LSM6DS0_ACC_FS_4G) + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LSM6DS0_ACC_SENS_4G; + else if(devp->config->accfullscale == LSM6DS0_ACC_FS_8G) + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LSM6DS0_ACC_SENS_8G; + else if(devp->config->accfullscale == LSM6DS0_ACC_FS_16G) + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LSM6DS0_ACC_SENS_16G; + else { + osalDbgAssert(FALSE, "reset_sensivity(), accelerometer full scale issue"); + msg = MSG_RESET; + } + return msg; +} + +/** + * @brief Changes the LSM6DS0Driver accelerometer fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LSM6DS0Driver interface. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t acc_set_full_scale(LSM6DS0Driver *devp, lsm6ds0_acc_fs_t fs) { + float newfs, scale; + uint8_t i, buff[2]; + msg_t msg; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LSM6DS0_READY), + "acc_set_full_scale(), invalid state"); + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "acc_set_full_scale(), channel not ready"); + + /* Computing new fullscale value.*/ + if(fs == LSM6DS0_ACC_FS_2G) { + newfs = LSM6DS0_ACC_2G; + } + else if(fs == LSM6DS0_ACC_FS_4G) { + newfs = LSM6DS0_ACC_4G; + } + else if(fs == LSM6DS0_ACC_FS_8G) { + newfs = LSM6DS0_ACC_8G; + } + else if(fs == LSM6DS0_ACC_FS_16G) { + newfs = LSM6DS0_ACC_16G; + } + else { + msg = MSG_RESET; + return msg; + } + + if(newfs != devp->accfullscale) { + /* Computing scale value.*/ + scale = newfs / devp->accfullscale; + devp->accfullscale = newfs; + +#if LSM6DS0_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM6DS0_SHARED_I2C */ + + /* Updating register.*/ + msg = lsm6ds0I2CReadRegister(devp->config->i2cp, + devp->config->slaveaddress, + LSM6DS0_AD_CTRL_REG6_XL, &buff[1], 1); + +#if LSM6DS0_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DS0_SHARED_I2C */ + + if(msg != MSG_OK) + return msg; + + buff[1] &= ~(LSM6DS0_CTRL_REG6_XL_FS_MASK); + buff[1] |= fs; + buff[0] = LSM6DS0_AD_CTRL_REG6_XL; + +#if LSM6DS0_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* LSM6DS0_SHARED_I2C */ + + msg = lsm6ds0I2CWriteRegister(devp->config->i2cp, + devp->config->slaveaddress, buff, 1); + +#if LSM6DS0_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DS0_SHARED_I2C */ + + if(msg != MSG_OK) + return msg; + + /* Scaling sensitivity and bias. Re-calibration is suggested anyway.*/ + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] *= scale; + devp->accbias[i] *= scale; + } + } + return msg; +} + +/** + * @brief Return the number of axes of the BaseGyroscope. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * + * @return the number of axes. + */ +static size_t gyro_get_axes_number(void *ip) { + (void)ip; + + return LSM6DS0_GYRO_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseGyroscope. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t gyro_read_raw(void *ip, int32_t axes[LSM6DS0_GYRO_NUMBER_OF_AXES]) { + LSM6DS0Driver* devp; + int16_t tmp; + uint8_t i, buff [2 * LSM6DS0_GYRO_NUMBER_OF_AXES]; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DS0Driver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == LSM6DS0_READY), + "gyro_read_raw(), invalid state"); +#if LSM6DS0_USE_I2C + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "gyro_read_raw(), channel not ready"); + +#if LSM6DS0_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM6DS0_SHARED_I2C */ + + msg = lsm6ds0I2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, + LSM6DS0_AD_OUT_X_L_G, buff, + LSM6DS0_GYRO_NUMBER_OF_AXES * 2); + +#if LSM6DS0_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DS0_SHARED_I2C */ +#endif /* LSM6DS0_USE_I2C */ + + for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) { + tmp = buff[2 * i] + (buff[2 * i + 1] << 8); + axes[i] = (int32_t)tmp; + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseGyroscope. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as DPS. + * @note The axes array must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t gyro_read_cooked(void *ip, float axes[]) { + LSM6DS0Driver* devp; + uint32_t i; + int32_t raw[LSM6DS0_GYRO_NUMBER_OF_AXES]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DS0Driver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == LSM6DS0_READY), + "gyro_read_cooked(), invalid state"); + + msg = gyro_read_raw(ip, raw); + for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++){ + axes[i] = (raw[i] * devp->gyrosensitivity[i]) - devp->gyrobias[i]; + } + return msg; +} + +/** + * @brief Samples bias values for the BaseGyroscope. + * @note The LSM6DS0 shall not be moved during the whole procedure. + * @note After this function internal bias is automatically updated. + * @note The behavior of this function depends on @p LSM6DS0_BIAS_ACQ_TIMES + * and @p LSM6DS0_BIAS_SETTLING_US. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t gyro_sample_bias(void *ip) { + LSM6DS0Driver* devp; + uint32_t i, j; + int32_t raw[LSM6DS0_GYRO_NUMBER_OF_AXES]; + int32_t buff[LSM6DS0_GYRO_NUMBER_OF_AXES] = {0, 0, 0}; + msg_t msg; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DS0Driver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == LSM6DS0_READY), + "gyro_sample_bias(), invalid state"); +#if LSM6DS0_USE_I2C + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "gyro_sample_bias(), channel not ready"); +#endif + + for(i = 0; i < LSM6DS0_GYRO_BIAS_ACQ_TIMES; i++){ + msg = gyro_read_raw(ip, raw); + if(msg != MSG_OK) + return msg; + for(j = 0; j < LSM6DS0_GYRO_NUMBER_OF_AXES; j++){ + buff[j] += raw[j]; + } + osalThreadSleepMicroseconds(LSM6DS0_GYRO_BIAS_SETTLING_US); + } + + for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++){ + devp->gyrobias[i] = (buff[i] / LSM6DS0_GYRO_BIAS_ACQ_TIMES); + devp->gyrobias[i] *= devp->gyrosensitivity[i]; + } + return msg; +} + +/** + * @brief Set bias values for the BaseGyroscope. + * @note Bias must be expressed as DPS. + * @note The bias buffer must be at least the same size of the BaseGyroscope + * axes number. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t gyro_set_bias(void *ip, float *bp) { + LSM6DS0Driver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DS0Driver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == LSM6DS0_READY), + "gyro_set_bias(), invalid state"); + + for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) { + devp->gyrobias[i] = bp[i]; + } + return msg; +} + +/** + * @brief Reset bias values for the BaseGyroscope. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t gyro_reset_bias(void *ip) { + LSM6DS0Driver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DS0Driver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == LSM6DS0_READY), + "gyro_reset_bias(), invalid state"); + + for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) + devp->gyrobias[i] = LSM6DS0_GYRO_BIAS; + return msg; +} + +/** + * @brief Set sensitivity values for the BaseGyroscope. + * @note Sensitivity must be expressed as DPS/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t gyro_set_sensivity(void *ip, float *sp) { + LSM6DS0Driver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (sp !=NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DS0Driver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == LSM6DS0_READY), + "gyro_set_sensivity(), invalid state"); + + for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) { + devp->gyrosensitivity[i] = sp[i]; + } + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseGyroscope. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t gyro_reset_sensivity(void *ip) { + LSM6DS0Driver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DS0Driver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == LSM6DS0_READY), + "gyro_reset_sensivity(), invalid state"); + + if(devp->config->gyrofullscale == LSM6DS0_GYRO_FS_245DPS) + for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) + devp->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_245DPS; + else if(devp->config->gyrofullscale == LSM6DS0_GYRO_FS_500DPS) + for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) + devp->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_500DPS; + else if(devp->config->gyrofullscale == LSM6DS0_GYRO_FS_2000DPS) + for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) + devp->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_2000DPS; + else { + osalDbgAssert(FALSE, "gyro_reset_sensivity(), full scale issue"); + return MSG_RESET; + } + return msg; +} + +/** + * @brief Changes the LSM6DS0Driver gyroscope fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p BaseGyroscope interface. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t gyro_set_full_scale(LSM6DS0Driver *devp, lsm6ds0_gyro_fs_t fs) { + float newfs, scale; + uint8_t i, buff[2]; + msg_t msg = MSG_OK; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LSM6DS0_READY), + "gyro_set_full_scale(), invalid state"); +#if LSM6DS0_USE_I2C + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "gyro_set_full_scale(), channel not ready"); +#endif + + if(fs == LSM6DS0_GYRO_FS_245DPS) { + newfs = LSM6DS0_GYRO_245DPS; + } + else if(fs == LSM6DS0_GYRO_FS_500DPS) { + newfs = LSM6DS0_GYRO_500DPS; + } + else if(fs == LSM6DS0_GYRO_FS_2000DPS) { + newfs = LSM6DS0_GYRO_2000DPS; + } + else { + return MSG_RESET; + } + + if(newfs != devp->gyrofullscale) { + scale = newfs / devp->gyrofullscale; + devp->gyrofullscale = newfs; + +#if LSM6DS0_USE_I2C +#if LSM6DS0_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM6DS0_SHARED_I2C */ + + /* Updating register.*/ + msg = lsm6ds0I2CReadRegister(devp->config->i2cp, + devp->config->slaveaddress, + LSM6DS0_AD_CTRL_REG1_G, &buff[1], 1); + +#if LSM6DS0_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DS0_SHARED_I2C */ +#endif /* LSM6DS0_USE_I2C */ + + buff[1] &= ~(LSM6DS0_CTRL_REG1_G_FS_MASK); + buff[1] |= fs; + buff[0] = LSM6DS0_AD_CTRL_REG1_G; + +#if LSM6DS0_USE_I2C +#if LSM6DS0_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM6DS0_SHARED_I2C */ + + lsm6ds0I2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + buff, 1); + +#if LSM6DS0_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DS0_SHARED_I2C */ +#endif /* LSM6DS0_USE_I2C */ + + /* Scaling sensitivity and bias. Re-calibration is suggested anyway. */ + for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) { + devp->gyrosensitivity[i] *= scale; + devp->gyrobias[i] *= scale; + } + } + return msg; +} + +static const struct LSM6DS0VMT vmt_device = { + (size_t)0, + acc_set_full_scale, gyro_set_full_scale +}; + +static const struct BaseAccelerometerVMT vmt_accelerometer = { + sizeof(struct LSM6DS0VMT*), + acc_get_axes_number, acc_read_raw, acc_read_cooked, + acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity +}; + +static const struct BaseGyroscopeVMT vmt_gyroscope = { + sizeof(struct LSM6DS0VMT*) + sizeof(BaseAccelerometer), + gyro_get_axes_number, gyro_read_raw, gyro_read_cooked, + gyro_sample_bias, gyro_set_bias, gyro_reset_bias, + gyro_set_sensivity, gyro_reset_sensivity +}; + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes an instance. + * + * @param[out] devp pointer to the @p LSM6DS0Driver object + * + * @init + */ +void lsm6ds0ObjectInit(LSM6DS0Driver *devp) { + devp->vmt = &vmt_device; + devp->acc_if.vmt = &vmt_accelerometer; + devp->gyro_if.vmt = &vmt_gyroscope; + + devp->config = NULL; + + devp->accaxes = LSM6DS0_ACC_NUMBER_OF_AXES; + devp->gyroaxes = LSM6DS0_GYRO_NUMBER_OF_AXES; + + devp->state = LSM6DS0_STOP; +} + +/** + * @brief Configures and activates LSM6DS0 Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LSM6DS0Driver object + * @param[in] config pointer to the @p LSM6DS0Config object + * + * @api + */ +void lsm6ds0Start(LSM6DS0Driver *devp, const LSM6DS0Config *config) { + uint32_t i; + uint8_t cr[5]; + osalDbgCheck((devp != NULL) && (config != NULL)); + + osalDbgAssert((devp->state == LSM6DS0_STOP) || + (devp->state == LSM6DS0_READY), + "lsm6ds0Start(), invalid state"); + + devp->config = config; + + /* Configuring common registers.*/ + + /* Control register 8 configuration block.*/ + { + cr[0] = LSM6DS0_AD_CTRL_REG8; + cr[1] = LSM6DS0_CTRL_REG8_IF_ADD_INC; +#if LSM6DS0_USE_ADVANCED || defined(__DOXYGEN__) + cr[1] |= devp->config->endianness | devp->config->blockdataupdate; +#endif + } +#if LSM6DS0_USE_I2C +#if LSM6DS0_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); +#endif /* LSM6DS0_SHARED_I2C */ + + i2cStart(devp->config->i2cp, devp->config->i2ccfg); + lsm6ds0I2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + cr, 1); + +#if LSM6DS0_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DS0_SHARED_I2C */ +#endif /* LSM6DS0_USE_I2C */ + + /* Configuring Accelerometer subsystem.*/ + /* Multiple write starting address.*/ + cr[0] = LSM6DS0_AD_CTRL_REG5_XL; + /* Control register 5 configuration block.*/ + { + cr[1] = LSM6DS0_CTRL_REG5_XL_XEN_XL | LSM6DS0_CTRL_REG5_XL_YEN_XL | + LSM6DS0_CTRL_REG5_XL_ZEN_XL; +#if LSM6DS0_USE_ADVANCED || defined(__DOXYGEN__) + cr[1] |= devp->config->accdecmode; +#endif + } + + /* Control register 6 configuration block.*/ + { + cr[2] = devp->config->accoutdatarate | + devp->config->accfullscale; + } + +#if LSM6DS0_USE_I2C +#if LSM6DS0_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* LSM6DS0_SHARED_I2C */ + + lsm6ds0I2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + cr, 2); + +#if LSM6DS0_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DS0_SHARED_I2C */ +#endif /* LSM6DS0_USE_I2C */ + + /* Storing sensitivity according to user settings */ + if(devp->config->accfullscale == LSM6DS0_ACC_FS_2G) { + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM6DS0_ACC_SENS_2G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + devp->accfullscale = LSM6DS0_ACC_2G; + } + else if(devp->config->accfullscale == LSM6DS0_ACC_FS_4G) { + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM6DS0_ACC_SENS_4G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + devp->accfullscale = LSM6DS0_ACC_4G; + } + else if(devp->config->accfullscale == LSM6DS0_ACC_FS_8G) { + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM6DS0_ACC_SENS_8G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + devp->accfullscale = LSM6DS0_ACC_8G; + } + else if(devp->config->accfullscale == LSM6DS0_ACC_FS_16G) { + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM6DS0_ACC_SENS_16G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + devp->accfullscale = LSM6DS0_ACC_16G; + } + else + osalDbgAssert(FALSE, "lsm6ds0Start(), accelerometer full scale issue"); + + /* Storing bias information */ + if(devp->config->accbias != NULL) + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = devp->config->accbias[i]; + else + for(i = 0; i < LSM6DS0_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = LSM6DS0_ACC_BIAS; + + /* Configuring Gyroscope subsystem.*/ + /* Multiple write starting address.*/ + cr[0] = LSM6DS0_AD_CTRL_REG1_G; + + /* Control register 1 configuration block.*/ + { + cr[1] = devp->config->gyrofullscale | + devp->config->gyrooutdatarate; + } + + /* Control register 2 configuration block.*/ + { + cr[2] = 0; +#if LSM6DS0_USE_ADVANCED || defined(__DOXYGEN__) + cr[2] |= devp->config->gyrooutsel; +#endif + } + + /* Control register 3 configuration block.*/ + { + cr[3] = 0; +#if LSM6DS0_USE_ADVANCED || defined(__DOXYGEN__) + cr[3] |= devp->config->gyrohpfenable | + devp->config->gyrolowmodecfg | + devp->config->gyrohpcfg; +#endif + } + + /* Control register 4 configuration block.*/ + { + cr[4] = LSM6DS0_CTRL_REG4_XEN_G | LSM6DS0_CTRL_REG4_YEN_G | + LSM6DS0_CTRL_REG4_ZEN_G; + } +#if LSM6DS0_USE_I2C +#if LSM6DS0_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* LSM6DS0_SHARED_I2C */ + + lsm6ds0I2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + cr, 4); + +#if LSM6DS0_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DS0_SHARED_I2C */ +#endif /* LSM6DS0_USE_I2C */ + + cr[0] = LSM6DS0_AD_CTRL_REG9; + /* Control register 9 configuration block.*/ + { + cr[1] = 0; + } +#if LSM6DS0_USE_I2C +#if LSM6DS0_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* LSM6DS0_SHARED_I2C */ + + lsm6ds0I2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + cr, 1); + +#if LSM6DS0_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DS0_SHARED_I2C */ +#endif /* LSM6DS0_USE_I2C */ + + if(devp->config->gyrofullscale == LSM6DS0_GYRO_FS_245DPS) { + for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) { + if(devp->config->gyrosensitivity == NULL) + devp->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_245DPS; + else + devp->gyrosensitivity[i] = devp->config->gyrosensitivity[i]; + } + devp->gyrofullscale = LSM6DS0_GYRO_245DPS; + } + else if(devp->config->gyrofullscale == LSM6DS0_GYRO_FS_500DPS) { + for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) { + if(devp->config->gyrosensitivity == NULL) + devp->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_500DPS; + else + devp->gyrosensitivity[i] = devp->config->gyrosensitivity[i]; + } + devp->gyrofullscale = LSM6DS0_GYRO_500DPS; + } + else if(devp->config->gyrofullscale == LSM6DS0_GYRO_FS_2000DPS) { + for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) { + if(devp->config->gyrosensitivity == NULL) + devp->gyrosensitivity[i] = LSM6DS0_GYRO_SENS_2000DPS; + else + devp->gyrosensitivity[i] = devp->config->gyrosensitivity[i]; + } + devp->gyrofullscale = LSM6DS0_GYRO_2000DPS; + } + else + osalDbgAssert(FALSE, "lsm6ds0Start(), gyroscope full scale issue"); + + /* Storing bias information */ + if(devp->config->gyrobias != NULL) + for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) + devp->gyrobias[i] = devp->config->gyrobias[i]; + else + for(i = 0; i < LSM6DS0_GYRO_NUMBER_OF_AXES; i++) + devp->gyrobias[i] = LSM6DS0_GYRO_BIAS; + + /* This is the MEMS transient recovery time */ + osalThreadSleepMilliseconds(5); + + devp->state = LSM6DS0_READY; +} + +/** + * @brief Deactivates the LSM6DS0 Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LSM6DS0Driver object + * + * @api + */ +void lsm6ds0Stop(LSM6DS0Driver *devp) { + uint8_t cr[2]; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LSM6DS0_STOP) || (devp->state == LSM6DS0_READY), + "lsm6ds0Stop(), invalid state"); + + if (devp->state == LSM6DS0_READY) { +#if LSM6DS0_USE_I2C +#if LSM6DS0_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* LSM6DS0_SHARED_I2C */ + + /* Disabling accelerometer.*/ + cr[0] = LSM6DS0_AD_CTRL_REG6_XL; + cr[1] = 0; + lsm6ds0I2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + cr, 1); + + /* Disabling gyroscope.*/ + cr[0] = LSM6DS0_AD_CTRL_REG9; + cr[1] = LSM6DS0_CTRL_REG9_SLEEP_G; + lsm6ds0I2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + cr, 1); + + i2cStop(devp->config->i2cp); +#if LSM6DS0_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DS0_SHARED_I2C */ +#endif /* LSM6DS0_USE_I2C */ + } + devp->state = LSM6DS0_STOP; +} +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.h b/ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.h new file mode 100644 index 0000000..d3afc9e --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.h @@ -0,0 +1,1034 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lsm6ds0.h + * @brief LSM6DS0 MEMS interface module header. + * + * @addtogroup LSM6DS0 + * @ingroup EX_ST + * @{ + */ +#ifndef _LSM6DS0_H_ +#define _LSM6DS0_H_ + +#include "ex_accelerometer.h" +#include "ex_gyroscope.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Version identification + * @{ + */ +/** + * @brief LSM6DS0 driver version string. + */ +#define EX_LSM6DS0_VERSION "1.1.2" + +/** + * @brief LSM6DS0 driver version major number. + */ +#define EX_LSM6DS0_MAJOR 1 + +/** + * @brief LSM6DS0 driver version minor number. + */ +#define EX_LSM6DS0_MINOR 1 + +/** + * @brief LSM6DS0 driver version patch number. + */ +#define EX_LSM6DS0_PATCH 2 +/** @} */ + +/** + * @brief LSM6DS0 accelerometer subsystem characteristics. + * @note Sensitivity is expressed as milli-G/LSB whereas + * 1 milli-G = 0.00980665 m/s^2. + * @note Bias is expressed as milli-G. + * + * @{ + */ +#define LSM6DS0_ACC_NUMBER_OF_AXES 3U + +#define LSM6DS0_ACC_2G 2.0f +#define LSM6DS0_ACC_4G 4.0f +#define LSM6DS0_ACC_8G 8.0f +#define LSM6DS0_ACC_16G 16.0f + +#define LSM6DS0_ACC_SENS_2G 0.061f +#define LSM6DS0_ACC_SENS_4G 0.122f +#define LSM6DS0_ACC_SENS_8G 0.244f +#define LSM6DS0_ACC_SENS_16G 0.732f + +#define LSM6DS0_ACC_BIAS 0.0f +/** @} */ + +/** + * @brief L3GD20 gyroscope system characteristics. + * @note Sensitivity is expressed as DPS/LSB whereas DPS stand for Degree + * per second [�/s]. + * @note Bias is expressed as DPS. + * + * @{ + */ +#define LSM6DS0_GYRO_NUMBER_OF_AXES 3U + +#define LSM6DS0_GYRO_245DPS 245.0f +#define LSM6DS0_GYRO_500DPS 500.0f +#define LSM6DS0_GYRO_2000DPS 2000.0f + +#define LSM6DS0_GYRO_SENS_245DPS 0.00875f +#define LSM6DS0_GYRO_SENS_500DPS 0.01750f +#define LSM6DS0_GYRO_SENS_2000DPS 0.07000f + +#define LSM6DS0_GYRO_BIAS 0.0f +/** @} */ + +/** + * @name LSM6DS0 communication interfaces related bit masks + * @{ + */ +#define LSM6DS0_DI_MASK 0xFF +#define LSM6DS0_DI(n) (1 << n) +#define LSM6DS0_AD_MASK 0x7F +#define LSM6DS0_AD(n) (1 << n) +#define LSM6DS0_MS (1 << 7) +/** @} */ + +/** + * @name LSM6DS0 register addresses + * @{ + */ +#define LSM6DS0_AD_ACT_THS 0x04 +#define LSM6DS0_AD_ACT_DUR 0x05 +#define LSM6DS0_AD_INT_GEN_CFG_XL 0x06 +#define LSM6DS0_AD_INT_GEN_THS_X_XL 0x07 +#define LSM6DS0_AD_INT_GEN_THS_Y_XL 0x08 +#define LSM6DS0_AD_INT_GEN_THS_Z_XL 0x09 +#define LSM6DS0_AD_INT_GEN_DUR_XL 0x0A +#define LSM6DS0_AD_REFERENCE_G 0x0B +#define LSM6DS0_AD_INT_CTRL 0x0C +#define LSM6DS0_AD_WHO_AM_I 0x0F +#define LSM6DS0_AD_CTRL_REG1_G 0x10 +#define LSM6DS0_AD_CTRL_REG2_G 0x11 +#define LSM6DS0_AD_CTRL_REG3_G 0x12 +#define LSM6DS0_AD_ORIENT_CFG_G 0x13 +#define LSM6DS0_AD_INT_GEN_SRC_G 0x14 +#define LSM6DS0_AD_OUT_TEMP_L 0x15 +#define LSM6DS0_AD_OUT_TEMP_H 0x16 +#define LSM6DS0_AD_STATUS_REG1 0x17 +#define LSM6DS0_AD_OUT_X_L_G 0x18 +#define LSM6DS0_AD_OUT_X_H_G 0x19 +#define LSM6DS0_AD_OUT_Y_L_G 0x1A +#define LSM6DS0_AD_OUT_Y_H_G 0x1B +#define LSM6DS0_AD_OUT_Z_L_G 0x1C +#define LSM6DS0_AD_OUT_Z_H_G 0x1D +#define LSM6DS0_AD_CTRL_REG4 0x1E +#define LSM6DS0_AD_CTRL_REG5_XL 0x1F +#define LSM6DS0_AD_CTRL_REG6_XL 0x20 +#define LSM6DS0_AD_CTRL_REG7_XL 0x21 +#define LSM6DS0_AD_CTRL_REG8 0x22 +#define LSM6DS0_AD_CTRL_REG9 0x23 +#define LSM6DS0_AD_CTRL_REG10 0x24 +#define LSM6DS0_AD_INT_GEN_SRC_XL 0x26 +#define LSM6DS0_AD_STATUS_REG2 0x27 +#define LSM6DS0_AD_OUT_X_L_XL 0x28 +#define LSM6DS0_AD_OUT_X_H_XL 0x29 +#define LSM6DS0_AD_OUT_Y_L_XL 0x2A +#define LSM6DS0_AD_OUT_Y_H_XL 0x2B +#define LSM6DS0_AD_OUT_Z_L_XL 0x2C +#define LSM6DS0_AD_OUT_Z_H_XL 0x2D +#define LSM6DS0_AD_FIFO_CTRL 0x2E +#define LSM6DS0_AD_FIFO_SRC 0x2F +#define LSM6DS0_AD_INT_GEN_CFG_G 0x30 +#define LSM6DS0_AD_INT_GEN_THS_XH_G 0x31 +#define LSM6DS0_AD_INT_GEN_THS_XL_G 0x32 +#define LSM6DS0_AD_INT_GEN_THS_YH_G 0x33 +#define LSM6DS0_AD_INT_GEN_THS_YL_G 0x34 +#define LSM6DS0_AD_INT_GEN_THS_ZH_G 0x35 +#define LSM6DS0_AD_INT_GEN_THS_ZL_G 0x36 +#define LSM6DS0_AD_INT_GEN_DUR_G 0x37 +/** @} */ + +/** + * @name LSM6DS0_AD_CTRL_REG1_G register bits definitions + * @{ + */ +#define LSM6DS0_CTRL_REG1_G 0xFA +#define LSM6DS0_CTRL_REG1_G_BW_G0 (1 << 0) +#define LSM6DS0_CTRL_REG1_G_BW_G1 (1 << 1) +#define LSM6DS0_CTRL_REG1_G_FS_MASK 0x1F +#define LSM6DS0_CTRL_REG1_G_FS_G0 (1 << 3) +#define LSM6DS0_CTRL_REG1_G_FS_G1 (1 << 4) +#define LSM6DS0_CTRL_REG1_G_ODR_G0 (1 << 5) +#define LSM6DS0_CTRL_REG1_G_ODR_G1 (1 << 6) +#define LSM6DS0_CTRL_REG1_G_ODR_G2 (1 << 7) +/** @} */ + +/** + * @name LSM6DS0_AD_CTRL_REG2_G register bits definitions + * @{ + */ +#define LSM6DS0_CTRL_REG2_G 0x0F +#define LSM6DS0_CTRL_REG2_G_OUT_SEL0 (1 << 0) +#define LSM6DS0_CTRL_REG2_G_OUT_SEL1 (1 << 1) +#define LSM6DS0_CTRL_REG2_G_INT_SEL0 (1 << 2) +#define LSM6DS0_CTRL_REG2_G_INT_SEL1 (1 << 3) +/** @} */ + +/** + * @name LSM6DS0_AD_CTRL_REG3_G register bits definitions + * @{ + */ +#define LSM6DS0_CTRL_REG3_G 0x64 +#define LSM6DS0_CTRL_REG3_G_HP_CF0_G (1 << 0) +#define LSM6DS0_CTRL_REG3_G_HP_CF1_G (1 << 1) +#define LSM6DS0_CTRL_REG3_G_HP_CF2_G (1 << 2) +#define LSM6DS0_CTRL_REG3_G_HP_CF3_G (1 << 3) +#define LSM6DS0_CTRL_REG3_G_HP_EN (1 << 6) +#define LSM6DS0_CTRL_REG3_G_LP_MODE (1 << 7) +/** @} */ + +/** + * @name LSM6DS0_AD_CTRL_REG4 register bits definitions + * @{ + */ +#define LSM6DS0_CTRL_REG4 0x3A +#define LSM6DS0_CTRL_REG4_4D_XL1 (1 << 0) +#define LSM6DS0_CTRL_REG4_LIR_XL1 (1 << 1) +#define LSM6DS0_CTRL_REG4_XEN_G (1 << 3) +#define LSM6DS0_CTRL_REG4_YEN_G (1 << 4) +#define LSM6DS0_CTRL_REG4_ZEN_G (1 << 5) +/** @} */ + +/** + * @name LSM6DS0_AD_CTRL_REG5_XL register bits definitions + * @{ + */ +#define LSM6DS0_CTRL_REG5_XL 0xF8 +#define LSM6DS0_CTRL_REG5_XL_XEN_XL (1 << 3) +#define LSM6DS0_CTRL_REG5_XL_YEN_XL (1 << 4) +#define LSM6DS0_CTRL_REG5_XL_ZEN_XL (1 << 5) +#define LSM6DS0_CTRL_REG5_XL_DEC0 (1 << 6) +#define LSM6DS0_CTRL_REG5_XL_DEC1 (1 << 7) +/** @} */ + +/** + * @name LSM6DS0_AD_CTRL_REG6_XL register bits definitions + * @{ + */ +#define LSM6DS0_CTRL_REG6_XL 0xFF +#define LSM6DS0_CTRL_REG6_XL_BW_XL0 (1 << 0) +#define LSM6DS0_CTRL_REG6_XL_BW_XL1 (1 << 1) +#define LSM6DS0_CTRL_REG6_XL_BW_SCAL_ODR (1 << 2) +#define LSM6DS0_CTRL_REG6_XL_FS_MASK 0x1F +#define LSM6DS0_CTRL_REG6_XL_FS0_XL (1 << 3) +#define LSM6DS0_CTRL_REG6_XL_FS1_XL (1 << 4) +#define LSM6DS0_CTRL_REG6_XL_ODR_XL0 (1 << 5) +#define LSM6DS0_CTRL_REG6_XL_ODR_XL1 (1 << 6) +#define LSM6DS0_CTRL_REG6_XL_ODR_XL2 (1 << 7) +/** @} */ + +/** + * @name LSM6DS0_AD_CTRL_REG7_XL register bits definitions + * @{ + */ +#define LSM6DS0_CTRL_REG7_XL 0xE5 +#define LSM6DS0_CTRL_REG7_XL_HPIS1 (1 << 0) +#define LSM6DS0_CTRL_REG7_XL_FDS (1 << 2) +#define LSM6DS0_CTRL_REG7_XL_DCF0 (1 << 5) +#define LSM6DS0_CTRL_REG7_XL_DCF1 (1 << 6) +#define LSM6DS0_CTRL_REG7_XL_HR (1 << 7) +/** @} */ + +/** + * @name LSM6DS0_AD_CTRL_REG8 register bits definitions + * @{ + */ +#define LSM6DS0_CTRL_REG8 0xFF +#define LSM6DS0_CTRL_REG8_SW_RESET (1 << 0) +#define LSM6DS0_CTRL_REG8_BLE (1 << 1) +#define LSM6DS0_CTRL_REG8_IF_ADD_INC (1 << 2) +#define LSM6DS0_CTRL_REG8_SIM (1 << 3) +#define LSM6DS0_CTRL_REG8_PP_OD (1 << 4) +#define LSM6DS0_CTRL_REG8_H_LACTIVE (1 << 5) +#define LSM6DS0_CTRL_REG8_BDU (1 << 6) +#define LSM6DS0_CTRL_REG8_BOOT (1 << 7) +/** @} */ + +/** + * @name LSM6DS0_AD_CTRL_REG9 register bits definitions + * @{ + */ +#define LSM6DS0_CTRL_REG9 0x5F +#define LSM6DS0_CTRL_REG9_STOP_ON_FTH (1 << 0) +#define LSM6DS0_CTRL_REG9_FIFO_EN (1 << 1) +#define LSM6DS0_CTRL_REG9_I2C_DISABLE (1 << 2) +#define LSM6DS0_CTRL_REG9_DRDY_MASK_BIT (1 << 3) +#define LSM6DS0_CTRL_REG9_FIFO_TEMP_EN (1 << 4) +#define LSM6DS0_CTRL_REG9_SLEEP_G (1 << 6) +/** @} */ + +/** + * @name LSM6DS0_AD_CTRL_REG10 register bits definitions + * @{ + */ +#define LSM6DS0_CTRL_REG10 0x05 +#define LSM6DS0_CTRL_REG10_ST_XL (1 << 0) +#define LSM6DS0_CTRL_REG10_ST_G (1 << 2) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief LSM6DS0 SPI interface switch. + * @details If set to @p TRUE the support for SPI is included. + * @note The default is @p FALSE. + */ +#if !defined(LSM6DS0_USE_SPI) || defined(__DOXYGEN__) +#define LSM6DS0_USE_SPI FALSE +#endif + +/** + * @brief LSM6DS0 shared SPI switch. + * @details If set to @p TRUE the device acquires SPI bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LSM6DS0_SHARED_SPI) || defined(__DOXYGEN__) +#define LSM6DS0_SHARED_SPI FALSE +#endif + +/** + * @brief LSM6DS0 I2C interface switch. + * @details If set to @p TRUE the support for I2C is included. + * @note The default is @p TRUE. + */ +#if !defined(LSM6DS0_USE_I2C) || defined(__DOXYGEN__) +#define LSM6DS0_USE_I2C TRUE +#endif + +/** + * @brief LSM6DS0 shared I2C switch. + * @details If set to @p TRUE the device acquires I2C bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LSM6DS0_SHARED_I2C) || defined(__DOXYGEN__) +#define LSM6DS0_SHARED_I2C FALSE +#endif + +/** + * @brief LSM6DS0 advanced configurations switch. + * @details If set to @p TRUE more configurations are available. + * @note The default is @p FALSE. + */ +#if !defined(LSM6DS0_USE_ADVANCED) || defined(__DOXYGEN__) +#define LSM6DS0_USE_ADVANCED FALSE +#endif + +/** + * @brief Number of acquisitions for gyroscope bias removal. + * @details This is the number of acquisitions performed to compute the + * bias. A repetition is required in order to remove noise. + */ +#if !defined(LSM6DS0_GYRO_BIAS_ACQ_TIMES) || defined(__DOXYGEN__) +#define LSM6DS0_GYRO_BIAS_ACQ_TIMES 50 +#endif + +/** + * @brief Settling time for gyroscope bias removal. + * @details This is the time between each bias acquisition. + */ +#if !defined(LSM6DS0_GYRO_BIAS_SETTLING_US) || defined(__DOXYGEN__) +#define LSM6DS0_GYRO_BIAS_SETTLING_US 5000 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !(LSM6DS0_USE_SPI ^ LSM6DS0_USE_I2C) +#error "LSM6DS0_USE_SPI and LSM6DS0_USE_I2C cannot be both true or both false" +#endif + +#if LSM6DS0_USE_SPI && !HAL_USE_SPI +#error "LSM6DS0_USE_SPI requires HAL_USE_SPI" +#endif + +#if LSM6DS0_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION +#error "LSM6DS0_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" +#endif + +#if LSM6DS0_USE_I2C && !HAL_USE_I2C +#error "LSM6DS0_USE_I2C requires HAL_USE_I2C" +#endif + +#if LSM6DS0_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION +#error "LSM6DS0_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" +#endif + +/* + * CHTODO: Add support for LSM6DS0 over SPI. + */ +#if LSM6DS0_USE_SPI +#error "LSM6DS0 over SPI still not supported" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @name LSM6DS0 data structures and types. + * @{ + */ +/** + * @brief Structure representing a LSM6DS0 driver. + */ +typedef struct LSM6DS0Driver LSM6DS0Driver; + +/** + * @brief Accelerometer and Gyroscope Slave Address. + */ +typedef enum { + LSM6DS0_SAD_GND = 0x6A, /**< SAD pin connected to GND. */ + LSM6DS0_SAD_VCC = 0x6B /**< SAD pin connected to VCC. */ +} lsm6ds0_sad_t; + +/** + * @brief LSM6DS0 accelerometer subsystem full scale. + */ +typedef enum { + LSM6DS0_ACC_FS_2G = 0x00, /**< Full scale �2g. */ + LSM6DS0_ACC_FS_4G = 0x10, /**< Full scale �4g. */ + LSM6DS0_ACC_FS_8G = 0x18, /**< Full scale �8g. */ + LSM6DS0_ACC_FS_16G = 0x08 /**< Full scale �16g. */ +} lsm6ds0_acc_fs_t; + +/** + * @brief LSM6DS0 accelerometer subsystem output data rate. + */ +typedef enum { + LSM6DS0_ACC_ODR_PD = 0x00, /**< Power down */ + LSM6DS0_ACC_ODR_10Hz = 0x20, /**< ODR 10 Hz */ + LSM6DS0_ACC_ODR_50Hz = 0x40, /**< ODR 50 Hz */ + LSM6DS0_ACC_ODR_119Hz = 0x60, /**< ODR 119 Hz */ + LSM6DS0_ACC_ODR_238Hz = 0x80, /**< ODR 238 Hz */ + LSM6DS0_ACC_ODR_476Hz = 0xA0, /**< ODR 476 Hz */ + LSM6DS0_ACC_ODR_952Hz = 0xC0 /**< ODR 952 Hz */ +} lsm6ds0_acc_odr_t; + +/** + * @brief LSM6DS0 accelerometer subsystem decimation mode. + */ +typedef enum { + LSM6DS0_ACC_DEC_DISABLED = 0x00, /**< Decimation disabled. */ + LSM6DS0_ACC_DEC_X2 = 0x40, /**< Output updated every 2 samples. */ + LSM6DS0_ACC_DEC_X4 = 0x80, /**< Output updated every 4 samples. */ + LSM6DS0_ACC_DEC_X8 = 0xC0 /**< Output updated every 8 samples. */ +} lsm6ds0_acc_dec_t; + +/** + * @brief LSM6DS0 gyroscope subsystem full scale. + */ +typedef enum { + LSM6DS0_GYRO_FS_245DPS = 0x00, /**< Full scale �245 degree per second */ + LSM6DS0_GYRO_FS_500DPS = 0x08, /**< Full scale �500 degree per second */ + LSM6DS0_GYRO_FS_2000DPS = 0x18 /**< Full scale �2000 degree per second */ +} lsm6ds0_gyro_fs_t; + +/** + * @brief LSM6DS0 gyroscope subsystem output data rate. + */ +typedef enum { + LSM6DS0_GYRO_ODR_PD = 0x00, + LSM6DS0_GYRO_ODR_95HZ_FC_25 = 0x10, + LSM6DS0_GYRO_ODR_14_9HZ_FC_5 = 0X20, + LSM6DS0_GYRO_ODR_59_5HZ_FC_16 = 0X40, + LSM6DS0_GYRO_ODR_119HZ_FC_14 = 0X60, + LSM6DS0_GYRO_ODR_119HZ_FC_31 = 0X61, + LSM6DS0_GYRO_ODR_238HZ_FC_14 = 0X80, + LSM6DS0_GYRO_ODR_238HZ_FC_29 = 0X81, + LSM6DS0_GYRO_ODR_238HZ_FC_63 = 0X82, + LSM6DS0_GYRO_ODR_238HZ_FC_78 = 0X83, + LSM6DS0_GYRO_ODR_476HZ_FC_21 = 0XA0, + LSM6DS0_GYRO_ODR_476HZ_FC_28 = 0XA1, + LSM6DS0_GYRO_ODR_476HZ_FC_57 = 0XA2, + LSM6DS0_GYRO_ODR_476HZ_FC_100 = 0XA3, + LSM6DS0_GYRO_ODR_952HZ_FC_33 = 0XC0, + LSM6DS0_GYRO_ODR_952HZ_FC_40 = 0XC1, + LSM6DS0_GYRO_ODR_952HZ_FC_58 = 0XC2, + LSM6DS0_GYRO_ODR_952HZ_FC_100 = 0XC3 +} lsm6ds0_gyro_odr_t; + +/** + * @brief LSM6DS0 gyroscope subsystem low mode configuration. + */ +typedef enum { + LSM6DS0_GYRO_LP_DISABLED = 0x00, /**< Low power mode disabled. */ + LSM6DS0_GYRO_LP_ENABLED = 0x80 /**< Low power mode enabled. */ +} lsm6ds0_gyro_lp_t; + +/** + * @brief LSM6DS0 gyroscope subsystem output selection. + */ +typedef enum { + LSM6DS0_GYRO_OUT_SEL_0 = 0x00, /**< Low pass filter 1. */ + LSM6DS0_GYRO_OUT_SEL_1 = 0x01, /**< High pass filter 1 if enabled. */ + LSM6DS0_GYRO_OUT_SEL_2 = 0x02 /**< Low pass filter 2. */ +} lsm6ds0_gyro_out_sel_t; + +/** + * @brief LSM6DS0 gyroscope subsystem high pass filter. + */ +typedef enum { + LSM6DS0_GYRO_HP_DISABLED = 0x00, /**< High pass filter disabled. */ + LSM6DS0_GYRO_HP_ENABLED = 0x40 /**< High pass filter enabled. */ +} lsm6ds0_gyro_hp_t; + +/** + * @brief LSM6DS0 gyroscope subsystem high pass filter configuration. + */ +typedef enum { + LSM6DS0_GYRO_HPCF_0 = 0x00, /**< Refer to table 48 of RM */ + LSM6DS0_GYRO_HPCF_1 = 0x01, + LSM6DS0_GYRO_HPCF_2 = 0x02, + LSM6DS0_GYRO_HPCF_3 = 0x03, + LSM6DS0_GYRO_HPCF_4 = 0x04, + LSM6DS0_GYRO_HPCF_5 = 0x05, + LSM6DS0_GYRO_HPCF_6 = 0x06, + LSM6DS0_GYRO_HPCF_7 = 0x07, + LSM6DS0_GYRO_HPCF_8 = 0x08, + LSM6DS0_GYRO_HPCF_9 = 0x09 +} lsm6ds0_gyro_hpcf_t; + +/** + * @brief LSM6DS0 block data update. + */ +typedef enum { + LSM6DS0_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */ + LSM6DS0_BDU_BLOCKED = 0x40 /**< Block data updated after reading. */ +} lsm6ds0_bdu_t; + +/** + * @brief LSM6DS0 endianness. + */ +typedef enum { + LSM6DS0_END_LITTLE = 0x00, /**< Little endian. */ + LSM6DS0_END_BIG = 0x20 /**< Big endian. */ +} lsm6ds0_end_t; + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + LSM6DS0_UNINIT = 0, /**< Not initialized. */ + LSM6DS0_STOP = 1, /**< Stopped. */ + LSM6DS0_READY = 2, /**< Ready. */ +} lsm6ds0_state_t; + +/** + * @brief LSM6DS0 configuration structure. + */ +typedef struct { +#if (LSM6DS0_USE_SPI) || defined(__DOXYGEN__) + /** + * @brief SPI driver associated to this LSM6DS0. + */ + SPIDriver *spip; + /** + * @brief SPI configuration associated to this LSM6DS0 accelerometer + * subsystem. + */ + const SPIConfig *accspicfg; +#endif /* LSM6DS0_USE_SPI */ +#if (LSM6DS0_USE_I2C) || defined(__DOXYGEN__) + /** + * @brief I2C driver associated to this LSM6DS0. + */ + I2CDriver *i2cp; + /** + * @brief I2C configuration associated to this LSM6DS0 accelerometer + * subsystem. + */ + const I2CConfig *i2ccfg; + /** + * @brief LSM6DS0 Slave Address + */ + lsm6ds0_sad_t slaveaddress; +#endif /* LSM6DS0_USE_I2C */ + /** + * @brief LSM6DS0 accelerometer subsystem initial sensitivity. + */ + float *accsensitivity; + /** + * @brief LSM6DS0 accelerometer subsystem initial bias. + */ + float *accbias; + /** + * @brief LSM6DS0 accelerometer subsystem full scale. + */ + lsm6ds0_acc_fs_t accfullscale; + /** + * @brief LSM6DS0 accelerometer subsystem output data rate. + */ + lsm6ds0_acc_odr_t accoutdatarate; +#if LSM6DS0_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief LSM6DS0 accelerometer subsystem decimation mode. + */ + lsm6ds0_acc_dec_t accdecmode; +#endif /* LSM6DS0_USE_ADVANCED */ + /** + * @brief LSM6DS0 gyroscope subsystem initial sensitivity. + */ + float *gyrosensitivity; + /** + * @brief LSM6DS0 gyroscope subsystem initial bias. + */ + float *gyrobias; + /** + * @brief LSM6DS0 gyroscope subsystem full scale. + */ + lsm6ds0_gyro_fs_t gyrofullscale; + /** + * @brief LSM6DS0 gyroscope subsystem output data rate. + */ + lsm6ds0_gyro_odr_t gyrooutdatarate; +#if LSM6DS0_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief LSM6DS0 gyroscope subsystem low mode configuration. + */ + lsm6ds0_gyro_lp_t gyrolowmodecfg; + /** + * @brief LSM6DS0 gyroscope subsystem output selection. + */ + lsm6ds0_gyro_out_sel_t gyrooutsel; + /** + * @brief LSM6DS0 gyroscope subsystem high pass filter. + */ + lsm6ds0_gyro_hp_t gyrohpfenable; + /** + * @brief LSM6DS0 gyroscope subsystem high pass filter configuration. + */ + lsm6ds0_gyro_hpcf_t gyrohpcfg; + /** + * @brief LSM6DS0 block data update + */ + lsm6ds0_bdu_t blockdataupdate; + /** + * @brief LSM6DS0 endianness + */ + lsm6ds0_end_t endianness; +#endif /* LSM6DS0_USE_ADVANCED */ +} LSM6DS0Config; + +/** + * @brief @p LSM6DS0 specific methods. + */ +#define _lsm6ds0_methods_alone \ + /* Change full scale value of LSM6DS0 accelerometer subsystem .*/ \ + msg_t (*acc_set_full_scale)(LSM6DS0Driver *devp, lsm6ds0_acc_fs_t fs); \ + /* Change full scale value of LSM6DS0 gyroscope subsystem .*/ \ + msg_t (*gyro_set_full_scale)(LSM6DS0Driver *devp, lsm6ds0_gyro_fs_t fs); + +/** + * @brief @p LSM6DS0 specific methods with inherited ones. + */ +#define _lsm6ds0_methods \ + _base_object_methods \ + _lsm6ds0_methods_alone + +/** + * @extends BaseObjectVMT + * + * @brief @p LSM6DS0 virtual methods table. + */ +struct LSM6DS0VMT { + _lsm6ds0_methods +}; + +/** + * @brief @p LSM6DS0Driver specific data. + */ +#define _lsm6ds0_data \ + _base_sensor_data \ + /* Driver state.*/ \ + lsm6ds0_state_t state; \ + /* Current configuration data.*/ \ + const LSM6DS0Config *config; \ + /* Accelerometer subsystem axes number.*/ \ + size_t accaxes; \ + /* Accelerometer subsystem current sensitivity.*/ \ + float accsensitivity[LSM6DS0_ACC_NUMBER_OF_AXES]; \ + /* Accelerometer subsystem current bias .*/ \ + float accbias[LSM6DS0_ACC_NUMBER_OF_AXES]; \ + /* Accelerometer subsystem current full scale value.*/ \ + float accfullscale; \ + /* Gyroscope subsystem axes number.*/ \ + size_t gyroaxes; \ + /* Gyroscope subsystem current sensitivity.*/ \ + float gyrosensitivity[LSM6DS0_GYRO_NUMBER_OF_AXES]; \ + /* Gyroscope subsystem current Bias.*/ \ + float gyrobias[LSM6DS0_GYRO_NUMBER_OF_AXES]; \ + /* Gyroscope subsystem current full scale value.*/ \ + float gyrofullscale; + +/** + * @brief LSM6DS0 6-axis accelerometer/gyroscope class. + */ +struct LSM6DS0Driver { + /** @brief Virtual Methods Table.*/ + const struct LSM6DS0VMT *vmt; + /** @brief Base accelerometer interface.*/ + BaseAccelerometer acc_if; + /** @brief Base gyroscope interface.*/ + BaseGyroscope gyro_if; + _lsm6ds0_data +}; +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Return the number of axes of the BaseAccelerometer. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * + * @return the number of axes. + * + * @api + */ +#define lsm6ds0AccelerometerGetAxesNumber(devp) \ + accelerometerGetAxesNumber(&((devp)->acc_if)) + +/** + * @brief Retrieves raw data from the BaseAccelerometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm6ds0AccelerometerReadRaw(devp, axes) \ + accelerometerReadRaw(&((devp)->acc_if), axes) + +/** + * @brief Retrieves cooked data from the BaseAccelerometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as milli-G. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm6ds0AccelerometerReadCooked(devp, axes) \ + accelerometerReadCooked(&((devp)->acc_if), axes) + +/** + * @brief Set bias values for the BaseAccelerometer. + * @note Bias must be expressed as milli-G. + * @note The bias buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm6ds0AccelerometerSetBias(devp, bp) \ + accelerometerSetBias(&((devp)->acc_if), bp) + +/** + * @brief Reset bias values for the BaseAccelerometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm6ds0AccelerometerResetBias(devp) \ + accelerometerResetBias(&((devp)->acc_if)) + +/** + * @brief Set sensitivity values for the BaseAccelerometer. + * @note Sensitivity must be expressed as milli-G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm6ds0AccelerometerSetSensitivity(devp, sp) \ + accelerometerSetSensitivity(&((devp)->acc_if), sp) + +/** + * @brief Reset sensitivity values for the BaseAccelerometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lsm6ds0AccelerometerResetSensitivity(devp) \ + accelerometerResetSensitivity(&((devp)->acc_if)) + +/** + * @brief Changes the LSM6DS0Driver accelerometer fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lsm6ds0AccelerometerSetFullScale(devp, fs) \ + (devp)->vmt->acc_set_full_scale(devp, fs) + +/** + * @brief Return the number of axes of the BaseGyroscope. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * + * @return the number of axes. + * + * @api + */ +#define lsm6ds0GyroscopeGetAxesNumber(devp) \ + gyroscopeGetAxesNumber(&((devp)->gyro_if)) + +/** + * @brief Retrieves raw data from the BaseGyroscope. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm6ds0GyroscopeReadRaw(devp, axes) \ + gyroscopeReadRaw(&((devp)->gyro_if), axes) + +/** + * @brief Retrieves cooked data from the BaseGyroscope. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as DPS. + * @note The axes array must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm6ds0GyroscopeReadCooked(devp, axes) \ + gyroscopeReadCooked(&((devp)->gyro_if), axes) + +/** + * @brief Samples bias values for the BaseGyroscope. + * @note The LSM6DS0 shall not be moved during the whole procedure. + * @note After this function internal bias is automatically updated. + * @note The behavior of this function depends on @p LSM6DS0_BIAS_ACQ_TIMES + * and @p LSM6DS0_BIAS_SETTLING_US. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm6ds0GyroscopeSampleBias(devp) \ + gyroscopeSampleBias(&((devp)->gyro_if)) + +/** + * @brief Set bias values for the BaseGyroscope. + * @note Bias must be expressed as DPS. + * @note The bias buffer must be at least the same size of the BaseGyroscope + * axes number. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm6ds0GyroscopeSetBias(devp, bp) \ + gyroscopeSetBias(&((devp)->gyro_if), bp) + +/** + * @brief Reset bias values for the BaseGyroscope. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm6ds0GyroscopeResetBias(devp) \ + gyroscopeResetBias(&((devp)->gyro_if)) + +/** + * @brief Set sensitivity values for the BaseGyroscope. + * @note Sensitivity must be expressed as DPS/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm6ds0GyroscopeSetSensitivity(devp, sp) \ + gyroscopeSetSensitivity(&((devp)->gyro_if), sp) + +/** + * @brief Reset sensitivity values for the BaseGyroscope. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lsm6ds0GyroscopeResetSensitivity(devp) \ + gyroscopeResetSensitivity(&((devp)->gyro_if)) + +/** + * @brief Changes the LSM6DS0Driver gyroscope fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LSM6DS0Driver. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lsm6ds0GyroscopeSetFullScale(devp, fs) \ + (devp)->vmt->acc_set_full_scale(devp, fs) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void lsm6ds0ObjectInit(LSM6DS0Driver *devp); + void lsm6ds0Start(LSM6DS0Driver *devp, const LSM6DS0Config *config); + void lsm6ds0Stop(LSM6DS0Driver *devp); +#ifdef __cplusplus +} +#endif + +#endif /* _LSM6DS0_H_ */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.mk b/ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.mk new file mode 100644 index 0000000..f3da344 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.mk @@ -0,0 +1,10 @@ +# List of all the LSM6DS0 device files. +LSM6DS0SRC := $(CHIBIOS)/os/ex/devices/ST/lsm6ds0.c + +# Required include directories +LSM6DS0INC := $(CHIBIOS)/os/ex/include \ + $(CHIBIOS)/os/ex/devices/ST + +# Shared variables +ALLCSRC += $(LSM6DS0SRC) +ALLINC += $(LSM6DS0INC) \ No newline at end of file diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.c b/ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.c new file mode 100644 index 0000000..56bc10c --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.c @@ -0,0 +1,1119 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lsm6dsl.c + * @brief LSM6DSL MEMS interface module code. + * + * @addtogroup LSM6DSL + * @ingroup EX_ST + * @{ + */ + +#include "hal.h" +#include "lsm6dsl.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if (LSM6DSL_USE_I2C) || defined(__DOXYGEN__) +/** + * @brief Reads registers value using I2C. + * @pre The I2C interface must be initialized and the driver started. + * @note IF_ADD_INC bit must be 1 in CTRL_REG8 + * + * @param[in] i2cp pointer to the I2C interface + * @param[in] sad slave address without R bit + * @param[in] reg first sub-register address + * @param[out] rxbuf pointer to an output buffer + * @param[in] n number of consecutive register to read + * @return the operation status. + * @notapi + */ +msg_t lsm6dslI2CReadRegister(I2CDriver *i2cp, lsm6dsl_sad_t sad, uint8_t reg, + uint8_t* rxbuf, size_t n) { + + return i2cMasterTransmitTimeout(i2cp, sad, ®, 1, rxbuf, n, + TIME_INFINITE); +} + +/** + * @brief Writes a value into a register using I2C. + * @pre The I2C interface must be initialized and the driver started. + * + * @param[in] i2cp pointer to the I2C interface + * @param[in] sad slave address without R bit + * @param[in] txbuf buffer containing sub-address value in first position + * and values to write + * @param[in] n size of txbuf less one (not considering the first + * element) + * @return the operation status. + * @notapi + */ +#define lsm6dslI2CWriteRegister(i2cp, sad, txbuf, n) \ + i2cMasterTransmitTimeout(i2cp, sad, txbuf, n + 1, NULL, 0, \ + TIME_INFINITE) +#endif /* LSM6DSL_USE_I2C */ + +/** + * @brief Return the number of axes of the BaseAccelerometer. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return the number of axes. + */ +static size_t acc_get_axes_number(void *ip) { + (void)ip; + + return LSM6DSL_ACC_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseAccelerometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t acc_read_raw(void *ip, int32_t axes[]) { + LSM6DSLDriver* devp; + uint8_t buff [LSM6DSL_ACC_NUMBER_OF_AXES * 2], i; + int16_t tmp; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DSLDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM6DSL_READY), + "acc_read_raw(), invalid state"); +#if LSM6DSL_USE_I2C + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "acc_read_raw(), channel not ready"); + +#if LSM6DSL_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM6DSL_SHARED_I2C */ + + msg = lsm6dslI2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, + LSM6DSL_AD_OUTX_L_XL, buff, + LSM6DSL_ACC_NUMBER_OF_AXES * 2); + +#if LSM6DSL_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DSL_SHARED_I2C */ +#endif /* LSM6DSL_USE_I2C */ + if(msg == MSG_OK) + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) { + tmp = buff[2 * i] + (buff[2 * i + 1] << 8); + axes[i] = (int32_t)tmp; + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseAccelerometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as milli-G. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t acc_read_cooked(void *ip, float axes[]) { + LSM6DSLDriver* devp; + uint32_t i; + int32_t raw[LSM6DSL_ACC_NUMBER_OF_AXES]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DSLDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM6DSL_READY), + "acc_read_cooked(), invalid state"); + + msg = acc_read_raw(ip, raw); + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) { + axes[i] = (raw[i] * devp->accsensitivity[i]) - devp->accbias[i]; + } + return msg; +} + +/** + * @brief Set bias values for the BaseAccelerometer. + * @note Bias must be expressed as milli-G. + * @note The bias buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_set_bias(void *ip, float *bp) { + LSM6DSLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DSLDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM6DSL_READY), + "acc_set_bias(), invalid state"); + + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) { + devp->accbias[i] = bp[i]; + } + return msg; +} + +/** + * @brief Reset bias values for the BaseAccelerometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_reset_bias(void *ip) { + LSM6DSLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DSLDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM6DSL_READY), + "acc_reset_bias(), invalid state"); + + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = LSM6DSL_ACC_BIAS; + return msg; +} + +/** + * @brief Set sensitivity values for the BaseAccelerometer. + * @note Sensitivity must be expressed as milli-G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t acc_set_sensivity(void *ip, float *sp) { + LSM6DSLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DSLDriver*, (BaseAccelerometer*)ip); + + osalDbgCheck((ip != NULL) && (sp != NULL)); + + osalDbgAssert((devp->state == LSM6DSL_READY), + "acc_set_sensivity(), invalid state"); + + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] = sp[i]; + } + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseAccelerometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseAccelerometer interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t acc_reset_sensivity(void *ip) { + LSM6DSLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DSLDriver*, (BaseAccelerometer*)ip); + + osalDbgAssert((devp->state == LSM6DSL_READY), + "acc_reset_sensivity(), invalid state"); + + if(devp->config->accfullscale == LSM6DSL_ACC_FS_2G) + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LSM6DSL_ACC_SENS_2G; + else if(devp->config->accfullscale == LSM6DSL_ACC_FS_4G) + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LSM6DSL_ACC_SENS_4G; + else if(devp->config->accfullscale == LSM6DSL_ACC_FS_8G) + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LSM6DSL_ACC_SENS_8G; + else if(devp->config->accfullscale == LSM6DSL_ACC_FS_16G) + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) + devp->accsensitivity[i] = LSM6DSL_ACC_SENS_16G; + else { + osalDbgAssert(FALSE, "reset_sensivity(), accelerometer full scale issue"); + msg = MSG_RESET; + } + return msg; +} + +/** + * @brief Changes the LSM6DSLDriver accelerometer fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LSM6DSLDriver interface. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t acc_set_full_scale(LSM6DSLDriver *devp, lsm6dsl_acc_fs_t fs) { + float newfs, scale; + uint8_t i, buff[2]; + msg_t msg; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LSM6DSL_READY), + "acc_set_full_scale(), invalid state"); + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "acc_set_full_scale(), channel not ready"); + + /* Computing new fullscale value.*/ + if(fs == LSM6DSL_ACC_FS_2G) { + newfs = LSM6DSL_ACC_2G; + } + else if(fs == LSM6DSL_ACC_FS_4G) { + newfs = LSM6DSL_ACC_4G; + } + else if(fs == LSM6DSL_ACC_FS_8G) { + newfs = LSM6DSL_ACC_8G; + } + else if(fs == LSM6DSL_ACC_FS_16G) { + newfs = LSM6DSL_ACC_16G; + } + else { + msg = MSG_RESET; + return msg; + } + + if(newfs != devp->accfullscale) { + /* Computing scale value.*/ + scale = newfs / devp->accfullscale; + devp->accfullscale = newfs; + +#if LSM6DSL_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM6DSL_SHARED_I2C */ + + /* Updating register.*/ + msg = lsm6dslI2CReadRegister(devp->config->i2cp, + devp->config->slaveaddress, + LSM6DSL_AD_CTRL1_XL, &buff[1], 1); + +#if LSM6DSL_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DSL_SHARED_I2C */ + + if(msg != MSG_OK) + return msg; + + buff[1] &= ~(LSMDSL_CTRL1_XL_FS_MASK); + buff[1] |= fs; + buff[0] = LSM6DSL_AD_CTRL1_XL; + +#if LSM6DSL_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* LSM6DSL_SHARED_I2C */ + + msg = lsm6dslI2CWriteRegister(devp->config->i2cp, + devp->config->slaveaddress, buff, 1); + +#if LSM6DSL_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DSL_SHARED_I2C */ + + if(msg != MSG_OK) + return msg; + + /* Scaling sensitivity and bias. Re-calibration is suggested anyway.*/ + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) { + devp->accsensitivity[i] *= scale; + devp->accbias[i] *= scale; + } + } + return msg; +} + +/** + * @brief Return the number of axes of the BaseGyroscope. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * + * @return the number of axes. + */ +static size_t gyro_get_axes_number(void *ip) { + (void)ip; + + return LSM6DSL_GYRO_NUMBER_OF_AXES; +} + +/** + * @brief Retrieves raw data from the BaseGyroscope. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t gyro_read_raw(void *ip, int32_t axes[LSM6DSL_GYRO_NUMBER_OF_AXES]) { + LSM6DSLDriver* devp; + int16_t tmp; + uint8_t i, buff [2 * LSM6DSL_GYRO_NUMBER_OF_AXES]; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DSLDriver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == LSM6DSL_READY), + "gyro_read_raw(), invalid state"); +#if LSM6DSL_USE_I2C + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "gyro_read_raw(), channel not ready"); + +#if LSM6DSL_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM6DSL_SHARED_I2C */ + + msg = lsm6dslI2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, + LSM6DSL_AD_OUTX_L_G, buff, + LSM6DSL_GYRO_NUMBER_OF_AXES * 2); + +#if LSM6DSL_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DSL_SHARED_I2C */ +#endif /* LSM6DSL_USE_I2C */ + + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) { + tmp = buff[2 * i] + (buff[2 * i + 1] << 8); + axes[i] = (int32_t)tmp; + } + return msg; +} + +/** + * @brief Retrieves cooked data from the BaseGyroscope. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as DPS. + * @note The axes array must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + */ +static msg_t gyro_read_cooked(void *ip, float axes[]) { + LSM6DSLDriver* devp; + uint32_t i; + int32_t raw[LSM6DSL_GYRO_NUMBER_OF_AXES]; + msg_t msg; + + osalDbgCheck((ip != NULL) && (axes != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DSLDriver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == LSM6DSL_READY), + "gyro_read_cooked(), invalid state"); + + msg = gyro_read_raw(ip, raw); + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++){ + axes[i] = (raw[i] * devp->gyrosensitivity[i]) - devp->gyrobias[i]; + } + return msg; +} + +/** + * @brief Samples bias values for the BaseGyroscope. + * @note The LSM6DSL shall not be moved during the whole procedure. + * @note After this function internal bias is automatically updated. + * @note The behavior of this function depends on @p LSM6DSL_BIAS_ACQ_TIMES + * and @p LSM6DSL_BIAS_SETTLING_US. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t gyro_sample_bias(void *ip) { + LSM6DSLDriver* devp; + uint32_t i, j; + int32_t raw[LSM6DSL_GYRO_NUMBER_OF_AXES]; + int32_t buff[LSM6DSL_GYRO_NUMBER_OF_AXES] = {0, 0, 0}; + msg_t msg; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DSLDriver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == LSM6DSL_READY), + "gyro_sample_bias(), invalid state"); +#if LSM6DSL_USE_I2C + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "gyro_sample_bias(), channel not ready"); +#endif + + for(i = 0; i < LSM6DSL_GYRO_BIAS_ACQ_TIMES; i++){ + msg = gyro_read_raw(ip, raw); + if(msg != MSG_OK) + return msg; + for(j = 0; j < LSM6DSL_GYRO_NUMBER_OF_AXES; j++){ + buff[j] += raw[j]; + } + osalThreadSleepMicroseconds(LSM6DSL_GYRO_BIAS_SETTLING_US); + } + + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++){ + devp->gyrobias[i] = (buff[i] / LSM6DSL_GYRO_BIAS_ACQ_TIMES); + devp->gyrobias[i] *= devp->gyrosensitivity[i]; + } + return msg; +} + +/** + * @brief Set bias values for the BaseGyroscope. + * @note Bias must be expressed as DPS. + * @note The bias buffer must be at least the same size of the BaseGyroscope + * axes number. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t gyro_set_bias(void *ip, float *bp) { + LSM6DSLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (bp != NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DSLDriver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == LSM6DSL_READY), + "gyro_set_bias(), invalid state"); + + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) { + devp->gyrobias[i] = bp[i]; + } + return msg; +} + +/** + * @brief Reset bias values for the BaseGyroscope. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t gyro_reset_bias(void *ip) { + LSM6DSLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DSLDriver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == LSM6DSL_READY), + "gyro_reset_bias(), invalid state"); + + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) + devp->gyrobias[i] = LSM6DSL_GYRO_BIAS; + return msg; +} + +/** + * @brief Set sensitivity values for the BaseGyroscope. + * @note Sensitivity must be expressed as DPS/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + */ +static msg_t gyro_set_sensivity(void *ip, float *sp) { + LSM6DSLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck((ip != NULL) && (sp !=NULL)); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DSLDriver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == LSM6DSL_READY), + "gyro_set_sensivity(), invalid state"); + + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) { + devp->gyrosensitivity[i] = sp[i]; + } + return msg; +} + +/** + * @brief Reset sensitivity values for the BaseGyroscope. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] ip pointer to @p BaseGyroscope interface. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t gyro_reset_sensivity(void *ip) { + LSM6DSLDriver* devp; + uint32_t i; + msg_t msg = MSG_OK; + + osalDbgCheck(ip != NULL); + + /* Getting parent instance pointer.*/ + devp = objGetInstance(LSM6DSLDriver*, (BaseGyroscope*)ip); + + osalDbgAssert((devp->state == LSM6DSL_READY), + "gyro_reset_sensivity(), invalid state"); + if(devp->config->gyrofullscale == LSM6DSL_GYRO_FS_125DPS) + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) + devp->gyrosensitivity[i] = LSM6DSL_GYRO_SENS_125DPS; + else if(devp->config->gyrofullscale == LSM6DSL_GYRO_FS_250DPS) + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) + devp->gyrosensitivity[i] = LSM6DSL_GYRO_SENS_250DPS; + else if(devp->config->gyrofullscale == LSM6DSL_GYRO_FS_500DPS) + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) + devp->gyrosensitivity[i] = LSM6DSL_GYRO_SENS_500DPS; + else if(devp->config->gyrofullscale == LSM6DSL_GYRO_FS_1000DPS) + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) + devp->gyrosensitivity[i] = LSM6DSL_GYRO_SENS_1000DPS; + else if(devp->config->gyrofullscale == LSM6DSL_GYRO_FS_2000DPS) + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) + devp->gyrosensitivity[i] = LSM6DSL_GYRO_SENS_2000DPS; + else { + osalDbgAssert(FALSE, "gyro_reset_sensivity(), full scale issue"); + return MSG_RESET; + } + return msg; +} + +/** + * @brief Changes the LSM6DSLDriver gyroscope fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p BaseGyroscope interface. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + */ +static msg_t gyro_set_full_scale(LSM6DSLDriver *devp, lsm6dsl_gyro_fs_t fs) { + float newfs, scale; + uint8_t i, buff[2]; + msg_t msg = MSG_OK; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LSM6DSL_READY), + "gyro_set_full_scale(), invalid state"); +#if LSM6DSL_USE_I2C + osalDbgAssert((devp->config->i2cp->state == I2C_READY), + "gyro_set_full_scale(), channel not ready"); +#endif + + if(fs == LSM6DSL_GYRO_FS_125DPS) { + newfs = LSM6DSL_GYRO_125DPS; + } + else if(fs == LSM6DSL_GYRO_FS_250DPS) { + newfs = LSM6DSL_GYRO_250DPS; + } + else if(fs == LSM6DSL_GYRO_FS_500DPS) { + newfs = LSM6DSL_GYRO_500DPS; + } + else if(fs == LSM6DSL_GYRO_FS_1000DPS) { + newfs = LSM6DSL_GYRO_1000DPS; + } + else if(fs == LSM6DSL_GYRO_FS_2000DPS) { + newfs = LSM6DSL_GYRO_2000DPS; + } + else { + return MSG_RESET; + } + + if(newfs != devp->gyrofullscale) { + scale = newfs / devp->gyrofullscale; + devp->gyrofullscale = newfs; + +#if LSM6DSL_USE_I2C +#if LSM6DSL_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM6DSL_SHARED_I2C */ + + /* Updating register.*/ + msg = lsm6dslI2CReadRegister(devp->config->i2cp, + devp->config->slaveaddress, + LSM6DSL_AD_CTRL2_G, &buff[1], 1); + +#if LSM6DSL_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DSL_SHARED_I2C */ +#endif /* LSM6DSL_USE_I2C */ + + buff[1] &= ~(LSMDSL_CTRL2_G_FS_MASK); + buff[1] |= fs; + buff[0] = LSM6DSL_AD_CTRL2_G; + +#if LSM6DSL_USE_I2C +#if LSM6DSL_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, + devp->config->i2ccfg); +#endif /* LSM6DSL_SHARED_I2C */ + + lsm6dslI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + buff, 1); + +#if LSM6DSL_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DSL_SHARED_I2C */ +#endif /* LSM6DSL_USE_I2C */ + + /* Scaling sensitivity and bias. Re-calibration is suggested anyway. */ + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) { + devp->gyrosensitivity[i] *= scale; + devp->gyrobias[i] *= scale; + } + } + return msg; +} + +static const struct LSM6DSLVMT vmt_device = { + (size_t)0, + acc_set_full_scale, gyro_set_full_scale +}; + +static const struct BaseAccelerometerVMT vmt_accelerometer = { + sizeof(struct LSM6DSLVMT*), + acc_get_axes_number, acc_read_raw, acc_read_cooked, + acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity +}; + +static const struct BaseGyroscopeVMT vmt_gyroscope = { + sizeof(struct LSM6DSLVMT*) + sizeof(BaseAccelerometer), + gyro_get_axes_number, gyro_read_raw, gyro_read_cooked, + gyro_sample_bias, gyro_set_bias, gyro_reset_bias, + gyro_set_sensivity, gyro_reset_sensivity +}; + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes an instance. + * + * @param[out] devp pointer to the @p LSM6DSLDriver object + * + * @init + */ +void lsm6dslObjectInit(LSM6DSLDriver *devp) { + devp->vmt = &vmt_device; + devp->acc_if.vmt = &vmt_accelerometer; + devp->gyro_if.vmt = &vmt_gyroscope; + + devp->config = NULL; + + devp->accaxes = LSM6DSL_ACC_NUMBER_OF_AXES; + devp->gyroaxes = LSM6DSL_GYRO_NUMBER_OF_AXES; + + devp->state = LSM6DSL_STOP; +} + +/** + * @brief Configures and activates LSM6DSL Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LSM6DSLDriver object + * @param[in] config pointer to the @p LSM6DSLConfig object + * + * @api + */ +void lsm6dslStart(LSM6DSLDriver *devp, const LSM6DSLConfig *config) { + uint32_t i; + uint8_t cr[11]; + osalDbgCheck((devp != NULL) && (config != NULL)); + + osalDbgAssert((devp->state == LSM6DSL_STOP) || + (devp->state == LSM6DSL_READY), + "lsm6dslStart(), invalid state"); + + devp->config = config; + + /* Enforcing multiple write configuration.*/ + { + cr[0] = LSM6DSL_AD_CTRL3_C; + cr[1] = LSMDSL_CTRL3_C_IF_INC; + } +#if LSM6DSL_USE_I2C +#if LSM6DSL_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); +#endif /* LSM6DSL_SHARED_I2C */ + + i2cStart(devp->config->i2cp, devp->config->i2ccfg); + lsm6dslI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + cr, 1); + +#if LSM6DSL_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DSL_SHARED_I2C */ +#endif /* LSM6DSL_USE_I2C */ + + /* Configuring all the control registers.*/ + /* Multiple write starting address.*/ + cr[0] = LSM6DSL_AD_CTRL1_XL; + /* Control register 1 configuration block.*/ + { + cr[1] = devp->config->accoutdatarate | + devp->config->accfullscale; + } + /* Control register 2 configuration block.*/ + { + cr[2] = devp->config->gyrooutdatarate | + devp->config->gyrofullscale; + } + /* Control register 3 configuration block.*/ + { + cr[3] = LSMDSL_CTRL3_C_IF_INC; +#if LSM6DSL_USE_ADVANCED || defined(__DOXYGEN__) + cr[3] |= devp->config->endianness | devp->config->blockdataupdate; +#endif + } + /* Control register 4 configuration block.*/ + { + cr[4] = 0; +#if LSM6DSL_USE_ADVANCED || defined(__DOXYGEN__) + if(devp->config->gyrolowpassfilter != LSM6DSL_GYRO_LPF_DISABLED) { + cr[4] |= LSMDSL_CTRL4_C_LPF1_SEL_G; + } + else { + /* Nothing to do. */ + } +#endif + } + /* Control register 5 configuration block.*/ + { + cr[5] = 0; + } + /* Control register 6 configuration block.*/ + { + cr[6] = 0; +#if LSM6DSL_USE_ADVANCED || defined(__DOXYGEN__) + cr[6] |= devp->config->acclpmode; + +#endif +#if LSM6DSL_USE_ADVANCED || defined(__DOXYGEN__) + if(devp->config->gyrolowpassfilter != LSM6DSL_GYRO_LPF_DISABLED) { + cr[6] |= devp->config->gyrolowpassfilter; + } + else { + /* Nothing to do. */ + } +#endif + } + /* Control register 7 configuration block.*/ + { + cr[7] = 0; +#if LSM6DSL_USE_ADVANCED || defined(__DOXYGEN__) + cr[7] |= devp->config->gyrolpmode; + +#endif + } + /* Control register 8 configuration block.*/ + { + cr[8] = 0; + } + /* Control register 9 configuration block.*/ + { + cr[9] = 0; + } + /* Control register 10 configuration block.*/ + { + cr[10] = 0; + } + +#if LSM6DSL_USE_I2C +#if LSM6DSL_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* LSM6DSL_SHARED_I2C */ + + lsm6dslI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + cr, 10); + +#if LSM6DSL_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DSL_SHARED_I2C */ +#endif /* LSM6DSL_USE_I2C */ + + /* Storing sensitivity according to user settings */ + if(devp->config->accfullscale == LSM6DSL_ACC_FS_2G) { + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM6DSL_ACC_SENS_2G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + devp->accfullscale = LSM6DSL_ACC_2G; + } + else if(devp->config->accfullscale == LSM6DSL_ACC_FS_4G) { + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM6DSL_ACC_SENS_4G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + devp->accfullscale = LSM6DSL_ACC_4G; + } + else if(devp->config->accfullscale == LSM6DSL_ACC_FS_8G) { + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM6DSL_ACC_SENS_8G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + devp->accfullscale = LSM6DSL_ACC_8G; + } + else if(devp->config->accfullscale == LSM6DSL_ACC_FS_16G) { + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) { + if(devp->config->accsensitivity == NULL) + devp->accsensitivity[i] = LSM6DSL_ACC_SENS_16G; + else + devp->accsensitivity[i] = devp->config->accsensitivity[i]; + } + devp->accfullscale = LSM6DSL_ACC_16G; + } + else + osalDbgAssert(FALSE, "lsm6dslStart(), accelerometer full scale issue"); + + /* Storing bias information */ + if(devp->config->accbias != NULL) + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = devp->config->accbias[i]; + else + for(i = 0; i < LSM6DSL_ACC_NUMBER_OF_AXES; i++) + devp->accbias[i] = LSM6DSL_ACC_BIAS; + + if(devp->config->gyrofullscale == LSM6DSL_GYRO_FS_125DPS) { + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) { + if(devp->config->gyrosensitivity == NULL) + devp->gyrosensitivity[i] = LSM6DSL_GYRO_SENS_125DPS; + else + devp->gyrosensitivity[i] = devp->config->gyrosensitivity[i]; + } + devp->gyrofullscale = LSM6DSL_GYRO_125DPS; + } + else if(devp->config->gyrofullscale == LSM6DSL_GYRO_FS_250DPS) { + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) { + if(devp->config->gyrosensitivity == NULL) + devp->gyrosensitivity[i] = LSM6DSL_GYRO_SENS_250DPS; + else + devp->gyrosensitivity[i] = devp->config->gyrosensitivity[i]; + } + devp->gyrofullscale = LSM6DSL_GYRO_250DPS; + } + else if(devp->config->gyrofullscale == LSM6DSL_GYRO_FS_500DPS) { + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) { + if(devp->config->gyrosensitivity == NULL) + devp->gyrosensitivity[i] = LSM6DSL_GYRO_SENS_500DPS; + else + devp->gyrosensitivity[i] = devp->config->gyrosensitivity[i]; + } + devp->gyrofullscale = LSM6DSL_GYRO_500DPS; + } + else if(devp->config->gyrofullscale == LSM6DSL_GYRO_FS_1000DPS) { + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) { + if(devp->config->gyrosensitivity == NULL) + devp->gyrosensitivity[i] = LSM6DSL_GYRO_SENS_1000DPS; + else + devp->gyrosensitivity[i] = devp->config->gyrosensitivity[i]; + } + devp->gyrofullscale = LSM6DSL_GYRO_1000DPS; + } + else if(devp->config->gyrofullscale == LSM6DSL_GYRO_FS_2000DPS) { + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) { + if(devp->config->gyrosensitivity == NULL) + devp->gyrosensitivity[i] = LSM6DSL_GYRO_SENS_2000DPS; + else + devp->gyrosensitivity[i] = devp->config->gyrosensitivity[i]; + } + devp->gyrofullscale = LSM6DSL_GYRO_2000DPS; + } + else + osalDbgAssert(FALSE, "lsm6dslStart(), gyroscope full scale issue"); + + /* Storing bias information */ + if(devp->config->gyrobias != NULL) + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) + devp->gyrobias[i] = devp->config->gyrobias[i]; + else + for(i = 0; i < LSM6DSL_GYRO_NUMBER_OF_AXES; i++) + devp->gyrobias[i] = LSM6DSL_GYRO_BIAS; + + /* This is the MEMS transient recovery time */ + osalThreadSleepMilliseconds(5); + + devp->state = LSM6DSL_READY; +} + +/** + * @brief Deactivates the LSM6DSL Complex Driver peripheral. + * + * @param[in] devp pointer to the @p LSM6DSLDriver object + * + * @api + */ +void lsm6dslStop(LSM6DSLDriver *devp) { + uint8_t cr[2]; + + osalDbgCheck(devp != NULL); + + osalDbgAssert((devp->state == LSM6DSL_STOP) || (devp->state == LSM6DSL_READY), + "lsm6dslStop(), invalid state"); + + if (devp->state == LSM6DSL_READY) { +#if LSM6DSL_USE_I2C +#if LSM6DSL_SHARED_I2C + i2cAcquireBus(devp->config->i2cp); + i2cStart(devp->config->i2cp, devp->config->i2ccfg); +#endif /* LSM6DSL_SHARED_I2C */ + + + cr[0] = LSM6DSL_AD_CTRL1_XL; + /* Disabling accelerometer.*/ + cr[1] = LSM6DSL_ACC_ODR_PD; + /* Disabling gyroscope.*/ + cr[2] = LSM6DSL_GYRO_ODR_PD; + lsm6dslI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, + cr, 2); + + i2cStop(devp->config->i2cp); +#if LSM6DSL_SHARED_I2C + i2cReleaseBus(devp->config->i2cp); +#endif /* LSM6DSL_SHARED_I2C */ +#endif /* LSM6DSL_USE_I2C */ + } + devp->state = LSM6DSL_STOP; +} +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.h b/ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.h new file mode 100644 index 0000000..4cffd78 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.h @@ -0,0 +1,1055 @@ +/* + ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file lsm6dsl.h + * @brief LSM6DSL MEMS interface module header. + * + * @addtogroup LSM6DSL + * @ingroup EX_ST + * @{ + */ +#ifndef _LSM6DSL_H_ +#define _LSM6DSL_H_ + +#include "ex_accelerometer.h" +#include "ex_gyroscope.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Version identification + * @{ + */ +/** + * @brief LSM6DSL driver version string. + */ +#define EX_LSM6DSL_VERSION "1.0.1" + +/** + * @brief LSM6DSL driver version major number. + */ +#define EX_LSM6DSL_MAJOR 1 + +/** + * @brief LSM6DSL driver version minor number. + */ +#define EX_LSM6DSL_MINOR 0 + +/** + * @brief LSM6DSL driver version patch number. + */ +#define EX_LSM6DSL_PATCH 1 +/** @} */ + +/** + * @brief LSM6DSL accelerometer subsystem characteristics. + * @note Sensitivity is expressed as milli-G/LSB whereas + * 1 milli-G = 0.00980665 m/s^2. + * @note Bias is expressed as milli-G. + * + * @{ + */ +#define LSM6DSL_ACC_NUMBER_OF_AXES 3U + +#define LSM6DSL_ACC_2G 2.0f +#define LSM6DSL_ACC_4G 4.0f +#define LSM6DSL_ACC_8G 8.0f +#define LSM6DSL_ACC_16G 16.0f + +#define LSM6DSL_ACC_SENS_2G 0.061f +#define LSM6DSL_ACC_SENS_4G 0.122f +#define LSM6DSL_ACC_SENS_8G 0.244f +#define LSM6DSL_ACC_SENS_16G 0.488f + +#define LSM6DSL_ACC_BIAS 0.0f +/** @} */ + +/** + * @brief L3GD20 gyroscope system characteristics. + * @note Sensitivity is expressed as DPS/LSB whereas DPS stand for Degree + * per second [�/s]. + * @note Bias is expressed as DPS. + * + * @{ + */ +#define LSM6DSL_GYRO_NUMBER_OF_AXES 3U + +#define LSM6DSL_GYRO_125DPS 125.0f +#define LSM6DSL_GYRO_250DPS 250.0f +#define LSM6DSL_GYRO_500DPS 500.0f +#define LSM6DSL_GYRO_1000DPS 1000.0f +#define LSM6DSL_GYRO_2000DPS 2000.0f + +#define LSM6DSL_GYRO_SENS_125DPS 0.004375f +#define LSM6DSL_GYRO_SENS_250DPS 0.008750f +#define LSM6DSL_GYRO_SENS_500DPS 0.017500f +#define LSM6DSL_GYRO_SENS_1000DPS 0.035000f +#define LSM6DSL_GYRO_SENS_2000DPS 0.070000f + +#define LSM6DSL_GYRO_BIAS 0.0f +/** @} */ + +/** + * @name LSM6DSL communication interfaces related bit masks + * @{ + */ +#define LSM6DSL_DI_MASK 0xFF +#define LSM6DSL_DI(n) (1 << n) +#define LSM6DSL_AD_MASK 0x7F +#define LSM6DSL_AD(n) (1 << n) +#define LSM6DSL_MS (1 << 7) +/** @} */ + +/** + * @name LSM6DSL register addresses + * @{ + */ +#define LSM6DSL_AD_FUNC_CFG_ACCESS 0x01 +#define LSM6DSL_AD_SENSOR_SYNC_TIME_FRAME 0x04 +#define LSM6DSL_AD_SENSOR_SYNC_RES_RATIO 0x05 +#define LSM6DSL_AD_FIFO_CTRL1 0x06 +#define LSM6DSL_AD_FIFO_CTRL2 0x07 +#define LSM6DSL_AD_FIFO_CTRL3 0x08 +#define LSM6DSL_AD_FIFO_CTRL4 0x09 +#define LSM6DSL_AD_FIFO_CTRL5 0x0A +#define LSM6DSL_AD_DRDY_PULSE_CFG_G 0x0B +#define LSM6DSL_AD_INT1_CTRL 0x0D +#define LSM6DSL_AD_INT2_CTRL 0x0E +#define LSM6DSL_AD_WHO_AM_I 0x0F +#define LSM6DSL_AD_CTRL1_XL 0x10 +#define LSM6DSL_AD_CTRL2_G 0x11 +#define LSM6DSL_AD_CTRL3_C 0x12 +#define LSM6DSL_AD_CTRL4_C 0x13 +#define LSM6DSL_AD_CTRL5_C 0x14 +#define LSM6DSL_AD_CTRL6_C 0x15 +#define LSM6DSL_AD_CTRL7_G 0x16 +#define LSM6DSL_AD_CTRL8_XL 0x17 +#define LSM6DSL_AD_CTRL9_XL 0x18 +#define LSM6DSL_AD_CTRL10_C 0x19 +#define LSM6DSL_AD_MASTER_CONFIG 0x1A +#define LSM6DSL_AD_WAKE_UP_SRC 0x1B +#define LSM6DSL_AD_TAP_SRC 0x1C +#define LSM6DSL_AD_D6D_SRC 0x1D +#define LSM6DSL_AD_STATUS_REG 0x1E +#define LSM6DSL_AD_OUT_TEMP_L 0x20 +#define LSM6DSL_AD_OUT_TEMP_H 0x21 +#define LSM6DSL_AD_OUTX_L_G 0x22 +#define LSM6DSL_AD_OUTX_H_G 0x23 +#define LSM6DSL_AD_OUTY_L_G 0x24 +#define LSM6DSL_AD_OUTY_H_G 0x25 +#define LSM6DSL_AD_OUTZ_L_G 0x26 +#define LSM6DSL_AD_OUTZ_H_G 0x27 +#define LSM6DSL_AD_OUTX_L_XL 0x28 +#define LSM6DSL_AD_OUTX_H_XL 0x29 +#define LSM6DSL_AD_OUTY_L_XL 0x2A +#define LSM6DSL_AD_OUTY_H_XL 0x2B +#define LSM6DSL_AD_OUTZ_L_XL 0x2C +#define LSM6DSL_AD_OUTZ_H_XL 0x2D +#define LSM6DSL_AD_SENSORHUB1_REG 0x2E +#define LSM6DSL_AD_SENSORHUB2_REG 0x2F +#define LSM6DSL_AD_SENSORHUB3_REG 0x30 +#define LSM6DSL_AD_SENSORHUB4_REG 0x31 +#define LSM6DSL_AD_SENSORHUB5_REG 0x32 +#define LSM6DSL_AD_SENSORHUB6_REG 0x33 +#define LSM6DSL_AD_SENSORHUB7_REG 0x34 +#define LSM6DSL_AD_SENSORHUB8_REG 0x35 +#define LSM6DSL_AD_SENSORHUB9_REG 0x36 +#define LSM6DSL_AD_SENSORHUB10_REG 0x37 +#define LSM6DSL_AD_SENSORHUB11_REG 0x38 +#define LSM6DSL_AD_SENSORHUB12_REG 0x39 +#define LSM6DSL_AD_FIFO_STATUS1 0x3A +#define LSM6DSL_AD_FIFO_STATUS2 0x3B +#define LSM6DSL_AD_FIFO_STATUS3 0x3C +#define LSM6DSL_AD_FIFO_STATUS4 0x3D +#define LSM6DSL_AD_FIFO_DATA_OUT_L 0x3E +#define LSM6DSL_AD_FIFO_DATA_OUT_H 0x3F +#define LSM6DSL_AD_TIMESTAMP0_REG 0x40 +#define LSM6DSL_AD_TIMESTAMP1_REG 0x41 +#define LSM6DSL_AD_TIMESTAMP2_REG 0x42 +#define LSM6DSL_AD_STEP_TIMESTAMP_L 0x49 +#define LSM6DSL_AD_STEP_TIMESTAMP_H 0x4A +#define LSM6DSL_AD_STEP_COUNTER_L 0x4B +#define LSM6DSL_AD_STEP_COUNTER_H 0x4C +#define LSM6DSL_AD_SENSORHUB13_REG 0x4D +#define LSM6DSL_AD_SENSORHUB14_REG 0x4E +#define LSM6DSL_AD_SENSORHUB15_REG 0x4F +#define LSM6DSL_AD_SENSORHUB16_REG 0x50 +#define LSM6DSL_AD_SENSORHUB17_REG 0x51 +#define LSM6DSL_AD_SENSORHUB18_REG 0x52 +#define LSM6DSL_AD_FUNC_SRC1 0x53 +#define LSM6DSL_AD_FUNC_SRC2 0x54 +#define LSM6DSL_AD_WRIST_TILT_IA 0x55 +#define LSM6DSL_AD_TAP_CFG 0x58 +#define LSM6DSL_AD_TAP_THS_6D 0x59 +#define LSM6DSL_AD_INT_DUR2 0x5A +#define LSM6DSL_AD_WAKE_UP_THS 0x5B +#define LSM6DSL_AD_WAKE_UP_DUR 0x5C +#define LSM6DSL_AD_FREE_FALL 0x5D +#define LSM6DSL_AD_MD1_CFG 0x5E +#define LSM6DSL_AD_MD2_CFG 0x5F +#define LSM6DSL_AD_MASTER_CMD_CODE 0x60 +#define LSM6DSL_AD_SENS_SYNC_SPI_ERROR_CODE 0x61 +#define LSM6DSL_AD_OUT_MAG_RAW_X_L 0x66 +#define LSM6DSL_AD_OUT_MAG_RAW_X_H 0x67 +#define LSM6DSL_AD_OUT_MAG_RAW_Y_L 0x68 +#define LSM6DSL_AD_OUT_MAG_RAW_Y_H 0x69 +#define LSM6DSL_AD_OUT_MAG_RAW_Z_L 0x6A +#define LSM6DSL_AD_OUT_MAG_RAW_Z_H 0x6B +#define LSM6DSL_AD_X_OFS_USR 0x73 +#define LSM6DSL_AD_Y_OFS_USR 0x74 +#define LSM6DSL_AD_Z_OFS_USR 0x75 +/** @} */ + +/** + * @name LSM6DSL_AD_CTRL1_XL register bits definitions + * @{ + */ +#define LSMDSL_CTRL1_XL_BW0_XL (1 << 0) +#define LSMDSL_CTRL1_XL_LPF1_BW_SEL (1 << 1) +#define LSMDSL_CTRL1_XL_FS_MASK 0x0C +#define LSMDSL_CTRL1_XL_FS_XL0 (1 << 2) +#define LSMDSL_CTRL1_XL_FS_XL1 (1 << 3) +#define LSMDSL_CTRL1_XL_ODR_XL0 (1 << 4) +#define LSMDSL_CTRL1_XL_ODR_XL1 (1 << 5) +#define LSMDSL_CTRL1_XL_ODR_XL2 (1 << 6) +#define LSMDSL_CTRL1_XL_ODR_XL3 (1 << 7) +/** @} */ + +/** + * @name LSM6DSL_AD_CTRL2_G register bits definitions + * @{ + */ +#define LSMDSL_CTRL2_G_FS_MASK 0x0E +#define LSMDSL_CTRL2_G_FS_125 (1 << 1) +#define LSMDSL_CTRL2_G_FS_G0 (1 << 2) +#define LSMDSL_CTRL2_G_FS_G1 (1 << 3) +#define LSMDSL_CTRL2_G_ODR_G0 (1 << 4) +#define LSMDSL_CTRL2_G_ODR_G1 (1 << 5) +#define LSMDSL_CTRL2_G_ODR_G2 (1 << 6) +#define LSMDSL_CTRL2_G_ODR_G3 (1 << 7) +/** @} */ + +/** + * @name LSM6DSL_AD_CTRL3_C register bits definitions + * @{ + */ +#define LSMDSL_CTRL3_C_SW_RESET (1 << 0) +#define LSMDSL_CTRL3_C_BLE (1 << 1) +#define LSMDSL_CTRL3_C_IF_INC (1 << 2) +#define LSMDSL_CTRL3_C_SIM (1 << 3) +#define LSMDSL_CTRL3_C_PP_OD (1 << 4) +#define LSMDSL_CTRL3_C_H_LACTIVE (1 << 5) +#define LSMDSL_CTRL3_C_BDU (1 << 6) +#define LSMDSL_CTRL3_C_BOOT (1 << 7) +/** @} */ + +/** + * @name LSM6DSL_AD_CTRL4_C register bits definitions + * @{ + */ +#define LSMDSL_CTRL4_C_NOT_USED_01 (1 << 0) +#define LSMDSL_CTRL4_C_LPF1_SEL_G (1 << 1) +#define LSMDSL_CTRL4_C_I2C_DISABLE (1 << 2) +#define LSMDSL_CTRL4_C_DRDY_MASK (1 << 3) +#define LSMDSL_CTRL4_C_DEN_DRDY_IN (1 << 4) +#define LSMDSL_CTRL4_C_INT2_ON_INT (1 << 5) +#define LSMDSL_CTRL4_C_SLEEP (1 << 6) +#define LSMDSL_CTRL4_C_DEN_XL_EN (1 << 7) +/** @} */ + +/** + * @name LSM6DSL_AD_CTRL5_C register bits definitions + * @{ + */ +#define LSMDSL_CTRL5_C_ST0_XL (1 << 0) +#define LSMDSL_CTRL5_C_ST1_XL (1 << 1) +#define LSMDSL_CTRL5_C_ST0_G (1 << 2) +#define LSMDSL_CTRL5_C_ST1_G (1 << 3) +#define LSMDSL_CTRL5_C_DEN_LH (1 << 4) +#define LSMDSL_CTRL5_C_ROUNDING0 (1 << 5) +#define LSMDSL_CTRL5_C_ROUNDING1 (1 << 6) +#define LSMDSL_CTRL5_C_ROUNDING2 (1 << 7) +/** @} */ + +/** + * @name LSM6DSL_AD_CTRL6_C register bits definitions + * @{ + */ +#define LSMDSL_CTRL6_C_FTYPE_0 (1 << 0) +#define LSMDSL_CTRL6_C_FTYPE_1 (1 << 1) +#define LSMDSL_CTRL6_C_USR_OFF_W (1 << 3) +#define LSMDSL_CTRL6_C_XL_HM_MODE (1 << 4) +#define LSMDSL_CTRL6_C_LVL2_EN (1 << 5) +#define LSMDSL_CTRL6_C_LVL_EN (1 << 6) +#define LSMDSL_CTRL6_C_TRIG_EN (1 << 7) +/** @} */ + +/** + * @name LSM6DSL_AD_CTRL7_G register bits definitions + * @{ + */ +#define LSMDSL_CTRL7_G_ROUNDING_ST (1 << 2) +#define LSMDSL_CTRL7_G_HPM0_G (1 << 4) +#define LSMDSL_CTRL7_G_HPM1_G (1 << 5) +#define LSMDSL_CTRL7_G_HP_EN_G (1 << 6) +#define LSMDSL_CTRL7_G_G_HM_MODE (1 << 7) +/** @} */ + +/** + * @name LSM6DSL_AD_CTRL8_XL register bits definitions + * @{ + */ +#define LSMDSL_CTRL8_XL_LOW_PASS_ON (1 << 0) +#define LSMDSL_CTRL8_XL_HP_SLOPE_XL (1 << 2) +#define LSMDSL_CTRL8_XL_INPUT_COMPO (1 << 3) +#define LSMDSL_CTRL8_XL_HP_REF_MODE (1 << 4) +#define LSMDSL_CTRL8_XL_HPCF_XL0 (1 << 5) +#define LSMDSL_CTRL8_XL_HPCF_XL1 (1 << 6) +#define LSMDSL_CTRL8_XL_LPF2_XL_EN (1 << 7) +/** @} */ + +/** + * @name LSM6DSL_AD_CTRL9_XL register bits definitions + * @{ + */ +#define LSMDSL_CTRL9_XL_SOFT_EN (1 << 2) +#define LSMDSL_CTRL9_XL_DEN_XL_G (1 << 4) +#define LSMDSL_CTRL9_XL_DEN_Z (1 << 5) +#define LSMDSL_CTRL9_XL_DEN_Y (1 << 6) +#define LSMDSL_CTRL9_XL_DEN_X (1 << 7) +/** @} */ + +/** + * @name LSM6DSL_AD_CTRL10_C register bits definitions + * @{ + */ +#define LSMDSL_CTRL10_C_SIGN_MOTION (1 << 0) +#define LSMDSL_CTRL10_C_PEDO_RST_ST (1 << 1) +#define LSMDSL_CTRL10_C_FUNC_EN (1 << 2) +#define LSMDSL_CTRL10_C_TILT_EN (1 << 3) +#define LSMDSL_CTRL10_C_PEDO_EN (1 << 4) +#define LSMDSL_CTRL10_C_TIMER_EN (1 << 5) +#define LSMDSL_CTRL10_C_WRIST_TILT (1 << 7) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief LSM6DSL SPI interface switch. + * @details If set to @p TRUE the support for SPI is included. + * @note The default is @p FALSE. + */ +#if !defined(LSM6DSL_USE_SPI) || defined(__DOXYGEN__) +#define LSM6DSL_USE_SPI FALSE +#endif + +/** + * @brief LSM6DSL shared SPI switch. + * @details If set to @p TRUE the device acquires SPI bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LSM6DSL_SHARED_SPI) || defined(__DOXYGEN__) +#define LSM6DSL_SHARED_SPI FALSE +#endif + +/** + * @brief LSM6DSL I2C interface switch. + * @details If set to @p TRUE the support for I2C is included. + * @note The default is @p TRUE. + */ +#if !defined(LSM6DSL_USE_I2C) || defined(__DOXYGEN__) +#define LSM6DSL_USE_I2C TRUE +#endif + +/** + * @brief LSM6DSL shared I2C switch. + * @details If set to @p TRUE the device acquires I2C bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LSM6DSL_SHARED_I2C) || defined(__DOXYGEN__) +#define LSM6DSL_SHARED_I2C FALSE +#endif + +/** + * @brief LSM6DSL advanced configurations switch. + * @details If set to @p TRUE more configurations are available. + * @note The default is @p FALSE. + */ +#if !defined(LSM6DSL_USE_ADVANCED) || defined(__DOXYGEN__) +#define LSM6DSL_USE_ADVANCED FALSE +#endif + +/** + * @brief Number of acquisitions for gyroscope bias removal. + * @details This is the number of acquisitions performed to compute the + * bias. A repetition is required in order to remove noise. + */ +#if !defined(LSM6DSL_GYRO_BIAS_ACQ_TIMES) || defined(__DOXYGEN__) +#define LSM6DSL_GYRO_BIAS_ACQ_TIMES 50 +#endif + +/** + * @brief Settling time for gyroscope bias removal. + * @details This is the time between each bias acquisition. + */ +#if !defined(LSM6DSL_GYRO_BIAS_SETTLING_US) || defined(__DOXYGEN__) +#define LSM6DSL_GYRO_BIAS_SETTLING_US 5000 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !(LSM6DSL_USE_SPI ^ LSM6DSL_USE_I2C) +#error "LSM6DSL_USE_SPI and LSM6DSL_USE_I2C cannot be both true or both false" +#endif + +#if LSM6DSL_USE_SPI && !HAL_USE_SPI +#error "LSM6DSL_USE_SPI requires HAL_USE_SPI" +#endif + +#if LSM6DSL_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION +#error "LSM6DSL_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" +#endif + +#if LSM6DSL_USE_I2C && !HAL_USE_I2C +#error "LSM6DSL_USE_I2C requires HAL_USE_I2C" +#endif + +#if LSM6DSL_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION +#error "LSM6DSL_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" +#endif + +/* + * CHTODO: Add support for LSM6DSL over SPI. + */ +#if LSM6DSL_USE_SPI +#error "LSM6DSL over SPI still not supported" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @name LSM6DSL data structures and types. + * @{ + */ +/** + * @brief Structure representing a LSM6DSL driver. + */ +typedef struct LSM6DSLDriver LSM6DSLDriver; + +/** + * @brief Accelerometer and Gyroscope Slave Address. + */ +typedef enum { + LSM6DSL_SAD_GND = 0x6A, /**< SAD pin connected to GND. */ + LSM6DSL_SAD_VCC = 0x6B /**< SAD pin connected to VCC. */ +} lsm6dsl_sad_t; + +/** + * @brief LSM6DSL accelerometer subsystem full scale. + */ +typedef enum { + LSM6DSL_ACC_FS_2G = 0x00, /**< Full scale �2g. */ + LSM6DSL_ACC_FS_4G = 0x40, /**< Full scale �4g. */ + LSM6DSL_ACC_FS_8G = 0x80, /**< Full scale �8g. */ + LSM6DSL_ACC_FS_16G = 0xC0 /**< Full scale �16g. */ +} lsm6dsl_acc_fs_t; + +/** + * @brief LSM6DSL accelerometer subsystem output data rate. + */ +typedef enum { + LSM6DSL_ACC_ODR_PD = 0x00, /**< Power down */ + LSM6DSL_ACC_ODR_1P6Hz = 0xB0, /**< ODR 1.6 Hz (Low Power only) */ + LSM6DSL_ACC_ODR_12P5Hz = 0x10, /**< ODR 12.5 Hz */ + LSM6DSL_ACC_ODR_26Hz = 0x20, /**< ODR 26 Hz */ + LSM6DSL_ACC_ODR_52Hz = 0x30, /**< ODR 52 Hz */ + LSM6DSL_ACC_ODR_104Hz = 0x40, /**< ODR 104 Hz */ + LSM6DSL_ACC_ODR_208Hz = 0x50, /**< ODR 208 Hz */ + LSM6DSL_ACC_ODR_416Hz = 0x60, /**< ODR 416 Hz */ + LSM6DSL_ACC_ODR_833Hz = 0x70, /**< ODR 833 Hz */ + LSM6DSL_ACC_ODR_1P66Hz = 0x80, /**< ODR 1.66 kHz */ + LSM6DSL_ACC_ODR_3P33Hz = 0x90, /**< ODR 3.33 kHz */ + LSM6DSL_ACC_ODR_6P66Hz = 0xA0 /**< ODR 6.66 kHz */ +} lsm6dsl_acc_odr_t; + +/** + * @brief LSM6DSL accelerometer subsystem output data rate. + */ +typedef enum { + LSM6DSL_ACC_LP_DISABLED = 0x00, /**< Low power disabled */ + LSM6DSL_ACC_LP_ENABLED = 0x10 /**< Low power enabled */ +} lsm6dsl_acc_lp_t; + +/** + * @brief LSM6DSL gyroscope subsystem full scale. + */ +typedef enum { + LSM6DSL_GYRO_FS_125DPS = 0x02, /**< Full scale �125 degree per second */ + LSM6DSL_GYRO_FS_250DPS = 0x00, /**< Full scale �250 degree per second */ + LSM6DSL_GYRO_FS_500DPS = 0x04, /**< Full scale �500 degree per second */ + LSM6DSL_GYRO_FS_1000DPS = 0x08, /**< Full scale �1000 degree per second */ + LSM6DSL_GYRO_FS_2000DPS = 0x0C /**< Full scale �2000 degree per second */ +} lsm6dsl_gyro_fs_t; + +/** + * @brief LSM6DSL gyroscope subsystem output data rate. + */ +typedef enum { + LSM6DSL_GYRO_ODR_PD = 0x00, /**< Power down */ + LSM6DSL_GYRO_ODR_12P5Hz = 0x10, /**< ODR 12.5 Hz */ + LSM6DSL_GYRO_ODR_26Hz = 0x20, /**< ODR 26 Hz */ + LSM6DSL_GYRO_ODR_52Hz = 0x30, /**< ODR 52 Hz */ + LSM6DSL_GYRO_ODR_104Hz = 0x40, /**< ODR 104 Hz */ + LSM6DSL_GYRO_ODR_208Hz = 0x50, /**< ODR 208 Hz */ + LSM6DSL_GYRO_ODR_416Hz = 0x60, /**< ODR 416 Hz */ + LSM6DSL_GYRO_ODR_833Hz = 0x70, /**< ODR 833 Hz */ + LSM6DSL_GYRO_ODR_1P66Hz = 0x80, /**< ODR 1.66 kHz */ + LSM6DSL_GYRO_ODR_3P33Hz = 0x90, /**< ODR 3.33 kHz */ + LSM6DSL_GYRO_ODR_6P66Hz = 0xA0 /**< ODR 6.66 kHz */ +} lsm6dsl_gyro_odr_t; + +/** + * @brief LSM6DSL gyroscope subsystem low mode configuration. + */ +typedef enum { + LSM6DSL_GYRO_LP_DISABLED = 0x00, /**< Low power mode disabled. */ + LSM6DSL_GYRO_LP_ENABLED = 0x80 /**< Low power mode enabled. */ +} lsm6dsl_gyro_lp_t; + +/** + * @brief LSM6DSL gyroscope subsystem output selection. + */ +typedef enum { + LSM6DSL_GYRO_LPF_DISABLED = -1, /**< Low pass filter disabled. */ + LSM6DSL_GYRO_LPF_FTYPE0 = 0x00, /**< Refer to table 68 of Datasheet. */ + LSM6DSL_GYRO_LPF_FTYPE1 = 0x01, /**< Refer to table 68 of Datasheet. */ + LSM6DSL_GYRO_LPF_FTYPE2 = 0x10, /**< Refer to table 68 of Datasheet. */ + LSM6DSL_GYRO_LPF_FTYPE3 = 0x11 /**< Refer to table 68 of Datasheet. */ +} lsm6dsl_gyro_lpf_t; + +/** + * @brief LSM6DSL block data update. + */ +typedef enum { + LSM6DSL_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */ + LSM6DSL_BDU_BLOCKED = 0x40 /**< Block data updated after reading. */ +} lsm6dsl_bdu_t; + +/** + * @brief LSM6DSL endianness. + */ +typedef enum { + LSM6DSL_END_LITTLE = 0x00, /**< Little endian. */ + LSM6DSL_END_BIG = 0x20 /**< Big endian. */ +} lsm6dsl_end_t; + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + LSM6DSL_UNINIT = 0, /**< Not initialized. */ + LSM6DSL_STOP = 1, /**< Stopped. */ + LSM6DSL_READY = 2, /**< Ready. */ +} lsm6dsl_state_t; + +/** + * @brief LSM6DSL configuration structure. + */ +typedef struct { +#if (LSM6DSL_USE_SPI) || defined(__DOXYGEN__) + /** + * @brief SPI driver associated to this LSM6DSL. + */ + SPIDriver *spip; + /** + * @brief SPI configuration associated to this LSM6DSL accelerometer + * subsystem. + */ + const SPIConfig *accspicfg; +#endif /* LSM6DSL_USE_SPI */ +#if (LSM6DSL_USE_I2C) || defined(__DOXYGEN__) + /** + * @brief I2C driver associated to this LSM6DSL. + */ + I2CDriver *i2cp; + /** + * @brief I2C configuration associated to this LSM6DSL accelerometer + * subsystem. + */ + const I2CConfig *i2ccfg; + /** + * @brief LSM6DSL Slave Address + */ + lsm6dsl_sad_t slaveaddress; +#endif /* LSM6DSL_USE_I2C */ + /** + * @brief LSM6DSL accelerometer subsystem initial sensitivity. + */ + float *accsensitivity; + /** + * @brief LSM6DSL accelerometer subsystem initial bias. + */ + float *accbias; + /** + * @brief LSM6DSL accelerometer subsystem full scale. + */ + lsm6dsl_acc_fs_t accfullscale; + /** + * @brief LSM6DSL accelerometer subsystem output data rate. + */ + lsm6dsl_acc_odr_t accoutdatarate; +#if LSM6DSL_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief LSM6DSL accelerometer subsystem low power mode. + */ + lsm6dsl_acc_lp_t acclpmode; +#endif /* LSM6DSL_USE_ADVANCED */ + /** + * @brief LSM6DSL gyroscope subsystem initial sensitivity. + */ + float *gyrosensitivity; + /** + * @brief LSM6DSL gyroscope subsystem initial bias. + */ + float *gyrobias; + /** + * @brief LSM6DSL gyroscope subsystem full scale. + */ + lsm6dsl_gyro_fs_t gyrofullscale; + /** + * @brief LSM6DSL gyroscope subsystem output data rate. + */ + lsm6dsl_gyro_odr_t gyrooutdatarate; +#if LSM6DSL_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief LSM6DSL gyroscope subsystem low mode configuration. + */ + lsm6dsl_gyro_lp_t gyrolpmode; + /** + * @brief LSM6DSL gyroscope subsystem low pass filter configuration. + */ + lsm6dsl_gyro_lpf_t gyrolowpassfilter; + /** + * @brief LSM6DSL block data update + */ + lsm6dsl_bdu_t blockdataupdate; + /** + * @brief LSM6DSL endianness + */ + lsm6dsl_end_t endianness; +#endif /* LSM6DSL_USE_ADVANCED */ +} LSM6DSLConfig; + +/** + * @brief @p LSM6DSL specific methods. + */ +#define _lsm6dsl_methods_alone \ + /* Change full scale value of LSM6DSL accelerometer subsystem .*/ \ + msg_t (*acc_set_full_scale)(LSM6DSLDriver *devp, lsm6dsl_acc_fs_t fs); \ + /* Change full scale value of LSM6DSL gyroscope subsystem .*/ \ + msg_t (*gyro_set_full_scale)(LSM6DSLDriver *devp, lsm6dsl_gyro_fs_t fs); + +/** + * @brief @p LSM6DSL specific methods with inherited ones. + */ +#define _lsm6dsl_methods \ + _base_object_methods \ + _lsm6dsl_methods_alone + +/** + * @extends BaseObjectVMT + * + * @brief @p LSM6DSL virtual methods table. + */ +struct LSM6DSLVMT { + _lsm6dsl_methods +}; + +/** + * @brief @p LSM6DSLDriver specific data. + */ +#define _lsm6dsl_data \ + _base_sensor_data \ + /* Driver state.*/ \ + lsm6dsl_state_t state; \ + /* Current configuration data.*/ \ + const LSM6DSLConfig *config; \ + /* Accelerometer subsystem axes number.*/ \ + size_t accaxes; \ + /* Accelerometer subsystem current sensitivity.*/ \ + float accsensitivity[LSM6DSL_ACC_NUMBER_OF_AXES]; \ + /* Accelerometer subsystem current bias .*/ \ + float accbias[LSM6DSL_ACC_NUMBER_OF_AXES]; \ + /* Accelerometer subsystem current full scale value.*/ \ + float accfullscale; \ + /* Gyroscope subsystem axes number.*/ \ + size_t gyroaxes; \ + /* Gyroscope subsystem current sensitivity.*/ \ + float gyrosensitivity[LSM6DSL_GYRO_NUMBER_OF_AXES]; \ + /* Gyroscope subsystem current Bias.*/ \ + float gyrobias[LSM6DSL_GYRO_NUMBER_OF_AXES]; \ + /* Gyroscope subsystem current full scale value.*/ \ + float gyrofullscale; + +/** + * @brief LSM6DSL 6-axis accelerometer/gyroscope class. + */ +struct LSM6DSLDriver { + /** @brief Virtual Methods Table.*/ + const struct LSM6DSLVMT *vmt; + /** @brief Base accelerometer interface.*/ + BaseAccelerometer acc_if; + /** @brief Base gyroscope interface.*/ + BaseGyroscope gyro_if; + _lsm6dsl_data +}; +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Return the number of axes of the BaseAccelerometer. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * + * @return the number of axes. + * + * @api + */ +#define lsm6dslAccelerometerGetAxesNumber(devp) \ + accelerometerGetAxesNumber(&((devp)->acc_if)) + +/** + * @brief Retrieves raw data from the BaseAccelerometer. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm6dslAccelerometerReadRaw(devp, axes) \ + accelerometerReadRaw(&((devp)->acc_if), axes) + +/** + * @brief Retrieves cooked data from the BaseAccelerometer. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as milli-G. + * @note The axes array must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm6dslAccelerometerReadCooked(devp, axes) \ + accelerometerReadCooked(&((devp)->acc_if), axes) + +/** + * @brief Set bias values for the BaseAccelerometer. + * @note Bias must be expressed as milli-G. + * @note The bias buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm6dslAccelerometerSetBias(devp, bp) \ + accelerometerSetBias(&((devp)->acc_if), bp) + +/** + * @brief Reset bias values for the BaseAccelerometer. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm6dslAccelerometerResetBias(devp) \ + accelerometerResetBias(&((devp)->acc_if)) + +/** + * @brief Set sensitivity values for the BaseAccelerometer. + * @note Sensitivity must be expressed as milli-G/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseAccelerometer axes number. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm6dslAccelerometerSetSensitivity(devp, sp) \ + accelerometerSetSensitivity(&((devp)->acc_if), sp) + +/** + * @brief Reset sensitivity values for the BaseAccelerometer. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lsm6dslAccelerometerResetSensitivity(devp) \ + accelerometerResetSensitivity(&((devp)->acc_if)) + +/** + * @brief Changes the LSM6DSLDriver accelerometer fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lsm6dslAccelerometerSetFullScale(devp, fs) \ + (devp)->vmt->acc_set_full_scale(devp, fs) + +/** + * @brief Return the number of axes of the BaseGyroscope. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * + * @return the number of axes. + * + * @api + */ +#define lsm6dslGyroscopeGetAxesNumber(devp) \ + gyroscopeGetAxesNumber(&((devp)->gyro_if)) + +/** + * @brief Retrieves raw data from the BaseGyroscope. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm6dslGyroscopeReadRaw(devp, axes) \ + gyroscopeReadRaw(&((devp)->gyro_if), axes) + +/** + * @brief Retrieves cooked data from the BaseGyroscope. + * @note This data is manipulated according to the formula + * cooked = (raw * sensitivity) - bias. + * @note Final data is expressed as DPS. + * @note The axes array must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm6dslGyroscopeReadCooked(devp, axes) \ + gyroscopeReadCooked(&((devp)->gyro_if), axes) + +/** + * @brief Samples bias values for the BaseGyroscope. + * @note The LSM6DSL shall not be moved during the whole procedure. + * @note After this function internal bias is automatically updated. + * @note The behavior of this function depends on @p LSM6DSL_BIAS_ACQ_TIMES + * and @p LSM6DSL_BIAS_SETTLING_US. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define lsm6dslGyroscopeSampleBias(devp) \ + gyroscopeSampleBias(&((devp)->gyro_if)) + +/** + * @brief Set bias values for the BaseGyroscope. + * @note Bias must be expressed as DPS. + * @note The bias buffer must be at least the same size of the BaseGyroscope + * axes number. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * @param[in] bp a buffer which contains biases. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm6dslGyroscopeSetBias(devp, bp) \ + gyroscopeSetBias(&((devp)->gyro_if), bp) + +/** + * @brief Reset bias values for the BaseGyroscope. + * @note Default biases value are obtained from device datasheet when + * available otherwise they are considered zero. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm6dslGyroscopeResetBias(devp) \ + gyroscopeResetBias(&((devp)->gyro_if)) + +/** + * @brief Set sensitivity values for the BaseGyroscope. + * @note Sensitivity must be expressed as DPS/LSB. + * @note The sensitivity buffer must be at least the same size of the + * BaseGyroscope axes number. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * @param[in] sp a buffer which contains sensitivities. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * + * @api + */ +#define lsm6dslGyroscopeSetSensitivity(devp, sp) \ + gyroscopeSetSensitivity(&((devp)->gyro_if), sp) + +/** + * @brief Reset sensitivity values for the BaseGyroscope. + * @note Default sensitivities value are obtained from device datasheet. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lsm6dslGyroscopeResetSensitivity(devp) \ + gyroscopeResetSensitivity(&((devp)->gyro_if)) + +/** + * @brief Changes the LSM6DSLDriver gyroscope fullscale value. + * @note This function also rescale sensitivities and biases based on + * previous and next fullscale value. + * @note A recalibration is highly suggested after calling this function. + * + * @param[in] devp pointer to @p LSM6DSLDriver. + * @param[in] fs new fullscale value. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET otherwise. + * + * @api + */ +#define lsm6dslGyroscopeSetFullScale(devp, fs) \ + (devp)->vmt->acc_set_full_scale(devp, fs) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void lsm6dslObjectInit(LSM6DSLDriver *devp); + void lsm6dslStart(LSM6DSLDriver *devp, const LSM6DSLConfig *config); + void lsm6dslStop(LSM6DSLDriver *devp); +#ifdef __cplusplus +} +#endif + +#endif /* _LSM6DSL_H_ */ + +/** @} */ diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.mk b/ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.mk new file mode 100644 index 0000000..0605f06 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.mk @@ -0,0 +1,10 @@ +# List of all the LSM6DSL device files. +LSM6DSLSRC := $(CHIBIOS)/os/ex/devices/ST/lsm6dsl.c + +# Required include directories +LSM6DSLINC := $(CHIBIOS)/os/ex/include \ + $(CHIBIOS)/os/ex/devices/ST + +# Shared variables +ALLCSRC += $(LSM6DSLSRC) +ALLINC += $(LSM6DSLINC) \ No newline at end of file diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/vl53l0x.h b/ChibiOS_20.3.2/os/ex/devices/ST/vl53l0x.h new file mode 100644 index 0000000..1fc8f9b --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/vl53l0x.h @@ -0,0 +1,443 @@ +/* + ChibiOS - Copyright (C) 2016..2018 Edoardo Lombardi, Rocco Marco Guglielmi + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +/** + * @file vl53l0x.h + * @brief VL53L0X MEMS interface module header. + * + * @addtogroup VL53L0X + * @ingroup EX_ST + * @{ + */ +#ifndef _VL53L0X_H_ +#define _VL53L0X_H_ + +#include "ex_rangefinder.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Version identification + * @{ + */ +/** + * @brief VL53L0X driver version string. + */ +#define EX_VL53L0X_VERSION "1.0.0" + +/** + * @brief VL53L0X driver version major number. + */ +#define EX_VL53L0X_MAJOR 1 + +/** + * @brief VL53L0X driver version minor number. + */ +#define EX_VL53L0X_MINOR 0 + +/** + * @brief VL53L0X driver version patch number. + */ +#define EX_VL53L0X_PATCH 0 +/** @} */ + +/** + * @brief VL53L0X rangefinder subsystem characteristics. + * @note Sensitivity is expressed as hPa/LSB whereas hPa stand for + * hectopascal. + * @note Bias is expressed as hPa. + * + * @{ + */ +#define VL53L0X_RANGE_NUMBER_OF_AXES 1U + +/* CHTODO: Check this. */ +#define VL53L0X_RANGE_SENS 0.00024414f +#define VL53L0X_RANGE_BIAS 0.0f +/** @} */ + +/** + * @name VL53L0X register addresses + * @{ + */ +#define VL53L0X_REG_SYSRANGE_START 0x00 +#define VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG 0x01 +#define VL53L0X_REG_SYSTEM_INTERMEASUREMENT_PERIOD 0x04 +#define VL53L0X_REG_SYSTEM_RANGE_CONFIG 0x09 +#define VL53L0X_REG_SYSTEM_INTERRUPT_CONFIG_GPIO 0x0A +#define VL53L0X_REG_SYSTEM_INTERRUPT_CLEAR 0x0B +#define VL53L0X_REG_SYSTEM_THRESH_HIGH 0x0C +#define VL53L0X_REG_SYSTEM_THRESH_LOW 0x0E + +#define VL53L0X_REG_RESULT_INTERRUPT_STATUS 0x13 +#define VL53L0X_REG_RESULT_RANGE_STATUS 0x14 + +#define VL53L0X_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS 0x20 +#define VL53L0X_REG_PRE_RANGE_CONFIG_MIN_SNR 0x27 +#define VL53L0X_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM 0x28 +#define VL53L0X_REG_ALGO_PHASECAL_LIM 0x30 +#define VL53L0X_REG_ALGO_PHASECAL_CONFIG_TIMEOUT 0x30 +#define VL53L0X_REG_GLOBAL_CONFIG_VCSEL_WIDTH 0x32 +#define VL53L0X_REG_HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT 0x33 + +#define VL53L0X_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT 0x44 +#define VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW 0x47 +#define VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH 0x48 +#define VL53L0X_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD 0x4E +#define VL53L0X_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET 0x4F + +#define VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD 0x50 +#define VL53L0X_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI 0x51 +#define VL53L0X_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_LO 0x52 +#define VL53L0X_REG_HISTOGRAM_CONFIG_READOUT_CTRL 0x55 +#define VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW 0x56 +#define VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH 0x57 + +#define VL53L0X_REG_MSRC_CONFIG_CONTROL 0x60 +#define VL53L0X_REG_PRE_RANGE_CONFIG_SIGMA_THRESH_HI 0x61 +#define VL53L0X_REG_PRE_RANGE_CONFIG_SIGMA_THRESH_LO 0x62 +#define VL53L0X_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT 0x64 +#define VL53L0X_REG_FINAL_RANGE_CONFIG_MIN_SNR 0x67 + +#define VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD 0x70 +#define VL53L0X_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI 0x71 +#define VL53L0X_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_LO 0x72 + +#define VL53L0X_REG_POWER_MANAGEMENT_GO1_POWER_FORCE 0x80 +#define VL53L0X_REG_SYSTEM_HISTOGRAM_BIN 0x81 +#define VL53L0X_REG_GPIO_HV_MUX_ACTIVE_HIGH 0x84 +#define VL53L0X_REG_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV 0x89 +#define VL53L0X_REG_I2C_SLAVE_DEVICE_ADDRESS 0x8A + +#define VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0 0xB0 +#define VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_1 0xB1 +#define VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_2 0xB2 +#define VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_3 0xB3 +#define VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_4 0xB4 +#define VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_5 0xB5 +#define VL53L0X_REG_GLOBAL_CONFIG_REF_EN_START_SELECT 0xB6 +#define VL53L0X_REG_RESULT_PEAK_SIGNAL_RATE_REF 0xB6 +#define VL53L0X_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN 0xBC +#define VL53L0X_REG_SOFT_RESET_GO2_SOFT_RESET_N 0xBF + +#define VL53L0X_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_RTN 0xC0 +#define VL53L0X_REG_IDENTIFICATION_MODEL_ID 0xC0 +#define VL53L0X_REG_IDENTIFICATION_REVISION_ID 0xC2 + +#define VL53L0X_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF 0xD0 +#define VL53L0X_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_REF 0xD4 + +#define VL53L0X_REG_OSC_CALIBRATE_VAL 0xF8 +/** @} */ + +/** + * @name VL53L0X_INT_CFG register bits definitions + * @{ + */ +#define VL53L0X_INT_CFG_MASK 0xFF +#define VL53L0X_INT_CFG_PHE (1 << 0) +#define VL53L0X_INT_CFG_PLE (1 << 1) +#define VL53L0X_INT_CFG_LIR (1 << 2) +#define VL53L0X_INT_CFG_DIFF_EN (1 << 3) +#define VL53L0X_INT_CFG_RESET_AZ (1 << 4) +#define VL53L0X_INT_CFG_AUTOZERO (1 << 5) +#define VL53L0X_INT_CFG_RESET_ARP (1 << 6) +#define VL53L0X_INT_CFG_AUTORIFP (1 << 7) +/** @} */ + +/** + * @name VL53L0X_CTRL_REG1 register bits definitions + * @{ + */ +#define VL53L0X_CTRL_REG1_MASK 0x7F +#define VL53L0X_CTRL_REG1_SIM (1 << 0) +#define VL53L0X_CTRL_REG1_BDU (1 << 1) +#define VL53L0X_CTRL_REG1_LPFP_CFG (1 << 2) +#define VL53L0X_CTRL_REG1_LPFP_EN (1 << 3) +#define VL53L0X_CTRL_REG1_ODR0 (1 << 4) +#define VL53L0X_CTRL_REG1_ODR1 (1 << 5) +#define VL53L0X_CTRL_REG1_ODR2 (1 << 6) +/** @} */ + +/** + * @name VL53L0X_CTRL_REG2 register bits definitions + * @{ + */ +#define VL53L0X_CTRL_REG2_MASK 0xFD +#define VL53L0X_CTRL_REG2_ONE_SHOT (1 << 0) +#define VL53L0X_CTRL_REG2_SWRESET (1 << 2) +#define VL53L0X_CTRL_REG2_I2C_DIS (1 << 3) +#define VL53L0X_CTRL_REG2_IF_ADD_INC (1 << 4) +#define VL53L0X_CTRL_REG2_STOP_ON_FTH (1 << 5) +#define VL53L0X_CTRL_REG2_FIFO_EN (1 << 6) +#define VL53L0X_CTRL_REG2_BOOT (1 << 7) +/** @} */ + +/** + * @name VL53L0X_CTRL_REG3 register bits definitions + * @{ + */ +#define VL53L0X_CTRL_REG3_MASK 0xFF +#define VL53L0X_CTRL_REG3_INT_S1 (1 << 0) +#define VL53L0X_CTRL_REG3_INT_S2 (1 << 1) +#define VL53L0X_CTRL_REG3_DRDY (1 << 2) +#define VL53L0X_CTRL_REG3_F_OVR (1 << 3) +#define VL53L0X_CTRL_REG3_F_FTH (1 << 4) +#define VL53L0X_CTRL_REG3_F_FSS5 (1 << 5) +#define VL53L0X_CTRL_REG3_PP_OD (1 << 6) +#define VL53L0X_CTRL_REG3_INT_H_L (1 << 7) +/** @} */ + +/** + * @name VL53L0X_INT_SRC register bits definitions + * @{ + */ +#define VL53L0X_INT_SRC_MASK 0x87 +#define VL53L0X_INT_SRC_PH (1 << 0) +#define VL53L0X_INT_SRC_PL (1 << 1) +#define VL53L0X_INT_SRC_IA (1 << 2) +#define VL53L0X_INT_SRC_BOOT_STATUS (1 << 8) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief VL53L0X I2C interface switch. + * @details If set to @p TRUE the support for I2C is included. + * @note The default is @p TRUE. + */ +#if !defined(VL53L0X_USE_I2C) || defined(__DOXYGEN__) +#define VL53L0X_USE_I2C TRUE +#endif + +/** + * @brief VL53L0X shared I2C switch. + * @details If set to @p TRUE the device acquires I2C bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION. + */ +#if !defined(VL53L0X_SHARED_I2C) || defined(__DOXYGEN__) +#define VL53L0X_SHARED_I2C FALSE +#endif + +/** + * @brief VL53L0X advanced configurations switch. + * @details If set to @p TRUE more configurations are available. + * @note The default is @p FALSE. + */ +#if !defined(VL53L0X_USE_ADVANCED) || defined(__DOXYGEN__) +#define VL53L0X_USE_ADVANCED FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if VL53L0X_USE_I2C && !HAL_USE_I2C +#error "VL53L0X_USE_I2C requires HAL_USE_I2C" +#endif + +#if VL53L0X_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION +#error "VL53L0X_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @name VL53L0X data structures and types. + * @{ + */ +/** + * @brief Structure representing a VL53L0X driver. + */ +typedef struct VL53L0XDriver VL53L0XDriver; + +/** + * @brief VL53L0X slave address + */ +typedef enum { + VL53L0X_SAD_DEFAULT = 0x29, /**< Default slave address */ +}vl53l0x_sad_t; + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + VL53L0X_UNINIT = 0, /**< Not initialized. */ + VL53L0X_STOP = 1, /**< Stopped. */ + VL53L0X_READY = 2, /**< Ready. */ +} vl53l0x_state_t; + +/** + * @brief VL53L0X configuration structure. + */ +typedef struct { +#if VL53L0X_USE_I2C || defined(__DOXYGEN__) + /** + * @brief I2C driver associated to this VL53L0X. + */ + I2CDriver *i2cp; + /** + * @brief I2C configuration associated to this VL53L0X. + */ + const I2CConfig *i2ccfg; + /** + * @brief VL53L0X slave address + */ + vl53l0x_sad_t slaveaddress; +#endif /* VL53L0X_USE_I2C */ +#if VL53L0X_USE_ADVANCED || defined(__DOXYGEN__) + /** + * @brief Dummy placeholder + */ +#endif +} VL53L0XConfig; + +/** + * @brief @p VL53L0X specific methods. + * @note No methods so far, just a common ancestor interface. + */ +#define _vl53l0x_methods_alone + +/** + * @brief @p VL53L0X specific methods with inherited ones. + */ +#define _vl53l0x_methods \ + _base_object_methods \ + _vl53l0x_methods_alone + +/** + * @extends BaseObjectVMT + * + * @brief @p VL53L0X virtual methods table. + */ +struct VL53L0XVMT { + _vl53l0x_methods +}; + +/** + * @brief @p VL53L0XDriver specific data. + */ +#define _vl53l0x_data \ + /* Driver state.*/ \ + vl53l0x_state_t state; \ + /* Current configuration data.*/ \ + const VL53L0XConfig *config; \ + /* RangeFinder subsystem axes number.*/ \ + size_t rangeaxes; + +/** + * @brief VL53L0X 2-axis rangemeter/thermometer class. + */ +struct VL53L0XDriver { + /** @brief Virtual Methods Table.*/ + const struct VL53L0XVMT *vmt; + /** @brief Base rangemeter interface.*/ + BaseRangeFinder range_if; + _vl53l0x_data +}; +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Return the number of axes of the BaseRangeFinder. + * + * @param[in] devp pointer to @p VL53L0XDriver. + * + * @return the number of axes. + * + * @api + */ +#define vl53l0xRangeFinderGetAxesNumber(devp) \ + rangemeterGetAxesNumber(&((devp)->range_if)) + +/** + * @brief Retrieves raw data from the BaseRangeFinder. + * @note This data is retrieved from MEMS register without any algebraical + * manipulation. + * @note The axes array must be at least the same size of the + * BaseRangeFinder axes number. + * + * @param[in] devp pointer to @p VL53L0XDriver. + * @param[out] axes a buffer which would be filled with raw data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define vl53l0xRangeFinderReadRaw(devp, axes) \ + rangemeterReadRaw(&((devp)->range_if), axes) + +/** + * @brief Retrieves cooked data from the BaseRangeFinder. + * @note Final data is expressed as mm. + * @note The axes array must be at least the same size of the + * BaseRangeFinder axes number. + * + * @param[in] devp pointer to @p VL53L0XDriver. + * @param[out] axes a buffer which would be filled with cooked data. + * + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. + * + * @api + */ +#define vl53l0xRangeFinderReadCooked(devp, axes) \ + rangemeterReadCooked(&((devp)->range_if), axes) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void vl53l0xObjectInit(VL53L0XDriver *devp); + void vl53l0xStart(VL53L0XDriver *devp, const VL53L0XConfig *config); + void vl53l0xStop(VL53L0XDriver *devp); +#ifdef __cplusplus +} +#endif + +#endif /* _VL53L0X_H_ */ + +/** @} */ + diff --git a/ChibiOS_20.3.2/os/ex/devices/ST/vl53l0x.mk b/ChibiOS_20.3.2/os/ex/devices/ST/vl53l0x.mk new file mode 100644 index 0000000..de22649 --- /dev/null +++ b/ChibiOS_20.3.2/os/ex/devices/ST/vl53l0x.mk @@ -0,0 +1,10 @@ +# List of all the VL53L0X device files. +VL53L0XSRC := $(CHIBIOS)/os/ex/devices/ST/vl53l0x.c + +# Required include directories +VL53L0XINC := $(CHIBIOS)/os/ex/include \ + $(CHIBIOS)/os/ex/devices/ST + +# Shared variables +ALLCSRC += $(VL53L0XSRC) +ALLINC += $(VL53L0XINC) \ No newline at end of file -- cgit v1.2.3