nanohub:drivers:st_lsm6dsm: added self-test procedure for accel, gyro and magn sensors

Change-Id: I003ad27788eae5dbc044df919b950c36a3d1f120
Signed-off-by: Denis Ciocca <denis.ciocca@st.com>
diff --git a/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm.c b/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm.c
index 2c1cade..51201d5 100644
--- a/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm.c
+++ b/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm.c
@@ -20,6 +20,7 @@
 #include <string.h>
 #include <sensors.h>
 #include <slab.h>
+#include <heap.h>
 #include <spi.h>
 #include <gpio.h>
 #include <atomic.h>
@@ -100,7 +101,7 @@
 #define LSM6DSM_SYNC_DELTA_INTERVAL                     100000000ULL    /* Sensor timestamp is synced with MCU every #n deltatime [ns] */
 
 /* SPI buffers */
-#define LSM6DSM_SPI_PACKET_SIZE                         70
+#define LSM6DSM_SPI_PACKET_SIZE                         75
 #define LSM6DSM_SPI_FIFO_SIZE                           1024
 #define LSM6DSM_BUF_MARGIN                              100
 #define SPI_BUF_SIZE                                    (LSM6DSM_SPI_FIFO_SIZE + LSM6DSM_BUF_MARGIN)
@@ -155,6 +156,7 @@
 #define LSM6DSM_CTRL2_G_ADDR                            (0x11)
 #define LSM6DSM_CTRL3_C_ADDR                            (0x12)
 #define LSM6DSM_CTRL4_C_ADDR                            (0x13)
+#define LSM6DSM_CTRL5_C_ADDR                            (0x14)
 #define LSM6DSM_EBD_STEP_COUNT_DELTA_ADDR               (0x15)
 #define LSM6DSM_CTRL10_C_ADDR                           (0x19)
 #define LSM6DSM_MASTER_CONFIG_ADDR                      (0x1a)
@@ -197,6 +199,18 @@
 #define LSM6DSM_FIFO_DECIMATION_FACTOR_16               (0x06)
 #define LSM6DSM_FIFO_DECIMATION_FACTOR_32               (0x07)
 
+/* LSM6DSM selftest related */
+#define LSM6DSM_NUM_AVERAGE_SELFTEST                    5
+#define LSM6DSM_NUM_AVERAGE_SELFTEST_SLOW               30
+#define LSM6DSM_ACCEL_SELFTEST_PS                       (0x01)
+#define LSM6DSM_GYRO_SELFTEST_PS                        (0x04)
+#define LSM6DSM_ACCEL_SELFTEST_NS                       (0x02)
+#define LSM6DSM_GYRO_SELFTEST_NS                        (0x0c)
+#define LSM6DSM_ACCEL_SELFTEST_HIGH_THR_LSB             6967            /* 1700mg @8g in LSB */
+#define LSM6DSM_ACCEL_SELFTEST_LOW_THR_LSB              368             /* 90mg @8g in LSB */
+#define LSM6DSM_GYRO_SELFTEST_HIGH_THR_LSB              10000           /* 700dps @2000dps in LSB */
+#define LSM6DSM_GYRO_SELFTEST_LOW_THR_LSB               2142            /* 150dps @2000dps in LSB */
+
 /* LSM6DSM embedded registers */
 #define LSM6DSM_EMBEDDED_SLV0_ADDR_ADDR                 (0x02)
 #define LSM6DSM_EMBEDDED_SLV0_SUBADDR_ADDR              (0x03)
@@ -382,7 +396,7 @@
                                                          (0 << 0))     /* SW_RESET */
 
 /* LSM6DSM_CTRL4_C_BASE: control register 4 default settings */
-#define LSM6DSM_CTRL4_C_BASE                             ((0 << 7) |    /* DEN_XL_EN */ \
+#define LSM6DSM_CTRL4_C_BASE                            ((0 << 7) |    /* DEN_XL_EN */ \
                                                          (0 << 6) |    /* SLEEP */ \
                                                          (1 << 5) |    /* INT2_on_INT1 */ \
                                                          (0 << 4) |    /* DEN_DRDY_MASK */ \
@@ -391,6 +405,9 @@
                                                          (0 << 1) |    /* LPF1_SEL_G */ \
                                                          (0 << 0))     /* (0) */
 
+/* LSM6DSM_CTRL5_C_BASE: control register 5 default settings */
+#define LSM6DSM_CTRL5_C_BASE                            (0x00)
+
 /* LSM6DSM_CTRL10_C_BASE: control register 10 default settings */
 #define LSM6DSM_CTRL10_C_BASE                           ((0 << 7) |    /* (WRIST_TILT_EN) */ \
                                                          (0 << 6) |    /* (0) */ \
@@ -468,6 +485,15 @@
     INIT_DONE,
 };
 
+enum SelfTestState {
+    SELFTEST_INITIALIZATION = 0,
+    SELFTEST_READ_EST_DATA,
+    SELFTEST_SECOND_STEP_INITIALIZATION,
+    SELFTEST_READ_NST_DATA,
+    SELFTEST_VERIFICATION,
+    SELFTEST_COMPLETED
+};
+
 enum SensorEvents {
     NO_EVT = -1,
     EVT_SPI_DONE = EVT_APP_START + 1,
@@ -488,6 +514,7 @@
     SENSOR_POWERING_DOWN,
     SENSOR_CONFIG_CHANGING,
     SENSOR_CONFIG_WATERMARK_CHANGING,
+    SENSOR_SELFTEST,
     SENSOR_INT1_STATUS_REG_HANDLING,
     SENSOR_INT1_OUTPUT_DATA_HANDLING,
     SENSOR_TIME_SYNC,
@@ -721,6 +748,15 @@
     bool timestampIsValid;
 };
 
