From a51c91e5be37c01d8c062fbc4cfdc5086ccfbd23 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Thu, 27 Nov 2014 18:38:45 +0100 Subject: [PATCH] add mag3110 magnetometer driver --- drivers/Makefile.include | 3 + drivers/include/mag3110.h | 193 ++++++++++++++++++++++++++ drivers/mag3110/Makefile | 1 + drivers/mag3110/include/mag3110_reg.h | 80 +++++++++++ drivers/mag3110/mag3110.c | 190 +++++++++++++++++++++++++ 5 files changed, 467 insertions(+) create mode 100644 drivers/include/mag3110.h create mode 100644 drivers/mag3110/Makefile create mode 100644 drivers/mag3110/include/mag3110_reg.h create mode 100644 drivers/mag3110/mag3110.c diff --git a/drivers/Makefile.include b/drivers/Makefile.include index b19b10c193..1161216849 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -34,3 +34,6 @@ endif ifneq (,$(filter mma8652,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/mma8652/include endif +ifneq (,$(filter mag3110,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/mag3110/include +endif diff --git a/drivers/include/mag3110.h b/drivers/include/mag3110.h new file mode 100644 index 0000000000..c9b529e0d2 --- /dev/null +++ b/drivers/include/mag3110.h @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2014 PHYTEC Messtechnik GmbH + * + * 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_mag3110 MAG3110 3-Axis Digital Magnetometer + * @ingroup drivers + * @brief Driver for the Freescale MAG3110 magnetometer. + * After initialization and set activ the magnetometer + * will make measurements at periodic times. + * The output rate and over sample ratio + * can be determined by magnetometer initialization. + * The measured values of magnetic field strength and + * die temperature have uncalibrated offsets. + * To get correct measuremend values, the individual + * offsets must be measured and set accordingly. + * + * @{ + * + * @file + * @brief Interface definition for the MAG3110 magnetometer driver. + * + * @author Johann Fischer + */ + +#ifndef MAG3110_H +#define MAG3110_H + +#include +#include +#include "periph/i2c.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef MAG3110_I2C_ADDRESS +#define MAG3110_I2C_ADDRESS 0x0E /**< Magnetometer Default Address */ +#endif + +#define MAG3110_DROS_8000_16 0 /**< Output Rate 80 Hz, Over Sample Ratio 16 */ +#define MAG3110_DROS_4000_32 1 /**< Output Rate 40 Hz, Over Sample Ratio 32 */ +#define MAG3110_DROS_2000_64 2 /**< Output Rate 20 Hz, Over Sample Ratio 64 */ +#define MAG3110_DROS_1000_128 3 /**< Output Rate 10 Hz, Over Sample Ratio 128 */ +#define MAG3110_DROS_4000_16 4 /**< Output Rate 40 Hz, Over Sample Ratio 16 */ +#define MAG3110_DROS_2000_32 5 /**< Output Rate 20 Hz, Over Sample Ratio 32 */ +#define MAG3110_DROS_1000_64 6 /**< Output Rate 10 Hz, Over Sample Ratio 64 */ +#define MAG3110_DROS_0500_128 7 /**< Output Rate 5 Hz, Over Sample Ratio 128 */ +#define MAG3110_DROS_2000_16 8 /**< Output Rate 20 Hz, Over Sample Ratio 16 */ +#define MAG3110_DROS_1000_32 9 /**< Output Rate 10 Hz, Over Sample Ratio 32 */ +#define MAG3110_DROS_0500_64 10 /**< Output Rate 5 Hz, Over Sample Ratio 64 */ +#define MAG3110_DROS_0250_128 11 /**< Output Rate 2.5 Hz, Over Sample Ratio 128 */ +#define MAG3110_DROS_1000_16 12 /**< Output Rate 10 Hz, Over Sample Ratio 16 */ +#define MAG3110_DROS_0500_32 13 /**< Output Rate 5 Hz, Over Sample Ratio 32 */ +#define MAG3110_DROS_0250_64 14 /**< Output Rate 2.5 Hz, Over Sample Ratio 64 */ +#define MAG3110_DROS_0125_128 15 /**< Output Rate 1.25 Hz, Over Sample Ratio 128 */ +#define MAG3110_DROS_0500_16 16 /**< Output Rate 5 Hz, Over Sample Ratio 16 */ +#define MAG3110_DROS_0250_32 17 /**< Output Rate 2.5 Hz, Over Sample Ratio 32 */ +#define MAG3110_DROS_0125_64 18 /**< Output Rate 1.25 Hz, Over Sample Ratio 64 */ +#define MAG3110_DROS_0063_128 19 /**< Output Rate 0.63 Hz, Over Sample Ratio 128 */ +#define MAG3110_DROS_0250_16 20 /**< Output Rate 2.5 Hz, Over Sample Ratio 16 */ +#define MAG3110_DROS_0125_32 21 /**< Output Rate 1.25 Hz, Over Sample Ratio 32 */ +#define MAG3110_DROS_0063_64 22 /**< Output Rate 0.63 Hz, Over Sample Ratio 64 */ +#define MAG3110_DROS_0031_128 23 /**< Output Rate 0.31 Hz, Over Sample Ratio 128 */ +#define MAG3110_DROS_0125_16 24 /**< Output Rate 1.25 Hz, Over Sample Ratio 16 */ +#define MAG3110_DROS_0063_32 25 /**< Output Rate 0.63 Hz, Over Sample Ratio 32 */ +#define MAG3110_DROS_0031_64 26 /**< Output Rate 0.31 Hz, Over Sample Ratio 64 */ +#define MAG3110_DROS_0016_128 27 /**< Output Rate 0.16 Hz, Over Sample Ratio 128 */ +#define MAG3110_DROS_0063_16 28 /**< Output Rate 0.63 Hz, Over Sample Ratio 16 */ +#define MAG3110_DROS_0031_32 29 /**< Output Rate 0.31 Hz, Over Sample Ratio 32 */ +#define MAG3110_DROS_0016_64 30 /**< Output Rate 0.16 Hz, Over Sample Ratio 64 */ +#define MAG3110_DROS_0008_128 31 /**< Output Rate 0.08 Hz, Over Sample Ratio 128 */ +#define MAG3110_DROS_DEFAULT MAG3110_DROS_0125_128 /**< Default Setting for testing */ + +/** + * @brief Device descriptor for MAG3110 magnetometer. + */ +typedef struct { + i2c_t i2c; /**< I2C device, the magnetometer is connected to */ + uint8_t addr; /**< the magnetometer's slave address on the I2C bus */ + bool initialized; /**< magnetometer status, true if magnetometer is initialized */ +} mag3110_t; + +/** + * @brief MAG3110 magnetometer test. + * This function looks for Device ID of the MAG3110 magnetometer. + * + * @param[in] dev device descriptor of magnetometer + * + * @return 0 on success + * @return -1 on error + */ +int mag3110_test(mag3110_t *dev); + +/** + * @brief Initialise the MAG3110 magnetometer driver. + * + * @param[out] dev device descriptor of magnetometer to initialize + * @param[in] i2c I2C bus the magnetometer is connected to + * @param[in] address magnetometer's I2C slave address + * @param[in] dros data rate and over sampling selection + * + * @return 0 on success + * @return -1 if dros parameter is wrong + * @return -2 if initialization of I2C bus failed + * @return -3 if magnetometer test failed + * @return -4 if magnetometer configuration failed + */ +int mag3110_init(mag3110_t *dev, i2c_t i2c, uint8_t address, uint8_t dros); + +/** + * @brief Set user offset correction. + * Offset correction register will be erased after accelerometer reset. + * + * @param[out] dev device descriptor of magnetometer + * @param[in] x offset offset correction value for x-axis + * @param[in] y offset offset correction value for y-axis + * @param[in] z offset offset correction value for z-axis + * + * @return 0 on success + * @return -1 on error + */ +int mag3110_set_user_offset(mag3110_t *dev, int16_t x, int16_t y, int16_t z); + +/** + * @brief Set active mode, this enables periodic measurements. + * + * @param[out] dev device descriptor of magnetometer + * + * @return 0 on success + * @return -1 on error + */ +int mag3110_set_active(mag3110_t *dev); + +/** + * @brief Set standby mode. + * + * @param[in] dev device descriptor of magnetometer + * + * @return 0 on success + * @return -1 on error + */ +int mag3110_set_standby(mag3110_t *dev); + +/** + * @brief Check for new set of measurement data. + * + * @param[in] dev device descriptor of magnetometer + * + * @return >0 if x-, y- and z-axis new sample is ready + * @return 0 if measurement is in progress + * @return -1 on error + */ +int mag3110_is_ready(mag3110_t *dev); + +/** + * @brief Read magnetometer's data. + * To get the actual values for the magnetic field in \f$\mu T\f$, + * one have to divide the returned values from the magnetometer by 10. + * + * @param[in] dev device descriptor of magnetometer + * @param[out] x x-axis magnetic field strength + * @param[out] y y-axis magnetic field strength + * @param[out] z z-axis magnetic field strength + * @param[out] status magnetometer status register + * + * @return 0 on success + * @return -1 on error + */ +int mag3110_read(mag3110_t *dev, int16_t *x, int16_t *y, int16_t *z, uint8_t *status); + +/** + * @brief Read die temperature. + * + * @param[in] dev device descriptor of magnetometer + * @param[out] dtemp die temperature + * + * @return 0 on success + * @return -1 on error + */ +int mag3110_read_dtemp(mag3110_t *dev, int8_t *dtemp); + +#ifdef __cplusplus +} +#endif + +#endif +/** @} */ diff --git a/drivers/mag3110/Makefile b/drivers/mag3110/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/mag3110/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/mag3110/include/mag3110_reg.h b/drivers/mag3110/include/mag3110_reg.h new file mode 100644 index 0000000000..928ba2c4d0 --- /dev/null +++ b/drivers/mag3110/include/mag3110_reg.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014 PHYTEC Messtechnik GmbH + * + * 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_mag3110 + * @{ + * + * @file + * @brief Register definition for the MAG3110 magnetometer driver. + * + * @author Johann Fischer + * + */ + +#ifndef __MAG3110_REG_H__ +#define __MAG3110_REG_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define MAG3110_DR_STATUS 0x00 /**< Data ready status per axis */ +#define MAG3110_OUT_X_MSB 0x01 /**< Bits [15:8] of X measurement */ +#define MAG3110_OUT_X_LSB 0x02 /**< Bits [7:0] of X measurement */ +#define MAG3110_OUT_Y_MSB 0x03 /**< Bits [15:8] of Y measurement */ +#define MAG3110_OUT_Y_LSB 0x04 /**< Bits [7:0] of Y measurement */ +#define MAG3110_OUT_Z_MSB 0x05 /**< Bits [15:8] of Z measurement */ +#define MAG3110_OUT_Z_LSB 0x06 /**< Bits [7:0] of Z measurement */ +#define MAG3110_WHO_AM_I 0x07 /**< Device Identification Register */ +#define MAG3110_SYSMOD 0x08 /**< FIFO Status Register */ +#define MAG3110_OFF_X_MSB 0x09 /**< Bits [15:8] of user X offset */ +#define MAG3110_OFF_X_LSB 0x0A /**< Bits [7:0] of user X offset */ +#define MAG3110_OFF_Y_MSB 0x0B /**< Bits [15:8] of user Y offset */ +#define MAG3110_OFF_Y_LSB 0x0C /**< Bits [7:0] of user Y offset */ +#define MAG3110_OFF_Z_MSB 0x0D /**< Bits [15:8] of user Z offset */ +#define MAG3110_OFF_Z_LSB 0x0E /**< Bits [7:0] of user Z offset */ +#define MAG3110_DIE_TEMP 0x0F /**< Temperature, signed 8 bits */ +#define MAG3110_CTRL_REG1 0x10 /**< Operation modes */ +#define MAG3110_CTRL_REG2 0x11 /**< Operation modes */ + +#define MAG3110_DR_STATUS_ZYXOW (1 << 7) +#define MAG3110_DR_STATUS_ZOW (1 << 6) +#define MAG3110_DR_STATUS_YOW (1 << 5) +#define MAG3110_DR_STATUS_XOW (1 << 4) +#define MAG3110_DR_STATUS_ZYXDR (1 << 3) +#define MAG3110_DR_STATUS_ZDR (1 << 2) +#define MAG3110_DR_STATUS_YDR (1 << 1) +#define MAG3110_DR_STATUS_XDR (1 << 0) + +#define MAG3110_ID 0xC4 /**< Device ID */ + +#define MAG3110_SYSMOD_STANDBY 0 +#define MAG3110_SYSMOD_ACTIVE_RAW 1 +#define MAG3110_SYSMOD_ACTIVE 2 + +#define MAG3110_CTRL_REG1_DROS_SHIFT 3 +#define MAG3110_CTRL_REG1_DROS_MASK 0xF8 +#define MAG3110_CTRL_REG1_DROS(x) (((uint8_t)(((uint8_t)(x))< + * + * @} + */ + +#include +#include +#include "periph/i2c.h" +#include "mag3110.h" +#include "mag3110_reg.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define I2C_SPEED I2C_SPEED_FAST + +int mag3110_test(mag3110_t *dev) +{ + char reg; + + if (i2c_read_regs(dev->i2c, dev->addr, MAG3110_WHO_AM_I, ®, 1) != 1) { + return -1; + } + + if (reg != MAG3110_ID) { + return -1; + } + + return 0; +} + +int mag3110_init(mag3110_t *dev, i2c_t i2c, uint8_t address, uint8_t dros) +{ + char reg; + + /* write device descriptor */ + dev->i2c = i2c; + dev->addr = address; + dev->initialized = false; + + if (dros > MAG3110_DROS_0008_128) { + return -1; + } + + /* initialize the I2C bus */ + if (i2c_init_master(i2c, I2C_SPEED) < 0) { + return -2; + } + + if (mag3110_test(dev)) { + return -3; + } + + /* enable automatic magnetic sensor reset */ + reg = MAG3110_CTRL_REG2_AUTO_MRST_EN; + + if (i2c_write_regs(dev->i2c, dev->addr, MAG3110_CTRL_REG2, ®, 1) != 1) { + return -4; + } + + reg = MAG3110_CTRL_REG1_DROS(dros); + + if (i2c_write_regs(dev->i2c, dev->addr, MAG3110_CTRL_REG1, ®, 1) != 1) { + return -4; + } + + dev->initialized = true; + + return 0; +} + +int mag3110_set_user_offset(mag3110_t *dev, int16_t x, int16_t y, int16_t z) +{ + char buf[6]; + + buf[0] = (char)(x >> 8); + buf[1] = (char)x; + buf[2] = (char)(y >> 8); + buf[3] = (char)y; + buf[4] = (char)(z >> 8); + buf[5] = (char)z; + + if (i2c_write_regs(dev->i2c, dev->addr, MAG3110_OFF_X_MSB, buf, 6) != 6) { + return -1; + } + + return 0; +} + +int mag3110_set_active(mag3110_t *dev) +{ + char reg; + + if (dev->initialized == false) { + return -1; + } + + if (i2c_read_regs(dev->i2c, dev->addr, MAG3110_CTRL_REG1, ®, 1) != 1) { + return -1; + } + + reg |= MAG3110_CTRL_REG1_AC; + + if (i2c_write_regs(dev->i2c, dev->addr, MAG3110_CTRL_REG1, ®, 1) != 1) { + return -1; + } + + return 0; +} + +int mag3110_set_standby(mag3110_t *dev) +{ + char reg; + + if (i2c_read_regs(dev->i2c, dev->addr, MAG3110_CTRL_REG1, ®, 1) != 1) { + return -1; + } + + reg &= ~MAG3110_CTRL_REG1_AC; + + if (i2c_write_regs(dev->i2c, dev->addr, MAG3110_CTRL_REG1, ®, 1) != 1) { + return -1; + } + + return 0; +} + +int mag3110_is_ready(mag3110_t *dev) +{ + char reg; + + if (dev->initialized == false) { + return -1; + } + + if (i2c_read_regs(dev->i2c, dev->addr, MAG3110_DR_STATUS, ®, 1) != 1) { + return -1; + } + + return (int)(reg & MAG3110_DR_STATUS_ZYXDR); +} + +int mag3110_read(mag3110_t *dev, int16_t *x, int16_t *y, int16_t *z, uint8_t *status) +{ + char buf[7]; + + if (dev->initialized == false) { + return -1; + } + + if (i2c_read_regs(dev->i2c, dev->addr, MAG3110_DR_STATUS, buf, 7) != 7) { + return -1; + } + + *status = buf[0]; + *x = ((int16_t)buf[1] << 8) | buf[2]; + *y = ((int16_t)buf[3] << 8) | buf[4]; + *z = ((int16_t)buf[5] << 8) | buf[6]; + + return 0; +} + +int mag3110_read_dtemp(mag3110_t *dev, int8_t *dtemp) +{ + if (dev->initialized == false) { + return -1; + } + + if (i2c_read_regs(dev->i2c, dev->addr, MAG3110_DIE_TEMP, (char *)dtemp, 1) != 1) { + return -1; + } + + return 0; +}