Sensor: mpr: Add Honeywell MPR driver

The Honeywell MPR sensor is a piezoresistive silicon pressure sensor,
which can be accessed via i2c.

https://sensing.honeywell.com/micropressure-mpr-series

Signed-off-by: Sven Herrmann <sven.herrmann@posteo.de>
This commit is contained in:
Sven Herrmann 2020-04-13 21:47:36 +02:00 committed by Carles Cufí
commit bded58cee5
10 changed files with 369 additions and 0 deletions

View file

@ -48,6 +48,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_MPR mpr)
add_subdirectory_ifdef(CONFIG_MPU6050 mpu6050)
add_subdirectory_ifdef(CONFIG_MS5607 ms5607)
add_subdirectory_ifdef(CONFIG_MS5837 ms5837)

View file

@ -127,6 +127,8 @@ source "drivers/sensor/mchp_tach_xec/Kconfig"
source "drivers/sensor/mcp9808/Kconfig"
source "drivers/sensor/mpr/Kconfig"
source "drivers/sensor/mpu6050/Kconfig"
source "drivers/sensor/ms5837/Kconfig"

View file

@ -0,0 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_MPR mpr.c)

View file

@ -0,0 +1,67 @@
# MPR pressure sensor configuration options
# Copyright (c) 2020 Sven Herrmann
# SPDX-License-Identifier: Apache-2.0
menuconfig MPR
bool "MPR pressure sensor"
depends on I2C && HAS_DTS_I2C
help
Enable driver for MPR pressure sensor.
if MPR
choice
prompt "MPR Pressure Range"
default MPR_PRESSURE_RANGE_0025
config MPR_PRESSURE_RANGE_0001
bool "0 to 1"
config MPR_PRESSURE_RANGE_01_6
bool "0 to 1.6"
config MPR_PRESSURE_RANGE_02_5
bool "0 to 2.5"
config MPR_PRESSURE_RANGE_0015
bool "0 to 15"
config MPR_PRESSURE_RANGE_0025
bool "0 to 25"
config MPR_PRESSURE_RANGE_0030
bool "0 to 30"
config MPR_PRESSURE_RANGE_0060
bool "0 to 60"
config MPR_PRESSURE_RANGE_0100
bool "0 to 100"
config MPR_PRESSURE_RANGE_0160
bool "0 to 160"
config MPR_PRESSURE_RANGE_0250
bool "0 to 250"
config MPR_PRESSURE_RANGE_0400
bool "0 to 400"
config MPR_PRESSURE_RANGE_0600
bool "0 to 600"
endchoice
choice
prompt "MPR Pressure Unit"
default MPR_PRESSURE_UNIT_P
config MPR_PRESSURE_UNIT_P
bool "psi"
config MPR_PRESSURE_UNIT_K
bool "kPa"
config MPR_PRESSURE_UNIT_B
bool "bar"
config MPR_PRESSURE_UNIT_M
bool "mbar"
endchoice
choice
prompt "MPR Transfer Function"
default MPR_TRANSFER_FUNCTION_A
config MPR_TRANSFER_FUNCTION_A
bool "A"
config MPR_TRANSFER_FUNCTION_B
bool "B"
config MPR_TRANSFER_FUNCTION_C
bool "C"
endchoice
endif # MPR

137
drivers/sensor/mpr/mpr.c Normal file
View file

