drivers: sensor: Add support for MMA8451Q (3-axis accelerometer)

Only basic features supported initially but more could be added from:
https://www.nxp.com/docs/en/data-sheet/MMA8451Q.pdf

fixes #9006

A sample app will be provided in a separate PR.

Signed-off-by: Lars Knudsen <larsgk@gmail.com>
This commit is contained in:
Lars Knudsen 2018-07-26 22:29:25 +02:00 committed by Maureen Helm
parent fd1fec8ad6
commit 9c0d7813e5
7 changed files with 333 additions and 0 deletions

View file

@ -29,6 +29,7 @@ add_subdirectory_ifdef(CONFIG_LSM9DS0_MFD lsm9ds0_mfd)
add_subdirectory_ifdef(CONFIG_MAX30101 max30101)
add_subdirectory_ifdef(CONFIG_MAX44009 max44009)
add_subdirectory_ifdef(CONFIG_MCP9808 mcp9808)
add_subdirectory_ifdef(CONFIG_MMA8451Q mma8451q)
add_subdirectory_ifdef(CONFIG_MPU6050 mpu6050)
add_subdirectory_ifdef(CONFIG_PMS7003 pms7003)
add_subdirectory_ifdef(CONFIG_TEMP_NRF5 nrf5)

View file

@ -101,6 +101,8 @@ source "drivers/sensor/max44009/Kconfig"
source "drivers/sensor/mcp9808/Kconfig"
source "drivers/sensor/mma8451q/Kconfig"
source "drivers/sensor/mpu6050/Kconfig"
source "drivers/sensor/nrf5/Kconfig"

View file

@ -0,0 +1,9 @@
#
# Copyright (c) 2018 Lars Knudsen
#
# SPDX-License-Identifier: Apache-2.0
#
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_MMA8451Q mma8451q.c)

View file

@ -0,0 +1,58 @@
# Kconfig - MMA8451Q Accelerometer sensor configuration options
#
# Copyright (c) 2018 Lars Knudsen
#
# SPDX-License-Identifier: Apache-2.0
#
menuconfig MMA8451Q
bool "MMA8451Q Accelerometer driver"
depends on I2C
help
Enable driver for MMA8451Q Accelerometer.
if !HAS_DTS_I2C_DEVICE
config MMA8451Q_NAME
string "Device name"
depends on MMA8451Q
default "MMA8451Q"
config MMA8451Q_I2C_NAME
string "I2C device name"
depends on MMA8451Q
default I2C_0_NAME
config MMA8451Q_I2C_ADDRESS
hex
prompt "I2C address for MMA8451Q Sensor"
depends on MMA8451Q
default 0x1D
help
I2C address of the MMA8451Q sensor.
0x1D: I2C_ADDR
endif # !HAS_DTS_I2C_DEVICE
config MMA8451Q_WHOAMI
hex "WHOAMI value"
depends on MMA8451Q
default 0x1A
help
The whoami value for MMA8451Q (0x1A).
choice
prompt "Range"
depends on MMA8451Q
default MMA8451Q_RANGE_2G
config MMA8451Q_RANGE_8G
bool "8g (0.976 mg/LSB)"
config MMA8451Q_RANGE_4G
bool "4g (0.488 mg/LSB)"
config MMA8451Q_RANGE_2G
bool "2g (0.244 mg/LSB)"
endchoice

View file

