1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

drivers/bmx055: initial implementation

This commit is contained in:
Semjon Kerner 2018-02-19 14:27:39 +01:00
parent 9bf532c313
commit 83153d6925
8 changed files with 680 additions and 0 deletions

View File

@ -47,6 +47,10 @@ ifneq (,$(filter bmp180,$(USEMODULE)))
USEMODULE += xtimer
endif
ifneq (,$(filter bmx055,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c
endif
ifneq (,$(filter bm%280,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c
USEMODULE += xtimer

View File

@ -169,3 +169,6 @@ endif
ifneq (,$(filter ata8520e,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ata8520e/include
endif
ifneq (,$(filter bmx055,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/bmx055/include
endif

1
drivers/bmx055/Makefile Normal file
View File

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

243
drivers/bmx055/bmx055.c Normal file
View File

@ -0,0 +1,243 @@
/*
* Copyright (C) 2017 Freie Universität Berlin
*
* 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_bmx055
* @{
*
* @file
* @brief Device driver interface for the BMX055 9-axis sensor
*
* @author Semjon Kerner <semjon.kerner@fu-berlin.de>
* @}
*/
#include <string.h>
#include <stdint.h>
#include <math.h>
#include "periph/i2c.h"
#include "periph/gpio.h"
#include "assert.h"
#include "bmx055.h"
#include "bmx055_internal.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define BUS_CLK (I2C_SPEED_FAST)
#define BUS (dev->p.i2c)
#define ADDR_MAG (dev->p.addr_mag)
#define ADDR_ACC (dev->p.addr_acc)
#define ADDR_GYRO (dev->p.addr_gyro)
#define GYRO_2000_DPS (2000U)
#define GYRO_MAX_SCALE (0x7FFFU)
/**
* @brief Array of available range values of accelerometer
*/
static const uint8_t acc_ranges[] = {
BIT_ACC_RANGE_2G,
BIT_ACC_RANGE_4G,
BIT_ACC_RANGE_8G,
BIT_ACC_RANGE_16G,
};
int bmx055_init(bmx055_t *dev, const bmx055_params_t *params)
{
assert(dev && params);
uint8_t tmp;
memcpy(&dev->p, params, sizeof(bmx055_params_t));
/* init i2c Bus */
if (i2c_init_master(dev->p.i2c, BUS_CLK) != 0) {
DEBUG("[bmx055] error: unable to init i2c bus\n");
return BMX055_NOBUS;
}
/* bring magnetometer from suspend mode to sleep mode just in case
* and try to read magnetometer id
* NOTE: this is necessary because the module id is 0x00 in suspend mode
*/
if (i2c_write_reg(BUS, ADDR_MAG, REG_MAG_PWRCTRL, BIT_MAG_PWRCTRL_VAL) != 1) {
DEBUG("[bmx055] error: no connection to magnetometer\n");
return BMX055_NODEV;
}
if (i2c_read_reg(BUS, ADDR_MAG, REG_MAG_CHIPID, &tmp) != 1) {
DEBUG("[bmx055] error: no connection to magnetometer\n");
return BMX055_NODEV;
}
if (tmp != REG_MAG_CHIPID_VAL) {
DEBUG("[bmx055] error: no connection to magnetometer\n");
return BMX055_NODEV;
}
/* try to read accelerometer id */
if (i2c_read_reg(BUS, ADDR_ACC, REG_ACC_CHIPID, &tmp) != 1) {
DEBUG("[bmx055] error: no connection to accelerometer\n");
return BMX055_NODEV;
}
if (tmp != REG_ACC_CHIPID_VAL) {
DEBUG("[bmx055] error: no connection to accelerometer\n");
return BMX055_NODEV;
}
/* try to read gyroscope id */
if (i2c_read_reg(BUS, ADDR_GYRO, REG_GYRO_CHIPID, &tmp) != 1) {
DEBUG("[bmx055] error: no connection to gyroscope\n");
return BMX055_NODEV;
}
if (tmp != REG_GYRO_CHIPID_VAL) {
DEBUG("[bmx055] error: no connection to gyroscope\n");
return BMX055_NODEV;
}
/* Init Magnetometer
*
* set magnetometer to normal mode (Bits 1 & 2 = 0x00)
* and set magnetometer sample rate (Bits 3 to 5)
*/
if (i2c_write_reg(BUS, ADDR_MAG, REG_MAG_OPMODE, (dev->p.mag_rate << 3)) != 1) {
DEBUG("[bmx055] error: setting magnetometer opmode\n");
return BMX055_NOWRITE;
}
/* Init Accelerometer
*
* softreset to bring module to normal mode
*/
if (i2c_write_reg(BUS, ADDR_ACC, 0x14, 0xB6) != 1) {
DEBUG("[bmx055] erro: setting accelerometer opmode\n");
return BMX055_NOWRITE;
}
/* setting acc range */
if (i2c_write_reg(BUS, ADDR_ACC, REG_ACC_RANGE, acc_ranges[dev->p.acc_range]) != 1) {
DEBUG("[bmx055] error: setting accelerometer range\n");
return BMX055_NOWRITE;
}
/* enable acc shadowing */
if (i2c_write_reg(BUS, ADDR_ACC, REG_ACC_SHDW, REG_ACC_SHDW_ENABLE) != 1) {
DEBUG("[bmx055] error: writing accelerometer shadowing bit\n");
return BMX055_NOWRITE;
}
/* Init Gyroscope
*
* The prefered way to bring the module to normal mode is using softreset.
* However, a softreset brings the module into an unknown state and
* deadlocks it. Hence it is not the way to go and normal mode is entered
* by writing into power mode control register.
*/
if (i2c_write_reg(BUS, ADDR_GYRO, REG_GYRO_PWRMD, REG_GYRO_PWRMD_NORM) != 1) {
DEBUG("[bmx055] error: setting gyroscope opmode\n");
return BMX055_NOWRITE;
}
/* setting gyro scale */
if (i2c_write_reg(BUS, ADDR_GYRO, REG_GYRO_SCALE, dev->p.gyro_scale) != 1) {
DEBUG("[bmx055] error: setting gyroscope scale\n");
return BMX055_NOWRITE;
}
/* enable gyro shadowing */
if (i2c_write_reg(BUS, ADDR_GYRO, REG_GYRO_SHDW, REG_GYRO_SHDW_EN) != 1) {
DEBUG("[bmx055] error: setting gyroscope shadowing bit\n");
return BMX055_NOWRITE;
}
return BMX055_OK;
}
int bmx055_mag_read(const bmx055_t *dev, int16_t *data)
{
assert(dev && data);
uint8_t tmp[7];
/* reading magnetometer data */
if (i2c_read_regs(BUS, ADDR_MAG, REG_MAG_DATA, &tmp, 7) != 7) {
DEBUG("[bmx055] error: reading magnetometer data\n");
return BMX055_NOREAD;
}
/* checking if new data was available */
if ((tmp[6] & BIT_MAG_DATARDY) != 1) {
DEBUG("[bmx055] error: no magnetometer data ready\n");
return BMX055_NOTREADY;
}
/* scaling raw mag data to mGs */
data[0] = (int16_t) (((int16_t)tmp[1] << 8) | tmp[0]) >> 3;
data[1] = (int16_t) (((int16_t)tmp[3] << 8) | tmp[2]) >> 3;
data[2] = (int16_t) (((int16_t)tmp[5] << 8) | tmp[4]) >> 1;
return BMX055_OK;
}
int bmx055_acc_read(const bmx055_t *dev, int16_t *data)
{
assert(dev && data);
uint8_t tmp[7];
/* reading accelerometer data */
if (i2c_read_regs(BUS, ADDR_ACC, REG_ACC_DATA, &tmp, 7) != 7) {
DEBUG("[bmx055] error: reading accelerometer data\n");
return BMX055_NOREAD;
}
if (((tmp[0] & 1) == 0) || ((tmp[2] & 1) == 0) || ((tmp[4] & 1) == 0)) {
DEBUG("[bmx055] error: no acceleration data ready\n");
return BMX055_NOTREADY;
}
/* scaling raw acc data to g */
for (int i = 0; i < 3; i++) {
data[i] = (int16_t) (((int16_t)tmp[(i * 2) + 1] << 8) | (tmp[i * 2] & 0xf0)) >> 4;
data[i] <<= (dev->p.acc_range);
}
return BMX055_OK;
}
int bmx055_gyro_read(const bmx055_t *dev, int16_t *data)
{
assert(dev && data);
uint8_t tmp[6];
int16_t shift[3];
int32_t compensation[3];
uint16_t scale;
/* converting scale info into real scaling values */
scale = (GYRO_2000_DPS / pow(2, dev->p.gyro_scale));
/* reading gyroscope data */
if (i2c_read_regs(BUS, ADDR_GYRO, REG_GYRO_DATA, &tmp, 6) != 6) {
DEBUG("[bmx055] error: reading gyroscope data\n");
return BMX055_NOREAD;
}
for (int i = 0; i < 3; i++) {
/* shifting and casting register data */
shift[i] = (((tmp[(i * 2) + 1] << 8) & 0xFF00) | (tmp[(i * 2)] & 0x00FF));
compensation[i] = (int32_t) shift[i];
/* scaling raw gyro data to dps */
compensation[i] *= scale;
compensation[i] /= GYRO_MAX_SCALE;
data[i] = (int16_t) compensation[i];
}
return BMX055_OK;
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (C) 2017 Freie Universität Berlin
*
* 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_bmx055
*
* @{
* @file
* @brief Definitions for the bmx055 device
*
* @author Semjon Kerner <semjon.kerner@fu-berlin.de>
*/
#ifndef BMX055_INTERNAL_H
#define BMX055_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name BMX055 magnetometer registers
* @{
*/
#define REG_MAG_CHIPID (0x40U)
#define REG_MAG_CHIPID_VAL (0x32U)
#define REG_MAG_OPMODE (0x4CU)
#define REG_MAG_PWRCTRL (0x4BU)
#define REG_MAG_DATA (0x42U)
/** @} */
/**
* @name BMX055 magnetometer bitfields and values
* @{
*/
#define BIT_MAG_PWRCTRL_VAL (0x01U)
#define BIT_MAG_DATARDY (0x01U)
/** @} */
/**
* @name BMX055 accelerometer registers and values
* @{
*/
#define REG_ACC_CHIPID (0x00U)
#define REG_ACC_CHIPID_VAL (0xFAU)
#define REG_ACC_SHDW (0x13U)
#define REG_ACC_SHDW_ENABLE (0x00U)
#define REG_ACC_DATA (0x02U)
/** @} */
/**
* @name BMX055 accelerometer range register and values
* @{
*/
#define REG_ACC_RANGE (0x0FU)
#define BIT_ACC_RANGE_2G (0x03U)
#define BIT_ACC_RANGE_4G (0x05U)
#define BIT_ACC_RANGE_8G (0x08U)
#define BIT_ACC_RANGE_16G (0x0CU)
/** @} */
/**
* @name BMX055 gyroscope registers and values
* @{
*/
#define REG_GYRO_CHIPID (0x00U)
#define REG_GYRO_CHIPID_VAL (0x0FU)
#define REG_GYRO_SCALE (0x0FU)
#define REG_GYRO_SHDW (0x13U)
#define REG_GYRO_SHDW_EN (0x00U)
#define REG_GYRO_PWRMD (0x11U)
#define REG_GYRO_PWRMD_NORM (0x00U)
#define REG_GYRO_DATA (0x02U)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* BMX055_INTERNAL_H */
/** @} */

View File

@ -0,0 +1,71 @@
/*
* Copyright (C) 2017 Freie Universität Berlin
*
* 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_bmx055
* @{
*
* @file
* @brief bmx055 adaption to the RIOT actuator/sensor interface
*
* @author Semjon Kerner <semjon.kerner@fu-berlin.de>
* @}
*/
#include <string.h>
#include "saul.h"
#include "bmx055.h"
static int read_mag(const void *dev, phydat_t *res)
{
if (bmx055_mag_read((bmx055_t *)dev, (int16_t *)res) != BMX055_OK) {
return 0;
}
res->unit = UNIT_GS;
res->scale = 0;
return 3;
}
static int read_acc(const void *dev, phydat_t *res)
{
if (bmx055_acc_read((bmx055_t *)dev, (int16_t *)res) != BMX055_OK) {
return 0;
}
res->unit = UNIT_G;
res->scale = -3;
return 3;
}
static int read_gyro(const void *dev, phydat_t *res)
{
if (bmx055_gyro_read((bmx055_t *)dev, (int16_t *)res) != BMX055_OK) {
return 0;
}
res->unit = UNIT_DPS;
res->scale = 0;
return 3;
}
const saul_driver_t bmx055_magnetometer_saul_driver = {
.read = read_mag,
.write = saul_notsup,
.type = SAUL_SENSE_MAG,
};
const saul_driver_t bmx055_accelerometer_saul_driver = {
.read = read_acc,
.write = saul_notsup,
.type = SAUL_SENSE_ACCEL,
};
const saul_driver_t bmx055_gyroscope_saul_driver = {
.read = read_gyro,
.write = saul_notsup,
.type = SAUL_SENSE_GYRO,
};

View File

@ -0,0 +1,102 @@
/*
* Copyright (C) 2017 Freie Universität Berlin
*
* 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_bmx055
*
* @{
* @file
* @brief Default configuration for bmx055 devices
*
* @author Semjon Kerner <semjon.kerner@fu-berlin.de>
*/
#ifndef BMX055_PARAMS_H
#define BMX055_PARAMS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "board.h"
/**
* @name Default configuration parameters for device BMX055
* @{
*/
#ifndef BMX055_PARAM_I2C
#define BMX055_PARAM_I2C I2C_DEV(0)
#endif
#ifndef BMX055_PARAM_MAG_ADDR
#define BMX055_PARAM_MAG_ADDR BMX055_MAG_ADDR_DEFAULT
#endif
#ifndef BMX055_PARAM_ACC_ADDR
#define BMX055_PARAM_ACC_ADDR BMX055_ACC_ADDR_DEFAULT
#endif
#ifndef BMX055_PARAM_GYRO_ADDR
#define BMX055_PARAM_GYRO_ADDR BMX055_GYRO_ADDR_DEFAULT
#endif
#ifndef BMX055_PARAM_INT1
#define BMX055_PARAM_INT1 GPIO_PIN(0, 0)
#endif
#ifndef BMX055_PARAM_INT2
#define BMX055_PARAM_INT2 GPIO_PIN(0, 1)
#endif
#ifndef BMX055_PARAM_MAG_RATE
#define BMX055_PARAM_MAG_RATE BMX055_MAG_DRATE_DEFAULT
#endif
#ifndef BMX055_PARAM_ACC_RANGE
#define BMX055_PARAM_ACC_RANGE BMX055_ACC_RANGE_2G
#endif
#ifndef BMX055_PARAM_GYRO_SCALE
#define BMX055_PARAM_GYRO_SCALE BMX055_GYRO_SCALE_2000DPS
#endif
#ifndef BMX055_PARAMS
#define BMX055_PARAMS \
{ .i2c = BMX055_PARAM_I2C, \
.addr_mag = BMX055_PARAM_MAG_ADDR, \
.addr_acc = BMX055_PARAM_ACC_ADDR, \
.addr_gyro = BMX055_PARAM_GYRO_ADDR, \
.int1_pin = BMX055_PARAM_INT1, \
.int2_pin = BMX055_PARAM_INT2, \
.mag_rate = BMX055_PARAM_MAG_RATE, \
.acc_range = BMX055_PARAM_ACC_RANGE, \
.gyro_scale = BMX055_PARAM_GYRO_SCALE, \
}
#endif
#ifndef BMX055_SAULINFO
#define BMX055_SAULINFO \
{ { .name = "Magnetometer (bmx055)" }, \
{ .name = "Accelerometer (bmx055)" }, \
{ .name = "Gyroscope (bmx055)" }, \
}
#endif
/** @} */
/**
* @brief BMX055 configuration
*/
static const bmx055_params_t bmx055_params[] = {
BMX055_PARAMS
};
/**
* @brief SAUL registry entires
*/
static const saul_reg_info_t bmx055_saul_info[][3] = {
BMX055_SAULINFO
};
#ifdef __cplusplus
}
#endif
#endif /* BMX055_PARAMS_H */
/** @} */

170
drivers/include/bmx055.h Normal file
View File

@ -0,0 +1,170 @@
/*
* Copyright (C) 2017 Freie Universität Berlin
*
* 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_bmx055 BMX055 9-axis sensor
* @ingroup drivers_sensors
* @brief Device driver for the Bosch BMX055 9-axis sensor
* @{
*
* @file
* @brief Device driver interface for the Bosch BMX055 9-axis sensor
*
* @note The current state of the driver only implements basic polling.
*
* @author Semjon Kerner <semjon.kerner@fu-berlin.de>
*/
#ifndef BMX055_H
#define BMX055_H
#include <stdint.h>
#include "periph/i2c.h"
#include "periph/gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name The sensors default I2C addresses
* @{
*/
#define BMX055_MAG_ADDR_DEFAULT (0x10U)
#define BMX055_ACC_ADDR_DEFAULT (0x18U)
#define BMX055_GYRO_ADDR_DEFAULT (0x68U)
/** @} */
/**
* @brief Status and error return codes
*/
enum {
BMX055_OK = 0, /**< exit without error */
BMX055_NOBUS = -1, /**< cannot connect to module on i2c bus */
BMX055_NODEV = -2, /**< cannot read any data from module */
BMX055_NOREAD = -3, /**< cannot read data from module */
BMX055_NOWRITE = -4, /**< cannot write data to module */
BMX055_NOTREADY = -5, /**< no new data ready for reading */
};
/**
* @brief Datarate for Magnetometer
*/
typedef enum {
BMX055_MAG_DRATE_DEFAULT = 0x0, /**< output data rate: 10 Hz */
BMX055_MAG_DRATE_02HZ = 0x1, /**< output data rate: 2 Hz */
BMX055_MAG_DRATE_06HZ = 0x2, /**< output data rate: 6 Hz */
BMX055_MAG_DRATE_08HZ = 0x3, /**< output data rate: 8 Hz*/
BMX055_MAG_DRATE_15HZ = 0x4, /**< output data rate: 15 Hz */
BMX055_MAG_DRATE_20HZ = 0x5, /**< output data rate: 20 Hz */
BMX055_MAG_DRATE_25HZ = 0x6, /**< output data rate: 25 Hz */
BMX055_MAG_DRATE_30HZ = 0x7, /**< output data rate: 30 Hz */
} bmx055_mag_rate_t;
/**
* @brief Range for Accelerometer
*/
typedef enum {
BMX055_ACC_RANGE_2G = 0x0, /**< range: 2g */
BMX055_ACC_RANGE_4G = 0x1, /**< range: 4g */
BMX055_ACC_RANGE_8G = 0x2, /**< range: 8g */
BMX055_ACC_RANGE_16G = 0x3, /**< range: 16g */
} bmx055_acc_range_t;
/**
* @brief Measurement scale for the gyro
*/
typedef enum {
BMX055_GYRO_SCALE_2000DPS = 0x0, /**< scale: 2000 degree per second */
BMX055_GYRO_SCALE_1000DPS = 0x1, /**< scale: 1000 degree per second */
BMX055_GYRO_SCALE_0500DPS = 0x2, /**< scale: 500 degree per second */
BMX055_GYRO_SCALE_0250DPS = 0x3, /**< scale: 250 degree per second */
BMX055_GYRO_SCALE_0125DPS = 0x4, /**< scale: 125 degree per second */
} bmx055_gyro_scale_t;
/**
* @brief Data structure holding the device parameters needed for initialization
*/
typedef struct {
i2c_t i2c; /**< I2C bus the device is connected to */
uint8_t addr_mag; /**< the magnetometer address on that bus */
uint8_t addr_acc; /**< the accelerometer address on that bus */
uint8_t addr_gyro; /**< the gyroscope address on that bus */
gpio_t int1_pin; /**< GPIO pin connected to the INT1 line */
gpio_t int2_pin; /**< GPIO pin connected to the INT2 line */
uint8_t mag_rate; /**< datarate of magnetometer */
uint8_t acc_range; /**< range of accelerometer */
uint8_t gyro_scale; /**< range of gyroscope*/
} bmx055_params_t;
/**
* @brief Device descriptor for BMX055 sensors
*/
typedef struct {
bmx055_params_t p; /**< Device initialization parameters*/
} bmx055_t;
/**
* @brief Initialize modules magnetometer, accelerometer, gyroscope
*
* @param[out] dev device descriptor of sensor to initialize
* @param[in] params default parameter values
*
* @return BMX055_OK on success
* @return BMX055_NOBUS if i2C connection can not be establish
* @return BMX055_NODEV if the register of a module can not be read
* @return BMX055_NOWRITE if a register can not be written
*/
int bmx055_init(bmx055_t *dev, const bmx055_params_t *params);
/**
* @brief Read magnetic field value in Gauss per second from magnetometer
*
* @param[in] dev device descriptor of magnetometer
* @param[out] data result vector in Gs per axis
*
* @return BMX055_OK on success
* @return BMX055_NOREAD if reading mag data is not possible
* @return BMX055_NOTRDY if no new data is available
*/
int bmx055_mag_read(const bmx055_t *dev, int16_t *data);
/**
* @brief Read acceleration value in g from accelerometer
*
* @param[in] dev device descriptor of accelerometer
* @param[out] data result vector in g per axis
*
* @return BMX055_OK on success
* @return BMX055_NOREAD if reading acc data is not possible
* @return BMX055_NOTRDY if no new data is available
*/
int bmx055_acc_read(const bmx055_t *dev, int16_t *data);
/**
* @brief Read angular speed value in degree per second from gyroscope
*
* @note The data of steady axis deviate from the expected values while
* moving the sensor in one of the other axis. Hence reading data for all axis
* at once may not always give the expected results.
*
* @param[in] dev device descriptor of gyroscope
* @param[out] data result vector in dps per axis
*
* @return BMX055_OK on success
* @return BMX055_NOREAD if reading gyro data is not possible
*/
int bmx055_gyro_read(const bmx055_t *dev, int16_t *data);
#ifdef __cplusplus
}
#endif
#endif /* BMX055_H */
/** @} */