@ -0,0 +1,137 @@
/* mpr.c - Driver for Honeywell MPR pressure sensor series */
/*
* Copyright (c) 2020 Sven Herrmann
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT honeywell_mpr
#include <errno.h>
#include <kernel.h>
#include <sys/__assert.h>
#include <drivers/sensor.h>
#include <drivers/i2c.h>
#include <sys/byteorder.h>
#include <init.h>
#include <logging/log.h>
#include "mpr.h"
#include "mpr_configuration.h"
LOG_MODULE_REGISTER(MPR, CONFIG_SENSOR_LOG_LEVEL);
static int mpr_init(struct device *dev)
{
struct mpr_data *data = dev->driver_data;
const struct mpr_config *cfg = dev->config->config_info;
data->i2c_master = device_get_binding(cfg->i2c_bus);
if (!data->i2c_master) {
LOG_ERR("mpr: i2c master not found: %s", cfg->i2c_bus);
return -EINVAL;
}
return 0;
}
static int mpr_read_reg(struct device *dev)
{
struct mpr_data *data = dev->driver_data;
const struct mpr_config *cfg = dev->config->config_info;
u8_t write_buf[] = { MPR_OUTPUT_MEASUREMENT_COMMAND, 0x00, 0x00 };
u8_t read_buf[4] = { 0x0 };
int rc = i2c_write(data->i2c_master, write_buf, sizeof(write_buf),
cfg->i2c_addr);
if (rc < 0) {
return rc;
}
u8_t retries = MPR_REG_READ_MAX_RETRIES;
for (; retries > 0; retries--) {
k_sleep(K_MSEC(MPR_REG_READ_DATA_CONV_DELAY_MS));
rc = i2c_read(data->i2c_master, read_buf, sizeof(read_buf),
cfg->i2c_addr);
if (rc < 0) {
return rc;
}
if (!(*read_buf & MPR_STATUS_MASK_POWER_ON)
|| (*read_buf & MPR_STATUS_MASK_INTEGRITY_TEST_FAILED)
|| (*read_buf & MPR_STATUS_MASK_MATH_SATURATION)) {
return -EIO;
}
if (!(*read_buf & MPR_STATUS_MASK_BUSY)) {
break;
}
}
if (retries == 0) {
return -EIO;
}
data->reg_val = (read_buf[1] << 16)
| (read_buf[2] << 8)
| read_buf[3];
return 0;
}
/* (reg_value - out_min) * (p_max - p_min)
* pressure = --------------------------------------- + p_min
* out_max - out_min
*
* returns pressure [kPa] * 10^6
*/
static inline void mpr_convert_reg(const u32_t *reg, s64_t *value)
{
*value = (*reg - MPR_OUTPUT_MIN) * (MPR_P_MAX - MPR_P_MIN);
*value *= MPR_CONVERSION_FACTOR;
*value /= MPR_OUTPUT_RANGE;
*value += MPR_P_MIN;
}
static int mpr_sample_fetch(struct device *dev, enum sensor_channel chan)
{
__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_PRESS);
return mpr_read_reg(dev);
}
static int mpr_channel_get(struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
const struct mpr_data *data = dev->driver_data;
__ASSERT_NO_MSG(chan == SENSOR_CHAN_PRESS);
s64_t value;
mpr_convert_reg(&data->reg_val, &value);
val->val1 = value / 1000000;
val->val2 = value % 1000000;
return 0;
}
static const struct sensor_driver_api mpr_api_funcs = {
.sample_fetch = mpr_sample_fetch,
.channel_get = mpr_channel_get,
};
static struct mpr_data mpr_data;
static const struct mpr_config mpr_cfg = {
.i2c_bus = DT_INST_BUS_LABEL(0),
.i2c_addr = DT_INST_REG_ADDR(0),
};
DEVICE_AND_API_INIT(mpr, DT_INST_LABEL(0), mpr_init, &mpr_data,
&mpr_cfg, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,
&mpr_api_funcs);