+/* LSM6DSMSelfTestResultPkt: calibration packet result data
+ * @header: describe packet size and application ID of packet.
+ * @dataHeader: payload of message.
+ */
+struct LSM6DSMSelfTestResultPkt {
+    struct HostHubRawPacket header;
+    struct SensorAppEventHeader dataHeader;
+} __attribute__((packed));
+
 /* struct LSM6DSMTask: driver task data
  * @sensors: sensor status data list.
  * @slaveConn: slave interface / communication data.
@@ -792,6 +828,7 @@
     uint64_t lastFifoReadTimestamp;
 
     enum InitState initState;
+    enum SelfTestState selftestState;
 
     uint32_t tid;
     uint32_t totalNumSteps;
@@ -800,9 +837,12 @@
 #if defined(LSM6DSM_I2C_MASTER_MAGNETOMETER_ENABLED) && defined(LSM6DSM_I2C_MASTER_BAROMETER_ENABLED)
     uint32_t baroTimerId;
 #endif /* LSM6DSM_I2C_MASTER_MAGNETOMETER_ENABLED, LSM6DSM_I2C_MASTER_BAROMETER_ENABLED */
+    int32_t dataSelftestEnabled[3];
+    int32_t dataSelftestNotEnabled[3];
 
     volatile uint8_t state;
 
+    uint8_t numSamplesSelftest;
     uint8_t mRetryLeft;
     uint8_t pedometerDependencies;
     uint8_t masterConfigDependencies;
@@ -1055,6 +1095,10 @@
     .sensorFlush = flush, \
     .sensorSendOneDirectEvt = send
 
+#define DEC_OPS_SELFTEST(power, firmware, rate, flush, selftest) \
+    DEC_OPS(power, firmware, rate, flush), \
+    .sensorSelfTest = selftest
+
 static bool lsm6dsm_setAccelPower(bool on, void *cookie);
 static bool lsm6dsm_setGyroPower(bool on, void *cookie);
 static bool lsm6dsm_setStepDetectorPower(bool on, void *cookie);
@@ -1076,6 +1120,11 @@
 static bool lsm6dsm_stepCounterFlush(void *cookie);
 static bool lsm6dsm_signMotionFlush(void *cookie);
 static bool lsm6dsm_stepCounterSendLastData(void *cookie, uint32_t tid);
+static bool lsm6dsm_runAccelSelfTest(void *cookie);
+static bool lsm6dsm_runGyroSelfTest(void *cookie);
+#ifdef LSM6DSM_I2C_MASTER_MAGNETOMETER_ENABLED
+static bool lsm6dsm_runMagnSelfTest(void *cookie);
+#endif /* LSM6DSM_I2C_MASTER_MAGNETOMETER_ENABLED */
 
 #ifdef LSM6DSM_I2C_MASTER_MAGNETOMETER_ENABLED
 static bool lsm6dsm_setMagnPower(bool on, void *cookie);
