drivers: add hmc5883l device driver

This commit is contained in:
Gunar Schorcht 2020-03-23 17:17:03 +01:00
parent 5aff374f3d
commit e6090adb3f
9 changed files with 831 additions and 0 deletions

View File

@ -292,6 +292,14 @@ ifneq (,$(filter hih6130,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c
endif
ifneq (,$(filter hmc5883l,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c
endif
ifneq (,$(filter hmc5883l_int,$(USEMODULE)))
FEATURES_REQUIRED += periph_gpio_irq
endif
ifneq (,$(filter hts221,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c
endif

View File

@ -144,6 +144,10 @@ ifneq (,$(filter hdc1000,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/hdc1000/include
endif
ifneq (,$(filter hmc5883l,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/hmc5883l/include
endif
ifneq (,$(filter hts221,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/hts221/include
endif

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

301
drivers/hmc5883l/hmc5883l.c Normal file
View File

@ -0,0 +1,301 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* 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_hmc5883l
* @brief Device driver for the Honeywell HMC5883L 3-axis digital compass
* @author Gunar Schorcht <gunar@schorcht.net>
* @file
* @{
*/
#include <string.h>
#include <stdlib.h>
#include "hmc5883l_regs.h"
#include "hmc5883l.h"
#include "log.h"
#include "xtimer.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#if ENABLE_DEBUG
#define DEBUG_DEV(f, d, ...) \
DEBUG("[hmc5883l] %s i2c dev=%d addr=%02x: " f "\n", \
__func__, d->dev, HMC5883L_I2C_ADDRESS, ## __VA_ARGS__);
#else /* ENABLE_DEBUG */
#define DEBUG_DEV(f, d, ...)
#endif /* ENABLE_DEBUG */
#define ERROR_DEV(f, d, ...) \
LOG_ERROR("[hmc5883l] %s i2c dev=%d addr=%02x: " f "\n", \
__func__, d->dev, HMC5883L_I2C_ADDRESS, ## __VA_ARGS__);
#define EXEC_RET(f, r) \
if ((r = f) != HMC5883L_OK) { \
DEBUG("[hmc5883l] %s: error code %d\n", __func__, res); \
return res; \
}
#define EXEC_RET_CODE(f, r, c) \
if ((r = f) != HMC5883L_OK) { \
DEBUG("[hmc5883l] %s: error code %d\n", __func__, res); \
return c; \
}
/** Forward declaration of functions for internal use */
static int _is_available(const hmc5883l_t *dev);
static int _reg_read(const hmc5883l_t *dev, uint8_t reg, uint8_t *data, uint16_t len);
static int _reg_write(const hmc5883l_t *dev, uint8_t reg, uint8_t data);
int hmc5883l_init(hmc5883l_t *dev, const hmc5883l_params_t *params)
{
int res = HMC5883L_OK;
assert(dev != NULL);
assert(params != NULL);
DEBUG_DEV("params=%p", dev, params);
/* init sensor data structure */
dev->dev = params->dev;
#if MODULE_HMC5883L_INT
dev->int_pin = params->int_pin;
#endif
dev->op_mode = params->op_mode;
dev->gain = params->gain;
/* check availability of the sensor */
EXEC_RET(_is_available(dev), res)
/* set configuration register A and B */
EXEC_RET(_reg_write(dev, HMC5883L_REG_CFG_A, params->meas_avg |
params->meas_mode |
params->dor), res);
EXEC_RET(_reg_write(dev, HMC5883L_REG_CFG_B, params->gain), res);
/* set operation mode */
EXEC_RET(_reg_write(dev, HMC5883L_REG_MODE, params->op_mode), res);
/* to set the LOCK flag, read the first data sample that is not valid */
uint8_t data[6];
EXEC_RET(_reg_read(dev, HMC5883L_REG_OUT_X_MSB, data, 6), res);
return res;
}
#ifdef MODULE_HMC5883L_INT
int hmc5883l_init_int(hmc5883l_t *dev, hmc5883l_drdy_int_cb_t cb, void *arg)
{
assert(dev != NULL);
assert(dev->int_pin != GPIO_UNDEF);
DEBUG_DEV("", dev);
if (gpio_init_int(dev->int_pin, GPIO_IN, GPIO_FALLING, cb, arg)) {
return HMC5883L_ERROR_COMMON;
}
return HMC5883L_OK;
}
#endif /* MODULE_HMC5883L_INT */
int hmc5883l_data_ready(const hmc5883l_t *dev)
{
assert(dev != NULL);
DEBUG_DEV("", dev);
int res = HMC5883L_OK;
uint8_t reg;
EXEC_RET(_reg_read(dev, HMC5883L_REG_STATUS, &reg, 1), res);
return (reg == HMC5883L_REG_STATUS_RDY) ? HMC5883L_OK : HMC5883L_ERROR_NO_DATA;
}
/*
* Scale factors for conversion of raw sensor data to uGs for possible
* sensitivities according to the datasheet.
*/
static const uint16_t HMC5883L_RES[] = {
730, /* uG/LSb for HMC5883L_GAIN_1370 with range +-0.88 Gs */
917, /* uG/LSb for HMC5883L_GAIN_1090 with range +-1.3 Gs */
1220, /* uG/LSb for HMC5883L_GAIN_820 with range +-1.9 Gs */
1515, /* uG/LSb for HMC5883L_GAIN_660 with range +-2.5 Gs */
2273, /* uG/LSb for HMC5883L_GAIN_440 with range +-4.0 Gs */
2564, /* uG/LSb for HMC5883L_GAIN_390 with range +-4.7 Gs */
3030, /* uG/LSb for HMC5883L_GAIN_330 with range +-5.6 Gs */
4348, /* uG/LSb for HMC5883L_GAIN_230 with range +-8.1 Gs */
};
int hmc5883l_read(const hmc5883l_t *dev, hmc5883l_data_t *data)
{
assert(dev != NULL);
assert(data != NULL);
DEBUG_DEV("data=%p", dev, data);
int res = HMC5883L_OK;
hmc5883l_raw_data_t raw;
EXEC_RET(hmc5883l_read_raw (dev, &raw), res);
/*
* The range of raw data is -2048 ... -2047. That is, raw data multiplied
* by scale fit into 32 bit integer.
*/
data->x = ((int32_t)raw.x * HMC5883L_RES[dev->gain >> HMC5883L_REG_CFG_B_GN_S]) / 1000;
data->y = ((int32_t)raw.y * HMC5883L_RES[dev->gain >> HMC5883L_REG_CFG_B_GN_S]) / 1000;
data->z = ((int32_t)raw.z * HMC5883L_RES[dev->gain >> HMC5883L_REG_CFG_B_GN_S]) / 1000;
return res;
}
int hmc5883l_read_raw(const hmc5883l_t *dev, hmc5883l_raw_data_t *raw)
{
assert(dev != NULL);
assert(raw != NULL);
DEBUG_DEV("raw=%p", dev, raw);
int res = HMC5883L_OK;
uint8_t data[6];
/* read raw data sample */
EXEC_RET_CODE(_reg_read(dev, HMC5883L_REG_OUT_X_MSB, data, 6),
res, HMC5883L_ERROR_RAW_DATA);
/* data MSB @ lower address */
raw->x = (data[0] << 8) | data[1];
raw->y = (data[4] << 8) | data[5];
raw->z = (data[2] << 8) | data[3];
return res;
}
int hmc5883l_power_down(hmc5883l_t *dev)
{
assert(dev != NULL);
DEBUG_DEV("", dev);
/* set operation mode to Idle mode with only 5 uA current */
return _reg_write(dev, HMC5883L_REG_MODE, HMC5883L_OP_MODE_IDLE);
}
int hmc5883l_power_up(hmc5883l_t *dev)
{
assert(dev != NULL);
DEBUG_DEV("", dev);
/* set operation mode to last operation mode */
return _reg_write(dev, HMC5883L_REG_MODE, dev->op_mode);
}
/** Functions for internal use only */
/**
* @brief Check the chip ID to test whether sensor is available
*/
static int _is_available(const hmc5883l_t *dev)
{
DEBUG_DEV("", dev);
int res = HMC5883L_OK;
uint8_t id_c[] = HMC5883L_ID;
uint8_t id_r[HMC5883L_ID_LEN];
/* read the chip id from HMC5883L_REG_ID_X */
EXEC_RET(_reg_read(dev, HMC5883L_REG_ID_A, id_r, HMC5883L_ID_LEN), res);
if (memcmp(id_r, id_c, HMC5883L_ID_LEN)) {
DEBUG_DEV("sensor is not available, wrong id %02x%02x%02x, "
"should be %02x%02x%02x",
dev, id_r[0], id_r[1], id_r[2], id_c[0], id_c[1], id_c[2]);
return HMC5883L_ERROR_WRONG_ID;
}
return res;
}
static int _reg_read(const hmc5883l_t *dev, uint8_t reg, uint8_t *data, uint16_t len)
{
assert(dev != NULL);
assert(data != NULL);
assert(len != 0);
DEBUG_DEV("read %d byte from sensor registers starting at addr 0x%02x",
dev, len, reg);
if (i2c_acquire(dev->dev)) {
DEBUG_DEV("could not acquire I2C bus", dev);
return HMC5883L_ERROR_I2C;
}
int res = i2c_read_regs(dev->dev, HMC5883L_I2C_ADDRESS, reg, data, len, 0);
i2c_release(dev->dev);
if (res == 0) {
if (ENABLE_DEBUG) {
printf("[hmc5883l] %s i2c dev=%d addr=%02x: read following bytes: ",
__func__, dev->dev, HMC5883L_I2C_ADDRESS);
for (unsigned i = 0; i < len; i++) {
printf("%02x ", data[i]);
}
printf("\n");
}
}
else {
DEBUG_DEV("could not read %d bytes from sensor registers "
"starting at addr %02x, reason %d (%s)",
dev, len, reg, res, strerror(res * -1));
return HMC5883L_ERROR_I2C;
}
return res;
}
static int _reg_write(const hmc5883l_t *dev, uint8_t reg, uint8_t data)
{
assert(dev != NULL);
DEBUG_DEV("write register 0x%02x", dev, reg);
if (ENABLE_DEBUG) {
printf("[hmc5883l] %s i2c dev=%d addr=%02x: write following bytes: ",
__func__, dev->dev, HMC5883L_I2C_ADDRESS);
printf("%02x ", data);
printf("\n");
}
if (i2c_acquire(dev->dev)) {
DEBUG_DEV("could not acquire I2C bus", dev);
return HMC5883L_ERROR_I2C;
}
int res = i2c_write_regs(dev->dev, HMC5883L_I2C_ADDRESS, reg, &data, 1, 0);
i2c_release(dev->dev);
if (res != 0) {
DEBUG_DEV("could not write to sensor registers "
"starting at addr 0x%02x, reason %d (%s)",
dev, reg, res, strerror(res * -1));
return HMC5883L_ERROR_I2C;
}
return res;
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* 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_hmc5883l
* @brief HMC5883L adaption to the RIOT actuator/sensor interface
* @author Gunar Schorcht <gunar@schorcht.net>
* @file
*/
#include <string.h>
#include "saul.h"
#include "hmc5883l.h"
static int read(const void *dev, phydat_t *res)
{
hmc5883l_data_t data;
int ret = hmc5883l_read((const hmc5883l_t *)dev, &data);
if (ret < 0) {
return -ECANCELED;
}
res->val[0] = data.x;
res->val[1] = data.y;
res->val[2] = data.z;
res->unit = UNIT_GS;
res->scale = -3;
return 3;
}
const saul_driver_t hmc5883l_saul_driver = {
.read = read,
.write = saul_notsup,
.type = SAUL_SENSE_MAG,
};

View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* 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_hmc5883l
* @brief Default configuration for the Honeywell HMC5883L 3-axis digital compass
* @author Gunar Schorcht <gunar@schorcht.net>
* @file
* @{
*/
#ifndef HMC5883L_PARAMS_H
#define HMC5883L_PARAMS_H
#include "board.h"
#include "hmc5883l.h"
#include "saul_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Set default configuration parameters
* @{
*/
#ifndef HMC5883L_PARAM_DEV
#define HMC5883L_PARAM_DEV I2C_DEV(0)
#endif
#ifndef HMC5883L_PARAM_DOR
#define HMC5883L_PARAM_DOR (HMC5883L_DOR_15)
#endif
#ifndef HMC5883L_PARAM_MEAS_MODE
#define HMC5883L_PARAM_MEAS_MODE (HMC5883L_MEAS_MODE_NORMAL)
#endif
#ifndef HMC5883L_PARAM_MEAS_AVG
#define HMC5883L_PARAM_MEAS_AVG (HMC5883L_MEAS_AVG_NONE)
#endif
#ifndef HMC5883L_PARAM_OP_MODE
#define HMC5883L_PARAM_OP_MODE (HMC5883L_OP_MODE_CONTINUOUS)
#endif
#ifndef HMC5883L_PARAM_GAIN
#define HMC5883L_PARAM_GAIN (HMC5883L_GAIN_1090)
#endif
#ifndef HMC5883L_PARAM_INT_PIN
#define HMC5883L_PARAM_INT_PIN (GPIO_UNDEF)
#endif
#ifdef MODULE_HMC5883L_INT
#ifndef HMC5883L_PARAMS
#define HMC5883L_PARAMS { \
.dev = HMC5883L_PARAM_DEV, \
.dor = HMC5883L_PARAM_DOR, \
.gain = HMC5883L_PARAM_GAIN, \
.int_pin = HMC5883L_PARAM_INT_PIN, \
.meas_mode = HMC5883L_PARAM_MEAS_MODE, \
.meas_avg = HMC5883L_PARAM_MEAS_AVG, \
.op_mode = HMC5883L_PARAM_OP_MODE, \
}
#endif /* HMC5883L_PARAMS */
#else /* MODULE_HMC5883L_INT */
#define HMC5883L_PARAMS { \
.dev = HMC5883L_PARAM_DEV, \
.dor = HMC5883L_PARAM_DOR, \
.gain = HMC5883L_PARAM_GAIN, \
.meas_mode = HMC5883L_PARAM_MEAS_MODE, \
.meas_avg = HMC5883L_PARAM_MEAS_AVG, \
.op_mode = HMC5883L_PARAM_OP_MODE, \
}
#endif /* MODULE_HMC5883L_INT */
#ifndef HMC5883L_SAUL_INFO
#define HMC5883L_SAUL_INFO { .name = "hmc5883l" }
#endif
/**@}*/
/**
* @brief Allocate some memory to store the actual configuration
*/
static const hmc5883l_params_t hmc5883l_params[] =
{
HMC5883L_PARAMS
};
/**
* @brief Additional meta information to keep in the SAUL registry
*/
static const saul_reg_info_t hmc5883l_saul_info[] =
{
HMC5883L_SAUL_INFO
};
#ifdef __cplusplus
}
#endif
#endif /* HMC5883L_PARAMS_H */
/** @} */

View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* 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_hmc5883l
* @brief Register definitions for the Honeywell HMC5883L 3-axis digital compass
* @author Gunar Schorcht <gunar@schorcht.net>
* @file
* @{
*/
#ifndef HMC5883L_REGS_H
#define HMC5883L_REGS_H
#ifdef __cplusplus
extern "C"
{
#endif
/** HMC5883L I2C address*/
#define HMC5883L_I2C_ADDRESS (0x1e)
/** HMC5883L chip id defined in Identification Registers A..C */
#define HMC5883L_ID { 0x48, 0x34, 0x33 }
/** HMC5883L chip id length */
#define HMC5883L_ID_LEN (3)
/**
* @name Register addresses
* @{
*/
#define HMC5883L_REG_CFG_A (0x00)
#define HMC5883L_REG_CFG_B (0x01)
#define HMC5883L_REG_MODE (0x02)
#define HMC5883L_REG_OUT_X_MSB (0x03)
#define HMC5883L_REG_OUT_X_LSB (0x04)
#define HMC5883L_REG_OUT_Y_MSB (0x05)
#define HMC5883L_REG_OUT_Y_LSB (0x06)
#define HMC5883L_REG_OUT_Z_MSB (0x07)
#define HMC5883L_REG_OUT_Z_LSB (0x08)
#define HMC5883L_REG_STATUS (0x09)
#define HMC5883L_REG_ID_A (0x0a)
#define HMC5883L_REG_ID_B (0x0b)
#define HMC5883L_REG_ID_C (0x0c)
/** @} */
/**
* @name Register structure definitions
* @{
*/
#define HMC5883L_REG_CFG_A_MA (0x60) /**< HMC5883L_REG_CFG_A<6:5> */
#define HMC5883L_REG_CFG_A_DO (0x1c) /**< HMC5883L_REG_CFG_A<4:2> */
#define HMC5883L_REG_CFG_A_MS (0x03) /**< HMC5883L_REG_CFG_A<1:0> */
#define HMC5883L_REG_CFG_B_GN (0xe0) /**< HMC5883L_REG_CFG_N<7:5> */
#define HMC5883L_REG_CFG_B_GN_S (5) /**< HMC5883L_REG_CFG_N<7:5> shift */
#define HMC5883L_REG_MODE_HS (0x80) /**< HMC5883L_REG_MODE<7> */
#define HMC5883L_REG_MODE_MD (0x03) /**< HMC5883L_REG_MODE<1:0> */
#define HMC5883L_REG_STATUS_LOCK (0x02) /**< HMC5883L_REG_STATUS<1> */
#define HMC5883L_REG_STATUS_RDY (0x01) /**< HMC5883L_REG_STATUS<0> */
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* HMC5883L_REGS_H */

296
drivers/include/hmc5883l.h Normal file
View File

@ -0,0 +1,296 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* 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_hmc5883l HMC5883L 3-axis digital compass
* @ingroup drivers_sensors
* @ingroup drivers_saul
* @brief Device driver for the Honeywell HMC5883L 3-axis digital compass
*
* The driver implements basic polling mode. The application can use
* different approaches to get new data, either
*
* - using the #hmc5883l_read function at a lower rate than the the DOR, or
* - using the data-ready interrupt (**DRDY**), see #hmc5883l_init_int.
*
* The data-ready interrupt (**DRDY**) is only be available when module
* `hmc5883l_int` is enabled.
*
* This driver provides @ref drivers_saul capabilities.
*
* @{
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @file
*/
#ifndef HMC5883L_H
#define HMC5883L_H
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdbool.h>
#include <stdint.h>
#include "periph/gpio.h"
#include "periph/i2c.h"
/** Definition of error codes */
typedef enum {
HMC5883L_OK = 0, /**< success */
HMC5883L_ERROR_I2C = -1, /**< any I2C communication error */
HMC5883L_ERROR_WRONG_ID = -2, /**< wrong id read */
HMC5883L_ERROR_NO_DATA = -3, /**< no data are available */
HMC5883L_ERROR_RAW_DATA = -4, /**< reading raw data failed */
HMC5883L_ERROR_COMMON = -5, /**< common error */
} hmc5883l_error_codes_t;
/**
* @brief Data output rates (DOR)
*
* The values correspond to bits <4:2> of the HMC5883L_REG_CFG_A register.
*/
typedef enum {
HMC5883L_DOR_0_75 = 0x00, /**< 0.75 Hz */
HMC5883L_DOR_1_5 = 0x04, /**< 1.5 Hz */
HMC5883L_DOR_3 = 0x08, /**< 3 Hz */
HMC5883L_DOR_7_5 = 0x0c, /**< 7.5 Hz */
HMC5883L_DOR_15 = 0x10, /**< 15 Hz (default) */
HMC5883L_DOR_30 = 0x14, /**< 30 Hz */
HMC5883L_DOR_75 = 0x18, /**< 75 Hz */
} hmc5883l_dor_t;
/**
* @brief Measurement modes
*
* The values correspond to bits <1:0> of the HMC5883L_REG_CFG_A register.
*/
typedef enum {
HMC5883L_MEAS_MODE_NORMAL = 0x00, /**< Normal measurement config */
HMC5883L_MEAS_MODE_BIAS_POS = 0x01, /**< Positive bias config for all axes */
HMC5883L_MEAS_MODE_BIAS_NEG = 0x02, /**< Negative bias config for all axes */
} hmc5883l_meas_mode_t;
/**
* @brief Measurement avaraging (number of samples are averaged for output)
*
* The values correspond to bits <6:5> of the HMC5883L_REG_CFG_A register.
*/
typedef enum {
HMC5883L_MEAS_AVG_NONE = 0x00, /**< No averaging */
HMC5883L_MEAS_AVG_2 = 0x20, /**< 2 samples are averaged */
HMC5883L_MEAS_AVG_4 = 0x40, /**< 4 samples are averaged */
HMC5883L_MEAS_AVG_8 = 0x60, /**< 8 samples are averaged */
} hmc5883l_meas_avg_t;
/**
* @brief Operation modes
*
* Values correspond to bits <1:0> of HMC5883L_REG_MODE register
*/
typedef enum {
HMC5883L_OP_MODE_CONTINUOUS = 0x00, /**< Continuous measurement */
HMC5883L_OP_MODE_SINGLE = 0x01, /**< Single measurement */
HMC5883L_OP_MODE_IDLE = 0x02, /**< Idle mode */
} hmc5883l_op_mode_t;
/**
* @brief Gain (determines the sensitivity and the range)
*
* The values correspond to bits <7:5> of the HMC5883L_REG_CFG_B_GN register.
*/
typedef enum {
HMC5883L_GAIN_1370 = 0x00, /**< Range +-0.88 Gs, Resolution 0.73 mGs/LSB */
HMC5883L_GAIN_1090 = 0x20, /**< Range +-1.3 Gs, Resolution 0.92 mGs/LSB */
HMC5883L_GAIN_820 = 0x40, /**< Range +-1.9 Gs, Resolution 1.22 mGs/LSB */
HMC5883L_GAIN_660 = 0x60, /**< Range +-2.5 Gs, Resolution 1.52 mGs/LSB */
HMC5883L_GAIN_440 = 0x80, /**< Range +-4.0 Gs, Resolution 2.27 mGs/LSB */
HMC5883L_GAIN_390 = 0xa0, /**< Range +-4.7 Gs, Resolution 2.56 mGs/LSB */
HMC5883L_GAIN_330 = 0xc0, /**< Range +-5.6 Gs, Resolution 3.03 mGs/LSB */
HMC5883L_GAIN_230 = 0xe0, /**< Range +-8.1 Gs, Resolution 4.35 mGs/LSB */
} hmc5883l_gain_t;
/**
* @brief Magnetic field values in milli-Gauss (mGs)
*/
typedef struct {
int16_t x; /**< magnetic field x-axis */
int16_t y; /**< magnetic field y-axis */
int16_t z; /**< magnetic field y-axis */
} hmc5883l_data_t;
/**
* @brief Raw data set as two complements
*/
typedef struct {
int16_t x; /**< magnetic field x-axis as 16 bit two's complements */
int16_t y; /**< magnetic field y-axis as 16 bit two's complements */
int16_t z; /**< magnetic field z-axis as 16 bit two's complements */
} hmc5883l_raw_data_t;
#if MODULE_HMC5883L_INT || DOXYGEN
/**
* @brief HMC5883L DRDY interrupt callback function type
*
* Function prototype for the function which is called on DRDY interrupt if
* the interrupt is activated by #hmc5883l_init_int and the interrupt pin is
* defined in device initialization parameters.
*
* @note The @p cb function is called in interrupt context. The application
* should do nothing time consuming and not directly access sensor data.
*/
typedef void (*hmc5883l_drdy_int_cb_t)(void *);
#endif /* MODULE_HMC5883L_INT || DOXYGEN */
/**
* @brief HMC5883L device initialization parameters
*/
typedef struct {
unsigned dev; /**< I2C device */
#if MODULE_HMC5883L_INT
gpio_t int_pin; /**< DRDY interrupt pin: if #GPIO_UNDEF, interrupts are not used */
#endif
hmc5883l_meas_mode_t meas_mode; /**< Measurement mode (default #HMC5883L_MEAS_MODE_NORMAL) */
hmc5883l_meas_avg_t meas_avg; /**< Measurement avaraging (default #HMC5883L_MEAS_AVG_NONE) */
hmc5883l_dor_t dor; /**< Data output rate (default #HMC5883L_DOR_15) */
hmc5883l_op_mode_t op_mode; /**< Operation mode (#HMC5883L_OP_MODE_CONTINUOUS) */
hmc5883l_gain_t gain; /**< Gain (default #HMC5883L_GAIN_1090) */
} hmc5883l_params_t;
/**
* @brief HMC5883L sensor device data structure type
*/
typedef struct {
unsigned dev; /**< I2C device */
#if MODULE_HMC5883L_INT
gpio_t int_pin; /**< DRDY interrupt pin: if #GPIO_UNDEF, interrupts are not used */
#endif
hmc5883l_op_mode_t op_mode; /**< Operation mode (#HMC5883L_OP_MODE_CONTINUOUS) */
hmc5883l_gain_t gain; /**< Gain (default #HMC5883L_GAIN_1090) */
} hmc5883l_t;
/**
* @brief Initialize the HMC5883L sensor device
*
* This function resets the sensor and initializes the sensor according to
* given initialization parameters. All registers are reset to default values.
*
* @param[in] dev device descriptor of HMC5883L sensor to be initialized
* @param[in] params HMC5883L initialization parameters
*
* @retval HMC5883L_OK on success
* @retval HMC5883L_ERROR_* a negative error code on error,
* see #hmc5883l_error_codes_t
*/
int hmc5883l_init(hmc5883l_t *dev, const hmc5883l_params_t *params);
#if MODULE_HMC5883L_INT || DOXYGEN
/**
* @brief Initialize and activate the DRDY interrupt of HMC5883L sensor device
*
* This function activates the DRDY interrupt and initializes the pin defined
* as the interrupt pin in the initialization parameters of the device. The
* @p cb parameter specifies the function, along with an optional argument
* @p arg, which is called when a DRDY interrupt is triggered.
*
* @warning The given callback function @p cb is executed in interrupt context.
* Make sure not to call any driver API function in that context.
* @note This function is only available when module `hmc5883l_int` is enabled.
*
* @param[in] dev device descriptor of HMC5883L sensor
* @param[in] cb function called when DRDY interrupt is triggered
* @param[in] arg argument for the callback function
*
* @retval HMC5883L_OK on success
* @retval HMC5883L_ERROR_* a negative error code on error,
* see #hmc5883l_error_codes_t
*/
int hmc5883l_init_int(hmc5883l_t *dev, hmc5883l_drdy_int_cb_t cb, void *arg);
#endif /* MODULE_HMC5883L_INT || DOXYGEN */
/**
* @brief Data-ready status function
*
* The function checks the status register and returns
*
* @param[in] dev device descriptor of HMC5883L sensor
*
* @retval HMC5883L_OK new data available
* @retval HMC5883L_ERROR_NO_DATA no new data available
* @retval HMC5883L_ERROR_* negative error code,
* see #hmc5883l_error_codes_t
*/
int hmc5883l_data_ready(const hmc5883l_t *dev);
/**
* @brief Read one sample of magnetic field values in milli-Gauss (mGs)
*
* Raw magnetometer data are read from the sensor and normalized them
* with respect to configured gain. Magnetic field values are given in
* milli-Gauss (mGs) to preserve full resolution:
*
* @param[in] dev device descriptor of HMC5883L sensor
* @param[out] data result vector in milli-Gauss (mGs) per axis
*
* @retval HMC5883L_OK on success
* @retval HMC5883L_ERROR_* a negative error code on error,
* see #hmc5883l_error_codes_t
*/
int hmc5883l_read(const hmc5883l_t *dev, hmc5883l_data_t *data);
/**
* @brief Read one sample of raw sensor data as 16 bit two's complements
*
* @param[in] dev device descriptor of HMC5883L sensor
* @param raw raw data vector
*
* @retval HMC5883L_OK on success
* @retval HMC5883L_ERROR_* a negative error code on error,
* see #hmc5883l_error_codes_t
*/
int hmc5883l_read_raw(const hmc5883l_t *dev, hmc5883l_raw_data_t *raw);
/**
* @brief Power down the sensor
*
* Changes the sensor operation mode to #HMC5883L_OP_MODE_IDLE in which
* almost all internal blocks are switched off. I2C interface is
* still active. The content of the configuration registers is preserved.
*
* @param[in] dev Device descriptor of HMC5883L device to read from
*
* @retval HMC5883L_OK on success
* @retval HMC5883L_ERROR_* negative error code, see #hmc5883l_error_codes_t
*/
int hmc5883l_power_down(hmc5883l_t *dev);
/**
* @brief Power up the sensor
*
* Swichtes the sensor back into the last active operation mode.
*
* @param[in] dev Device descriptor of HMC5883L device to read from
*
* @retval HMC5883L_OK on success
* @retval HMC5883L_ERROR_* negative error code, see #hmc5883l_error_codes_t
*/
int hmc5883l_power_up(hmc5883l_t *dev);
#ifdef __cplusplus
}
#endif
#endif /* HMC5883L_H */
/** @} */

View File

@ -149,6 +149,9 @@ PSEUDOMODULES += cc1100
PSEUDOMODULES += cc1100e
PSEUDOMODULES += cc1101
# interrupt variant of the HMC5883L driver
PSEUDOMODULES += hmc5883l_int
# interrupt variant of the ITG320X driver as pseudo module
PSEUDOMODULES += itg320x_int