drivers: add hmc5883l device driver
This commit is contained in:
parent
5aff374f3d
commit
e6090adb3f
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
1
drivers/hmc5883l/Makefile
Normal file
1
drivers/hmc5883l/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
301
drivers/hmc5883l/hmc5883l.c
Normal file
301
drivers/hmc5883l/hmc5883l.c
Normal 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, ®, 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;
|
||||
}
|
||||
40
drivers/hmc5883l/hmc5883l_saul.c
Normal file
40
drivers/hmc5883l/hmc5883l_saul.c
Normal 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,
|
||||
};
|
||||
103
drivers/hmc5883l/include/hmc5883l_params.h
Normal file
103
drivers/hmc5883l/include/hmc5883l_params.h
Normal 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 */
|
||||
/** @} */
|
||||
75
drivers/hmc5883l/include/hmc5883l_regs.h
Normal file
75
drivers/hmc5883l/include/hmc5883l_regs.h
Normal 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
296
drivers/include/hmc5883l.h
Normal 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 */
|
||||
/** @} */
|
||||
@ -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
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user