sensor: add driver for BMA280 accelerometer
Add device driver for the BMA280 I2C-based triaxial accelerometer sensor, which supports reading data from the accel-x, accel-y, accel-z and temperature channels. The driver also has support for data-ready and any-motion triggers. Datasheet: http://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMA280-DS000-11_published.pdf Origin: Original Change-Id: Iff7246d7dd4a9358ec7a71e8ffbcfcccd49e393c Signed-off-by: Bogdan Davidoaia <bogdan.m.davidoaia@intel.com> Signed-off-by: Teodora Baluta <teodora.baluta@intel.com>
This commit is contained in:
parent
ace49af6b0
commit
fe9c947fee
|
@ -44,6 +44,8 @@ config SENSOR_DEBUG
|
|||
help
|
||||
This option enables debug output for sensor drivers.
|
||||
|
||||
source "drivers/sensor/Kconfig.bma280"
|
||||
|
||||
source "drivers/sensor/Kconfig.mcp9808"
|
||||
|
||||
source "drivers/sensor/Kconfig.sx9500"
|
||||
|
|
201
drivers/sensor/Kconfig.bma280
Normal file
201
drivers/sensor/Kconfig.bma280
Normal file
|
@ -0,0 +1,201 @@
|
|||
# Kconfig.bma280 - BMA280 Three Axis Accelerometer configuration options
|
||||
|
||||
#
|
||||
# Copyright (c) 2016 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
menuconfig BMA280
|
||||
bool
|
||||
prompt "BMA280 Three Axis Accelerometer"
|
||||
depends on SENSOR && I2C
|
||||
default n
|
||||
help
|
||||
Enable driver for BMA280 I2C-based triaxial accelerometer sensor.
|
||||
|
||||
config BMA280_NAME
|
||||
string
|
||||
prompt "Driver name"
|
||||
default "BMA280"
|
||||
depends on BMA280
|
||||
help
|
||||
Device name with which the BMA280 sensor is identified.
|
||||
|
||||
config BMA280_INIT_PRIORITY
|
||||
int
|
||||
prompt "Init priority"
|
||||
depends on BMA280
|
||||
default 70
|
||||
help
|
||||
Device driver initialization priority.
|
||||
|
||||
choice
|
||||
prompt "I2C address"
|
||||
depends on BMA280
|
||||
default BMA280_I2C_ADDR_0x18
|
||||
help
|
||||
I2C address of the BMA280 sensor.
|
||||
|
||||
config BMA280_I2C_ADDR_0x18
|
||||
bool
|
||||
prompt "0x18"
|
||||
help
|
||||
Choose this option if the SDO pin is pulled to GND.
|
||||
|
||||
config BMA280_I2C_ADDR_0x19
|
||||
bool
|
||||
prompt "0x19"
|
||||
help
|
||||
Choose this option if the SDO pin is pulled to VDDIO.
|
||||
|
||||
endchoice
|
||||
|
||||
config BMA280_I2C_MASTER_DEV_NAME
|
||||
string
|
||||
prompt "I2C master where BMA280 is connected"
|
||||
depends on BMA280
|
||||
default "I2C0"
|
||||
help
|
||||
Specify the device name of the I2C master device to which BMA280 is
|
||||
connected.
|
||||
|
||||
choice
|
||||
prompt "Trigger mode"
|
||||
depends on BMA280
|
||||
default BMA280_TRIGGER_GLOBAL_FIBER
|
||||
help
|
||||
Specify the type of triggering to be used by the driver.
|
||||
|
||||
config BMA280_TRIGGER_NONE
|
||||
bool
|
||||
prompt "No trigger"
|
||||
|
||||
config BMA280_TRIGGER_GLOBAL_FIBER
|
||||
bool
|
||||
prompt "Use global fiber"
|
||||
depends on GPIO
|
||||
select BMA280_TRIGGER
|
||||
select SENSOR_DELAYED_WORK
|
||||
|
||||
config BMA280_TRIGGER_OWN_FIBER
|
||||
bool
|
||||
prompt "Use own fiber"
|
||||
depends on GPIO
|
||||
select BMA280_TRIGGER
|
||||
|
||||
endchoice
|
||||
|
||||
config BMA280_TRIGGER
|
||||
bool
|
||||
depends on BMA280
|
||||
|
||||
config BMA280_GPIO_DEV_NAME
|
||||
string
|
||||
prompt "GPIO device"
|
||||
default "GPIO_0"
|
||||
depends on BMA280 && BMA280_TRIGGER
|
||||
help
|
||||
The device name of the GPIO device to which the BMA280 interrupt pins
|
||||
are connected.
|
||||
|
||||
config BMA280_GPIO_PIN_NUM
|
||||
int
|
||||
prompt "Interrupt GPIO pin number"
|
||||
default 0
|
||||
depends on BMA280 && BMA280_TRIGGER
|
||||
help
|
||||
The number of the GPIO on which the interrupt signal from the BMA280
|
||||
chip will be received.
|
||||
|
||||
config BMA280_FIBER_PRIORITY
|
||||
int
|
||||
prompt "Fiber priority"
|
||||
depends on BMA280 && BMA280_TRIGGER_OWN_FIBER
|
||||
default 10
|
||||
help
|
||||
Priority of fiber used by the driver to handle interrupts.
|
||||
|
||||
config BMA280_FIBER_STACK_SIZE
|
||||
int
|
||||
prompt "Fiber stack size"
|
||||
depends on BMA280 && BMA280_TRIGGER_OWN_FIBER
|
||||
default 1024
|
||||
help
|
||||
Stack size of fiber used by the driver to handle interrupts.
|
||||
|
||||
choice
|
||||
prompt "Acceleration measurement range"
|
||||
depends on BMA280
|
||||
default BMA280_PMU_RANGE_2G
|
||||
help
|
||||
Measurement range for acceleration values.
|
||||
|
||||
config BMA280_PMU_RANGE_2G
|
||||
bool
|
||||
prompt "+/-2g"
|
||||
|
||||
config BMA280_PMU_RANGE_4G
|
||||
bool
|
||||
prompt "+/-4g"
|
||||
|
||||
config BMA280_PMU_RANGE_8G
|
||||
bool
|
||||
prompt "+/-8g"
|
||||
|
||||
config BMA280_PMU_RANGE_16G
|
||||
bool
|
||||
prompt "+/-16g"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Acceleration data filter bandwidth"
|
||||
depends on BMA280
|
||||
default BMA280_PMU_BW_7
|
||||
help
|
||||
Bandwidth of filtered acceleration data.
|
||||
|
||||
config BMA280_PMU_BW_1
|
||||
bool
|
||||
prompt "7.81Hz"
|
||||
|
||||
config BMA280_PMU_BW_2
|
||||
bool
|
||||
prompt "15.63HZ"
|
||||
|
||||
config BMA280_PMU_BW_3
|
||||
bool
|
||||
prompt "31.25Hz"
|
||||
|
||||
config BMA280_PMU_BW_4
|
||||
bool
|
||||
prompt "62.5Hz"
|
||||
|
||||
config BMA280_PMU_BW_5
|
||||
bool
|
||||
prompt "125Hz"
|
||||
|
||||
config BMA280_PMU_BW_6
|
||||
bool
|
||||
prompt "250HZ"
|
||||
|
||||
config BMA280_PMU_BW_7
|
||||
bool
|
||||
prompt "500Hz"
|
||||
|
||||
config BMA280_PMU_BW_8
|
||||
bool
|
||||
prompt "unfiltered"
|
||||
|
||||
endchoice
|
|
@ -2,6 +2,8 @@ ccflags-y +=-I$(srctree)/drivers
|
|||
|
||||
obj-$(CONFIG_SENSOR_DELAYED_WORK) += sensor.o
|
||||
|
||||
obj-$(CONFIG_BMA280) += sensor_bma280.o
|
||||
obj-$(CONFIG_BMA280_TRIGGER) += sensor_bma280_trigger.o
|
||||
obj-$(CONFIG_MCP9808) += sensor_mcp9808.o
|
||||
obj-$(CONFIG_MCP9808_TRIGGER) += sensor_mcp9808_trigger.o
|
||||
obj-$(CONFIG_SX9500) += sensor_sx9500.o
|
||||
|
|
217
drivers/sensor/sensor_bma280.c
Normal file
217
drivers/sensor/sensor_bma280.c
Normal file
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <i2c.h>
|
||||
#include <init.h>
|
||||
#include <sensor.h>
|
||||
|
||||
#include "sensor_bma280.h"
|
||||
|
||||
static int bma280_reg_burst_read(struct bma280_data *drv_data,
|
||||
uint8_t reg, uint8_t *buff,
|
||||
int buff_len)
|
||||
{
|
||||
struct i2c_msg msgs[2] = {
|
||||
{
|
||||
.buf = ®,
|
||||
.len = 1,
|
||||
.flags = I2C_MSG_WRITE | I2C_MSG_RESTART,
|
||||
},
|
||||
{
|
||||
.buf = buff,
|
||||
.len = buff_len,
|
||||
.flags = I2C_MSG_READ | I2C_MSG_STOP,
|
||||
},
|
||||
};
|
||||
|
||||
return i2c_transfer(drv_data->i2c, msgs, 2, BMA280_I2C_ADDRESS);
|
||||
}
|
||||
|
||||
int bma280_reg_read(struct bma280_data *drv_data,
|
||||
uint8_t reg, uint8_t *val)
|
||||
{
|
||||
return bma280_reg_burst_read(drv_data, reg, val, 1);
|
||||
}
|
||||
|
||||
int bma280_reg_write(struct bma280_data *drv_data,
|
||||
uint8_t reg, uint8_t val)
|
||||
{
|
||||
uint8_t tx_buf[2] = {reg, val};
|
||||
|
||||
return i2c_write(drv_data->i2c, tx_buf, sizeof(tx_buf),
|
||||
BMA280_I2C_ADDRESS);
|
||||
}
|
||||
|
||||
int bma280_reg_update(struct bma280_data *drv_data,
|
||||
uint8_t reg, uint8_t mask, uint8_t val)
|
||||
{
|
||||
uint8_t old_val = 0;
|
||||
uint8_t new_val;
|
||||
|
||||
if (bma280_reg_read(drv_data, reg, &old_val) != DEV_OK) {
|
||||
return DEV_FAIL;
|
||||
}
|
||||
|
||||
new_val = old_val & ~mask;
|
||||
new_val |= val & mask;
|
||||
|
||||
return bma280_reg_write(drv_data, reg, new_val);
|
||||
}
|
||||
|
||||
static int bma280_sample_fetch(struct device *dev)
|
||||
{
|
||||
struct bma280_data *drv_data = dev->driver_data;
|
||||
uint8_t buf[6];
|
||||
uint8_t lsb;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* since all accel data register addresses are consecutive,
|
||||
* a burst read can be used to read all the samples
|
||||
*/
|
||||
rc = bma280_reg_burst_read(drv_data, BMA280_REG_ACCEL_X_LSB, buf, 6);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not read accel axis data\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
|
||||
lsb = (buf[0] & BMA280_ACCEL_LSB_MASK) >> BMA280_ACCEL_LSB_SHIFT;
|
||||
drv_data->x_sample = (((int8_t)buf[1]) << BMA280_ACCEL_LSB_BITS) + lsb;
|
||||
|
||||
lsb = (buf[2] & BMA280_ACCEL_LSB_MASK) >> BMA280_ACCEL_LSB_SHIFT;
|
||||
drv_data->y_sample = (((int8_t)buf[3]) << BMA280_ACCEL_LSB_BITS) + lsb;
|
||||
|
||||
lsb = (buf[4] & BMA280_ACCEL_LSB_MASK) >> BMA280_ACCEL_LSB_SHIFT;
|
||||
drv_data->z_sample = (((int8_t)buf[5]) << BMA280_ACCEL_LSB_BITS) + lsb;
|
||||
|
||||
rc = bma280_reg_read(drv_data, BMA280_REG_TEMP, (uint8_t *)&drv_data->temp_sample);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not read temperature data\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
|
||||
return DEV_OK;
|
||||
}
|
||||
|
||||
static int bma280_channel_get(struct device *dev,
|
||||
enum sensor_channel chan,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
struct bma280_data *drv_data = dev->driver_data;
|
||||
int64_t raw_val;
|
||||
|
||||
/*
|
||||
* See datasheet "Sensor data" section for
|
||||
* more details on processing sample data.
|
||||
*/
|
||||
if (chan == SENSOR_CHAN_ACCEL_X) {
|
||||
raw_val = drv_data->x_sample;
|
||||
} else if (chan == SENSOR_CHAN_ACCEL_Y) {
|
||||
raw_val = drv_data->y_sample;
|
||||
} else if (chan == SENSOR_CHAN_ACCEL_Z) {
|
||||
raw_val = drv_data->z_sample;
|
||||
} else if (chan == SENSOR_CHAN_TEMP) {
|
||||
/* temperature_val = 23 + sample / 2 */
|
||||
val->type = SENSOR_TYPE_INT_PLUS_MICRO;
|
||||
val->val1 = (drv_data->temp_sample >> 1) + 23;
|
||||
val->val2 = 500000 * (drv_data->temp_sample & 1);
|
||||
return DEV_OK;
|
||||
} else {
|
||||
return DEV_INVALID_OP;
|
||||
}
|
||||
|
||||
/* accel_val = sample * BMA280_ACCEL_SCALE / 1000 */
|
||||
val->type = SENSOR_TYPE_INT_PLUS_MICRO;
|
||||
raw_val = raw_val * BMA280_ACCEL_SCALE;
|
||||
val->val1 = raw_val / 1000000000L;
|
||||
val->val2 = (raw_val % 1000000000L) / 1000;
|
||||
|
||||
/* normalize val to make sure val->val2 is positive */
|
||||
if (val->val2 < 0) {
|
||||
val->val1 -= 1;
|
||||
val->val2 += 1000000;
|
||||
}
|
||||
|
||||
return DEV_OK;
|
||||
}
|
||||
|
||||
static struct sensor_driver_api bma280_driver_api = {
|
||||
#if CONFIG_BMA280_TRIGGER
|
||||
.attr_set = bma280_attr_set,
|
||||
.trigger_set = bma280_trigger_set,
|
||||
#endif
|
||||
.sample_fetch = bma280_sample_fetch,
|
||||
.channel_get = bma280_channel_get,
|
||||
};
|
||||
|
||||
int bma280_init(struct device *dev)
|
||||
{
|
||||
struct bma280_data *drv_data = dev->driver_data;
|
||||
uint8_t id = 0;
|
||||
int rc;
|
||||
|
||||
dev->driver_api = &bma280_driver_api;
|
||||
|
||||
drv_data->i2c = device_get_binding(CONFIG_BMA280_I2C_MASTER_DEV_NAME);
|
||||
if (drv_data->i2c == NULL) {
|
||||
DBG("Could not get pointer to %s device\n",
|
||||
CONFIG_BMA280_I2C_MASTER_DEV_NAME);
|
||||
return DEV_INVALID_CONF;
|
||||
}
|
||||
|
||||
/* read device ID */
|
||||
rc = bma280_reg_read(drv_data, BMA280_REG_CHIP_ID, &id);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not read chip id\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
|
||||
if (id != BMA280_CHIP_ID) {
|
||||
DBG("Unexpected chip id (%x)\n", id);
|
||||
return DEV_FAIL;
|
||||
}
|
||||
|
||||
/* set the data filter bandwidth */
|
||||
rc = bma280_reg_write(drv_data, BMA280_REG_PMU_BW,
|
||||
BMA280_PMU_BW);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not set data filter bandwidth\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
|
||||
/* set g-range */
|
||||
rc = bma280_reg_write(drv_data, BMA280_REG_PMU_RANGE,
|
||||
BMA280_PMU_RANGE);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not set data g-range\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BMA280_TRIGGER
|
||||
rc = bma280_init_interrupt(dev);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not initialize interrupts\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return DEV_OK;
|
||||
}
|
||||
|
||||
struct bma280_data bma280_driver;
|
||||
|
||||
DEVICE_INIT(bma280, CONFIG_BMA280_NAME, bma280_init, &bma280_driver,
|
||||
NULL, SECONDARY, CONFIG_BMA280_INIT_PRIORITY);
|
177
drivers/sensor/sensor_bma280.h
Normal file
177
drivers/sensor/sensor_bma280.h
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __SENSOR_BMA280_H__
|
||||
#define __SENSOR_BMA280_H__
|
||||
|
||||
#include <device.h>
|
||||
#include <misc/util.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef CONFIG_SENSOR_DEBUG
|
||||
#define DBG(...) { ; }
|
||||
#else
|
||||
#include <misc/printk.h>
|
||||
#define DBG printk
|
||||
#endif /* CONFIG_SENSOR_DEBUG */
|
||||
|
||||
#if CONFIG_BMA280_I2C_ADDR_0x18
|
||||
#define BMA280_I2C_ADDRESS 0x18
|
||||
#elif CONFIG_BMA280_I2C_ADDR_0x19
|
||||
#define BMA280_I2C_ADDRESS 0x19
|
||||
#endif
|
||||
|
||||
#define BMA280_REG_CHIP_ID 0x00
|
||||
#define BMA280_CHIP_ID 0xFB
|
||||
|
||||
#define BMA280_REG_PMU_BW 0x10
|
||||
#if CONFIG_BMA280_PMU_BW_1
|
||||
#define BMA280_PMU_BW 0x08
|
||||
#elif CONFIG_BMA280_PMU_BW_2
|
||||
#define BMA280_PMU_BW 0x09
|
||||
#elif CONFIG_BMA280_PMU_BW_3
|
||||
#define BMA280_PMU_BW 0x0A
|
||||
#elif CONFIG_BMA280_PMU_BW_4
|
||||
#define BMA280_PMU_BW 0x0B
|
||||
#elif CONFIG_BMA280_PMU_BW_5
|
||||
#define BMA280_PMU_BW 0x0C
|
||||
#elif CONFIG_BMA280_PMU_BW_6
|
||||
#define BMA280_PMU_BW 0x0D
|
||||
#elif CONFIG_BMA280_PMU_BW_7
|
||||
#define BMA280_PMU_BW 0x0E
|
||||
#elif CONFIG_BMA280_PMU_BW_8
|
||||
#define BMA280_PMU_BW 0x0F
|
||||
#endif
|
||||
|
||||
/*
|
||||
* accel and slope scale measured in nano-m/s^2 instead
|
||||
* of m/s^2 to avoid using struct sensor_value for it
|
||||
*/
|
||||
#define GRAVITY_CONST 9807
|
||||
#define BMA280_REG_PMU_RANGE 0x0F
|
||||
#if CONFIG_BMA280_PMU_RANGE_2G
|
||||
#define BMA280_PMU_RANGE 0x03
|
||||
#define BMA280_ACCEL_SCALE (244 * GRAVITY_CONST)
|
||||
#define BMA280_SLOPE_TH_SCALE 3910
|
||||
#elif CONFIG_BMA280_PMU_RANGE_4G
|
||||
#define BMA280_PMU_RANGE 0x05
|
||||
#define BMA280_ACCEL_SCALE (488 * GRAVITY_CONST)
|
||||
#define BMA280_SLOPE_TH_SCALE 7810
|
||||
#elif CONFIG_BMA280_PMU_RANGE_8G
|
||||
#define BMA280_PMU_RANGE 0x08
|
||||
#define BMA280_ACCEL_SCALE (977 * GRAVITY_CONST)
|
||||
#define BMA280_SLOPE_TH_SCALE 15630
|
||||
#elif CONFIG_BMA280_PMU_RANGE_16G
|
||||
#define BMA280_PMU_RANGE 0x0C
|
||||
#define BMA280_ACCEL_SCALE (1953 * GRAVITY_CONST)
|
||||
#define BMA280_SLOPE_TH_SCALE 31250
|
||||
#endif
|
||||
|
||||
#define BMA280_REG_TEMP 0x08
|
||||
|
||||
#define BMA280_REG_INT_STATUS_0 0x09
|
||||
#define BMA280_BIT_SLOPE_INT_STATUS BIT(2)
|
||||
#define BMA280_REG_INT_STATUS_1 0x0A
|
||||
#define BMA280_BIT_DATA_INT_STATUS BIT(7)
|
||||
|
||||
#define BMA280_REG_INT_EN_0 0x16
|
||||
#define BMA280_BIT_SLOPE_EN_X BIT(0)
|
||||
#define BMA280_BIT_SLOPE_EN_Y BIT(1)
|
||||
#define BMA280_BIT_SLOPE_EN_Z BIT(2)
|
||||
#define BMA280_SLOPE_EN_XYZ (BMA280_BIT_SLOPE_EN_X | \
|
||||
BMA280_BIT_SLOPE_EN_Y | BMA280_BIT_SLOPE_EN_X)
|
||||
|
||||
#define BMA280_REG_INT_EN_1 0x17
|
||||
#define BMA280_BIT_DATA_EN BIT(4)
|
||||
|
||||
#define BMA280_REG_INT_MAP_0 0x19
|
||||
#define BMA280_INT_MAP_0_BIT_SLOPE BIT(2)
|
||||
|
||||
#define BMA280_REG_INT_MAP_1 0x1A
|
||||
#define BMA280_INT_MAP_1_BIT_DATA BIT(0)
|
||||
|
||||
#define BMA280_REG_INT_RST_LATCH 0x21
|
||||
#define BMA280_INT_MODE_LATCH 0x0F
|
||||
#define BMA280_BIT_INT_LATCH_RESET BIT(7)
|
||||
|
||||
#define BMA280_REG_INT_5 0x27
|
||||
#define BMA280_SLOPE_DUR_SHIFT 0
|
||||
#define BMA280_SLOPE_DUR_MASK (3 << BMA280_SLOPE_DUR_SHIFT)
|
||||
|
||||
#define BMA280_REG_SLOPE_TH 0x28
|
||||
|
||||
#define BMA280_REG_ACCEL_X_LSB 0x2
|
||||
#define BMA280_REG_ACCEL_Y_LSB 0x4
|
||||
#define BMA280_REG_ACCEL_Z_LSB 0x6
|
||||
#define BMA280_ACCEL_LSB_BITS 6
|
||||
#define BMA280_ACCEL_LSB_SHIFT 2
|
||||
#define BMA280_ACCEL_LSB_MASK (0x3F << BMA280_ACCEL_LSB_SHIFT)
|
||||
#define BMA280_REG_ACCEL_X_MSB 0x3
|
||||
#define BMA280_REG_ACCEL_Y_MSB 0x5
|
||||
#define BMA280_REG_ACCEL_Z_MSB 0x7
|
||||
|
||||
#define BMA280_FIBER_PRIORITY 10
|
||||
#define BMA280_FIBER_STACKSIZE_UNIT 1024
|
||||
|
||||
struct bma280_data {
|
||||
struct device *i2c;
|
||||
int16_t x_sample;
|
||||
int16_t y_sample;
|
||||
int16_t z_sample;
|
||||
int8_t temp_sample;
|
||||
|
||||
#ifdef CONFIG_BMA280_TRIGGER
|
||||
struct device *gpio;
|
||||
|
||||
struct sensor_trigger data_ready_trigger;
|
||||
sensor_trigger_handler_t data_ready_handler;
|
||||
|
||||
struct sensor_trigger any_motion_trigger;
|
||||
sensor_trigger_handler_t any_motion_handler;
|
||||
|
||||
#if defined(CONFIG_BMA280_TRIGGER_OWN_FIBER)
|
||||
char __stack fiber_stack[CONFIG_BMA280_FIBER_STACK_SIZE];
|
||||
struct nano_sem gpio_sem;
|
||||
#elif defined(CONFIG_BMA280_TRIGGER_GLOBAL_FIBER)
|
||||
struct sensor_work work;
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_BMA280_TRIGGER */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_BMA280_TRIGGER
|
||||
int bma280_reg_write(struct bma280_data *drv_data,
|
||||
uint8_t reg, uint8_t val);
|
||||
|
||||
int bma280_reg_read(struct bma280_data *drv_data,
|
||||
uint8_t reg, uint8_t *val);
|
||||
|
||||
int bma280_reg_update(struct bma280_data *drv_data,
|
||||
uint8_t reg, uint8_t mask, uint8_t val);
|
||||
|
||||
int bma280_trigger_set(struct device *dev,
|
||||
const struct sensor_trigger *trig,
|
||||
sensor_trigger_handler_t handler);
|
||||
|
||||
int bma280_attr_set(struct device *dev,
|
||||
enum sensor_channel chan,
|
||||
enum sensor_attribute attr,
|
||||
const struct sensor_value *val);
|
||||
|
||||
int bma280_init_interrupt(struct device *dev);
|
||||
#endif
|
||||
|
||||
#endif /* __SENSOR_BMA280_H__ */
|
255
drivers/sensor/sensor_bma280_trigger.c
Normal file
255
drivers/sensor/sensor_bma280_trigger.c
Normal file
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <device.h>
|
||||
#include <gpio.h>
|
||||
#include <misc/util.h>
|
||||
#include <nanokernel.h>
|
||||
#include <sensor.h>
|
||||
|
||||
#include "sensor_bma280.h"
|
||||
|
||||
extern struct bma280_data bma280_driver;
|
||||
|
||||
int bma280_attr_set(struct device *dev,
|
||||
enum sensor_channel chan,
|
||||
enum sensor_attribute attr,
|
||||
const struct sensor_value *val)
|
||||
{
|
||||
struct bma280_data *drv_data = dev->driver_data;
|
||||
uint64_t slope_th;
|
||||
int rc;
|
||||
|
||||
if (chan != SENSOR_CHAN_ACCEL_ANY) {
|
||||
return DEV_INVALID_OP;
|
||||
}
|
||||
|
||||
if (attr == SENSOR_ATTR_SLOPE_TH) {
|
||||
slope_th = (uint64_t)val->val1 * 1000 / BMA280_SLOPE_TH_SCALE;
|
||||
rc = bma280_reg_write(drv_data, BMA280_REG_SLOPE_TH,
|
||||
(uint8_t)slope_th);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not set slope threshold\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
} else if (attr == SENSOR_ATTR_SLOPE_DUR) {
|
||||
rc = bma280_reg_update(drv_data, BMA280_REG_INT_5,
|
||||
BMA280_SLOPE_DUR_MASK,
|
||||
val->val1 << BMA280_SLOPE_DUR_SHIFT);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not set slope duration\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
} else {
|
||||
return DEV_INVALID_OP;
|
||||
}
|
||||
|
||||
return DEV_OK;
|
||||
}
|
||||
|
||||
static void bma280_gpio_callback(struct device *dev, uint32_t pin)
|
||||
{
|
||||
gpio_pin_disable_callback(dev, pin);
|
||||
|
||||
#if defined(CONFIG_BMA280_TRIGGER_OWN_FIBER)
|
||||
nano_sem_give(&bma280_driver.gpio_sem);
|
||||
#elif defined(CONFIG_BMA280_TRIGGER_GLOBAL_FIBER)
|
||||
nano_isr_fifo_put(sensor_get_work_fifo(), &bma280_driver.work);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void bma280_fiber_cb(void *arg)
|
||||
{
|
||||
struct device *dev = arg;
|
||||
struct bma280_data *drv_data = dev->driver_data;
|
||||
uint8_t status = 0;
|
||||
|
||||
/* check for data ready */
|
||||
bma280_reg_read(drv_data, BMA280_REG_INT_STATUS_1, &status);
|
||||
if (status & BMA280_BIT_DATA_INT_STATUS &&
|
||||
drv_data->data_ready_handler != NULL) {
|
||||
drv_data->data_ready_handler(dev, &drv_data->data_ready_trigger);
|
||||
}
|
||||
|
||||
/* check for any motion */
|
||||
bma280_reg_read(drv_data, BMA280_REG_INT_STATUS_0, &status);
|
||||
if (status & BMA280_BIT_SLOPE_INT_STATUS &&
|
||||
drv_data->any_motion_handler != NULL) {
|
||||
drv_data->any_motion_handler(dev, &drv_data->data_ready_trigger);
|
||||
|
||||
/* clear latched interrupt */
|
||||
bma280_reg_update(drv_data, BMA280_REG_INT_RST_LATCH,
|
||||
BMA280_BIT_INT_LATCH_RESET,
|
||||
BMA280_BIT_INT_LATCH_RESET);
|
||||
}
|
||||
|
||||
gpio_pin_enable_callback(drv_data->gpio, CONFIG_BMA280_GPIO_PIN_NUM);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BMA280_TRIGGER_OWN_FIBER
|
||||
static void bma280_fiber(int dev_ptr, int unused)
|
||||
{
|
||||
struct device *dev = INT_TO_POINTER(dev_ptr);
|
||||
struct bma280_data *drv_data = dev->driver_data;
|
||||
|
||||
ARG_UNUSED(unused);
|
||||
|
||||
while (1) {
|
||||
nano_fiber_sem_take(&drv_data->gpio_sem, TICKS_UNLIMITED);
|
||||
bma280_fiber_cb(dev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int bma280_trigger_set(struct device *dev,
|
||||
const struct sensor_trigger *trig,
|
||||
sensor_trigger_handler_t handler)
|
||||
{
|
||||
struct bma280_data *drv_data = dev->driver_data;
|
||||
int rc;
|
||||
|
||||
if (trig->type == SENSOR_TRIG_DATA_READY) {
|
||||
/* disable data ready interrupt while changing trigger params */
|
||||
rc = bma280_reg_update(drv_data, BMA280_REG_INT_EN_1,
|
||||
BMA280_BIT_DATA_EN, 0);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not disable data ready interrupt\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
|
||||
drv_data->data_ready_handler = handler;
|
||||
if (handler == NULL) {
|
||||
return DEV_OK;
|
||||
}
|
||||
drv_data->data_ready_trigger = *trig;
|
||||
|
||||
/* enable data ready interrupt */
|
||||
rc = bma280_reg_update(drv_data, BMA280_REG_INT_EN_1,
|
||||
BMA280_BIT_DATA_EN, BMA280_BIT_DATA_EN);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not enable data ready interrupt\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
} else if (trig->type == SENSOR_TRIG_DELTA) {
|
||||
/* disable any-motion interrupt while changing trigger params */
|
||||
rc = bma280_reg_update(drv_data, BMA280_REG_INT_EN_0,
|
||||
BMA280_SLOPE_EN_XYZ, 0);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not disable data ready interrupt\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
|
||||
drv_data->any_motion_handler = handler;
|
||||
if (handler == NULL) {
|
||||
return DEV_OK;
|
||||
}
|
||||
drv_data->any_motion_trigger = *trig;
|
||||
|
||||
/* enable any-motion interrupt */
|
||||
rc = bma280_reg_update(drv_data, BMA280_REG_INT_EN_0,
|
||||
BMA280_SLOPE_EN_XYZ, BMA280_SLOPE_EN_XYZ);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not enable data ready interrupt\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
} else {
|
||||
return DEV_INVALID_OP;
|
||||
}
|
||||
|
||||
return DEV_OK;
|
||||
}
|
||||
|
||||
int bma280_init_interrupt(struct device *dev)
|
||||
{
|
||||
struct bma280_data *drv_data = dev->driver_data;
|
||||
int rc;
|
||||
|
||||
/* set latched interrupts */
|
||||
rc = bma280_reg_write(drv_data, BMA280_REG_INT_RST_LATCH,
|
||||
BMA280_BIT_INT_LATCH_RESET |
|
||||
BMA280_INT_MODE_LATCH);
|
||||
if (rc != 0) {
|
||||
DBG("Could not set latched interrupts\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
|
||||
/* setup data ready gpio interrupt */
|
||||
drv_data->gpio = device_get_binding(CONFIG_BMA280_GPIO_DEV_NAME);
|
||||
if (drv_data->gpio == NULL) {
|
||||
DBG("Cannot get pointer to %s device\n",
|
||||
CONFIG_BMA280_GPIO_DEV_NAME);
|
||||
return DEV_INVALID_CONF;
|
||||
}
|
||||
|
||||
gpio_pin_configure(drv_data->gpio, CONFIG_BMA280_GPIO_PIN_NUM,
|
||||
GPIO_DIR_IN | GPIO_INT | GPIO_INT_LEVEL |
|
||||
GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE);
|
||||
|
||||
rc = gpio_set_callback(drv_data->gpio, bma280_gpio_callback);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not set gpio callback\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
|
||||
/* map data ready interrupt to INT1 */
|
||||
rc = bma280_reg_update(drv_data, BMA280_REG_INT_MAP_1,
|
||||
BMA280_INT_MAP_1_BIT_DATA,
|
||||
BMA280_INT_MAP_1_BIT_DATA);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not map data ready interrupt pin\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
|
||||
/* map any-motion interrupt to INT1 */
|
||||
rc = bma280_reg_update(drv_data, BMA280_REG_INT_MAP_0,
|
||||
BMA280_INT_MAP_0_BIT_SLOPE,
|
||||
BMA280_INT_MAP_0_BIT_SLOPE);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not map any-motion interrupt pin\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
|
||||
/* disable data ready interrupt */
|
||||
rc = bma280_reg_update(drv_data, BMA280_REG_INT_EN_1,
|
||||
BMA280_BIT_DATA_EN, 0);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not disable data ready interrupt\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
|
||||
/* disable any-motion interrupt */
|
||||
rc = bma280_reg_update(drv_data, BMA280_REG_INT_EN_0,
|
||||
BMA280_SLOPE_EN_XYZ, 0);
|
||||
if (rc != DEV_OK) {
|
||||
DBG("Could not disable data ready interrupt\n");
|
||||
return DEV_FAIL;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BMA280_TRIGGER_OWN_FIBER)
|
||||
nano_sem_init(&drv_data->gpio_sem);
|
||||
|
||||
fiber_start(drv_data->fiber_stack, CONFIG_BMA280_FIBER_STACK_SIZE,
|
||||
(nano_fiber_entry_t)bma280_fiber, POINTER_TO_INT(dev),
|
||||
0, CONFIG_BMA280_FIBER_PRIORITY, 0);
|
||||
#elif defined(CONFIG_BMA280_TRIGGER_GLOBAL_FIBER)
|
||||
drv_data->work.handler = bma280_fiber_cb;
|
||||
drv_data->work.arg = dev;
|
||||
#endif
|
||||
|
||||
gpio_pin_enable_callback(drv_data->gpio, CONFIG_BMA280_GPIO_PIN_NUM);
|
||||
|
||||
return DEV_OK;
|
||||
}
|
Loading…
Reference in a new issue