diff --git a/boards/limifrog-v1/Makefile.dep b/boards/limifrog-v1/Makefile.dep new file mode 100644 index 0000000000..2c1c87fc08 --- /dev/null +++ b/boards/limifrog-v1/Makefile.dep @@ -0,0 +1,3 @@ +ifneq (,$(filter saul_default,$(USEMODULE))) + USEMODULE += lis3mdl +endif diff --git a/boards/limifrog-v1/include/board.h b/boards/limifrog-v1/include/board.h index 2cde01b70b..69d4970f6d 100644 --- a/boards/limifrog-v1/include/board.h +++ b/boards/limifrog-v1/include/board.h @@ -51,6 +51,14 @@ extern "C" { #define XTIMER_WIDTH (16U) /** @} */ + /** + * @name Define the interface to the LIS3MDL 3-axis magnetometer + * @{ + */ +#define LIS3MDL_PARAM_I2C (I2C_DEV(1)) +#define LIS3MDL_PARAM_ADDR (0x28) +/** @} */ + /** * @brief Initialize board specific hardware, including clock, LEDs and std-IO */ diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 3065cab2ed..053d54a3c7 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -301,3 +301,8 @@ ifneq (,$(filter xbee,$(USEMODULE))) USEMODULE += xtimer USEMODULE += netif endif + +ifneq (,$(filter lis3mdl,$(USEMODULE))) + FEATURES_REQUIRED += periph_i2c + USEMODULE += xtimer +endif diff --git a/drivers/Makefile.include b/drivers/Makefile.include index ff5dac66bf..7f6c3571bd 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -151,3 +151,6 @@ endif ifneq (,$(filter hts221,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/hts221/include endif +ifneq (,$(filter lis3mdl,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lis3mdl/include +endif diff --git a/drivers/include/lis3mdl.h b/drivers/include/lis3mdl.h index 4e8370a823..0630124f0a 100644 --- a/drivers/include/lis3mdl.h +++ b/drivers/include/lis3mdl.h @@ -38,14 +38,6 @@ typedef struct { int16_t z_axis; /**< Magnometer data from z_axis */ } lis3mdl_3d_data_t; -/** - * @brief Device descriptor for LIS3MDL sensor - */ -typedef struct { - i2c_t i2c; /**< I2C device */ - uint8_t addr; /**< Magnometer I2C address */ -} lis3mdl_t; - /** * @brief Operating mode of x- and y-axis for LIS3MDL */ @@ -98,25 +90,37 @@ typedef enum { LIS3MDL_OP_PDOWN = 0x11, /**< Power-down mode */ } lis3mdl_op_t; +/** + * @brief Device initialization parameters + */ +typedef struct { + i2c_t i2c; /**< I2C device */ + uint8_t addr; /**< Magnometer I2C address */ + lis3mdl_xy_mode_t xy_mode; /**< Power mode of x- and y-axis */ + lis3mdl_z_mode_t z_mode; /**< Power mode of z-axis */ + lis3mdl_odr_t odr; /**< Output data rate */ + lis3mdl_scale_t scale; /**< Scale factor */ + lis3mdl_op_t op_mode; /**< Operation mode */ +} lis3mdl_params_t; + + +/** + * @brief Device descriptor for LIS3MDL sensor + */ +typedef struct { + lis3mdl_params_t params; /**< Initialization parameters */ +} lis3mdl_t; + /** * @brief Initialize a new LIS3DML device. * * @param[in] dev device descriptor of LIS3MDL - * @param[in] i2c I2C device connected to - * @param[in] address I2C address of the magnometer - * @param[in] xy_mode power mode of x- and y-axis - * @param[in] z_mode power mode of z-axis - * @param[in] odr output data rate of magnometer - * @param[in] scale scale configuration of magnometer - * @param[in] op_mode operation mode of the device + * @param[in] params initialization parameters * * @return 0 on success * @return -1 on error */ -int lis3mdl_init(lis3mdl_t *dev, i2c_t i2c, uint8_t address, - lis3mdl_xy_mode_t xy_mode, lis3mdl_z_mode_t z_mode, - lis3mdl_odr_t odr, lis3mdl_scale_t scale, - lis3mdl_op_t op_mode); +int lis3mdl_init(lis3mdl_t *dev, const lis3mdl_params_t *params); /** * @brief Reads the magnometer value of LIS3MDL. diff --git a/drivers/lis3mdl/include/lis3mdl_params.h b/drivers/lis3mdl/include/lis3mdl_params.h new file mode 100644 index 0000000000..1ad49976cd --- /dev/null +++ b/drivers/lis3mdl/include/lis3mdl_params.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2017 Inria + * + * 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_lis3mdl + * + * @{ + * @file + * @brief Default configuration for LIS3MDL devices + * + * @author Alexandre Abadie + */ + +#ifndef LIS3MDL_PARAMS_H +#define LIS3MDL_PARAMS_H + +#include "board.h" +#include "lis3mdl.h" +#include "saul_reg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Set default configuration parameters + * @{ + */ +#ifndef LIS3MDL_PARAM_I2C +#define LIS3MDL_PARAM_I2C (I2C_DEV(0)) +#endif +#ifndef LIS3MDL_PARAM_ADDR +#define LIS3MDL_PARAM_ADDR (0x1E) +#endif +#ifndef LIS3MDL_PARAM_XYMODE +#define LIS3MDL_PARAM_XYMODE (LIS3MDL_XY_MODE_HIGH) +#endif +#ifndef LIS3MDL_PARAM_ZMODE +#define LIS3MDL_PARAM_ZMODE (LIS3MDL_Z_MODE_HIGH) +#endif +#ifndef LIS3MDL_PARAM_ODR +#define LIS3MDL_PARAM_ODR (LIS3MDL_ODR_10Hz) +#endif +#ifndef LIS3MDL_PARAM_SCALE +#define LIS3MDL_PARAM_SCALE (4) +#endif +#ifndef LIS3MDL_PARAM_OPMODE +#define LIS3MDL_PARAM_OPMODE (LIS3MDL_OP_CONT_CONV) +#endif + +#ifndef LIS3MDL_PARAMS +#define LIS3MDL_PARAMS { .i2c = LIS3MDL_PARAM_I2C, \ + .addr = LIS3MDL_PARAM_ADDR, \ + .xy_mode = LIS3MDL_PARAM_XYMODE, \ + .z_mode = LIS3MDL_PARAM_ZMODE, \ + .odr = LIS3MDL_PARAM_SCALE, \ + .scale = LIS3MDL_PARAM_ODR, \ + .op_mode = LIS3MDL_PARAM_OPMODE } +#endif +#ifndef LIS3MDL_SAUL_INFO +#define LIS3MDL_SAUL_INFO { .name = "lis3mdl" } +#endif +/**@}*/ + +/** + * @brief Allocate some memory to store the actual configuration + */ +static const lis3mdl_params_t lis3mdl_params[] = +{ + LIS3MDL_PARAMS +}; + +/** + * @brief Additional meta information to keep in the SAUL registry + */ +static const saul_reg_info_t lis3mdl_saul_info[] = +{ + LIS3MDL_SAUL_INFO +}; + +#ifdef __cplusplus +} +#endif + +#endif /* LIS3MDL_PARAMS_H */ +/** @} */ diff --git a/drivers/lis3mdl/lis3mdl.c b/drivers/lis3mdl/lis3mdl.c index 665bfa7222..e9612907ed 100644 --- a/drivers/lis3mdl/lis3mdl.c +++ b/drivers/lis3mdl/lis3mdl.c @@ -32,6 +32,9 @@ #define GAUSS_DIVIDER (1000) +#define DEV_I2C (dev->params.i2c) +#define DEV_ADDR (dev->params.addr) + /** * @brief Takes an unsigned value representing a two's complement number * and returns the signed number it represents @@ -51,47 +54,41 @@ } } -int lis3mdl_init(lis3mdl_t *dev, - i2c_t i2c, - uint8_t address, - lis3mdl_xy_mode_t xy_mode, - lis3mdl_z_mode_t z_mode, - lis3mdl_odr_t odr, - lis3mdl_scale_t scale, - lis3mdl_op_t op_mode) { +int lis3mdl_init(lis3mdl_t *dev, const lis3mdl_params_t *params) +{ + dev->params = *params; + uint8_t tmp; - dev->i2c = i2c; - dev->addr = address; + i2c_acquire(DEV_I2C); - i2c_acquire(dev->i2c); - - if (i2c_init_master(i2c, I2C_SPEED_NORMAL) < 0) { + if (i2c_init_master(DEV_I2C, I2C_SPEED_NORMAL) < 0) { DEBUG("LIS3MDL: Master initialization failed\n"); return -1; } - i2c_read_reg(dev->i2c, dev->addr, LIS3DML_WHO_AM_I_REG, &tmp); + i2c_read_reg(DEV_I2C, DEV_ADDR, LIS3DML_WHO_AM_I_REG, &tmp); if (tmp != LIS3MDL_CHIP_ID) { - DEBUG("LIS3MDL: Identification failed\n"); + DEBUG("LIS3MDL: Identification failed, %02X != %02X\n", + tmp, LIS3MDL_CHIP_ID); return -1; } tmp = ( LIS3MDL_MASK_REG1_TEMP_EN /* enable temperature sensor */ - | xy_mode /* set x-, y-axis operative mode */ - | odr); /* set output data rate */ - i2c_write_reg(dev->i2c, dev->addr, LIS3MDL_CTRL_REG1, tmp); + | dev->params.xy_mode /* set x-, y-axis operative mode */ + | dev->params.odr); /* set output data rate */ + i2c_write_reg(DEV_I2C, DEV_ADDR, LIS3MDL_CTRL_REG1, tmp); /* set Full-scale configuration */ - i2c_write_reg(dev->i2c, dev->addr, LIS3MDL_CTRL_REG2, scale); + i2c_write_reg(DEV_I2C, DEV_ADDR, LIS3MDL_CTRL_REG2, dev->params.scale); /* set continuous-conversion mode */ - i2c_write_reg(dev->i2c, dev->addr, LIS3MDL_CTRL_REG3, op_mode); + i2c_write_reg(DEV_I2C, DEV_ADDR, LIS3MDL_CTRL_REG3, dev->params.op_mode); /* set z-axis operative mode */ - i2c_write_reg(dev->i2c, dev->addr, LIS3MDL_CTRL_REG4, z_mode); + i2c_write_reg(DEV_I2C, DEV_ADDR, LIS3MDL_CTRL_REG4, dev->params.z_mode); - i2c_release(dev->i2c); + i2c_release(DEV_I2C); return 0; } @@ -100,15 +97,15 @@ void lis3mdl_read_mag(const lis3mdl_t *dev, lis3mdl_3d_data_t *data) { uint8_t tmp[2] = {0, 0}; - i2c_acquire(dev->i2c); + i2c_acquire(DEV_I2C); - i2c_read_regs(dev->i2c, dev->addr, LIS3MDL_OUT_X_L_REG, &tmp[0], 2); + i2c_read_regs(DEV_I2C, DEV_ADDR, LIS3MDL_OUT_X_L_REG, &tmp[0], 2); data->x_axis = (tmp[1] << 8) | tmp[0]; - i2c_read_regs(dev->i2c, dev->addr, LIS3MDL_OUT_Y_L_REG, &tmp[0], 2); + i2c_read_regs(DEV_I2C, DEV_ADDR, LIS3MDL_OUT_Y_L_REG, &tmp[0], 2); data->y_axis = (tmp[1] << 8) | tmp[0]; - i2c_read_regs(dev->i2c, dev->addr, LIS3MDL_OUT_Z_L_REG, &tmp[0], 2); + i2c_read_regs(DEV_I2C, DEV_ADDR, LIS3MDL_OUT_Z_L_REG, &tmp[0], 2); data->z_axis = (tmp[1] << 8) | tmp[0]; data->x_axis = _twos_complement(data->x_axis); @@ -120,14 +117,14 @@ void lis3mdl_read_mag(const lis3mdl_t *dev, lis3mdl_3d_data_t *data) data->y_axis /= GAUSS_DIVIDER; data->z_axis /= GAUSS_DIVIDER; - i2c_release(dev->i2c); + i2c_release(DEV_I2C); } void lis3mdl_read_temp(const lis3mdl_t *dev, int16_t *value) { - i2c_acquire(dev->i2c); - i2c_read_regs(dev->i2c, dev->addr, LIS3MDL_TEMP_OUT_L_REG, (uint8_t*)value, 2); - i2c_release(dev->i2c); + i2c_acquire(DEV_I2C); + i2c_read_regs(DEV_I2C, DEV_ADDR, LIS3MDL_TEMP_OUT_L_REG, (uint8_t*)value, 2); + i2c_release(DEV_I2C); *value = _twos_complement(*value); @@ -136,11 +133,11 @@ void lis3mdl_read_temp(const lis3mdl_t *dev, int16_t *value) void lis3mdl_enable(const lis3mdl_t *dev) { - i2c_acquire(dev->i2c); + i2c_acquire(DEV_I2C); /* Z-axis medium-power mode */ - i2c_write_reg(dev->i2c, dev->addr, + i2c_write_reg(DEV_I2C, DEV_ADDR, LIS3MDL_CTRL_REG3, LIS3MDL_MASK_REG3_Z_MEDIUM_POWER); - i2c_release(dev->i2c); + i2c_release(DEV_I2C); } void lis3mdl_disable(const lis3mdl_t *dev) @@ -148,7 +145,7 @@ void lis3mdl_disable(const lis3mdl_t *dev) uint8_t tmp = ( LIS3MDL_MASK_REG3_LOW_POWER_EN /**< enable power-down mode */ | LIS3MDL_MASK_REG3_Z_LOW_POWER); /**< Z-axis low-power mode */ - i2c_acquire(dev->i2c); - i2c_write_reg(dev->i2c, dev->addr, LIS3MDL_CTRL_REG3, tmp); - i2c_release(dev->i2c); + i2c_acquire(DEV_I2C); + i2c_write_reg(DEV_I2C, DEV_ADDR, LIS3MDL_CTRL_REG3, tmp); + i2c_release(DEV_I2C); } diff --git a/drivers/lis3mdl/lis3mdl_saul.c b/drivers/lis3mdl/lis3mdl_saul.c new file mode 100644 index 0000000000..7c2c973ebb --- /dev/null +++ b/drivers/lis3mdl/lis3mdl_saul.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2017 Inria + * + * 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_lis3mdl + * @{ + * + * @file + * @brief LIS3MDL adaption to the RIOT actuator/sensor interface + * + * @author Alexandre Abadie + * + * @} + */ + +#include + +#include "saul.h" +#include "lis3mdl.h" + +static int read_mag(const void *dev, phydat_t *res) +{ + const lis3mdl_t *d = (const lis3mdl_t *)dev; + + lis3mdl_read_mag(d, (lis3mdl_3d_data_t *)res); + + res->unit = UNIT_GS; + res->scale = -3; + return 3; +} + +const saul_driver_t lis3mdl_saul_mag_driver = { + .read = read_mag, + .write = saul_notsup, + .type = SAUL_SENSE_MAG, +}; diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index c482210bf5..aa3768f04f 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -274,6 +274,10 @@ void auto_init(void) extern void auto_init_lis3dh(void); auto_init_lis3dh(); #endif +#ifdef MODULE_LIS3MDL +extern void auto_init_lis3mdl(void); +auto_init_lis3mdl(); +#endif #ifdef MODULE_MAG3110 extern void auto_init_mag3110(void); auto_init_mag3110(); diff --git a/sys/auto_init/saul/auto_init_lis3mdl.c b/sys/auto_init/saul/auto_init_lis3mdl.c new file mode 100644 index 0000000000..9febe34aef --- /dev/null +++ b/sys/auto_init/saul/auto_init_lis3mdl.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2017 Inria + * + * 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 auto_init_saul + * @{ + * + * @file + * @brief Auto initialization of LIS3MDL magnetometer + * + * @author Alexandre Abadie + * + * @} + */ + +#ifdef MODULE_LIS3MDL + +#include "log.h" +#include "saul_reg.h" +#include "lis3mdl.h" +#include "lis3mdl_params.h" + +/** + * @brief Define the number of configured sensors + */ +#define LIS3MDL_NUM (sizeof(lis3mdl_params)/sizeof(lis3mdl_params[0])) + +/** + * @brief Allocate memory for the device descriptors + */ +static lis3mdl_t lis3mdl_devs[LIS3MDL_NUM]; + +/** + * @brief Memory for the SAUL registry entries + */ +static saul_reg_t saul_entries[LIS3MDL_NUM]; + +/** + * @brief Define the number of saul info + */ +#define LIS3MDL_INFO_NUM (sizeof(lis3mdl_saul_info)/sizeof(lis3mdl_saul_info[0])) + +/** + * @brief Reference the driver structs + */ +extern saul_driver_t lis3mdl_saul_mag_driver; + +void auto_init_lis3mdl(void) +{ + assert(LIS3MDL_NUM == LIS3MDL_INFO_NUM); + + for (unsigned int i = 0; i < LIS3MDL_NUM; i++) { + LOG_DEBUG("[auto_init_saul] initializing lis3mdl #%u\n", i); + + if (lis3mdl_init(&lis3mdl_devs[i], &lis3mdl_params[i]) < 0) { + LOG_ERROR("[auto_init_saul] error initializing lis3mdl #%u\n", i); + continue; + } + + saul_entries[i].dev = &(lis3mdl_devs[i]); + saul_entries[i].name = lis3mdl_saul_info[i].name; + saul_entries[i].driver = &lis3mdl_saul_mag_driver; + saul_reg_add(&(saul_entries[i])); + } +} + +#else +typedef int dont_be_pedantic; +#endif /* MODULE_LIS3MDL */ diff --git a/tests/driver_lis3mdl/Makefile b/tests/driver_lis3mdl/Makefile index a5b1b84777..301b1fd379 100644 --- a/tests/driver_lis3mdl/Makefile +++ b/tests/driver_lis3mdl/Makefile @@ -1,25 +1,7 @@ BOARD ?= limifrog-v1 include ../Makefile.tests_common -# only this board is known (yet) to provide the sensor LIS3MDL -BOARD_WHITELIST = limifrog-v1 - -FEATURES_REQUIRED = periph_i2c periph_gpio - USEMODULE += lis3mdl USEMODULE += xtimer -ifneq (,$(TEST_LIS3MDL_I2C)) - CFLAGS += -DTEST_LIS3MDL_I2C=$(TEST_LIS3MDL_I2C) -else - # set random default - CFLAGS += -DTEST_LIS3MDL_I2C=I2C_DEV\(1\) -endif -ifneq (,$(TEST_LIS3MDL_MAG_ADDR)) - CFLAGS += -DTEST_LIS3MDL_MAG_ADDR=$(TEST_LIS3MDL_MAG_ADDR) -else - # set random default 7 bit address - CFLAGS += -DTEST_LIS3MDL_MAG_ADDR=28 -endif - include $(RIOTBASE)/Makefile.include diff --git a/tests/driver_lis3mdl/main.c b/tests/driver_lis3mdl/main.c index f74af6b05e..f31da84a31 100644 --- a/tests/driver_lis3mdl/main.c +++ b/tests/driver_lis3mdl/main.c @@ -18,33 +18,23 @@ * * @} */ -#ifndef TEST_LIS3MDL_I2C -#error "TEST_LIS3MDL_I2C not defined" -#endif -#ifndef TEST_LIS3MDL_MAG_ADDR -#error "TEST_LIS3MDL_MAG_ADDR not defined" -#endif #include #include "xtimer.h" #include "lis3mdl.h" +#include "lis3mdl_params.h" #define SLEEP (800 * 800U) int main(void) { lis3mdl_t dev; - lis3mdl_3d_data_t mag_value; - int16_t temp_value = 0; - puts("\nLIS3MDL test application"); - printf("Initializing LIS3MDL sensor at I2C_%i ... \n", TEST_LIS3MDL_I2C); + puts("LIS3MDL test application"); + puts("Initializing LIS3MDL sensor"); - if (lis3mdl_init(&dev, TEST_LIS3MDL_I2C, TEST_LIS3MDL_MAG_ADDR, - LIS3MDL_XY_MODE_MEDIUM, - LIS3MDL_Z_MODE_MEDIUM, LIS3MDL_ODR_10Hz, - LIS3MDL_SCALE_4G, LIS3MDL_OP_CONT_CONV) == 0) { + if (lis3mdl_init(&dev, &lis3mdl_params[0]) == 0) { puts("[ OK ]\n"); } else { @@ -52,11 +42,15 @@ int main(void) return 1; } - while(1){ + while(1) { + lis3mdl_3d_data_t mag_value; lis3mdl_read_mag(&dev, &mag_value); - printf("Magnetometer [G]:\tX: %2d\tY: %2d\tZ: %2d\n", mag_value.x_axis, - mag_value.y_axis, - mag_value.z_axis); + printf("Magnetometer [G]:\tX: %2d\tY: %2d\tZ: %2d\n", + mag_value.x_axis, + mag_value.y_axis, + mag_value.z_axis); + + int16_t temp_value; lis3mdl_read_temp(&dev, &temp_value); printf("Temperature:\t\t%i°C\n", temp_value);