aboutsummaryrefslogtreecommitdiffstats
path: root/ChibiOS_20.3.2/os/ex/devices
diff options
context:
space:
mode:
Diffstat (limited to 'ChibiOS_20.3.2/os/ex/devices')
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.c788
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.h403
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/Bosch/bmp085.mk10
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/hts221.c781
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/hts221.h707
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/hts221.mk10
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.c642
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.h725
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/l3gd20.mk10
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.c554
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.h566
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lis302dl.mk10
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.c641
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.h708
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lis3dsh.mk10
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.c627
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.h670
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lis3mdl.mk10
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.c686
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.h724
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lps22hb.mk10
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lps25h.c696
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lps25h.h740
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lps25h.mk10
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.c906
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.h919
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lsm303agr.mk10
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.c1175
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.h955
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lsm303dlhc.mk10
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.c1109
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.h1034
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lsm6ds0.mk10
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.c1119
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.h1055
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/lsm6dsl.mk10
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/vl53l0x.h443
-rw-r--r--ChibiOS_20.3.2/os/ex/devices/ST/vl53l0x.mk10
38 files changed, 19503 insertions, 0 deletions
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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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, &reg, 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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, &reg, 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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, &reg, 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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 <http://www.gnu.org/licenses/>.
+
+*/
+
+/**
+ * @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