43
drivers/sensor/mpr/mpr.h Normal file
View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2020 Sven Herrmann
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_MPR_H_
#define ZEPHYR_DRIVERS_SENSOR_MPR_H_
/* MPR output measurement command */
#define MPR_OUTPUT_MEASUREMENT_COMMAND (0xAA)
/* MPR status byte masks */
#define MPR_STATUS_MASK_MATH_SATURATION (0x01)
#define MPR_STATUS_MASK_INTEGRITY_TEST_FAILED (0x04)
#define MPR_STATUS_MASK_BUSY (0x20)
#define MPR_STATUS_MASK_POWER_ON (0x40)
/* MPR register read maximum retries */
#ifndef MPR_REG_READ_MAX_RETRIES
#define MPR_REG_READ_MAX_RETRIES (3)
#endif
/* MPR register read data conversion delay [ms] */
#ifndef MPR_REG_READ_DATA_CONV_DELAY_MS
#define MPR_REG_READ_DATA_CONV_DELAY_MS (5)
#endif
struct mpr_data {
struct device *i2c_master;
u32_t reg_val;
};
struct mpr_config {
const char *i2c_bus;
u16_t i2c_addr;
};
int mpr_reg_read(struct device *dev, u8_t reg, u16_t *val);
#endif /* ZEPHYR_DRIVERS_SENSOR_MPR_H_ */

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2020 Sven Herrmann
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_MPR_CONFIGURATION_H_
#define ZEPHYR_DRIVERS_SENSOR_MPR_CONFIGURATION_H_
/*
* Pressure Range
*
* MIN is always 0
*/
#define MPR_P_MIN (0)
#if defined(CONFIG_MPR_PRESSURE_RANGE_0001)
#define MPR_P_MAX (1)
#elif defined(CONFIG_MPR_PRESSURE_RANGE_01_6)
#define MPR_P_MAX (1.6)
#elif defined(CONFIG_MPR_PRESSURE_RANGE_02_5)
#define MPR_P_MAX (2.5)
#elif defined(CONFIG_MPR_PRESSURE_RANGE_0015)
#define MPR_P_MAX (15)
#elif defined(CONFIG_MPR_PRESSURE_RANGE_0025)
#define MPR_P_MAX (25)
#elif defined(CONFIG_MPR_PRESSURE_RANGE_0030)
#define MPR_P_MAX (30)
#elif defined(CONFIG_MPR_PRESSURE_RANGE_0060)
#define MPR_P_MAX (60)
#elif defined(CONFIG_MPR_PRESSURE_RANGE_0100)
#define MPR_P_MAX (100)
#elif defined(CONFIG_MPR_PRESSURE_RANGE_0160)
#define MPR_P_MAX (160)
#elif defined(CONFIG_MPR_PRESSURE_RANGE_0250)
#define MPR_P_MAX (250)
#elif defined(CONFIG_MPR_PRESSURE_RANGE_0400)
#define MPR_P_MAX (400)
#elif defined(CONFIG_MPR_PRESSURE_RANGE_0600)
#define MPR_P_MAX (600)
#else
#error "MPR: Unknown pressure range."
#endif
/*
* Pressure Unit
*/
#if defined(CONFIG_MPR_PRESSURE_UNIT_P)
/* psi to kPa conversion factor: 6.894757 * 10^6 */
#define MPR_CONVERSION_FACTOR (6894757)
#elif defined(CONFIG_MPR_PRESSURE_UNIT_K)
/* kPa to kPa conversion factor: 1 * 10^6 */
#define MPR_CONVERSION_FACTOR (1000000)
#elif defined(CONFIG_MPR_PRESSURE_UNIT_B)
/* bar to kPa conversion factor: 100 * 10^6 */
#define MPR_CONVERSION_FACTOR (100000000)
#elif defined(CONFIG_MPR_PRESSURE_UNIT_M)
/* mbar to kPa conversion factor: 0.1 * 10^6 */
#define MPR_CONVERSION_FACTOR (100000)
#else
#error "MPR: Unknown pressure unit."
#endif
/*
* Transfer function
*/
#if defined(CONFIG_MPR_TRANSFER_FUNCTION_A)
#define MPR_OUTPUT_MIN (0x19999A) /* 10% of 2^24 */
#define MPR_OUTPUT_MAX (0xE66666) /* 90% of 2^24 */
#elif defined(CONFIG_MPR_TRANSFER_FUNCTION_B)
#define MPR_OUTPUT_MIN (0x66666) /* 2.5% of 2^24 */
#define MPR_OUTPUT_MAX (0x399999) /* 22.5% of 2^24 */
#elif defined(CONFIG_MPR_TRANSFER_FUNCTION_C)
#define MPR_OUTPUT_MIN (0x333333) /* 20% of 2^24 */
#define MPR_OUTPUT_MAX (0xCCCCCC) /* 80% of 2^24 */
#else
#error "MPR: Unknown pressure reference."
#endif
#define MPR_OUTPUT_RANGE (MPR_OUTPUT_MAX - MPR_OUTPUT_MIN)
#endif /* ZEPHYR_DRIVERS_SENSOR_MPR_CONFIGURATION_H_ */

View file

@ -0,0 +1,9 @@
# SPDX-License-Identifier: Apache-2.0
description: |
Honeywell Digital Pressure Sensor. For details see here:
https://sensing.honeywell.com/micropressure-mpr-series
compatible: "honeywell,mpr"
include: i2c-device.yaml

View file

@ -517,3 +517,9 @@ test_i2c_bq274xx: bq27xx@47 {
taper-current = <45>;
terminate-voltage = <3000>;
};
test_i2c_mpr: mpr@18 {
compatible = "honeywell,mpr";
label = "MPR";
reg = <0x18>;
};

View file

@ -30,3 +30,4 @@ CONFIG_HMC5883L=y
CONFIG_HP206C=y
CONFIG_HTS221=y
CONFIG_ADXL345=y
CONFIG_MPR=y