diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 4607c76281..46584327a5 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -451,6 +451,17 @@ ifneq (,$(filter pulse_counter,$(USEMODULE))) FEATURES_REQUIRED += periph_gpio_irq endif +ifneq (,$(filter qmc5883l_int,$(USEMODULE))) + USEMODULE += qmc5883l +endif + +ifneq (,$(filter qmc5883l,$(USEMODULE))) + FEATURES_REQUIRED += periph_i2c + ifneq (,$(filter qmc5883l_int,$(USEMODULE))) + FEATURES_REQUIRED += periph_gpio_irq + endif +endif + ifneq (,$(filter rgbled,$(USEMODULE))) USEMODULE += color endif diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 3b8ea0fe1d..e6b5037cf3 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -238,6 +238,10 @@ ifneq (,$(filter pulse_counter,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/pulse_counter/include endif +ifneq (,$(filter qmc5883l,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/qmc5883l/include +endif + ifneq (,$(filter rn2xx3,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/rn2xx3/include endif diff --git a/drivers/include/qmc5883l.h b/drivers/include/qmc5883l.h new file mode 100644 index 0000000000..58435805fa --- /dev/null +++ b/drivers/include/qmc5883l.h @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2019 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup drivers_qmc5883l QMC5883L 3-Axis Digital Magnetic Sensor + * @ingroup drivers_sensors + * @ingroup drivers_saul + * @brief Driver for QST QMC5883L digital magnetic sensor + * + * # About + * This module provides a device driver for the QML5883L magnetic sensor + * (digital compass) by QST. This device is a successor and similar to the + * Honeywell HMC5883L, it does use a different register map and uses a different + * style of configuration. + * + * # Usage + * Use the qmc5883l_init() function to initialize your sensor. On exit of the + * initialization function, the sensor is put into continuous sampling mode + * (power on) mode. + * + * For reading the sampled data, you have two options: use polling or use + * interrupt based notifications. + * + * ## Polling + * You call periodically call qmc5883l_read[_raw]() directly and simply check + * the return value to be QMC5883L_OK or QMC5883L_OVERFLOW for valid data. + * Alternatively call qmc5883l_data_ready() to explicitly ask the sensor if new + * data is available. + * + * ## Interrupt based + * For the interrupt mode to be available, you have to build the driver with the + * associated functions using `USEMODULE += qmc5883l_int`. + * + * To configure and enable interrupt notifications for data ready events use the + * qmc5883l_init_int() function. This will setup the configured interrupt pin + * (params->pin_drdy) and enable the DRDY pin output for the QMC5883L sensor. + * + * @warning The DRDY interrupt callback is executed in interrupt context, so + * **do not** call any driver API function directly inside the + * callback! Instead use some IPC to notify a thread. + * + * @{ + * + * @file + * @brief API definition for the QMC5883L device driver + * + * @author Hauke Petersen + */ + +#ifndef QMC5883L_H +#define QMC5883L_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#include "periph/gpio.h" +#include "periph/i2c.h" + +/** + * @brief Static QMC5883L I2C address (can not be changed) + */ +#define QMC5883L_ADDR (0x0d) + +/** + * @brief Error codes used by the QMC5883L driver + */ +enum { + QMC5883L_OK, /**< success */ + QMC5883L_NODATA, /**< no data are available */ + QMC5883L_OVERFLOW, /**< at least one axis overflowed its range */ + QMC5883L_BUSERR, /**< i2c bus error */ + QMC5883L_NOCFG, /**< configuration error */ +}; + +/** + * @brief Output data rate + * + * "Output data rate is controlled by ODR registers. Four data update + * frequencies can be selected: 10Hz, 50Hz, 100Hz and 200Hz. For most of + * compassing applications, we recommend 10 Hz for low power consumption. For + * gaming, the high update rate such as 100Hz or 200Hz can be used." + * (datasheet V1.0, p.17) + */ +typedef enum { + QMC5883L_ODR_10HZ = (0u << 2), /**< 10Hz data output rate */ + QMC5883L_ODR_50HZ = (1u << 2), /**< 50Hz data output rate */ + QMC5883L_ODR_100HZ = (2u << 2), /**< 100Hz data output rate */ + QMC5883L_ODR_200HZ = (3u << 2), /**< 200Hz data output rate */ +} qmc5883l_odr_t; + +/** + * @brief Output value range + * + * "Field ranges of the magnetic sensor can be selected through the register + * RNG. The full scale field range is determined by the application + * environments. For magnetic clear environment, low field range such as + * +/- 2gauss can be used. The field range goes hand in hand with the + * sensitivity of the magnetic sensor. The lowest field range has the highest + * sensitivity, therefore, higher resolution." (datasheet V1.0, p.17) + */ +typedef enum { + QMC5883L_RNG_2G = (0u << 4), /**< 2 Gauss data output range */ + QMC5883L_RNG_8G = (1u << 4), /**< 8 Gauss data output range */ +} qmc5883l_rng_t; + +/** + * @brief Over sample rate (bandwidth of internal digital filter) + * + * "Over sample Rate (OSR) registers are used to control bandwidth of an + * internal digital filter. Larger OSR value leads to smaller filter bandwidth, + * less in-band noise and higher power consumption. It could be used to reach a + * good balance between noise and power. Four over sample ratio can be + * selected, 64, 128, 256 or 512." (datasheet V1.0, p.17) + */ +typedef enum { + QMC5883L_OSR_512 = (0u << 6), /**< 512 samples per reading */ + QMC5883L_OSR_256 = (1u << 6), /**< 256 samples per reading */ + QMC5883L_OSR_128 = (2u << 6), /**< 128 samples per reading */ + QMC5883L_OSR_64 = (3u << 6), /**< 64 samples per reading */ +} qmc5883l_osr_t; + +/** + * @brief QMC5883L initialization parameters + */ +typedef struct { + i2c_t i2c; /**< I2C bus the sensor is connected to */ + gpio_t pin_drdy; /**< DRDY ISR pin, set to GPIO_UNDEF if unused */ + qmc5883l_odr_t odr; /**< output data rate */ + qmc5883l_rng_t rng; /**< output data range */ + qmc5883l_osr_t osr; /**< oversampling rate */ +} qmc5883l_params_t; + +/** + * @brief QMC5883L device descriptor + */ +typedef struct { + i2c_t i2c; /**< I2C bus the sensor is connected to */ + gpio_t pin_drdy; /**< DRDY interrupt pin */ + uint8_t cfg; /**< actual applied device configuration */ +} qmc5883l_t; + +/** + * @brief Initialize the given QMC5883L magnetic sensor + * + * @pre dev != NULL + * @pre params != NULL + * + * @param[out] dev QMC5883L device descriptor + * @param[in] params configuration parameters + * + * @return QMC5883L_OK on success + * @return QMC5883L_NOCFG on configuration error + * @return QMC5883L_BUSERR on any I2C bus error + */ +int qmc5883l_init(qmc5883l_t *dev, const qmc5883l_params_t *params); + +/** + * @brief Check if new data is available + * + * @pre dev != NULL + * + * @param[in] dev QMC5883L device descriptor + * + * @return QMC5883L_OK if new data is available + * @return QMC5883L_NODATA if no new data is available + * @return QMC5883L_BUSERR on any I2C bus error + */ +int qmc5883l_data_ready(const qmc5883l_t *dev); + +/** + * @brief Read sampled data from the device [converted to milli-Gauss] + * + * @pre dev != NULL + * @pre data_out != NULL + * + * @param[in] dev QMC5883L device descriptor + * @param[out] data_out buffer for holding the resulting vector, **must** be + able to hold 3 data items (x, y, z) + * + * @return QMC5883L_OK on data being written to @p data_out + * @return QMC5883L_OVERFLOW on data successfully read, but at least one data + item overflowed its data range + * @return QMC5883L_NODATA if no new data is available, nothing is written to + @p data_out + * @return QMC5883L_BUSERR on any I2C bus error + */ +int qmc5883l_read(const qmc5883l_t *dev, int16_t *data_out); + +/** + * @brief Read RAW data from the device + * + * This function returns the configured data range of 2 or 8 Gauss mapped to + * 16-bit signed integers [--32768:32767]. + * + * @pre dev != NULL + * @pre data_out != NULL + * + * @param[in] dev QMC5883L device descriptor + * @param[out] data_out buffer for holding the resulting vector, **must** be + able to hold 3 data items (x, y, z) + * + * @return QMC5883L_OK on data being written to @p data_out + * @return QMC5883L_OVERFLOW on data successfully read, but at least one data + item overflowed its data range + * @return QMC5883L_NODATA if no new data is available, nothing is written to + @p data_out + * @return QMC5883L_BUSERR on any I2C bus error + */ +int qmc5883l_read_raw(const qmc5883l_t *dev, int16_t *data_out); + +/** + * @brief Power on the sensor (put it into continuous sampling mode) + * + * @pre dev != NULL + * + * @param[in] dev QMC5883L device descriptor + * + * @return QMC5883L_OK on success + * @return QMC5883L_BUSERR on any I2C bus error + */ +int qmc5883l_poweron(const qmc5883l_t *dev); + +/** + * @brief Power off the sensor (put it into standby mode) + * + * @pre dev != NULL + * + * @param[in] dev QMC5883L device descriptor + * + * @return QMC5883L_OK on success + * @return QMC5883L_BUSERR on any I2C bus error + */ +int qmc5883l_poweroff(const qmc5883l_t *dev); + +#if defined(MODULE_QMC5883L_INT) || defined(DOXYGEN) +/** + * @brief Initialize data ready (DRDY) interrupt notifications + * + * After this function is called the DRDY interrupt is enabled, so there is no + * need to call qmc5883l_irq_enable() afterwards. + */ + +/** + * @brief Configure and enable the data ready (DRDY) interrupt + * + * This function sets up the configured GPIO pin to trigger the given callback + * for rising edges and it enables the interrupt signal generation for the + * given QMC5883L sensor. + * + * @warning The given callback function is executed in interrupt context. Make + sure not to call any driver API function in that context! + * + * @pre dev != NULL + * @pre cb != NULL + * + * @param[in] dev QMC583L device descriptor + * @param[in] cb callback function triggered on DRDY events + * @param[in] arg optional user argument passed to @p cb + * + * @return QMC5883L_OK on success + * @return QMC5883L_NOCFG on GPIO configuration errors + * @return QMC5883L_BUSERR on any I2C bus error + */ +int qmc5883l_init_int(const qmc5883l_t *dev, gpio_cb_t cb, void *arg); + +/** + * @brief Enable the data ready (DRDY) interrupt + * + * @note Call this function only after you have configured the DRDY interrupt + * + * @pre dev != NULL + * + * @param[in] dev QMC5883L device descriptor + * + * @return QMC5883L_OK on success + * @return QMC5883L_BUSERR on any I2C bus error + */ +int qmc5883l_irq_enable(const qmc5883l_t *dev); + +/** + * @brief Disable the data ready (DRDY) interrupt + * + * @pre dev != NULL + * + * @param[in] dev QMC5883L device descriptor + * + * @return QMC5883L_OK on success + * @return QMC5883L_BUSERR on any I2C bus error + */ +int qmc5883l_irq_disable(const qmc5883l_t *dev); +#endif /* defined(MODULE_QMC5883L_INT) || defined(DOXYGEN) */ + +#ifdef __cplusplus +} +#endif + +#endif /* QMC5883L_H */ +/** @} */ diff --git a/drivers/qmc5883l/Makefile b/drivers/qmc5883l/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/qmc5883l/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/qmc5883l/include/qmc5883l_params.h b/drivers/qmc5883l/include/qmc5883l_params.h new file mode 100644 index 0000000000..8b84681191 --- /dev/null +++ b/drivers/qmc5883l/include/qmc5883l_params.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2019 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_qmc5883l + * + * @{ + * @file + * @brief Default configuration for QMC5883L devices + * + * @author Hauke Petersen + */ + +#ifndef QMC5883L_PARAMS_H +#define QMC5883L_PARAMS_H + +#include "saul_reg.h" +#include "board.h" +#include "qmc5883l.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Set default configuration parameters for QMC5883L devices + * @{ + */ +#ifndef QMC5883L_PARAM_I2C +#define QMC5883L_PARAM_I2C I2C_DEV(0) +#endif +#ifndef QMC5883L_PARAM_PIN_DRDY +#define QMC5883L_PARAM_PIN_DRDY (GPIO_UNDEF) +#endif +#ifndef QMC5883L_PARAM_ODR +#define QMC5883L_PARAM_ODR (QMC5883L_ODR_10HZ) +#endif +#ifndef QMC5883L_PARAM_RNG +#define QMC5883L_PARAM_RNG (QMC5883L_RNG_2G) +#endif +#ifndef QMC5883L_PARAM_OSR +#define QMC5883L_PARAM_OSR (QMC5883L_OSR_64) +#endif + +#ifndef QMC5883L_PARAMS +#define QMC5883L_PARAMS { .i2c = QMC5883L_PARAM_I2C, \ + .pin_drdy = QMC5883L_PARAM_PIN_DRDY, \ + .odr = QMC5883L_PARAM_ODR, \ + .rng = QMC5883L_PARAM_RNG, \ + .osr = QMC5883L_PARAM_OSR } +#endif + +#ifndef QMC5883L_SAUL_INFO +#define QMC5883L_SAUL_INFO { .name = "qmc5883l" } +#endif +/**@}*/ + +/** + * @brief QMC5883L configuration + */ +static const qmc5883l_params_t qmc5883l_params[] = +{ + QMC5883L_PARAMS +}; + +/** + * @brief Additional meta information to keep in the SAUL registry + */ +static const saul_reg_info_t qmc5883l_saul_info[] = +{ + QMC5883L_SAUL_INFO +}; + +#ifdef __cplusplus +} +#endif + +#endif /* QMC5883L_PARAMS_H */ +/** @} */ diff --git a/drivers/qmc5883l/qmc5883l.c b/drivers/qmc5883l/qmc5883l.c new file mode 100644 index 0000000000..ecb4f1a45f --- /dev/null +++ b/drivers/qmc5883l/qmc5883l.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2019 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup drivers_qmc5883l + * @{ + * + * @file + * @brief Implementation of the QMC5883L device driver + * + * @author Hauke Petersen + * + * @} + */ + +#include + +#include "assert.h" +#include "periph/gpio.h" +#include "qmc5883l.h" +#include "qmc5883l_internal.h" + +/* shortcut to the i2c device address */ +#define ADDR QMC5883L_ADDR + +static int _reg_read(const qmc5883l_t *dev, uint8_t reg, + uint8_t *val, int acquire, int release) +{ + if (acquire) { + if (i2c_acquire(dev->i2c) != 0) { + return QMC5883L_BUSERR; + } + } + int res = i2c_read_reg(dev->i2c, ADDR, reg, val, 0); + if ((release) || (res != 0)) { + i2c_release(dev->i2c); + } + return (res == 0) ? QMC5883L_OK : QMC5883L_BUSERR; +} + +static int _reg_write(const qmc5883l_t *dev, uint8_t reg, + uint8_t val, int acquire, int release) +{ + if (acquire) { + if (i2c_acquire(dev->i2c) != 0) { + return QMC5883L_BUSERR; + } + } + int res = i2c_write_reg(dev->i2c, ADDR, reg, val, 0); + if ((release) || (res != 0)) { + i2c_release(dev->i2c); + } + return (res == 0) ? QMC5883L_OK : QMC5883L_BUSERR; +} + +int qmc5883l_init(qmc5883l_t *dev, const qmc5883l_params_t *params) +{ + assert(dev); + assert(params); + int res; + + dev->i2c = params->i2c; + dev->pin_drdy = params->pin_drdy; + dev->cfg = (params->odr | params->rng | params->osr | QMC5883L_CONT); + + /* lets start with a soft reset */ + res = _reg_write(dev, QMC5883L_CTRL2, QMC5883L_SOFT_RST, 1, 0); + if (res != QMC5883L_OK) { + return res; + } + + /* verify the reset by reading the status register, should be all zeros */ + uint8_t tmp; + if (i2c_read_reg(dev->i2c, ADDR, QMC5883L_STATUS, &tmp, 0) != 0) { + i2c_release(dev->i2c); + return QMC5883L_BUSERR; + } + if (tmp != 0) { + i2c_release(dev->i2c); + return QMC5883L_NOCFG; + } + + /* write the actual device configuration */ + res = _reg_write(dev, QMC5883L_SETRESET, 0x01, 0, 0); + if (res != QMC5883L_OK) { + return res; + } + res = _reg_write(dev, QMC5883L_CTRL2, QMC5883L_INT_ENB, 0, 0); + if (res != QMC5883L_OK) { + return res; + } + return _reg_write(dev, QMC5883L_CTRL1, (dev->cfg | QMC5883L_CONT), 0, 1); +} + +int qmc5883l_data_ready(const qmc5883l_t *dev) +{ + assert(dev); + uint8_t status; + + int res = _reg_read(dev, QMC5883L_STATUS, &status, 1, 1); + if (res != QMC5883L_OK) { + return res; + } + return (status & QMC5883L_DRDY) ? QMC5883L_OK : QMC5883L_NODATA; +} + +int qmc5883l_read(const qmc5883l_t *dev, int16_t *data_out) +{ + assert(data_out); + int16_t tmp[3]; + + int res = qmc5883l_read_raw(dev, tmp); + if ((res == QMC5883L_OK) || (res == QMC5883L_OVERFLOW)) { + uint16_t scale = (dev->cfg & QMC5883L_RNG_8G) ? 3 : 12; + for (unsigned i = 0; i < 3; i++) { + data_out[i] = tmp[i] / scale; + } + } + + return res; +} + +int qmc5883l_read_raw(const qmc5883l_t *dev, int16_t *data_out) +{ + assert(dev); + assert(data_out); + + int res; + uint8_t status; + uint8_t tmp[6]; + + res = _reg_read(dev, QMC5883L_STATUS, &status, 1, 0); + if (res != QMC5883L_OK) { + return res; + } + if (!(status & QMC5883L_DRDY)) { + res = QMC5883L_NODATA; + goto done; + } + if (status & QMC5883L_OVL) { + res = QMC5883L_OVERFLOW; + } + if (i2c_read_regs(dev->i2c, ADDR, QMC5883L_DOXL, tmp, 6, 0) != 0) { + res = QMC5883L_BUSERR; + goto done; + } + + /* convert data to host byte order */ + data_out[0] = (int16_t)tmp[1] << 8 | tmp[0]; + data_out[1] = (int16_t)tmp[3] << 8 | tmp[2]; + data_out[2] = (int16_t)tmp[5] << 8 | tmp[4]; + +done: + i2c_release(dev->i2c); + return res; +} + +int qmc5883l_poweron(const qmc5883l_t *dev) +{ + assert(dev); + return _reg_write(dev, QMC5883L_CTRL1, dev->cfg, 1, 1); +} + +int qmc5883l_poweroff(const qmc5883l_t *dev) +{ + assert(dev); + return _reg_write(dev, QMC5883L_CTRL1, 0, 1, 1); +} + +#ifdef MODULE_QMC5883L_INT +int qmc5883l_init_int(const qmc5883l_t *dev, gpio_cb_t cb, void *arg) +{ + assert(dev); + assert(cb); + + if (dev->pin_drdy == GPIO_UNDEF) { + return QMC5883L_NOCFG; + } + if (gpio_init_int(dev->pin_drdy, GPIO_IN, GPIO_RISING, cb, arg) != 0) { + return QMC5883L_NOCFG; + } + return _reg_write(dev, QMC5883L_CTRL2, 0, 1, 1); +} + +int qmc5883l_irq_enable(const qmc5883l_t *dev) +{ + assert(dev); + gpio_irq_enable(dev->pin_drdy); + return _reg_write(dev, QMC5883L_CTRL2, 0, 1, 1); +} + +int qmc5883l_irq_disable(const qmc5883l_t *dev) +{ + assert(dev); + gpio_irq_disable(dev->pin_drdy); + return _reg_write(dev, QMC5883L_CTRL2, QMC5883L_INT_ENB, 1, 1); +} +#endif /* MODULE_QMC5883L_INT */ diff --git a/drivers/qmc5883l/qmc5883l_internal.h b/drivers/qmc5883l/qmc5883l_internal.h new file mode 100644 index 0000000000..5b40a88b88 --- /dev/null +++ b/drivers/qmc5883l/qmc5883l_internal.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2019 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_qmc5883l + * @{ + * + * @file + * @brief Register definitions for the QMC5883L device driver + * + * @author Hauke Petersen + */ + +#ifndef QMC5883L_INTERNAL_H +#define QMC5883L_INTERNAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @name Register map + * @{ + */ +#define QMC5883L_DOXL (0x00) +#define QMC5883L_DOXH (0x01) +#define QMC5883L_DOYL (0x02) +#define QMC5883L_DOYH (0x03) +#define QMC5883L_DOZL (0x04) +#define QMC5883L_DOZH (0x05) +#define QMC5883L_STATUS (0x06) +#define QMC5883L_TOUTL (0x07) +#define QMC5883L_TOUTH (0x08) +#define QMC5883L_CTRL1 (0x09) +#define QMC5883L_CTRL2 (0x0a) +#define QMC5883L_SETRESET (0x0b) +/** @} */ + +/** + * @name Device modes + * @{ + */ +#define QMC5883L_STANDBY (0x00) +#define QMC5883L_CONT (0x01) +/** @} */ + +/** + * @name Device status flags + * @{ + */ +#define QMC5883L_DRDY (0x01) +#define QMC5883L_OVL (0x02) +#define QMC5883L_DOR (0x04) +/** @} */ + +/** + * @name Configuration bitfields + * @{ + */ +#define QMC5883L_INT_ENB (0x01) +#define QMC5883L_ROL_PNT (0x40) +#define QMC5883L_SOFT_RST (0x80) +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* QMC5883L_INTERNAL_H */ +/** @} */ diff --git a/drivers/qmc5883l/qmc5883l_saul.c b/drivers/qmc5883l/qmc5883l_saul.c new file mode 100644 index 0000000000..3b6236c310 --- /dev/null +++ b/drivers/qmc5883l/qmc5883l_saul.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup drivers_qmc5883l + * @{ + * + * @file + * @brief SAUL mapping for the QMC5883L sensor driver + * + * @author Hauke Petersen + * + * @} + */ + + +#include + +#include "saul.h" +#include "qmc5883l.h" + +static int read(const void *dev, phydat_t *res) +{ + int ret = qmc5883l_read((const qmc5883l_t *)dev, res->val); + if ((ret == QMC5883L_OK) || (ret == QMC5883L_OVERFLOW)) { + res->unit = UNIT_GS; + res->scale = -3; + return 3; + } + return -ECANCELED; +} + +const saul_driver_t qmc5883l_saul_driver = { + .read = read, + .write = saul_notsup, + .type = SAUL_SENSE_MAG, +}; diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index f54c5a2993..9a8ca1be98 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -68,6 +68,7 @@ PSEUDOMODULES += posix_headers PSEUDOMODULES += printf_float PSEUDOMODULES += prng PSEUDOMODULES += prng_% +PSEUDOMODULES += qmc5883l_int PSEUDOMODULES += riotboot_% PSEUDOMODULES += saul_adc PSEUDOMODULES += saul_default