@@ -1096,10 +1145,10 @@
 #endif /* LSM6DSM_I2C_MASTER_BAROMETER_ENABLED */
 
 static const struct SensorOps LSM6DSMSensorOps[NUM_SENSORS] = {
-    { DEC_OPS(lsm6dsm_setGyroPower, lsm6dsm_gyroFirmwareUpload, lsm6dsm_setGyroRate, lsm6dsm_gyroFlush) },
-    { DEC_OPS(lsm6dsm_setAccelPower, lsm6dsm_accelFirmwareUpload, lsm6dsm_setAccelRate, lsm6dsm_accelFlush) },
+    { DEC_OPS_SELFTEST(lsm6dsm_setGyroPower, lsm6dsm_gyroFirmwareUpload, lsm6dsm_setGyroRate, lsm6dsm_gyroFlush, lsm6dsm_runGyroSelfTest) },
+    { DEC_OPS_SELFTEST(lsm6dsm_setAccelPower, lsm6dsm_accelFirmwareUpload, lsm6dsm_setAccelRate, lsm6dsm_accelFlush, lsm6dsm_runAccelSelfTest) },
 #ifdef LSM6DSM_I2C_MASTER_MAGNETOMETER_ENABLED
-    { DEC_OPS(lsm6dsm_setMagnPower, lsm6dsm_magnFirmwareUpload, lsm6dsm_setMagnRate, lsm6dsm_magnFlush) },
+    { DEC_OPS_SELFTEST(lsm6dsm_setMagnPower, lsm6dsm_magnFirmwareUpload, lsm6dsm_setMagnRate, lsm6dsm_magnFlush, lsm6dsm_runMagnSelfTest) },
 #endif /* LSM6DSM_I2C_MASTER_MAGNETOMETER_ENABLED */
 #ifdef LSM6DSM_I2C_MASTER_BAROMETER_ENABLED
     { DEC_OPS(lsm6dsm_setPressPower, lsm6dsm_pressFirmwareUpload, lsm6dsm_setPressRate, lsm6dsm_pressFlush) },
@@ -1381,6 +1430,380 @@
 }
 
 /*
+ * lsm6dsm_sendSelfTestResult: send to nanohub result of self-test
+ * @sensorType: android sensor type.
+ * @result: status message to send (PASS/ERROR).
+ */
+static void lsm6dsm_sendSelfTestResult(uint8_t sensorType, uint8_t result)
+{
+    struct LSM6DSMSelfTestResultPkt *data;
+
+    data = heapAlloc(sizeof(struct LSM6DSMSelfTestResultPkt));
+    if (!data) {
+        ERROR_PRINT("sendSelfTestResult: cannot allocate self-test result packet\n");
+        return;
+    }
+
+    data->header.appId = LSM6DSM_APP_ID;
+    data->header.dataLen = (sizeof(struct LSM6DSMSelfTestResultPkt) - sizeof(struct HostHubRawPacket));
+
+    data->dataHeader.msgId = SENSOR_APP_MSG_ID_TEST_RESULT;
+    data->dataHeader.sensorType = sensorType;
+    data->dataHeader.status = result;
+
+    if (!osEnqueueEvtOrFree(EVT_APP_TO_HOST, data, heapFree)) {
+        ERROR_PRINT("sendSelfTestResult: failed to enqueue self-test result packet\n");
+    }
+}
+
+/*
+ * lsm6dsm_runGapSelfTestProgram: state machine that is executing self-test verifying data gap
+ * @idx: sensor driver index.
+ */
+static void lsm6dsm_runGapSelfTestProgram(enum SensorIndex idx)
+{
+    TDECL();
+    uint8_t *sensorData, numberOfAverage;
+
+    numberOfAverage = LSM6DSM_NUM_AVERAGE_SELFTEST;
+
+    switch (T(selftestState)) {
+    case SELFTEST_INITIALIZATION:
+        DEBUG_PRINT("runGapSelfTestProgram: initialization\n");
+
+        T(numSamplesSelftest) = 0;
+        memset(T(dataSelftestEnabled), 0, 3 * sizeof(int32_t));
+        memset(T(dataSelftestNotEnabled), 0, 3 * sizeof(int32_t));
+
+        /* Enable self-test & power on sensor */
+        switch (idx) {
+        case ACCEL:
+            SPI_WRITE(LSM6DSM_CTRL5_C_ADDR, LSM6DSM_CTRL5_C_BASE | LSM6DSM_ACCEL_SELFTEST_PS);
+            SPI_WRITE(LSM6DSM_CTRL1_XL_ADDR, LSM6DSM_CTRL1_XL_BASE | LSM6DSM_ODR_104HZ_REG_VALUE, 30000);
+            break;
+        case GYRO:
+            SPI_WRITE(LSM6DSM_CTRL5_C_ADDR, LSM6DSM_CTRL5_C_BASE | LSM6DSM_GYRO_SELFTEST_PS);
+            SPI_WRITE(LSM6DSM_CTRL2_G_ADDR, LSM6DSM_CTRL2_G_BASE | LSM6DSM_ODR_104HZ_REG_VALUE, 30000);
+            break;
+#if defined(LSM6DSM_I2C_MASTER_LSM303AGR) || defined(LSM6DSM_I2C_MASTER_LIS3MDL)
+        case MAGN:
+            /* Enable accelerometer and sensor-hub */
+            SPI_WRITE(LSM6DSM_CTRL1_XL_ADDR, LSM6DSM_CTRL1_XL_BASE | LSM6DSM_ODR_104HZ_REG_VALUE);
+            SPI_WRITE(LSM6DSM_MASTER_CONFIG_ADDR, LSM6DSM_MASTER_CONFIG_BASE | LSM6DSM_MASTER_CONFIG_MASTER_ON, 10000);
+            T(masterConfigRegister) |= LSM6DSM_MASTER_CONFIG_MASTER_ON;
+
+            uint8_t rateIndex = ARRAY_SIZE(LSM6DSMSHRates) - 2;
+
+#ifdef LSM6DSM_I2C_MASTER_LSM303AGR
+            SPI_WRITE_SLAVE_SENSOR_REGISTER(LSM303AGR_CFG_REG_B_M_ADDR, LSM303AGR_OFFSET_CANCELLATION, SENSOR_HZ(104.0f), MAGN);
+            SPI_WRITE_SLAVE_SENSOR_REGISTER(LSM303AGR_CFG_REG_C_M_ADDR,
+                    LSM303AGR_CFG_REG_C_M_BASE | LSM303AGR_ENABLE_SELFTEST, SENSOR_HZ(104.0f), MAGN);
+
+            SPI_WRITE_SLAVE_SENSOR_REGISTER(LSM6DSM_SENSOR_SLAVE_MAGN_ODR_ADDR,
+                    LSM6DSM_SENSOR_SLAVE_MAGN_ODR_BASE | LSM6DSM_SENSOR_SLAVE_MAGN_POWER_ON_VALUE |
+                    LSM6DSM_SENSOR_SLAVE_MAGN_RATES_REG_VALUE(rateIndex), SENSOR_HZ(104.0f), MAGN, 200000);
+#else /* LSM6DSM_I2C_MASTER_LSM303AGR */
+            SPI_WRITE_SLAVE_SENSOR_REGISTER(LSM6DSM_SENSOR_SLAVE_MAGN_POWER_ADDR,
+                    LSM6DSM_SENSOR_SLAVE_MAGN_POWER_BASE | LSM6DSM_SENSOR_SLAVE_MAGN_POWER_ON_VALUE, SENSOR_HZ(104.0f), MAGN);
+            SPI_WRITE_SLAVE_SENSOR_REGISTER(LSM6DSM_SENSOR_SLAVE_MAGN_ODR_ADDR,
+                    LSM6DSM_SENSOR_SLAVE_MAGN_ODR_BASE | LSM6DSM_SENSOR_SLAVE_MAGN_RATES_REG_VALUE(rateIndex) | LIS3MDL_ENABLE_SELFTEST,
+                    SENSOR_HZ(104.0f), MAGN);
+#endif /* LSM6DSM_I2C_MASTER_LSM303AGR */
+            break;
+#endif /* LSM6DSM_I2C_MASTER_LSM303AGR, LSM6DSM_I2C_MASTER_LIS3MDL */
+        default:
+            return;
+        }
+
+        T(selftestState) = SELFTEST_READ_EST_DATA;
+        lsm6dsm_spiBatchTxRx(&T_SLAVE_INTERFACE(mode), lsm6dsm_spiCallback, &T(sensors[idx]), __FUNCTION__);
+        break;
+
+    case SELFTEST_READ_EST_DATA:
+#ifdef LSM6DSM_I2C_MASTER_LSM303AGR
+        if (idx == MAGN)
+            numberOfAverage = LSM6DSM_NUM_AVERAGE_SELFTEST_SLOW;
+#endif /* LSM6DSM_I2C_MASTER_LSM303AGR */
+
+        if (T(numSamplesSelftest) > 0) {
+            sensorData = &T_SLAVE_INTERFACE(tmpDataBuffer[1]);
+            T(dataSelftestEnabled[0]) += (int16_t)*((uint16_t *)&sensorData[0]);
+            T(dataSelftestEnabled[1]) += (int16_t)*((uint16_t *)&sensorData[2]);
+            T(dataSelftestEnabled[2]) += (int16_t)*((uint16_t *)&sensorData[4]);
+        }
+        T(numSamplesSelftest)++;
+
+        if (T(numSamplesSelftest) <= numberOfAverage) {
+            DEBUG_PRINT("runGapSelfTestProgram: reading output data while self-test is enabled\n");
+
+            switch (idx) {
+            case ACCEL:
+                SPI_READ(LSM6DSM_OUTX_L_XL_ADDR, LSM6DSM_ONE_SAMPLE_BYTE, &T_SLAVE_INTERFACE(tmpDataBuffer), 10000);
+                break;
+            case GYRO:
+                SPI_READ(LSM6DSM_OUTX_L_G_ADDR, LSM6DSM_ONE_SAMPLE_BYTE, &T_SLAVE_INTERFACE(tmpDataBuffer), 10000);
+                break;
+#if defined(LSM6DSM_I2C_MASTER_LSM303AGR) || defined(LSM6DSM_I2C_MASTER_LIS3MDL)
+            case MAGN:
+                SPI_READ(LSM6DSM_OUT_SENSORHUB1_ADDR, LSM6DSM_ONE_SAMPLE_BYTE, &T_SLAVE_INTERFACE(tmpDataBuffer), 20000);
+                break;
+#endif /* LSM6DSM_I2C_MASTER_LSM303AGR, LSM6DSM_I2C_MASTER_LIS3MDL */
+            default:
+                return;
+            }
+            lsm6dsm_spiBatchTxRx(&T_SLAVE_INTERFACE(mode), lsm6dsm_spiCallback, &T(sensors[idx]), __FUNCTION__);
+            break;
+        }
+
+        T(dataSelftestEnabled[0]) /= numberOfAverage;
+        T(dataSelftestEnabled[1]) /= numberOfAverage;
+        T(dataSelftestEnabled[2]) /= numberOfAverage;
+        T(selftestState) = SELFTEST_SECOND_STEP_INITIALIZATION;
+
+    case SELFTEST_SECOND_STEP_INITIALIZATION:
+        DEBUG_PRINT("runGapSelfTestProgram: second step initialization\n");
+
+        T(numSamplesSelftest) = 0;
+
+        /* Disable self-test */
+        switch (idx) {
+        case ACCEL:
+        case GYRO:
+            SPI_WRITE(LSM6DSM_CTRL5_C_ADDR, LSM6DSM_CTRL5_C_BASE, 30000);
+            break;
+#if defined(LSM6DSM_I2C_MASTER_LSM303AGR) || defined(LSM6DSM_I2C_MASTER_LIS3MDL)
+        case MAGN: ;
+#ifdef LSM6DSM_I2C_MASTER_LSM303AGR
+            SPI_WRITE_SLAVE_SENSOR_REGISTER(LSM303AGR_CFG_REG_C_M_ADDR, LSM303AGR_CFG_REG_C_M_BASE, SENSOR_HZ(104.0f), MAGN, 200000);
+#else /* LSM6DSM_I2C_MASTER_LSM303AGR */
+            uint8_t rateIndex = ARRAY_SIZE(LSM6DSMSHRates) - 2;
+
+            SPI_WRITE_SLAVE_SENSOR_REGISTER(LSM6DSM_SENSOR_SLAVE_MAGN_ODR_ADDR,
+                    LSM6DSM_SENSOR_SLAVE_MAGN_ODR_BASE | LSM6DSM_SENSOR_SLAVE_MAGN_RATES_REG_VALUE(rateIndex),
+                    SENSOR_HZ(104.0f), MAGN);
+#endif /* LSM6DSM_I2C_MASTER_LSM303AGR */
+            break;
+#endif /* LSM6DSM_I2C_MASTER_LSM303AGR, LSM6DSM_I2C_MASTER_LIS3MDL */
+        default:
+            return;
+        }
+
+        T(selftestState) = SELFTEST_READ_NST_DATA;
+        lsm6dsm_spiBatchTxRx(&T_SLAVE_INTERFACE(mode), lsm6dsm_spiCallback, &T(sensors[idx]), __FUNCTION__);
+        break;
+
+    case SELFTEST_READ_NST_DATA:
+#ifdef LSM6DSM_I2C_MASTER_LSM303AGR
+        if (idx == MAGN)
+            numberOfAverage = LSM6DSM_NUM_AVERAGE_SELFTEST_SLOW;
+#endif /* LSM6DSM_I2C_MASTER_LSM303AGR */
+
+        if (T(numSamplesSelftest) > 0) {
+            sensorData = &T_SLAVE_INTERFACE(tmpDataBuffer[1]);
+            T(dataSelftestNotEnabled[0]) += (int16_t)*((uint16_t *)&sensorData[0]);
+            T(dataSelftestNotEnabled[1]) += (int16_t)*((uint16_t *)&sensorData[2]);
+            T(dataSelftestNotEnabled[2]) += (int16_t)*((uint16_t *)&sensorData[4]);
+        }
+        T(numSamplesSelftest)++;
+
+        if (T(numSamplesSelftest) <= numberOfAverage) {
+            DEBUG_PRINT("runGapSelfTestProgram: reading output data while self-test is disabled\n");
+
+            switch (idx) {
+            case ACCEL:
+                SPI_READ(LSM6DSM_OUTX_L_XL_ADDR, LSM6DSM_ONE_SAMPLE_BYTE, &T_SLAVE_INTERFACE(tmpDataBuffer), 10000);
+                break;
+            case GYRO:
+                SPI_READ(LSM6DSM_OUTX_L_G_ADDR, LSM6DSM_ONE_SAMPLE_BYTE, &T_SLAVE_INTERFACE(tmpDataBuffer), 10000);
+                break;
+#if defined(LSM6DSM_I2C_MASTER_LSM303AGR) || defined(LSM6DSM_I2C_MASTER_LIS3MDL)
+            case MAGN:
+                SPI_READ(LSM6DSM_OUT_SENSORHUB1_ADDR, LSM6DSM_ONE_SAMPLE_BYTE, &T_SLAVE_INTERFACE(tmpDataBuffer), 20000);
+                break;
+#endif /* LSM6DSM_I2C_MASTER_LSM303AGR, LSM6DSM_I2C_MASTER_LIS3MDL */
+            default:
+                return;
+            }
+            lsm6dsm_spiBatchTxRx(&T_SLAVE_INTERFACE(mode), lsm6dsm_spiCallback, &T(sensors[idx]), __FUNCTION__);
+            break;
+        }
+
+        T(dataSelftestNotEnabled[0]) /= numberOfAverage;
+        T(dataSelftestNotEnabled[1]) /= numberOfAverage;
+        T(dataSelftestNotEnabled[2]) /= numberOfAverage;
+        T(selftestState) = SELFTEST_VERIFICATION;
+
+    case SELFTEST_VERIFICATION: ;
+        uint8_t i, sType;
+        int32_t dataGap[3];
+        bool testPassed = true;
+        int32_t lower_threshold[3], higher_threshold[3];
+
+        dataGap[0] = abs(T(dataSelftestEnabled[0]) - T(dataSelftestNotEnabled[0]));
+        dataGap[1] = abs(T(dataSelftestEnabled[1]) - T(dataSelftestNotEnabled[1]));
+        dataGap[2] = abs(T(dataSelftestEnabled[2]) - T(dataSelftestNotEnabled[2]));
+
+        switch (idx) {
+        case ACCEL:
+            sType = SENS_TYPE_ACCEL;
+            lower_threshold[0] = lower_threshold[1] = lower_threshold[2] = LSM6DSM_ACCEL_SELFTEST_LOW_THR_LSB;
+            higher_threshold[0] = higher_threshold[1] = higher_threshold[2] = LSM6DSM_ACCEL_SELFTEST_HIGH_THR_LSB;
+
+            /* Power off sensor */
+            SPI_WRITE(LSM6DSM_CTRL1_XL_ADDR, LSM6DSM_CTRL1_XL_BASE);
+            break;
+        case GYRO:
+            sType = SENS_TYPE_GYRO;
+            lower_threshold[0] = lower_threshold[1] = lower_threshold[2] = LSM6DSM_GYRO_SELFTEST_LOW_THR_LSB;
+            higher_threshold[0] = higher_threshold[1] = higher_threshold[2] = LSM6DSM_GYRO_SELFTEST_HIGH_THR_LSB;
+
+            /* Power off sensor */
+            SPI_WRITE(LSM6DSM_CTRL2_G_ADDR, LSM6DSM_CTRL2_G_BASE);
+            break;
+#if defined(LSM6DSM_I2C_MASTER_LSM303AGR) || defined(LSM6DSM_I2C_MASTER_LIS3MDL)
+        case MAGN:
+            sType = SENS_TYPE_MAG;
+
+#ifdef LSM6DSM_I2C_MASTER_LSM303AGR
+            lower_threshold[0] = lower_threshold[1] = lower_threshold[2] = LSM303AGR_SELFTEST_LOW_THR_LSB;
+            higher_threshold[0] = higher_threshold[1] = higher_threshold[2] = LSM303AGR_SELFTEST_HIGH_THR_LSB;
+
+            SPI_WRITE_SLAVE_SENSOR_REGISTER(LSM303AGR_CFG_REG_B_M_ADDR, 0x00, SENSOR_HZ(104.0f), MAGN);
+#else /* LSM6DSM_I2C_MASTER_LSM303AGR */
+            lower_threshold[0] = lower_threshold[1] = LIS3MDL_SELFTEST_LOW_THR_XY_LSB;
+            higher_threshold[0] = higher_threshold[1] = LIS3MDL_SELFTEST_HIGH_THR_XY_LSB;
+            lower_threshold[2] = LIS3MDL_SELFTEST_LOW_THR_Z_LSB;
+            higher_threshold[2] = LIS3MDL_SELFTEST_HIGH_THR_Z_LSB;
+#endif /* LSM6DSM_I2C_MASTER_LSM303AGR */
+
+            /* Power off sensor */
+            SPI_WRITE_SLAVE_SENSOR_REGISTER(LSM6DSM_SENSOR_SLAVE_MAGN_POWER_ADDR,
+                    LSM6DSM_SENSOR_SLAVE_MAGN_POWER_BASE | LSM6DSM_SENSOR_SLAVE_MAGN_POWER_OFF_VALUE, SENSOR_HZ(104.0f), MAGN);
+
+            /* Disable accelerometer and sensor-hub */
+            SPI_WRITE(LSM6DSM_MASTER_CONFIG_ADDR, LSM6DSM_MASTER_CONFIG_BASE);
+            SPI_WRITE(LSM6DSM_CTRL1_XL_ADDR, LSM6DSM_CTRL1_XL_BASE);
+            T(masterConfigRegister) &= ~LSM6DSM_MASTER_CONFIG_MASTER_ON;
+            break;
+#endif /* LSM6DSM_I2C_MASTER_LSM303AGR, LSM6DSM_I2C_MASTER_LIS3MDL */
+        default:
+            return;
+        }
+
+        for (i = 0; i < 3; i++) {
+            if ((dataGap[i] < lower_threshold[i]) || (dataGap[i] > higher_threshold[i])) {
+                testPassed = false;
+                ERROR_PRINT("runGapSelfTestProgram: axis-%d out of spec! test-enabled: %ldLSB ** test-disabled: %ldLSB, ** delta: %ldLSB\n",
+                            i, T(dataSelftestEnabled[i]), T(dataSelftestNotEnabled[i]), dataGap[i]);
+            }
+        }
+        INFO_PRINT("runGapSelfTestProgram: completed. Test result: %s\n", testPassed ? "pass" : "fail");
+
+        if (testPassed)
+            lsm6dsm_sendSelfTestResult(sType, SENSOR_APP_EVT_STATUS_SUCCESS);
+        else
+            lsm6dsm_sendSelfTestResult(sType, SENSOR_APP_EVT_STATUS_ERROR);
+
+        T(selftestState) = SELFTEST_COMPLETED;
+        lsm6dsm_spiBatchTxRx(&T_SLAVE_INTERFACE(mode), lsm6dsm_spiCallback, &T(sensors[idx]), __FUNCTION__);
+        break;
+
+    default:
+        break;
+    }
+}
+
+#ifdef LSM6DSM_I2C_MASTER_AK09916
+/*
+ * lsm6dsm_runAbsoluteSelfTestProgram: state machine that is executing self-test verifying absolute value
+ */
+static void lsm6dsm_runAbsoluteSelfTestProgram()
+{
+    TDECL();
+    uint8_t *sensorData;
+
+    switch (T(selftestState)) {
+    case SELFTEST_INITIALIZATION: ;
+        DEBUG_PRINT("runAbsoluteSelfTestProgram: initialization\n");
+
+        T(numSamplesSelftest) = 0;
+        memset(T(dataSelftestEnabled), 0, 3 * sizeof(int32_t));
+
+        /* Enable accelerometer and sensor-hub */
+        SPI_WRITE(LSM6DSM_CTRL1_XL_ADDR, LSM6DSM_CTRL1_XL_BASE | LSM6DSM_ODR_104HZ_REG_VALUE);
+        SPI_WRITE(LSM6DSM_MASTER_CONFIG_ADDR, LSM6DSM_MASTER_CONFIG_BASE | LSM6DSM_MASTER_CONFIG_MASTER_ON, 20000);
+        T(masterConfigRegister) |= LSM6DSM_MASTER_CONFIG_MASTER_ON;
+
+        SPI_WRITE_SLAVE_SENSOR_REGISTER(AK09916_CNTL2_ADDR, AK09916_ENABLE_SELFTEST_MODE, SENSOR_HZ(104.0f), MAGN, 20000);
+
+        T(selftestState) = SELFTEST_READ_EST_DATA;
+        lsm6dsm_spiBatchTxRx(&T_SLAVE_INTERFACE(mode), lsm6dsm_spiCallback, &T(sensors[MAGN]), __FUNCTION__);
+        break;
+
+    case SELFTEST_READ_EST_DATA:
+        if (T(numSamplesSelftest) > 0) {
+            sensorData = &T_SLAVE_INTERFACE(tmpDataBuffer[1]);
+            T(dataSelftestEnabled[0]) += (int16_t)*((uint16_t *)&sensorData[0]);
+            T(dataSelftestEnabled[1]) += (int16_t)*((uint16_t *)&sensorData[2]);
+            T(dataSelftestEnabled[2]) += (int16_t)*((uint16_t *)&sensorData[4]);
+        }
+        T(numSamplesSelftest)++;
+
+        if (T(numSamplesSelftest) <= LSM6DSM_NUM_AVERAGE_SELFTEST) {
+            DEBUG_PRINT("runAbsoluteSelfTestProgram: reading output data while self-test is enabled\n");
+
+            SPI_READ(LSM6DSM_OUT_SENSORHUB1_ADDR, LSM6DSM_ONE_SAMPLE_BYTE, &T_SLAVE_INTERFACE(tmpDataBuffer), 20000);
+            lsm6dsm_spiBatchTxRx(&T_SLAVE_INTERFACE(mode), lsm6dsm_spiCallback, &T(sensors[MAGN]), __FUNCTION__);
+            break;
+        }
+
+        T(dataSelftestEnabled[0]) /= LSM6DSM_NUM_AVERAGE_SELFTEST;
+        T(dataSelftestEnabled[1]) /= LSM6DSM_NUM_AVERAGE_SELFTEST;
+        T(dataSelftestEnabled[2]) /= LSM6DSM_NUM_AVERAGE_SELFTEST;
+        T(selftestState) = SELFTEST_VERIFICATION;
+
+    case SELFTEST_VERIFICATION: ;
+        bool testPassed = true;
+
+        if ((T(dataSelftestEnabled[0]) < AK09916_SELFTEST_LOW_THR_XY_LSB) ||
+                (T(dataSelftestEnabled[0]) > AK09916_SELFTEST_HIGH_THR_XYZ_LSB)) {
+            testPassed = false;
+            ERROR_PRINT("runAbsoluteSelfTestProgram: axis-0 out of spec! Read: %ldLSB\n", T(dataSelftestEnabled[0]));
+        }
+        if ((T(dataSelftestEnabled[1]) < AK09916_SELFTEST_LOW_THR_XY_LSB) ||
+                (T(dataSelftestEnabled[1]) > AK09916_SELFTEST_HIGH_THR_XYZ_LSB)) {
+            testPassed = false;
+            ERROR_PRINT("runAbsoluteSelfTestProgram: axis-1 out of spec! Read: %ldLSB\n", T(dataSelftestEnabled[1]));
+        }
+        if ((T(dataSelftestEnabled[2]) < AK09916_SELFTEST_LOW_THR_Z_LSB) ||
+                (T(dataSelftestEnabled[2]) > AK09916_SELFTEST_HIGH_THR_XYZ_LSB)) {
+            testPassed = false;
+            ERROR_PRINT("runAbsoluteSelfTestProgram: axis-2 out of spec! Read: %ldLSB\n", T(dataSelftestEnabled[2]));
+        }
+
+        INFO_PRINT("runAbsoluteSelfTestProgram: completed. Test result: %s\n", testPassed ? "pass" : "fail");
+
+        if (testPassed)
+            lsm6dsm_sendSelfTestResult(SENS_TYPE_MAG, SENSOR_APP_EVT_STATUS_SUCCESS);
+        else
+            lsm6dsm_sendSelfTestResult(SENS_TYPE_MAG, SENSOR_APP_EVT_STATUS_ERROR);
+
+        /* Disable accelerometer and sensor-hub */
+        SPI_WRITE(LSM6DSM_MASTER_CONFIG_ADDR, LSM6DSM_MASTER_CONFIG_BASE);
+        SPI_WRITE(LSM6DSM_CTRL1_XL_ADDR, LSM6DSM_CTRL1_XL_BASE);
+        T(masterConfigRegister) &= ~LSM6DSM_MASTER_CONFIG_MASTER_ON;
+
+        T(selftestState) = SELFTEST_COMPLETED;
+        lsm6dsm_spiBatchTxRx(&T_SLAVE_INTERFACE(mode), lsm6dsm_spiCallback, &T(sensors[MAGN]), __FUNCTION__);
+        break;
+
+    default:
+        break;
+    }
+}
+#endif /* LSM6DSM_I2C_MASTER_AK09916 */
+
+/*
  * lsm6dsm_writeEmbeddedRegister: write embedded register
  * @addr: address of register to be written.
  * @value: value to write.
@@ -2517,18 +2940,18 @@
         T(sensors[MAGN]).samplesDecimator = ((T(fifoCntl).triggerRate / T(fifoCntl).decimators[FIFO_DS3]) / T(sensors[MAGN]).samplesFifoDecimator) / T(sensors[MAGN]).rate[MAGN];
         T(sensors[MAGN]).samplesDecimatorCounter = T(sensors[MAGN]).samplesDecimator - 1;
 
-#ifdef LSM6DSM_I2C_MASTER_LSM303AGR
-        SPI_WRITE_SLAVE_SENSOR_REGISTER(LSM6DSM_SENSOR_SLAVE_MAGN_ODR_ADDR,
-                LSM6DSM_SENSOR_SLAVE_MAGN_ODR_BASE | LSM6DSM_SENSOR_SLAVE_MAGN_POWER_ON_VALUE | LSM6DSM_SENSOR_SLAVE_MAGN_RATES_REG_VALUE(i),
-                T(sensors[ACCEL]).hwRate, MAGN);
-#else /* LSM6DSM_I2C_MASTER_LSM303AGR */
+#ifdef LSM6DSM_I2C_MASTER_LIS3MDL
         SPI_WRITE_SLAVE_SENSOR_REGISTER(LSM6DSM_SENSOR_SLAVE_MAGN_POWER_ADDR,
                 LSM6DSM_SENSOR_SLAVE_MAGN_POWER_BASE | LSM6DSM_SENSOR_SLAVE_MAGN_POWER_ON_VALUE,
                 T(sensors[ACCEL]).hwRate, MAGN);
         SPI_WRITE_SLAVE_SENSOR_REGISTER(LSM6DSM_SENSOR_SLAVE_MAGN_ODR_ADDR,
                 LSM6DSM_SENSOR_SLAVE_MAGN_ODR_BASE | LSM6DSM_SENSOR_SLAVE_MAGN_RATES_REG_VALUE(i),
                 T(sensors[ACCEL]).hwRate, MAGN);