@ -0,0 +1,182 @@
/*
* Copyright (c) 2018 Lars Knudsen
* Copyright (c) 2016 Freescale Semiconductor, Inc. (sample conversion)
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <device.h>
#include <i2c.h>
#include <kernel.h>
#include <misc/util.h>
#include <sensor.h>
#include "mma8451q.h"
/* Data-sheet: https://www.nxp.com/docs/en/data-sheet/MMA8451Q.pdf */
static int mma8451q_sample_fetch(struct device *dev, enum sensor_channel chan)
{
const struct mma8451q_config *config = dev->config->config_info;
struct mma8451q_data *data = dev->driver_data;
u8_t buf[6];
/* Read data from all three axes at the same time. */
if (i2c_burst_read(data->i2c, config->i2c_address,
MMA8451Q_OUT_X_MSB, buf, 6) < 0) {
SYS_LOG_ERR("Could not read accelerometer data");
return -EIO;
}
data->x = (buf[0] << 8) | buf[1];
data->y = (buf[2] << 8) | buf[3];
data->z = (buf[4] << 8) | buf[5];
return 0;
}
static void mma8451q_accel_convert(struct sensor_value *val, s16_t raw,
enum mma8451q_range range)
{
u8_t frac_bits;
s64_t micro_ms2;
/* The range encoding is convenient to compute the number of fractional
* bits:
* - 2g mode (range = 0) has 14 fractional bits
* - 4g mode (range = 1) has 13 fractional bits
* - 8g mode (range = 2) has 12 fractional bits
*/
frac_bits = 14 - range;
/* Convert units to micro m/s^2. Intermediate results before the shift
* are 40 bits wide.
*/
micro_ms2 = (raw * SENSOR_G) >> frac_bits;
/* The maximum possible value is 8g, which in units of micro m/s^2
* always fits into 32-bits. Cast down to s32_t so we can use a
* faster divide.
*/
val->val1 = (s32_t) micro_ms2 / 1000000;
val->val2 = (s32_t) micro_ms2 % 1000000;
}
static int mma8451q_channel_get(struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
const struct mma8451q_config *config = dev->config->config_info;
struct mma8451q_data *data = dev->driver_data;
switch (chan) {
case SENSOR_CHAN_ACCEL_X:
mma8451q_accel_convert(val, data->x, config->range);
break;
case SENSOR_CHAN_ACCEL_Y:
mma8451q_accel_convert(val, data->y, config->range);
break;
case SENSOR_CHAN_ACCEL_Z:
mma8451q_accel_convert(val, data->z, config->range);
break;
case SENSOR_CHAN_ACCEL_XYZ:
mma8451q_accel_convert(val++, data->x, config->range);
mma8451q_accel_convert(val++, data->y, config->range);
mma8451q_accel_convert(val++, data->z, config->range);
break;
default:
return -ENOTSUP;
}
return 0;
}
static const struct sensor_driver_api mma8451q_driver_api = {
.sample_fetch = mma8451q_sample_fetch,
.channel_get = mma8451q_channel_get,
};
int mma8451q_init(struct device *dev)
{
const struct mma8451q_config *config = dev->config->config_info;
struct mma8451q_data *data = dev->driver_data;
data->i2c = device_get_binding(config->i2c_name);
if (data->i2c == NULL) {
SYS_LOG_ERR("Failed to get pointer to %s device!",
config->i2c_name);
return -EINVAL;
}
u8_t whoami;
if (i2c_reg_read_byte(data->i2c, config->i2c_address,
MMA8451Q_REG_WHOAMI, &whoami)) {
SYS_LOG_ERR("Could not get WHOAMI value");
return -EIO;
}
if (whoami != config->whoami) {
SYS_LOG_ERR("WHOAMI value received 0x%x, expected 0x%x",
whoami, MMA8451Q_REG_WHOAMI);
return -EIO;
}
if (i2c_reg_write_byte(data->i2c, config->i2c_address,
MMA8451Q_CTRL_REG1, 0) < 0) {
SYS_LOG_ERR("Could not set accel in config mode");
return -EIO;
}
if (i2c_reg_write_byte(data->i2c, config->i2c_address,
MMA8451Q_XYZ_DATA_CFG, config->range) < 0) {
SYS_LOG_ERR("Could not set range");
return -EIO;
}
if (i2c_reg_write_byte(data->i2c, config->i2c_address,
MMA8451Q_CTRL_REG2, 0) < 0) {
SYS_LOG_ERR("Could not set to normal mode");
return -EIO;
}
if (i2c_reg_write_byte(data->i2c, config->i2c_address,
MMA8451Q_CTRL_REG3, 0) < 0) {
SYS_LOG_ERR("Could not set to low polarity, push-pull output");
return -EIO;
}
if (i2c_reg_write_byte(data->i2c, config->i2c_address,
MMA8451Q_CTRL_REG1, 0x09) < 0) {
SYS_LOG_ERR("Could not set data rate to 800Hz");
return -EIO;
}
SYS_LOG_DBG("Init complete");
return 0;
}
static const struct mma8451q_config mma8451q_config = {
.i2c_name = CONFIG_MMA8451Q_I2C_NAME,
.i2c_address = CONFIG_MMA8451Q_I2C_ADDRESS,
.whoami = CONFIG_MMA8451Q_WHOAMI,
#if CONFIG_MMA8451Q_RANGE_8G
.range = MMA8451Q_RANGE_8G,
#elif CONFIG_MMA8451Q_RANGE_4G
.range = MMA8451Q_RANGE_4G,
#else
.range = MMA8451Q_RANGE_2G,
#endif
};
static struct mma8451q_data mma8451q_data;
DEVICE_AND_API_INIT(mma8451q, CONFIG_MMA8451Q_NAME, mma8451q_init,
&mma8451q_data, &mma8451q_config, POST_KERNEL,
CONFIG_SENSOR_INIT_PRIORITY, &mma8451q_driver_api);

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2018 Lars Knudsen
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _SENSOR_MMA8451Q
#define _SENSOR_MMA8451Q
#include <device.h>
#include <misc/util.h>
#define MMA8451Q_OUT_X_MSB 0x01
#define MMA8451Q_OUT_Y_MSB 0x03
#define MMA8451Q_OUT_Z_MSB 0x05
#define MMA8451Q_REG_WHOAMI 0x0d
#define MMA8451Q_XYZ_DATA_CFG 0x0E
#define MMA8451Q_CTRL_REG1 0x2A
#define MMA8451Q_CTRL_REG2 0x2B
#define MMA8451Q_CTRL_REG3 0x2C
#define MMA8451Q_CTRL_REG4 0x2D
#define MMA8451Q_CTRL_REG5 0x2E
#define MMA8451Q_NUM_ACCEL_CHANNELS 3
enum mma8451q_channel {
MMA8451Q_CHANNEL_ACCEL_X = 0,
MMA8451Q_CHANNEL_ACCEL_Y,
MMA8451Q_CHANNEL_ACCEL_Z,
};
enum mma8451q_range {
MMA8451Q_RANGE_2G = 0,
MMA8451Q_RANGE_4G,
MMA8451Q_RANGE_8G,
};
struct mma8451q_config {
char *i2c_name;
u8_t i2c_address;
u8_t whoami;
enum mma8451q_range range;
};
struct mma8451q_data {
struct device *i2c;
s16_t x;
s16_t y;
s16_t z;
};
#define SYS_LOG_DOMAIN "MMA8451Q"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_SENSOR_LEVEL
#include <logging/sys_log.h>
#endif /* _SENSOR_MMA8451Q_ */

View file

@ -0,0 +1,22 @@
#
# Copyright (c) 2018, Lars Knudsen
#
# SPDX-License-Identifier: Apache-2.0
#
---
title: MMA8451Q 3-axis Accelerometer
id: nxp,mma8451q
version: 0.1
description: >
This is a representation of the MMA8451Q 3-axis Accelerometer
sensor
inherits:
!include i2c-device.yaml
properties:
compatible:
constraint: "nxp,mma8451q"
...