diff --git a/configs/spresense/include/board.h b/configs/spresense/include/board.h index 17f66c86a9a..e701cb0dc3a 100644 --- a/configs/spresense/include/board.h +++ b/configs/spresense/include/board.h @@ -49,6 +49,7 @@ #include "cxd56_power.h" #include "cxd56_flash.h" #include "cxd56_gs2200m.h" +#include "cxd56_bmi160.h" #include "cxd56_sdcard.h" #include "cxd56_wdt.h" diff --git a/configs/spresense/include/cxd56_bmi160.h b/configs/spresense/include/cxd56_bmi160.h new file mode 100644 index 00000000000..834cb2f7e5d --- /dev/null +++ b/configs/spresense/include/cxd56_bmi160.h @@ -0,0 +1,84 @@ +/**************************************************************************** + * configs/spresense/include/cxd56_bmi160.h + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __BOARD_COMMON_INCLUDE_CXD56_BMI160_H +#define __BOARD_COMMON_INCLUDE_CXD56_BMI160_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: board_bmi160_initialize + * + * Description: + * Initialize BMI160 i2c driver and register the BMI160 device. + * + ****************************************************************************/ + +int board_bmi160_initialize(int bus); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARD_COMMON_INCLUDE_CXD56_BMI160_H */ diff --git a/configs/spresense/src/Makefile b/configs/spresense/src/Makefile index c4eed3beb90..3d0836ee2a4 100644 --- a/configs/spresense/src/Makefile +++ b/configs/spresense/src/Makefile @@ -92,4 +92,8 @@ ifeq ($(CONFIG_WL_GS2200M),y) CSRCS += cxd56_gs2200m.c endif +ifeq ($(CONFIG_SENSORS_BMI160_I2C),y) +CSRCS += cxd56_bmi160_i2c.c +endif + include $(TOPDIR)/configs/Board.mk diff --git a/configs/spresense/src/cxd56_bmi160_i2c.c b/configs/spresense/src/cxd56_bmi160_i2c.c new file mode 100644 index 00000000000..11ac31dfc04 --- /dev/null +++ b/configs/spresense/src/cxd56_bmi160_i2c.c @@ -0,0 +1,86 @@ +/**************************************************************************** + * configs/spresense/src/cxd56_bmi160_i2c.c + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "cxd56_i2c.h" + +#ifdef CONFIG_CXD56_DECI_GYRO +#define GYRO_NR_SEQS 3 +#else +#define GYRO_NR_SEQS 1 +#endif + +#ifdef CONFIG_CXD56_DECI_ACCEL +#define ACCEL_NR_SEQS 3 +#else +#define ACCEL_NR_SEQS 1 +#endif + +int board_bmi160_initialize(int bus) +{ + int ret; + FAR struct i2c_master_s *i2c; + + sninfo("Initializing BMI160..\n"); + + /* Initialize i2c deivce */ + + i2c = cxd56_i2cbus_initialize(bus); + if (!i2c) + { + snerr("ERROR: Failed to initialize i2c%d.\n", bus); + return -ENODEV; + } + + ret = bmi160_register("/dev/accel0", i2c); + if (ret < 0) + { + snerr("Error registering BMI160\n"); + } + + return ret; +} diff --git a/configs/spresense/src/cxd56_bringup.c b/configs/spresense/src/cxd56_bringup.c index 2197f1d8a2f..4700cff753a 100644 --- a/configs/spresense/src/cxd56_bringup.c +++ b/configs/spresense/src/cxd56_bringup.c @@ -346,5 +346,13 @@ int cxd56_bringup(void) } #endif +#ifdef CONFIG_SENSORS_BMI160_I2C + ret = board_bmi160_initialize(0); + if (ret < 0) + { + _err("ERROR: Failed to initialze BMI160. \n"); + } +#endif + return 0; } diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig index 1f93e7813a3..394f9688938 100644 --- a/drivers/sensors/Kconfig +++ b/drivers/sensors/Kconfig @@ -49,6 +49,36 @@ config SENSORS_BMG160 ---help--- Enable driver support for the Bosch BMG160 gyroscope sensor. + +config SENSORS_BMI160 + bool "Bosch BMI160 Inertial Measurement Sensor support" + default n + select I2C + ---help--- + Enable driver support for the Bosch BMI160 Inertial + Measurement sensor + +if SENSORS_BMI160 + +choice + prompt "BMI160 Interface" + default SENSORS_BMI160_SPI + +config SENSORS_BMI160_I2C + bool "BMI160 I2C Interface" + select I2C + ---help--- + Enables support for the I2C interface + +config SENSORS_BMI160_SPI + bool "BMI160 SPI Interface" + select SPI + ---help--- + Enables support for the SPI interface + +endchoice +endif + config SENSORS_BMP180 bool "Bosch BMP180 Barometer Sensor support" default n diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs index 5cf0f1a6c6e..360cbe18f21 100644 --- a/drivers/sensors/Make.defs +++ b/drivers/sensors/Make.defs @@ -105,6 +105,10 @@ ifeq ($(CONFIG_SENSORS_BMG160),y) CSRCS += bmg160.c endif +ifeq ($(CONFIG_SENSORS_BMI160),y) + CSRCS += bmi160.c +endif + ifeq ($(CONFIG_SENSORS_BMP180),y) CSRCS += bmp180.c endif diff --git a/drivers/sensors/bmi160.c b/drivers/sensors/bmi160.c new file mode 100644 index 00000000000..4ecf7a36dd3 --- /dev/null +++ b/drivers/sensors/bmi160.c @@ -0,0 +1,786 @@ +/**************************************************************************** + * drivers/sensors/bmi160.c + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(CONFIG_SENSORS_BMI160) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define DEVID 0xd1 +#define BMI160_I2C_ADDR 0x68 /* If SDO pin is pulled to VDDIO, use 0x69 */ +#define BMI160_I2C_FREQ 400000 + +#define BMI160_CHIP_ID (0x00) /* Chip ID */ +#define BMI160_ERROR (0x02) /* Error register */ +#define BMI160_PMU_STAT (0x03) /* Current power mode */ +#define BMI160_DATA_0 (0x04) /* MAG X 7:0 (LSB) */ +#define BMI160_DATA_1 (0x05) /* MAG X 15:8 (MSB) */ +#define BMI160_DATA_2 (0x06) /* MAG Y 7:0 (LSB) */ +#define BMI160_DATA_3 (0x07) /* MAG Y 15:8 (MSB) */ +#define BMI160_DATA_4 (0x08) /* MAG Z 7:0 (LSB) */ +#define BMI160_DATA_5 (0x09) /* MAG Z 15:8 (MSB) */ +#define BMI160_DATA_6 (0x0A) /* RHALL 7:0 (LSB) */ +#define BMI160_DATA_7 (0x0B) /* RHALL 15:8 (MSB) */ +#define BMI160_DATA_8 (0x0C) /* GYR X 7:0 (LSB) */ +#define BMI160_DATA_9 (0x0D) /* GYR X 15:8 (MSB) */ +#define BMI160_DATA_10 (0x0E) /* GYR Y 7:0 (LSB) */ +#define BMI160_DATA_11 (0x0F) /* GYR Y 15:8 (MSB) */ +#define BMI160_DATA_12 (0x10) /* GYR Z 7:0 (LSB) */ +#define BMI160_DATA_13 (0x11) /* GYR Z 15:8 (MSB) */ +#define BMI160_DATA_14 (0x12) /* ACC X 7:0 (LSB) */ +#define BMI160_DATA_15 (0x13) /* ACC X 15:8 (MSB) */ +#define BMI160_DATA_16 (0x14) /* ACC Y 7:0 (LSB) */ +#define BMI160_DATA_17 (0x15) /* ACC Y 15:8 (MSB) */ +#define BMI160_DATA_18 (0x16) /* ACC Z 7:0 (LSB) */ +#define BMI160_DATA_19 (0x17) /* ACC Z 15:8 (MSB) */ +#define BMI160_SENSORTIME_0 (0x18) /* Sensor time 0 */ +#define BMI160_SENSORTIME_1 (0x19) /* Sensor time 1 */ +#define BMI160_SENSORTIME_2 (0x1A) /* Sensor time 2 */ +#define BMI160_STAT (0x1B) /* Status register */ +#define BMI160_INTR_STAT_0 (0x1C) /* Interrupt status */ +#define BMI160_INTR_STAT_1 (0x1D) +#define BMI160_INTR_STAT_2 (0x1E) +#define BMI160_INTR_STAT_3 (0x1F) +#define BMI160_TEMPERATURE_0 (0x20) /* Temperature */ +#define BMI160_TEMPERATURE_1 (0x21) +#define BMI160_FIFO_LENGTH_0 (0x22) /* FIFO length */ +#define BMI160_FIFO_LENGTH_1 (0x23) +#define BMI160_FIFO_DATA (0x24) +#define BMI160_ACCEL_CONFIG (0x40) /* ACCEL config for ODR, bandwidth and undersampling */ +#define BMI160_ACCEL_RANGE (0x41) /* ACCEL range */ +#define BMI160_GYRO_CONFIG (0x42) /* GYRO config for ODR and bandwidth */ +#define BMI160_GYRO_RANGE (0x43) /* GYRO range */ +#define BMI160_MAG_CONFIG (0x44) /* MAG config for ODR */ +#define BMI160_FIFO_DOWN (0x45) /* GYRO and ACCEL downsampling rates for FIFO */ +#define BMI160_FIFO_CONFIG_0 (0x46) /* FIFO config */ +#define BMI160_FIFO_CONFIG_1 (0x47) +#define BMI160_MAG_IF_0 (0x4B) /* MAG interface */ +#define BMI160_MAG_IF_1 (0x4C) +#define BMI160_MAG_IF_2 (0x4D) +#define BMI160_MAG_IF_3 (0x4E) +#define BMI160_MAG_IF_4 (0x4F) +#define BMI160_INTR_ENABLE_0 (0x50) /* Interrupt enable */ +#define BMI160_INTR_ENABLE_1 (0x51) +#define BMI160_INTR_ENABLE_2 (0x52) +#define BMI160_INTR_OUT_CTRL (0x53) +#define BMI160_INTR_LATCH (0x54) /* Latch duration */ +#define BMI160_INTR_MAP_0 (0x55) /* Map interrupt */ +#define BMI160_INTR_MAP_1 (0x56) +#define BMI160_INTR_MAP_2 (0x57) +#define BMI160_INTR_DATA_0 (0x58) /* Data source */ +#define BMI160_INTR_DATA_1 (0x59) +#define BMI160_INTR_LOWHIGH_0 (0x5A) /* Threshold interrupt */ +#define BMI160_INTR_LOWHIGH_1 (0x5B) +#define BMI160_INTR_LOWHIGH_2 (0x5C) +#define BMI160_INTR_LOWHIGH_3 (0x5D) +#define BMI160_INTR_LOWHIGH_4 (0x5E) +#define BMI160_INTR_MOTION_0 (0x5F) +#define BMI160_INTR_MOTION_1 (0x60) +#define BMI160_INTR_MOTION_2 (0x61) +#define BMI160_INTR_MOTION_3 (0x62) +#define BMI160_INTR_TAP_0 (0x63) +#define BMI160_INTR_TAP_1 (0x64) +#define BMI160_INTR_ORIENT_0 (0x65) +#define BMI160_INTR_ORIENT_1 (0x66) +#define BMI160_INTR_FLAT_0 (0x67) +#define BMI160_INTR_FLAT_1 (0x68) +#define BMI160_FOC_CONFIG (0x69) /* Fast offset configuration */ +#define BMI160_CONFIG (0x6A) /* Miscellaneous configuration */ +#define BMI160_IF_CONFIG (0x6B) /* Serial interface configuration */ +#define BMI160_PMU_TRIGGER (0x6C) /* GYRO power mode trigger */ +#define BMI160_SELF_TEST (0x6D) /* Self test */ +#define BMI160_NV_CONFIG (0x70) /* SPI/I2C selection */ +#define BMI160_OFFSET_0 (0x71) /* ACCEL and GYRO offset */ +#define BMI160_OFFSET_1 (0x72) +#define BMI160_OFFSET_2 (0x73) +#define BMI160_OFFSET_3 (0x74) +#define BMI160_OFFSET_4 (0x75) +#define BMI160_OFFSET_5 (0x76) +#define BMI160_OFFSET_6 (0x77) +#define BMI160_STEP_COUNT_0 (0x78) /* Step counter interrupt */ +#define BMI160_STEP_COUNT_1 (0x79) +#define BMI160_STEP_CONFIG_0 (0x7A) /* Step counter configuration */ +#define BMI160_STEP_CONFIG_1 (0x7B) +#define BMI160_CMD (0x7e) /* Command register */ + +/* Register 0x40 - ACCEL_CONFIG accel bandwidth */ + +#define ACCEL_OSR4_AVG1 (0 << 4) +#define ACCEL_OSR2_AVG2 (1 << 4) +#define ACCEL_NORMAL_AVG4 (2 << 4) +#define ACCEL_CIC_AVG8 (3 << 4) +#define ACCEL_RES_AVG2 (4 << 4) +#define ACCEL_RES_AVG4 (5 << 4) +#define ACCEL_RES_AVG8 (6 << 4) +#define ACCEL_RES_AVG16 (7 << 4) +#define ACCEL_RES_AVG32 (8 << 4) +#define ACCEL_RES_AVG64 (9 << 4) +#define ACCEL_RES_AVG128 (10 << 4) + +#define ACCEL_ODR_0_78HZ (0x01) +#define ACCEL_ODR_1_56HZ (0x02) +#define ACCEL_ODR_3_12HZ (0x03) +#define ACCEL_ODR_6_25HZ (0x04) +#define ACCEL_ODR_12_5HZ (0x05) +#define ACCEL_ODR_25HZ (0x06) +#define ACCEL_ODR_50HZ (0x07) +#define ACCEL_ODR_100HZ (0x08) +#define ACCEL_ODR_200HZ (0x09) +#define ACCEL_ODR_400HZ (0x0A) +#define ACCEL_ODR_800HZ (0x0B) +#define ACCEL_ODR_1600HZ (0x0C) + +/* Register 0x42 - GYRO_CONFIG accel bandwidth */ + +#define GYRO_OSR4_MODE (0x00 << 4) +#define GYRO_OSR2_MODE (0x01 << 4) +#define GYRO_NORMAL_MODE (0x02 << 4) +#define GYRO_CIC_MODE (0x03 << 4) + +#define GYRO_ODR_25HZ (0x06) +#define GYRO_ODR_50HZ (0x07) +#define GYRO_ODR_100HZ (0x08) +#define GYRO_ODR_200HZ (0x09) +#define GYRO_ODR_400HZ (0x0A) +#define GYRO_ODR_800HZ (0x0B) +#define GYRO_ODR_1600HZ (0x0C) +#define GYRO_ODR_3200HZ (0x0D) + +/* Register 0x7b STEP_CONFIG_1 */ + +#define STEP_CNT_EN (1 << 3) + +/* Register 0x7e - CMD */ + +#define ACCEL_PM_SUSPEND (0X10) +#define ACCEL_PM_NORMAL (0x11) +#define ACCEL_PM_LOWPOWER (0X12) +#define GYRO_PM_SUSPEND (0x14) +#define GYRO_PM_NORMAL (0x15) +#define GYRO_PM_FASTSTARTUP (0x17) +#define MAG_PM_SUSPEND (0x18) +#define MAG_PM_NORMAL (0x19) +#define MAG_PM_LOWPOWER (0x1A) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct bmi160_dev_s +{ +#ifdef CONFIG_SENSORS_BMI160_I2C + FAR struct i2c_master_s *i2c; /* I2C interface */ + uint8_t addr; /* I2C address */ + int freq; /* Frequency <= 3.4MHz */ + +#else /* CONFIG_SENSORS_BMI160_SPI */ + FAR struct spi_dev_s *spi; /* SPI interface */ + +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint8_t bmi160_getreg8(FAR struct bmi160_dev_s *priv, + uint8_t regaddr); +static void bmi160_putreg8(FAR struct bmi160_dev_s *priv, uint8_t regaddr, + uint8_t regval); +static uint16_t bmi160_getreg16(FAR struct bmi160_dev_s *priv, + uint8_t regaddr); +static void bmi160_getregs(FAR struct bmi160_dev_s *priv, uint8_t regaddr, + uint8_t *regval, int len); + +/* Character driver methods */ + +static int bmi160_open(FAR struct file *filep); +static int bmi160_close(FAR struct file *filep); +static ssize_t bmi160_read(FAR struct file *filep, FAR char *buffer, + size_t len); +static int bmi160_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); + +static int bmi160_checkid(FAR struct bmi160_dev_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This the vtable that supports the character driver interface */ + +static const struct file_operations g_bmi160fops = +{ + bmi160_open, /* open */ + bmi160_close, /* close */ + bmi160_read, /* read */ + 0, /* write */ + 0, /* seek */ + bmi160_ioctl, /* ioctl */ +}; + +/**************************************************************************** + * Name: bmi160_configspi + * + * Description: + * + ****************************************************************************/ +#ifdef CONFIG_SENSORS_BMI160_SPI +static inline void bmi160_configspi(FAR struct spi_dev_s *spi) +{ + /* Configure SPI for the BMI160 */ + + SPI_SETMODE(spi, SPIDEV_MODE3); + SPI_SETBITS(spi, 8); + (void)SPI_HWFEATURES(spi, 0); + (void)SPI_SETFREQUENCY(spi, BMI160_SPI_MAXFREQUENCY); +} +#endif + +/**************************************************************************** + * Name: bmi160_getreg8 + * + * Description: + * Read from an 8-bit BMI160 register + * + ****************************************************************************/ + +static uint8_t bmi160_getreg8(FAR struct bmi160_dev_s *priv, uint8_t regaddr) +{ + uint8_t regval = 0; + +#ifdef CONFIG_SENSORS_BMI160_I2C + struct i2c_msg_s msg[2]; + int ret; + + msg[0].frequency = priv->freq; + msg[0].addr = priv->addr; + msg[0].flags = 0; + msg[0].buffer = ®addr; + msg[0].length = 1; + + msg[1].frequency = priv->freq; + msg[1].addr = priv->addr; + msg[1].flags = I2C_M_READ; + msg[1].buffer = ®val; + msg[1].length = 1; + + ret = I2C_TRANSFER(priv->i2c, msg, 2); + if (ret < 0) + { + snerr("I2C_TRANSFER failed: %d\n", ret); + } + +#else /* CONFIG_SENSORS_BMI160_SPI */ + /* If SPI bus is shared then lock and configure it */ + + (void)SPI_LOCK(priv->spi, true); + bmi160_configspi(priv->spi); + + /* Select the BMI160 */ + + SPI_SELECT(priv->spi, SPIDEV_ACCELEROMETER(0), true); + + /* Send register to read and get the next byte */ + + (void)SPI_SEND(priv->spi, regaddr | 0x80); + SPI_RECVBLOCK(priv->spi, ®val, 1); + + /* Deselect the BMI160 */ + + SPI_SELECT(priv->spi, SPIDEV_ACCELEROMETER(0), false); + + /* Unlock bus */ + + (void)SPI_LOCK(priv->spi, false); +#endif + + return regval; +} + +/**************************************************************************** + * Name: bmi160_putreg8 + * + * Description: + * Write a value to an 8-bit BMI160 register + * + ****************************************************************************/ + +static void bmi160_putreg8(FAR struct bmi160_dev_s *priv, uint8_t regaddr, + uint8_t regval) +{ +#ifdef CONFIG_SENSORS_BMI160_I2C + struct i2c_msg_s msg[2]; + int ret; + uint8_t txbuffer[2]; + + txbuffer[0] = regaddr; + txbuffer[1] = regval; + + msg[0].frequency = priv->freq; + msg[0].addr = priv->addr; + msg[0].flags = 0; + msg[0].buffer = txbuffer; + msg[0].length = 2; + + ret = I2C_TRANSFER(priv->i2c, msg, 1); + if (ret < 0) + { + snerr("I2C_TRANSFER failed: %d\n", ret); + } + +#else /* CONFIG_SENSORS_BMI160_SPI */ + /* If SPI bus is shared then lock and configure it */ + + (void)SPI_LOCK(priv->spi, true); + bmi160_configspi(priv->spi); + + /* Select the BMI160 */ + + SPI_SELECT(priv->spi, SPIDEV_ACCELEROMETER(0), true); + + /* Send register address and set the value */ + + (void)SPI_SEND(priv->spi, regaddr); + (void)SPI_SEND(priv->spi, regval); + + /* Deselect the BMI160 */ + + SPI_SELECT(priv->spi, SPIDEV_ACCELEROMETER(0), false); + + /* Unlock bus */ + + (void)SPI_LOCK(priv->spi, false); + +#endif +} + +/**************************************************************************** + * Name: bmi160_getreg16 + * + * Description: + * Read 16-bits of data from an BMI160 register + * + ****************************************************************************/ + +static uint16_t bmi160_getreg16(FAR struct bmi160_dev_s *priv, + uint8_t regaddr) +{ + uint16_t regval = 0; + +#ifdef CONFIG_SENSORS_BMI160_I2C + struct i2c_msg_s msg[2]; + int ret; + + msg[0].frequency = priv->freq; + msg[0].addr = priv->addr; + msg[0].flags = 0; + msg[0].buffer = ®addr; + msg[0].length = 1; + + msg[1].frequency = priv->freq; + msg[1].addr = priv->addr; + msg[1].flags = I2C_M_READ; + msg[1].buffer = (uint8_t *)®val; + msg[1].length = 2; + + ret = I2C_TRANSFER(priv->i2c, msg, 2); + if (ret < 0) + { + snerr("I2C_TRANSFER failed: %d\n", ret); + } + +#else /* CONFIG_SENSORS_BMI160_SPI */ + /* If SPI bus is shared then lock and configure it */ + + (void)SPI_LOCK(priv->spi, true); + bmi160_configspi(priv->spi); + + /* Select the BMI160 */ + + SPI_SELECT(priv->spi, SPIDEV_ACCELEROMETER(0), true); + + /* Send register to read and get the next 2 bytes */ + + (void)SPI_SEND(priv->spi, regaddr | 0x80); + SPI_RECVBLOCK(priv->spi, ®val, 2); + + /* Deselect the BMI160 */ + + SPI_SELECT(priv->spi, SPIDEV_ACCELEROMETER(0), false); + + /* Unlock bus */ + + (void)SPI_LOCK(priv->spi, false); +#endif + + return regval; +} + +/**************************************************************************** + * Name: bmi160_getregs + * + * Description: + * Read cnt bytes from specified dev_addr and reg_addr + * + ****************************************************************************/ + +static void bmi160_getregs(FAR struct bmi160_dev_s *priv, uint8_t regaddr, + uint8_t *regval, int len) +{ +#ifdef CONFIG_SENSORS_BMI160_I2C + struct i2c_msg_s msg[2]; + int ret; + + msg[0].frequency = priv->freq; + msg[0].addr = priv->addr; + msg[0].flags = 0; + msg[0].buffer = ®addr; + msg[0].length = 1; + + msg[1].frequency = priv->freq; + msg[1].addr = priv->addr; + msg[1].flags = I2C_M_READ; + msg[1].buffer = regval; + msg[1].length = len; + + ret = I2C_TRANSFER(priv->i2c, msg, 2); + if (ret < 0) + { + snerr("I2C_TRANSFER failed: %d\n", ret); + } + +#else /* CONFIG_SENSORS_BMI160_SPI */ + /* If SPI bus is shared then lock and configure it */ + + (void)SPI_LOCK(priv->spi, true); + bmi160_configspi(priv->spi); + + /* Select the BMI160 */ + + SPI_SELECT(priv->spi, SPIDEV_ACCELEROMETER(0), true); + + /* Send register to read and get the next 2 bytes */ + + (void)SPI_SEND(priv->spi, regaddr | 0x80); + SPI_RECVBLOCK(priv->spi, regval, len); + + /* Deselect the BMI160 */ + + SPI_SELECT(priv->spi, SPIDEV_ACCELEROMETER(0), false); + + /* Unlock bus */ + + (void)SPI_LOCK(priv->spi, false); + +#endif +} + +/**************************************************************************** + * Name: bmi160_set_normal_imu + * + * Description: + * set bmi160 to normal IMU mode. + * + ****************************************************************************/ + +static void bmi160_set_normal_imu(FAR struct bmi160_dev_s *priv) +{ + /* Set accel & gyro as normal mode. */ + + bmi160_putreg8(priv, BMI160_CMD, ACCEL_PM_NORMAL); + up_mdelay(30); + bmi160_putreg8(priv, BMI160_CMD, GYRO_PM_NORMAL); + up_mdelay(30); + + /* Set accel & gyro output data rate. */ + + bmi160_putreg8(priv, BMI160_ACCEL_CONFIG, + ACCEL_NORMAL_AVG4 | ACCEL_ODR_100HZ); + bmi160_putreg8(priv, BMI160_GYRO_CONFIG, GYRO_NORMAL_MODE | GYRO_ODR_100HZ); +} + +/**************************************************************************** + * Name: bmi160_open + * + * Description: + * Standard character driver open method. + * + ****************************************************************************/ + +static int bmi160_open(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct bmi160_dev_s *priv = inode->i_private; + + bmi160_set_normal_imu(priv); + + return OK; +} + +/**************************************************************************** + * Name: bmi160_close + * + * Description: + * Standard character driver close method. + * + ****************************************************************************/ + +static int bmi160_close(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct bmi160_dev_s *priv = inode->i_private; + + /* Set suspend mode to each sensors. */ + + bmi160_putreg8(priv, BMI160_CMD, ACCEL_PM_SUSPEND); + up_mdelay(30); + + bmi160_putreg8(priv, BMI160_CMD, GYRO_PM_SUSPEND); + up_mdelay(30); + + return OK; +} + +/**************************************************************************** + * Name: bmi160_read + * + * Description: + * Standard character driver read method. + * + ****************************************************************************/ + +static ssize_t bmi160_read(FAR struct file *filep, FAR char *buffer, + size_t len) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct bmi160_dev_s *priv = inode->i_private; + FAR struct accel_gyro_st_s *p = (FAR struct accel_gyro_st_s *)buffer; + + if (len < sizeof(struct accel_gyro_st_s)) + { + snerr("Expected buffer size is %d\n", sizeof(struct accel_gyro_st_s)); + return 0; + } + + bmi160_getregs(priv, BMI160_DATA_8, (FAR uint8_t *)buffer, 15); + + /* Adjust sensing time into 24 bit */ + + p->sensor_time >>= 8; + + return len; +} + +static void bmi160_enable_stepcounter(FAR struct bmi160_dev_s *priv, + int enable) +{ + uint8_t val; + + val = bmi160_getreg8(priv, BMI160_STEP_CONFIG_1); + if (enable) + { + val |= STEP_CNT_EN; + } + else + { + val &= ~STEP_CNT_EN; + } + bmi160_putreg8(priv, BMI160_STEP_CONFIG_1, val); + + sninfo("Step counter %sabled.\n", val & STEP_CNT_EN ? "en" : "dis"); +} + +/**************************************************************************** + * Name: bmi160_ioctl + * + * Description: + * Standard character driver ioctl method. + * + ****************************************************************************/ + +static int bmi160_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct bmi160_dev_s *priv = inode->i_private; + int ret = OK; + + switch (cmd) + { + /* Enable bmi160 step counter. Arg: int value */ + + case SNIOC_ENABLESC: + { + bmi160_enable_stepcounter(priv, (int)arg); + } + break; + + /* Read bmi160 step count. Arg: int16_t* pointer */ + + case SNIOC_READSC: + { + int16_t *ptr = (FAR int16_t *)((uintptr_t)arg); + + DEBUGASSERT(ptr != NULL); + + *ptr = bmi160_getreg16(priv, BMI160_STEP_COUNT_0); + } + break; + + default: + snerr("Unrecognized cmd: %d\n", cmd); + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: bmi160_checkid + * + * Description: + * Read and verify the BMI160 chip ID + * + ****************************************************************************/ + +static int bmi160_checkid(FAR struct bmi160_dev_s *priv) +{ + uint8_t devid = 0; + + /* Read device ID */ + + devid = bmi160_getreg8(priv, BMI160_CHIP_ID); + sninfo("devid: %04x\n", devid); + + if (devid != (uint16_t) DEVID) + { + /* ID is not Correct */ + + return -ENODEV; + } + + return OK; +} + +/**************************************************************************** + * Name: bmi160_register + * + * Description: + * Register the BMI160 character device as 'devpath' + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/press0" + * dev - An instance of the SPI interface to use to communicate with + * BMI160 + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_SENSORS_BMI160_I2C +int bmi160_register(FAR const char *devpath, FAR struct i2c_master_s *dev) +#else /* CONFIG_SENSORS_BMI160_SPI */ +int bmi160_register(FAR const char *devpath, FAR struct spi_dev_s *dev) +#endif +{ + FAR struct bmi160_dev_s *priv; + int ret; + + priv = (FAR struct bmi160_dev_s *)kmm_malloc(sizeof(struct bmi160_dev_s)); + if (!priv) + { + snerr("Failed to allocate instance\n"); + return -ENOMEM; + } +#ifdef CONFIG_SENSORS_BMI160_I2C + priv->i2c = dev; + priv->addr = BMI160_I2C_ADDR; + priv->freq = BMI160_I2C_FREQ; + +#else /* CONFIG_SENSORS_BMI160_SPI */ + priv->spi = dev; + + /* BMI160 detects communication bus is SPI by rising edge of CS. */ + + bmi160_getreg8(priv, 0x7f); + bmi160_getreg8(priv, 0x7f); /* workaround: fail to switch SPI, run twice */ + up_udelay(200); + +#endif + + ret = bmi160_checkid(priv); + if (ret < 0) + { + snerr("Wrong Device ID!\n"); + kmm_free(priv); + return ret; + } + + /* To avoid gyro wakeup it is required to write 0x00 to 0x6C */ + + bmi160_putreg8(priv, BMI160_PMU_TRIGGER, 0); + + ret = register_driver(devpath, &g_bmi160fops, 0666, priv); + if (ret < 0) + { + snerr("Failed to register driver: %d\n", ret); + kmm_free(priv); + } + + sninfo("BMI160 driver loaded successfully!\n"); + return OK; +} + +#endif /* CONFIG_SENSORS_BMI160 */ diff --git a/include/nuttx/sensors/bmi160.h b/include/nuttx/sensors/bmi160.h new file mode 100644 index 00000000000..1d5a764ef58 --- /dev/null +++ b/include/nuttx/sensors/bmi160.h @@ -0,0 +1,148 @@ +/**************************************************************************** + * include/nuttx/sensors/bmi160.h + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_SENSORS_BMI160_H +#define __INCLUDE_NUTTX_SENSORS_BMI160_H + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BMI160_SPI_MAXFREQUENCY 10000000 + +/* Configuration ************************************************************/ + +/* Power mode */ + +#define BMI160_PM_SUSPEND (0x00) +#define BMI160_PM_NORMAL (0x01) +#define BMI160_PM_LOWPOWER (0x02) +#define BMI160_PM_FASTSTARTUP (0x03) + +/* Output data rate */ + +#define BMI160_ACCEL_ODR_0_78HZ (0x01) +#define BMI160_ACCEL_ODR_1_56HZ (0x02) +#define BMI160_ACCEL_ODR_3_12HZ (0x03) +#define BMI160_ACCEL_ODR_6_25HZ (0x04) +#define BMI160_ACCEL_ODR_12_5HZ (0x05) +#define BMI160_ACCEL_ODR_25HZ (0x06) +#define BMI160_ACCEL_ODR_50HZ (0x07) +#define BMI160_ACCEL_ODR_100HZ (0x08) +#define BMI160_ACCEL_ODR_200HZ (0x09) +#define BMI160_ACCEL_ODR_400HZ (0x0A) +#define BMI160_ACCEL_ODR_800HZ (0x0B) +#define BMI160_ACCEL_ODR_1600HZ (0x0C) + +/* IOCTL Commands ***********************************************************/ + +#define SNIOC_ENABLESC _SNIOC(0x0001) /* Arg: uint8_t value */ +#define SNIOC_READSC _SNIOC(0x0002) /* Arg: int16_t* pointer */ +#define SNIOC_SETACCPM _SNIOC(0x0003) /* Arg: uint8_t value */ +#define SNIOC_SETACCODR _SNIOC(0x0004) /* Arg: uint8_t value */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ +/**************************************************************************** + * struct 6-axis data + ****************************************************************************/ +struct accel_t +{ + int16_t x; + int16_t y; + int16_t z; +}; + +struct gyro_t +{ + int16_t x; + int16_t y; + int16_t z; +}; + +struct accel_gyro_st_s +{ + struct gyro_t gyro; + struct accel_t accel; + uint32_t sensor_time; +}; + +struct spi_dev_s; +struct i2c_master_s; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: bmi160_register + * + * Description: + * Register the BMI160 character device as 'devpath' + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/accel0" + * dev - An instance of the SPI or I2C interface to use to communicate + * with BMI160 + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +# ifdef CONFIG_SENSORS_BMI160_I2C +int bmi160_register(FAR const char *devpath, FAR struct i2c_master_s *dev); +# else +int bmi160_register(FAR const char *devpath, FAR struct spi_dev_s *dev); +# endif + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_SENSORS_BMI160_H */