-#endif /* LSM6DSM_I2C_MASTER_LSM303AGR */
+#else /* LSM6DSM_I2C_MASTER_LIS3MDL */
+        SPI_WRITE_SLAVE_SENSOR_REGISTER(LSM6DSM_SENSOR_SLAVE_MAGN_ODR_ADDR,
+                LSM6DSM_SENSOR_SLAVE_MAGN_ODR_BASE | LSM6DSM_SENSOR_SLAVE_MAGN_POWER_ON_VALUE | LSM6DSM_SENSOR_SLAVE_MAGN_RATES_REG_VALUE(i),
+                T(sensors[ACCEL]).hwRate, MAGN);
+#endif /* LSM6DSM_I2C_MASTER_LIS3MDL */
 
         lsm6dsm_spiBatchTxRx(&T_SLAVE_INTERFACE(mode), lsm6dsm_spiCallback, &T(sensors[MAGN]), __FUNCTION__);
     } else {
@@ -2968,12 +3391,90 @@
 }
 
 /*
+ * lsm6dsm_runAccelSelfTest: execute accelerometer self-test
+ * @cookie: private data.
+ */
+static bool lsm6dsm_runAccelSelfTest(void *cookie)
+{
+    TDECL();
+
+    if (trySwitchState(SENSOR_SELFTEST)) {
+        if (!T(sensors[ACCEL]).enabled && (T(sensors[ACCEL]).hwRate == 0) && (T(sensors[GYRO]).hwRate == 0)) {
+            INFO_PRINT("runAccelSelfTest: executing accelerometer selftest\n");
+            T(selftestState) = SELFTEST_INITIALIZATION;
+            lsm6dsm_runGapSelfTestProgram(ACCEL);
+            return true;
+        } else
+            SET_STATE(SENSOR_IDLE);
+    }
+
+    ERROR_PRINT("runAccelSelfTest: cannot run selftest because sensor is busy!\n");
+    lsm6dsm_sendSelfTestResult(SENS_TYPE_ACCEL, SENSOR_APP_EVT_STATUS_BUSY);
+
+    return false;
+}
+
+/*
+ * lsm6dsm_runGyroSelfTest: execute gyroscope self-test
+ * @cookie: private data.
+ */
+static bool lsm6dsm_runGyroSelfTest(void *cookie)
+{
+    TDECL();
+
+    if (trySwitchState(SENSOR_SELFTEST)) {
+        if (!T(sensors[GYRO]).enabled && (T(sensors[GYRO]).hwRate == 0) && (T(sensors[ACCEL]).hwRate == 0)) {
+            INFO_PRINT("runGyroSelfTest: executing gyroscope selftest\n");
+            T(selftestState) = SELFTEST_INITIALIZATION;
+            lsm6dsm_runGapSelfTestProgram(GYRO);
+            return true;
+        } else
+            SET_STATE(SENSOR_IDLE);
+    }
+
+    ERROR_PRINT("runGyroSelfTest: cannot run selftest because sensor is busy!\n");
+    lsm6dsm_sendSelfTestResult(SENS_TYPE_GYRO, SENSOR_APP_EVT_STATUS_BUSY);
+
+    return false;
+}
+
+#ifdef LSM6DSM_I2C_MASTER_MAGNETOMETER_ENABLED
+/*
+ * lsm6dsm_runMagnSelfTest: execute magnetometer self-test
+ * @cookie: private data.
+ */
+static bool lsm6dsm_runMagnSelfTest(void *cookie)
+{
+    TDECL();
+
+    if (trySwitchState(SENSOR_SELFTEST)) {
+        if (!T(sensors[MAGN]).enabled && (T(sensors[MAGN]).hwRate == 0) && (T(sensors[GYRO]).hwRate == 0) && (T(sensors[ACCEL]).hwRate == 0)) {
+            INFO_PRINT("runMagnSelfTest: executing magnetometer selftest\n");
+            T(selftestState) = SELFTEST_INITIALIZATION;
+#ifdef LSM6DSM_I2C_MASTER_AK09916
+            lsm6dsm_runAbsoluteSelfTestProgram();
+#else
+            lsm6dsm_runGapSelfTestProgram(MAGN);
+#endif
+            return true;
+        } else
+            SET_STATE(SENSOR_IDLE);
+    }
+
+    ERROR_PRINT("runMagnSelfTest: cannot run selftest because sensor is busy!\n");
+    lsm6dsm_sendSelfTestResult(SENS_TYPE_MAG, SENSOR_APP_EVT_STATUS_BUSY);
+
+    return false;
+}
+#endif /* LSM6DSM_I2C_MASTER_MAGNETOMETER_ENABLED */
+
+/*
  * lsm6dsm_sensorInit: initial sensors configuration
  */
 static void lsm6dsm_sensorInit(void)
 {
     TDECL();
-    uint8_t buffer[4];
+    uint8_t buffer[5];
 
     switch (T(initState)) {
     case RESET_LSM6DSM:
@@ -2998,7 +3499,8 @@
         buffer[1] = LSM6DSM_CTRL2_G_BASE;                            /* LSM6DSM_CTRL2_G */
         buffer[2] = LSM6DSM_CTRL3_C_BASE;                            /* LSM6DSM_CTRL3_C */
         buffer[3] = LSM6DSM_CTRL4_C_BASE;                            /* LSM6DSM_CTRL4_C */
-        SPI_MULTIWRITE(LSM6DSM_CTRL1_XL_ADDR, buffer, 4);
+        buffer[4] = LSM6DSM_CTRL5_C_BASE;                            /* LSM6DSM_CTRL4_C */
+        SPI_MULTIWRITE(LSM6DSM_CTRL1_XL_ADDR, buffer, 5);
 
         buffer[0] = LSM6DSM_CTRL10_C_BASE | LSM6DSM_RESET_PEDOMETER; /* LSM6DSM_CTRL10_C */
         buffer[1] = LSM6DSM_MASTER_CONFIG_BASE;                      /* LSM6DSM_MASTER_CONFIG */
@@ -3749,6 +4251,25 @@
         returnIdle = true;
         break;
 
+    case SENSOR_SELFTEST:
+        mSensor = (struct LSM6DSMSensor *)evtData;
+
+        if (T(selftestState == SELFTEST_COMPLETED)) {
+            returnIdle = true;
+        } else {
+#ifdef LSM6DSM_I2C_MASTER_AK09916
+            if (mSensor->idx == MAGN) {
+                lsm6dsm_runAbsoluteSelfTestProgram();
+            } else {
+                lsm6dsm_runGapSelfTestProgram(mSensor->idx);
+            }
+#else /* LSM6DSM_I2C_MASTER_AK09916 */
+            lsm6dsm_runGapSelfTestProgram(mSensor->idx);
+#endif /* LSM6DSM_I2C_MASTER_AK09916 */
+        }
+
+        break;
+
     case SENSOR_INT1_STATUS_REG_HANDLING:
         if (T(sensors[STEP_DETECTOR].enabled) && (T_SLAVE_INTERFACE(funcSrcBuffer[1]) & LSM6DSM_FUNC_SRC_STEP_DETECTED)) {
             osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_STEP_DETECT), NULL, NULL);
diff --git a/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm_ak09916_slave.h b/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm_ak09916_slave.h
index 9574d07..125a780 100644
--- a/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm_ak09916_slave.h
+++ b/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm_ak09916_slave.h
@@ -41,6 +41,12 @@
 #define AK09916_POWER_ON_VALUE                          (0x02)
 #define AK09916_POWER_OFF_VALUE                         (0x00)
 #define AK09916_OUTDATA_LEN                             (0x06)
+#define AK09916_ENABLE_SELFTEST_MODE                    (0x10)
+
+/* Selftest related */
+#define AK09916_SELFTEST_HIGH_THR_XYZ_LSB               200
+#define AK09916_SELFTEST_LOW_THR_XY_LSB                 -200
+#define AK09916_SELFTEST_LOW_THR_Z_LSB                  -1000
 
 
 /* AK09916 default base registers status */
diff --git a/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm_lis3mdl_slave.h b/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm_lis3mdl_slave.h
index e44a506..2832a38 100644
--- a/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm_lis3mdl_slave.h
+++ b/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm_lis3mdl_slave.h
@@ -47,6 +47,13 @@
 #define LIS3MDL_POWER_ON_VALUE                          (0x00)
 #define LIS3MDL_POWER_OFF_VALUE                         (0x03)
 #define LIS3MDL_OUTDATA_LEN                             (0x06)
+#define LIS3MDL_ENABLE_SELFTEST                         (0x01)
+
+/* Selftest related */
+#define LIS3MDL_SELFTEST_HIGH_THR_XY_LSB                6843
+#define LIS3MDL_SELFTEST_HIGH_THR_Z_LSB                 2281
+#define LIS3MDL_SELFTEST_LOW_THR_XY_LSB                 2281
+#define LIS3MDL_SELFTEST_LOW_THR_Z_LSB                  228
 
 
 /* LIS3MDL default base registers status */
diff --git a/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm_lsm303agr_slave.h b/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm_lsm303agr_slave.h
index 5cf144e..f0a3e44 100644
--- a/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm_lsm303agr_slave.h
+++ b/firmware/os/drivers/st_lsm6dsm/st_lsm6dsm_lsm303agr_slave.h
@@ -33,6 +33,7 @@
 /* LSM303AGR registers */
 #define LSM303AGR_WAI_ADDR                              (0x4f)
 #define LSM303AGR_CFG_REG_A_M_ADDR                      (0x60)
+#define LSM303AGR_CFG_REG_B_M_ADDR                      (0x61)
 #define LSM303AGR_CFG_REG_C_M_ADDR                      (0x62)
 #define LSM303AGR_OUTDATA_ADDR                          (0x68)
 
@@ -40,12 +41,18 @@
 #define LSM303AGR_POWER_ON_VALUE                        (0x00)
 #define LSM303AGR_POWER_OFF_VALUE                       (0x03)
 #define LSM303AGR_OUTDATA_LEN                           (0x06)
+#define LSM303AGR_OFFSET_CANCELLATION                   (0x02)
+#define LSM303AGR_ENABLE_SELFTEST                       (0x02)
+
+/* Selftest related */
+#define LSM303AGR_SELFTEST_HIGH_THR_LSB                 333
+#define LSM303AGR_SELFTEST_LOW_THR_LSB                  10
 
 
 /* LSM303AGR default base registers status */
 /* LSM303AGR_CFG_REG_A_M_BASE: configuration register 1 default settings */
-#define LSM303AGR_CFG_REG_A_M_BASE                     ((0 << 7) |   /* (0) */ \
-                                                        (0 << 6) |    /* (0) */ \
+#define LSM303AGR_CFG_REG_A_M_BASE                     ((1 << 7) |    /* COMP_TEMP_EN */ \
+                                                        (0 << 6) |    /* REBOOT */ \
                                                         (0 << 5) |    /* SOFT_RST */ \
                                                         (0 << 4) |    /* LP */ \
                                                         (0 << 3) |    /* ODR1 */ \
@@ -54,7 +61,7 @@
                                                         (0 << 0))     /* MD0 */
 
 /* LSM303AGR_CFC_REG_C_M_BASE: configuration register 3 default settings */
-#define LSM303AGR_CFG_REG_C_M_BASE                     ((0 << 7) |   /* (0) */ \
+#define LSM303AGR_CFG_REG_C_M_BASE                     ((0 << 7) |    /* (0) */ \
                                                         (0 << 6) |    /* INT_MAG_PIN */ \
                                                         (0 << 5) |    /* I2C_DIS */ \
                                                         (1 << 4) |    /* BDU */ \