diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 64f61a969309fcb4705a06b537dbec3884d87843..b0307a1e1eb15f7af93ebe4c011c4b0c3f358322 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -123,6 +123,11 @@ ifneq (,$(filter feetech,$(USEMODULE))) USEMODULE += uart_half_duplex endif +ifneq (,$(filter fxos8700,$(USEMODULE))) + USEMODULE += xtimer + FEATURES_REQUIRED += periph_i2c +endif + ifneq (,$(filter grove_ledbar,$(USEMODULE))) USEMODULE += my9221 endif diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 4f6c8687e6eef027b6ab2dfd50e54f965cceca36..72c0e6117abe3b946a1011fb7b86fd879f0d478b 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -70,6 +70,10 @@ ifneq (,$(filter feetech,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/feetech/include endif +ifneq (,$(filter fxos8700,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/fxos8700/include +endif + ifneq (,$(filter grove_ledbar,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/grove_ledbar/include endif diff --git a/drivers/fxos8700/Makefile b/drivers/fxos8700/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..48422e909a47d7cd428d10fa73825060ccc8d8c2 --- /dev/null +++ b/drivers/fxos8700/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/fxos8700/fxos8700.c b/drivers/fxos8700/fxos8700.c new file mode 100644 index 0000000000000000000000000000000000000000..1fb216cef8c4fa5ae4532409c82f53b6895faea2 --- /dev/null +++ b/drivers/fxos8700/fxos8700.c @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2018 UC Berkeley + * + * 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. + */ + +/** + * @file + * @brief Driver for the FXOS8700 3-axis accelerometer/magnetometer + * + * @author Michael Andersen <m.andersen@cs.berkeley.edu> + * @author Hyung-Sin Kim <hs.kim@cs.berkeleyedu> + */ + + +#include "periph/i2c.h" +#include "xtimer.h" +#include "fxos8700.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define I2C_SPEED I2C_SPEED_FAST + +#define FXOS8700_FULLDATA_LENGTH (12) + +static int fxos8700_read_regs(const fxos8700_t* dev, uint8_t reg, uint8_t* data, size_t len) +{ + i2c_acquire(dev->p.i2c); + if (i2c_read_regs(dev->p.i2c, dev->p.addr, reg, (char*) data, len) <= 0) { + DEBUG("[fxos8700] Can't read register 0x%x\n", reg); + i2c_release(dev->p.i2c); + return FXOS8700_BUSERR; + } + i2c_release(dev->p.i2c); + + return FXOS8700_OK; +} + +static int fxos8700_write_regs(const fxos8700_t* dev, uint8_t reg, uint8_t* data, size_t len) +{ + i2c_acquire(dev->p.i2c); + if (i2c_write_regs(dev->p.i2c, dev->p.addr, reg, (char*) data, len) <= 0) { + DEBUG("[fxos8700] Can't write to register 0x%x\n", reg); + i2c_release(dev->p.i2c); + return FXOS8700_BUSERR; + } + i2c_release(dev->p.i2c); + + return FXOS8700_OK; +} + +int fxos8700_init(fxos8700_t* dev, const fxos8700_params_t *params) +{ + uint8_t config; + + if ((params->addr < 0x1C) || (params->addr > 0x1F)) { + DEBUG("[fxos8700] Invalid address\n"); + return FXOS8700_ADDRERR; + } + dev->p.addr = params->addr; + dev->p.i2c = params->i2c; + dev->p.acc_range = params->acc_range; + dev->p.renew_interval = params->renew_interval; + + i2c_acquire(dev->p.i2c); + if (i2c_init_master(dev->p.i2c, I2C_SPEED) != 0) { + DEBUG("[fxos8700] Can't initialize I2C master\n"); + i2c_release(dev->p.i2c); + return FXOS8700_NOBUS; + } + + if (i2c_read_regs(dev->p.i2c, dev->p.addr, FXOS8700_REG_WHO_AM_I, &config, 1) <= 0) { + i2c_release(dev->p.i2c); + DEBUG("[fxos8700] Could not read WHOAMI\n"); + return FXOS8700_NOBUS; + } + if (config != FXOS8700_WHO_AM_I_VAL) { + i2c_release(dev->p.i2c); + DEBUG("[fxos8700] WHOAMI is wrong (%2x)\n", config); + return FXOS8700_NODEV; + } + i2c_release(dev->p.i2c); + + /* Configure the ODR to maximum (400Hz in hybrid mode) */ + config = FXOS8700_REG_CTRL_REG1_ODR__400HZ & FXOS8700_REG_CTRL_REG1_MASK__ODR; + if (fxos8700_write_regs(dev, FXOS8700_REG_CTRL_REG1, &config, 1) != FXOS8700_OK) { + return FXOS8700_BUSERR; + } + dev->config = config; + /* Activate hybrid mode */ + config = FXOS8700_REG_M_CTRL_REG1_HMS__HYBRID & FXOS8700_REG_M_CTRL_REG1_MASK__HMS; + if (fxos8700_write_regs(dev, FXOS8700_REG_M_CTRL_REG1, &config, 1) != FXOS8700_OK) { + return FXOS8700_BUSERR; + } + /* Set burst read mode (accel + magnet together) */ + config = FXOS8700_REG_M_CTRL_REG2_MASK__HYB_AUTOINC_MODE; + if (fxos8700_write_regs(dev, FXOS8700_REG_M_CTRL_REG2, &config, 1) != FXOS8700_OK) { + return FXOS8700_BUSERR; + } + /* Set accelerator's full-scale range */ + if (fxos8700_read_regs(dev, FXOS8700_REG_XYZ_DATA_CFG, &config, 1) != FXOS8700_OK) { + return FXOS8700_BUSERR; + } + config &= ~FXOS8700_REG_XYZ_DATA_CFG_MASK__FS; + config |= dev->p.acc_range & FXOS8700_REG_XYZ_DATA_CFG_MASK__FS; + if (fxos8700_write_regs(dev, FXOS8700_REG_XYZ_DATA_CFG, &config, 1) != FXOS8700_OK) { + return FXOS8700_BUSERR; + } + + /* initial read for caching operation */ + if (fxos8700_read(dev, &dev->acc_cached, &dev->mag_cached) != FXOS8700_OK) { + return FXOS8700_BUSERR; + } + dev->last_read_time = xtimer_now_usec(); + + return FXOS8700_OK; +} + + +int fxos8700_set_active(const fxos8700_t* dev) +{ + uint8_t config = dev->config | FXOS8700_REG_CTRL_REG1_MASK__ACTIVE; + if (fxos8700_write_regs(dev, FXOS8700_REG_CTRL_REG1, &config, 1) != FXOS8700_OK) { + return FXOS8700_BUSERR; + } + return FXOS8700_OK; +} + +int fxos8700_set_idle(const fxos8700_t* dev) +{ + uint8_t config = dev->config & ~FXOS8700_REG_CTRL_REG1_MASK__ACTIVE; + if (fxos8700_write_regs(dev, FXOS8700_REG_CTRL_REG1, &config, 1) != FXOS8700_OK) { + return FXOS8700_BUSERR; + } + return FXOS8700_OK; +} + +int fxos8700_read(const fxos8700_t* dev, fxos8700_measurement_t* acc, + fxos8700_measurement_t* mag) +{ + uint8_t data[12]; + uint8_t ready = 0; + + if (fxos8700_set_active(dev)) { + return FXOS8700_BUSERR; + } + + while (!(ready & FXOS8700_REG_STATUS_MASK__XYZ_READY)) { + fxos8700_read_regs(dev, FXOS8700_REG_STATUS, &ready, 1); + } + while (!(ready & FXOS8700_REG_M_DR_STATUS_MASK__XYZ_READY)) { + fxos8700_read_regs(dev, FXOS8700_REG_M_DR_STATUS, &ready, 1); + } + + /* Read all data at once */ + if (fxos8700_read_regs(dev, FXOS8700_REG_OUT_X_MSB, &data[0], FXOS8700_FULLDATA_LENGTH)) { + return FXOS8700_BUSERR; + } + + if (fxos8700_set_idle(dev)) { + return FXOS8700_BUSERR; + } + + /* Read accelerometer */ + if (acc) { +#if FXOS8700_USE_ACC_RAW_VALUES + acc->x = (int16_t) ((data[0] << 8) | data[1]) >> 2; + acc->y = (int16_t) ((data[2] << 8) | data[3]) >> 2; + acc->z = (int16_t) ((data[4] << 8) | data[5]) >> 2; +#else + int32_t acc_raw_x = (int16_t) ((data[0] << 8) | data[1]) >> 2; + int32_t acc_raw_y = (int16_t) ((data[2] << 8) | data[3]) >> 2; + int32_t acc_raw_z = (int16_t) ((data[4] << 8) | data[5]) >> 2; + switch(dev->p.acc_range) { + case FXOS8700_REG_XYZ_DATA_CFG_FS__2G: + acc->x = (int16_t) ((acc_raw_x * 244) / 100); + acc->y = (int16_t) ((acc_raw_y * 244) / 100); + acc->z = (int16_t) ((acc_raw_z * 244) / 100); + break; + case FXOS8700_REG_XYZ_DATA_CFG_FS__4G: + acc->x = (int16_t) ((acc_raw_x * 488) / 1000); + acc->y = (int16_t) ((acc_raw_y * 488) / 1000); + acc->z = (int16_t) ((acc_raw_z * 488) / 1000); + break; + case FXOS8700_REG_XYZ_DATA_CFG_FS__8G: + acc->x = (int16_t) ((acc_raw_x * 976) / 1000); + acc->y = (int16_t) ((acc_raw_y * 976) / 1000); + acc->z = (int16_t) ((acc_raw_z * 976) / 1000); + break; + default: + return FXOS8700_NODEV; + } +#endif + } + /* Read magnetometer */ + if (mag) { + mag->x = (int16_t) ((data[6] << 8) | data[7]); + mag->y = (int16_t) ((data[8] << 8) | data[9]); + mag->z = (int16_t) ((data[10] << 8) | data[11]); + } + return FXOS8700_OK; +} + +int fxos8700_read_cached(const void *dev, fxos8700_measurement_t* acc, + fxos8700_measurement_t* mag) +{ + fxos8700_t* fxos_dev = (fxos8700_t *)dev; + uint32_t now = xtimer_now_usec(); + + /* check if readings are outdated */ + if (now - fxos_dev->last_read_time > fxos_dev->p.renew_interval) { + /* refresh cache and update last_read_time */ + if (fxos8700_read(fxos_dev, &fxos_dev->acc_cached, &fxos_dev->mag_cached) + != FXOS8700_OK) { + return FXOS8700_BUSERR; + } + fxos_dev->last_read_time = now; + } + + /* Read cached data */ + if (acc) { + acc->x = fxos_dev->acc_cached.x; + acc->y = fxos_dev->acc_cached.y; + acc->z = fxos_dev->acc_cached.z; + } + if (mag) { + mag->x = fxos_dev->mag_cached.x; + mag->y = fxos_dev->mag_cached.y; + mag->z = fxos_dev->mag_cached.z; + } + return FXOS8700_OK; +} diff --git a/drivers/fxos8700/fxos8700_saul.c b/drivers/fxos8700/fxos8700_saul.c new file mode 100644 index 0000000000000000000000000000000000000000..adc13877f3a3b51f410b6f97446b235cd064f857 --- /dev/null +++ b/drivers/fxos8700/fxos8700_saul.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2018 UC Berkeley + * + * 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_fxos8700 + * @{ + * + * @file + * @brief FXOS8700 adaption to the RIOT actuator/sensor interface + * + * @author Hyung-Sin Kim <hs.kim@cs.berkeley.edu> + * + * @} + */ + +#include <string.h> + +#include "saul.h" +#include "fxos8700.h" + +static int read_mag(const void *dev, phydat_t *res) +{ + if (fxos8700_read_cached(dev, NULL, (fxos8700_measurement_t *)res) + != FXOS8700_OK) { + /* Read failure */ + return -ECANCELED; + } + res->unit = UNIT_GS; + res->scale = -3; + return 3; +} + +static int read_acc(const void *dev, phydat_t *res) +{ + if (fxos8700_read_cached(dev, (fxos8700_measurement_t *)res, NULL) + != FXOS8700_OK) { + /* Read failure */ + return -ECANCELED; + } +#if FXOS8700_USE_ACC_RAW_VALUES + res->unit = UNIT_NONE; + res->scale = 0; +#else + res->unit = UNIT_G; + if (((fxos8700_t *)dev)->p.acc_range == FXOS8700_REG_XYZ_DATA_CFG_FS__2G) { + res->scale = -4; + } else { + res->scale = -3; + } +#endif + return 3; +} + +const saul_driver_t fxos8700_saul_mag_driver = { + .read = read_mag, + .write = saul_notsup, + .type = SAUL_SENSE_MAG, +}; + +const saul_driver_t fxos8700_saul_acc_driver = { + .read = read_acc, + .write = saul_notsup, + .type = SAUL_SENSE_ACCEL, +}; diff --git a/drivers/fxos8700/include/fxos8700_params.h b/drivers/fxos8700/include/fxos8700_params.h new file mode 100644 index 0000000000000000000000000000000000000000..2ceed74237c2c0fd1dbd7350ef10eb14178a2296 --- /dev/null +++ b/drivers/fxos8700/include/fxos8700_params.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018 UC Berkeley + * + * 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_fxos8700 + * + * @{ + * @file + * @brief Default configuration for FXOS8700 devices + * + * @author Hyung-Sin Kim <hs.kim@cs.berkeley.edu> + */ + +#ifndef FXOS8700_PARAMS_H +#define FXOS8700_PARAMS_H + +#include "board.h" +#include "fxos8700.h" +#include "saul_reg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Default configuration parameters for the FXOS8700 driver + * + * The valid address range is 0x1E - 0x1F depending on the configuration of the + * address pins SA0 and SA1. + * + * @{ + */ +#ifndef FXOS8700_PARAM_I2C +#define FXOS8700_PARAM_I2C I2C_DEV(0) +#endif +#ifndef FXOS8700_PARAM_ADDR +#define FXOS8700_PARAM_ADDR 0x1E +#endif +#ifndef FXOS8700_PARAM_ACC_RANGE +#define FXOS8700_PARAM_ACC_RANGE FXOS8700_REG_XYZ_DATA_CFG_FS__8G +#endif +#ifndef FXOS8700_PARAM_RENEW_INTERVAL +#define FXOS8700_PARAM_RENEW_INTERVAL 1000000ul +#endif + +#ifndef FXOS8700_PARAMS +#define FXOS8700_PARAMS { .i2c = FXOS8700_PARAM_I2C, \ + .addr = FXOS8700_PARAM_ADDR, \ + .acc_range = FXOS8700_PARAM_ACC_RANGE, \ + .renew_interval = FXOS8700_PARAM_RENEW_INTERVAL } +#endif +#ifndef FXOS8700_SAUL_INFO +#define FXOS8700_SAUL_INFO { .name = "fxos8700" } +#endif +/**@}*/ + +/** + * @brief FXOS8700 configuration + */ +static const fxos8700_params_t fxos8700_params[] = +{ + FXOS8700_PARAMS +}; + +/** + * @brief Additional meta information to keep in the SAUL registry + */ +static const saul_reg_info_t fxos8700_saul_info[] = +{ + FXOS8700_SAUL_INFO +}; + +#ifdef __cplusplus +} +#endif + +#endif /* FXOS8700_PARAMS_H */ +/** @} */ diff --git a/drivers/fxos8700/include/fxos8700_regs.h b/drivers/fxos8700/include/fxos8700_regs.h new file mode 100644 index 0000000000000000000000000000000000000000..c0f235ab698588905e4b7b70b7430c83e72ff09f --- /dev/null +++ b/drivers/fxos8700/include/fxos8700_regs.h @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2018 UC Berkeley + * + * 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_fxos8700 + * @{ + * + * @file + * @brief Register definitions for FXOS8700 devices + * + * @author Michael Andersen <m.andersen@cs.berkeley.edu> + * @author Hyung-Sin Kim <hs.kim@cs.berkeley.edu> + */ + +#ifndef FXOS8700_REGS_H +#define FXOS8700_REGS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @name FXOS8700 register addresses + * @{ + */ +#define FXOS8700_REG_STATUS (0x00) +#define FXOS8700_REG_OUT_X_MSB (0x01) +#define FXOS8700_REG_OUT_X_LSB (0x02) +#define FXOS8700_REG_OUT_Y_MSB (0x03) +#define FXOS8700_REG_OUT_Y_LSB (0x04) +#define FXOS8700_REG_OUT_Z_MSB (0x05) +#define FXOS8700_REG_OUT_Z_LSB (0x06) +#define FXOS8700_REG_F_SETUP (0x09) +#define FXOS8700_REG_TRIG_CFG (0x0A) +#define FXOS8700_REG_SYSMOD (0x0B) +#define FXOS8700_REG_INT_SOURCE (0x0C) +#define FXOS8700_REG_WHO_AM_I (0x0D) +#define FXOS8700_REG_XYZ_DATA_CFG (0x0E) +#define FXOS8700_REG_HP_FILTER_CUTOFF (0x0F) +#define FXOS8700_REG_PL_STATUS (0x10) +#define FXOS8700_REG_PL_CFG (0x11) +#define FXOS8700_REG_PL_COUNT (0x12) +#define FXOS8700_REG_PL_BF_ZCOMP (0x13) +#define FXOS8700_REG_PL_THS_REG (0x14) +#define FXOS8700_REG_A_FFMT_CFG (0x15) +#define FXOS8700_REG_A_FFMT_SRC (0x16) +#define FXOS8700_REG_A_FFMT_THS (0x17) +#define FXOS8700_REG_A_FFMT_COUNT (0x18) +#define FXOS8700_REG_TRANSIENT_CFG (0x1D) +#define FXOS8700_REG_TRANSIENT_SRC (0x1E) +#define FXOS8700_REG_TRANSIENT_THS (0x1F) +#define FXOS8700_REG_TRANSIENT_COUNT (0x20) +#define FXOS8700_REG_PULSE_CFG (0x21) +#define FXOS8700_REG_PULSE_SRC (0x22) +#define FXOS8700_REG_PULSE_THSX (0x23) +#define FXOS8700_REG_PULSE_THSY (0x24) +#define FXOS8700_REG_PULSE_THSZ (0x25) +#define FXOS8700_REG_PULSE_TMLT (0x26) +#define FXOS8700_REG_PULSE_LTCY (0x27) +#define FXOS8700_REG_PULSE_WIND (0x28) +#define FXOS8700_REG_ASLP_COUNT (0x29) +#define FXOS8700_REG_CTRL_REG1 (0x2A) +#define FXOS8700_REG_CTRL_REG2 (0x2B) +#define FXOS8700_REG_CTRL_REG3 (0x2C) +#define FXOS8700_REG_CTRL_REG4 (0x2D) +#define FXOS8700_REG_CTRL_REG5 (0x2E) +#define FXOS8700_REG_OFF_X (0x2F) +#define FXOS8700_REG_OFF_Y (0x30) +#define FXOS8700_REG_OFF_Z (0x31) +#define FXOS8700_REG_M_DR_STATUS (0x32) +#define FXOS8700_REG_M_OUT_X_MSB (0x33) +#define FXOS8700_REG_M_OUT_X_LSB (0x34) +#define FXOS8700_REG_M_OUT_Y_MSB (0x35) +#define FXOS8700_REG_M_OUT_Y_LSB (0x36) +#define FXOS8700_REG_M_OUT_Z_MSB (0x37) +#define FXOS8700_REG_M_OUT_Z_LSB (0x38) +#define FXOS8700_REG_CMP_X_MSB (0x39) +#define FXOS8700_REG_CMP_X_LSB (0x3A) +#define FXOS8700_REG_CMP_Y_MSB (0x3B) +#define FXOS8700_REG_CMP_Y_LSB (0x3C) +#define FXOS8700_REG_CMP_Z_MSB (0x3D) +#define FXOS8700_REG_CMP_Z_LSB (0x3E) +#define FXOS8700_REG_M_OFF_X_MSB (0x3F) +#define FXOS8700_REG_M_OFF_X_LSB (0x40) +#define FXOS8700_REG_M_OFF_Y_MSB (0x41) +#define FXOS8700_REG_M_OFF_Y_LSB (0x42) +#define FXOS8700_REG_M_OFF_Z_MSB (0x43) +#define FXOS8700_REG_M_OFF_Z_LSB (0x44) +#define FXOS8700_REG_MAX_X_MSB (0x45) +#define FXOS8700_REG_MAX_X_LSB (0x46) +#define FXOS8700_REG_MAX_Y_MSB (0x47) +#define FXOS8700_REG_MAX_Y_LSB (0x48) +#define FXOS8700_REG_MAX_Z_MSB (0x49) +#define FXOS8700_REG_MAX_Z_LSB (0x4A) +#define FXOS8700_REG_MIN_X_MSB (0x4B) +#define FXOS8700_REG_MIN_X_LSB (0x4C) +#define FXOS8700_REG_MIN_Y_MSB (0x4D) +#define FXOS8700_REG_MIN_Y_LSB (0x4E) +#define FXOS8700_REG_MIN_Z_MSB (0x4F) +#define FXOS8700_REG_MIN_Z_LSB (0x50) +#define FXOS8700_REG_TEMP (0x51) +#define FXOS8700_REG_M_THS_CFG (0x52) +#define FXOS8700_REG_M_THS_SRC (0x53) +#define FXOS8700_REG_M_THS_X_MSB (0x54) +#define FXOS8700_REG_M_THS_X_LSB (0x55) +#define FXOS8700_REG_M_THS_Y_MSB (0x56) +#define FXOS8700_REG_M_THS_Y_LSB (0x57) +#define FXOS8700_REG_M_THS_Z_MSB (0x58) +#define FXOS8700_REG_M_THS_Z_LSB (0x59) +#define FXOS8700_REG_M_THS_COUNT (0x5A) +#define FXOS8700_REG_M_CTRL_REG1 (0x5B) +#define FXOS8700_REG_M_CTRL_REG2 (0x5C) +#define FXOS8700_REG_M_CTRL_REG3 (0x5D) +#define FXOS8700_REG_M_INT_SRC (0x5E) +#define FXOS8700_REG_A_VECM_CFG (0x5F) +#define FXOS8700_REG_A_VECM_THS_MSB (0x60) +#define FXOS8700_REG_A_VECM_THS_LSB (0x61) +#define FXOS8700_REG_A_VECM_CNT (0x62) +#define FXOS8700_REG_A_VECM_INITX_MSB (0x63) +#define FXOS8700_REG_A_VECM_INITX_LSB (0x64) +#define FXOS8700_REG_A_VECM_INITY_MSB (0x65) +#define FXOS8700_REG_A_VECM_INITY_LSB (0x66) +#define FXOS8700_REG_A_VECM_INITZ_MSB (0x67) +#define FXOS8700_REG_A_VECM_INITZ_LSB (0x68) +#define FXOS8700_REG_M_VECM_CFG (0x69) +#define FXOS8700_REG_M_VECM_THS_MSB (0x6A) +#define FXOS8700_REG_M_VECM_THS_LSB (0x6B) +#define FXOS8700_REG_M_VECM_CNT (0x6C) +#define FXOS8700_REG_M_VECM_INITX_MSB (0x6D) +#define FXOS8700_REG_M_VECM_INITX_LSB (0x6E) +#define FXOS8700_REG_M_VECM_INITY_MSB (0x6F) +#define FXOS8700_REG_M_VECM_INITY_LSB (0x70) +#define FXOS8700_REG_M_VECM_INITZ_MSB (0x71) +#define FXOS8700_REG_M_VECM_INITZ_LSB (0x72) +#define FXOS8700_REG_A_FFMT_THS_X_MSB (0x73) +#define FXOS8700_REG_A_FFMT_THS_X_LSB (0x74) +#define FXOS8700_REG_A_FFMT_THS_Y_MSB (0x75) +#define FXOS8700_REG_A_FFMT_THS_Y_LSB (0x76) +#define FXOS8700_REG_A_FFMT_THS_Z_MSB (0x77) +#define FXOS8700_REG_A_FFMT_THS_Z_LSB (0x78) +/** @} */ + +/** + * @name Device ID + * @{ + */ +#define FXOS8700_WHO_AM_I_VAL (0xC7) +/** @} */ + +/** + * @name Data ready status + * @{ + */ +#define FXOS8700_REG_STATUS_MASK__XYZ_READY (0x08) +#define FXOS8700_REG_M_DR_STATUS_MASK__XYZ_READY (0x08) +/** @} */ + +/** + * @name Output data rate (ODR) and Active mode configuration + * @{ + */ +#define FXOS8700_REG_CTRL_REG1_MASK__ODR (0x38) +#define FXOS8700_REG_CTRL_REG1_ODR__400HZ (0x00) +#define FXOS8700_REG_CTRL_REG1_ODR__200HZ (0x08) +#define FXOS8700_REG_CTRL_REG1_ODR__100HZ (0x10) +#define FXOS8700_REG_CTRL_REG1_ODR__50HZ (0x18) +#define FXOS8700_REG_CTRL_REG1_ODR__25HZ (0x20) + +#define FXOS8700_REG_CTRL_REG1_MASK__ACTIVE (0x01) +/** @} */ + +/** + * @name Sensing mode configuration + * @{ + */ +#define FXOS8700_REG_M_CTRL_REG1_MASK__HMS (0x03) +#define FXOS8700_REG_M_CTRL_REG1_HMS__ACC_ONLY (0x00) +#define FXOS8700_REG_M_CTRL_REG1_HMS__MAG_ONLY (0x01) +#define FXOS8700_REG_M_CTRL_REG1_HMS__HYBRID (0x03) +/** @} */ + +/** + * @name Burst-read mode configuration + * @{ + */ +#define FXOS8700_REG_M_CTRL_REG2_MASK__HYB_AUTOINC_MODE (0x20) +/** @} */ + +/** + * @name Accelerator full-scale range configuration + * @{ + */ +#define FXOS8700_REG_XYZ_DATA_CFG_MASK__FS (0x03) +#define FXOS8700_REG_XYZ_DATA_CFG_FS__2G (0x00) +#define FXOS8700_REG_XYZ_DATA_CFG_FS__4G (0x01) +#define FXOS8700_REG_XYZ_DATA_CFG_FS__8G (0x02) +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* FXOS8700_REGS_H */ +/** @} */ diff --git a/drivers/include/fxos8700.h b/drivers/include/fxos8700.h new file mode 100644 index 0000000000000000000000000000000000000000..f6cc1ea981943a1c04de001307a74a9f2e97d6bb --- /dev/null +++ b/drivers/include/fxos8700.h @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2018 UC Berkeley + * + * 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_fxos8700 FXOS8700 3-axis accelerometer/magnetometer + * @ingroup drivers_sensors + * @brief Driver for the FXOS8700 3-axis accelerometer/magnetometer + * + * The connection between the MCU and the FXOS8700 is based on the + * I2C-interface. + * + * @{ + * + * @file + * @brief Interface definition for the FXOS8700 sensor driver + * + * @author Michael Andersen <m.andersen@cs.berkeley.edu> + * @author Hyung-Sin Kim <hs.kim@cs.berkeley.edu> + */ + +#ifndef FXOS8700_H +#define FXOS8700_H + +#include <stdint.h> +#include "periph/i2c.h" +#include "fxos8700_regs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Default raw value mode for accelerator + * + * If set to 0, measurements will be converted to mg. + * If set to 1, raw adc readings will be returned. + */ +#ifndef FXOS8700_USE_ACC_RAW_VALUES +#define FXOS8700_USE_ACC_RAW_VALUES (0) +#endif + +/** + * @brief FXOS8700 specific return values + */ +enum { + FXOS8700_OK = 0, /**< everything went as expected */ + FXOS8700_ADDRERR = -1, /**< no FXOS8700 device found on the bus */ + FXOS8700_NOBUS = -2, /**< errors while initializing the I2C bus */ + FXOS8700_NODEV = -3, /**< no FXOS8700 device found on the bus */ + FXOS8700_BUSERR = -4 /**< error during I2C communication */ +}; + +/** + * @brief Parameters needed for device initialization + */ +typedef struct { + i2c_t i2c; /**< I2C device that sensor is connected to */ + uint8_t addr; /**< I2C address of this particular sensor */ + uint8_t acc_range; /**< Accelerator full-scale range */ + uint32_t renew_interval; /**< Interval for cache renewal */ +} fxos8700_params_t; + +/** + * @brief Individual 3-axis measurement + */ +typedef struct { + int16_t x; /**< x axis of 3-axis measurement */ + int16_t y; /**< y axis of 3-axis measurement */ + int16_t z; /**< z axis of 3-axis measurement */ +} fxos8700_measurement_t; + +/** + * @brief Device descriptor for a FXOS8700 device + */ +typedef struct { + uint8_t config; /**< sensor configuration including active mode */ + fxos8700_measurement_t acc_cached; /**< cached 3-axis acceleration */ + fxos8700_measurement_t mag_cached; /**< cached 3-axis magnetic field */ + uint32_t last_read_time; /**< last time when cached data was refreshed */ + fxos8700_params_t p; /**< configuration parameters */ +} fxos8700_t; + +/** + * @brief Initialize an FXOS8700 device + * + * @param[out] dev device descriptor + * @param[in] params parameters for device + * + * @return FXOS8700_OK on success + * @return FXOS8700_NOBUS on I2C initialization error + * @return FXOS8700_BUSERR on I2C communication error + * @return FXOS8700_ADDRERR on invalid address + * @return FXOS8700_NODEV if no FXOS8700 device found on bus + */ +int fxos8700_init(fxos8700_t* dev, const fxos8700_params_t* params); + +/** + * @brief Convenience function for turning on the FXOS8700 + * + * This function will trigger a new conversion, wait for the conversion to be + * finished and the get the results from the device. + * + * @param[in] dev device descriptor of sensor + * + * @return FXOS8700_OK on success + * @return FXOS8700_BUSERR on I2C communication failures + */ +int fxos8700_set_active(const fxos8700_t* dev); + +/** + * @brief Convenience function for turning off the FXOS8700 + * + * This function will trigger a new conversion, wait for the conversion to be + * finished and the get the results from the device. + * + * @param[in] dev device descriptor of sensor + * + * @return FXOS8700_OK on success + * @return FXOS8700_BUSERR on I2C communication failures + */ +int fxos8700_set_idle(const fxos8700_t* dev); + +/** + * @brief Convenience function for reading acceleration and magnetic field + * + * This function will trigger a new conversion, wait for the conversion to be + * finished and the get the results from the device. + * + * @param[in] dev device descriptor of sensor + * @param[out] acc 3-axis acceleration [in milli grativy acceleration (mg) ] + * @param[out] mag 3-axis magnetic field [in degree milli Gauss (mGs) ] + * + * @return FXOS8700_OK on success + * @return FXOS8700_BUSERR on I2C communication failures + */ +int fxos8700_read(const fxos8700_t* dev, fxos8700_measurement_t* acc, fxos8700_measurement_t* mag); + +/** + * @brief Extended read function including caching capability + * + * This function will return cached values if they are within the sampling + * period (FXOS8700_RENEW_INTERVAL), or will trigger a new conversion, wait for + * the conversion to be finished and the get the results from the device. + * + * @param[in] dev device descriptor of sensor + * @param[out] acc 3-axis acceleration [in milli grativy acceleration (mg) ] + * @param[out] mag 3-axis magnetic field [in degree milli Gauss (mGs) ] + * + * @return FXOS8700_OK on success + * @return FXOS8700_BUSERR on I2C communication failures + */ +int fxos8700_read_cached(const void* dev, fxos8700_measurement_t* acc, fxos8700_measurement_t* mag); +#ifdef __cplusplus +} +#endif + +#endif /* FXOS8700_H */ +/** @} */ diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 6cdaded5b3ddbc6a32b03f9e227bfdc93685fa0d..87e7459783031215d2c1cb1440e463e5cc651fff 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -353,6 +353,10 @@ auto_init_mpu9150(); extern void auto_init_hdc1000(void); auto_init_hdc1000(); #endif +#ifdef MODULE_FXOS8700 + extern void auto_init_fxos8700(void); + auto_init_fxos8700(); +#endif #ifdef MODULE_HTS221 extern void auto_init_hts221(void); auto_init_hts221(); diff --git a/sys/auto_init/saul/auto_init_fxos8700.c b/sys/auto_init/saul/auto_init_fxos8700.c new file mode 100644 index 0000000000000000000000000000000000000000..3c78b4cb1add99799f8bb615197b16f47919198b --- /dev/null +++ b/sys/auto_init/saul/auto_init_fxos8700.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 UC Berkeley + * + * 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 for FXOS8700 devices + * + * @author Hyung-Sin Kim <hs.kim@cs.berkeley.edu> + * + * @} + */ + +#ifdef MODULE_FXOS8700 + +#include "log.h" +#include "saul_reg.h" +#include "fxos8700_params.h" + +/** + * @brief Define the number of configured sensors + */ +#define FXOS8700_NUM (sizeof(fxos8700_params)/sizeof(fxos8700_params[0])) + +/** + * @brief Allocate memory for the device descriptors + */ +static fxos8700_t fxos8700_devs[FXOS8700_NUM]; + +/** + * @brief Memory for the SAUL registry entries + */ +static saul_reg_t saul_entries[FXOS8700_NUM * 2]; + +/** + * @name Reference the driver struct + * @{ + */ +extern saul_driver_t fxos8700_saul_acc_driver; +extern saul_driver_t fxos8700_saul_mag_driver; +/** @} */ + + +void auto_init_fxos8700(void) +{ + for (unsigned i = 0; i < FXOS8700_NUM; i++) { + LOG_DEBUG("[auto_init_saul] initializing fxos8700 #%u\n", i); + + int res = fxos8700_init(&fxos8700_devs[i], &fxos8700_params[i]); + if (res != 0) { + LOG_ERROR("[auto_init_saul] error initializing fxos8700 #%u\n", i); + } + else { + saul_entries[(i * 2)].dev = &(fxos8700_devs[i]); + saul_entries[(i * 2)].name = fxos8700_saul_info[i].name; + saul_entries[(i * 2)].driver = &fxos8700_saul_acc_driver; + saul_entries[(i * 2) + 1].dev = &(fxos8700_devs[i]); + saul_entries[(i * 2) + 1].name = fxos8700_saul_info[i].name; + saul_entries[(i * 2) + 1].driver = &fxos8700_saul_mag_driver; + saul_reg_add(&(saul_entries[(i * 2)])); + saul_reg_add(&(saul_entries[(i * 2) + 1])); + } + } +} + +#else +typedef int dont_be_pedantic; +#endif /* MODULE_FXOS8700 */ diff --git a/tests/driver_fxos8700/Makefile b/tests/driver_fxos8700/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d33ac2a1e9838bd36e74f9de7d6741eb12e08bcb --- /dev/null +++ b/tests/driver_fxos8700/Makefile @@ -0,0 +1,5 @@ +include ../Makefile.tests_common + +USEMODULE += fxos8700 + +include $(RIOTBASE)/Makefile.include diff --git a/tests/driver_fxos8700/README.md b/tests/driver_fxos8700/README.md new file mode 100644 index 0000000000000000000000000000000000000000..90b8961e5f0a8a12b078d81416585f73b9beda69 --- /dev/null +++ b/tests/driver_fxos8700/README.md @@ -0,0 +1,12 @@ +# About +This is a manual test application for the FXOS8700 driver. + +# Usage +This test application will initialize the FXOS8700 sensor with the configuration +as specified in the default `fxos8700_params.h` file. + +If you want to use this test application with different parameters, you can +simply override the default FXOS8700_PARAMS. + +After initialization, the sensor reads the 3-axis acceleration and 3-axis +magnetic field values every second and prints them to STDOUT. diff --git a/tests/driver_fxos8700/main.c b/tests/driver_fxos8700/main.c new file mode 100644 index 0000000000000000000000000000000000000000..092be5f58b68cdce37e854c1d4bfd87d7c89780d --- /dev/null +++ b/tests/driver_fxos8700/main.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 UC Berkeley + * + * 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 tests + * @{ + * + * @file + * @brief Test application for the PULSE_COUNTER driver + * + * @author Hyung-Sin Kim <hs.kim@cs.berkeley.edu> + * + * @} + */ + +#include <stdio.h> + +#include "xtimer.h" +#include "fxos8700_params.h" + +int main(void) +{ + fxos8700_t dev; + + puts("FXOS8700 driver test application\n"); + + /* Initialization */ + if (fxos8700_init(&dev, &fxos8700_params[0])) { + puts("[Failed]"); + return 1; + } + else { + puts("[OK]\n"); + } + + while (1) { + /* Acceleration and Magnetic field reading */ + fxos8700_measurement_t acc, mag; + if (fxos8700_read(&dev, &acc, &mag) != FXOS8700_OK) { + puts("Read failure\n"); + } + else { + printf("acceleration: (%d, %d, %d)\n", acc.x, acc.y, acc.z); + printf("magnetic field: (%d, %d, %d)\n", mag.x, mag.y, mag.z); + } + xtimer_usleep(US_PER_SEC); + } + + return 0; +}