zephyr/drivers/sensor/ms5607/ms5607.c

337 lines
7.2 KiB
C

/*
* Copyright (c) 2019 Thomas Schmid <tom@lfence.de>
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT meas_ms5607
#include <init.h>
#include <kernel.h>
#include <sys/byteorder.h>
#include <drivers/sensor.h>
#include <sys/__assert.h>
#include "ms5607.h"
#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(ms5607);
static void ms5607_compensate(struct ms5607_data *data,
const int32_t adc_temperature,
const int32_t adc_pressure)
{
int64_t dT;
int64_t OFF;
int64_t SENS;
int64_t temp_sq;
int64_t Ti;
int64_t OFFi;
int64_t SENSi;
/* first order compensation as per datasheet
* (https://www.te.com/usa-en/product-CAT-BLPS0035.html) section
* PRESSURE AND TEMPERATURE CALCULATION
*/
dT = adc_temperature - ((uint32_t)(data->t_ref) << 8);
data->temperature = 2000 + (dT * data->tempsens) / (1ll << 23);
OFF = ((int64_t)(data->off_t1) << 17) + (dT * data->tco) / (1ll << 6);
SENS = ((int64_t)(data->sens_t1) << 16) + (dT * data->tcs) / (1ll << 7);
/* Second order compensation as per datasheet
* (https://www.te.com/usa-en/product-CAT-BLPS0035.html) section
* SECOND ORDER TEMPERATURE COMPENSATION
*/
temp_sq = (int64_t)(data->temperature - 2000) *
(int64_t)(data->temperature - 2000);
if (data->temperature < 2000) {
Ti = (dT * dT) / (1ll << 31);
OFFi = (61ll * temp_sq) / (1ll << 4);
SENSi = 2ll * temp_sq;
if (data->temperature < -1500) {
temp_sq = (int64_t)(data->temperature + 1500) *
(int64_t)(data->temperature + 1500);
OFFi += 15ll * temp_sq;
SENSi += 8ll * temp_sq;
}
} else {
SENSi = 0;
OFFi = 0;
Ti = 0;
}
OFF -= OFFi;
SENS -= SENSi;
data->temperature -= Ti;
data->pressure = (SENS * (int64_t)adc_pressure / (1ll << 21) - OFF) /
(1ll << 15);
}
static int ms5607_read_prom(const struct ms5607_data *data, uint8_t cmd,
uint16_t *val)
{
int err;
err = data->tf->read_prom(data, cmd, val);
if (err < 0) {
LOG_ERR("Error reading prom");
return err;
}
return 0;
}
static int ms5607_get_measurement(const struct ms5607_data *data,
uint32_t *val,
uint8_t cmd,
uint8_t delay)
{
int err;
*val = 0U;
err = data->tf->start_conversion(data, cmd);
if (err < 0) {
return err;
}
k_msleep(delay);
err = data->tf->read_adc(data, val);
if (err < 0) {
return err;
}
return 0;
}
static int ms5607_sample_fetch(struct device *dev, enum sensor_channel channel)
{
struct ms5607_data *data = dev->driver_data;
int err;
uint32_t adc_pressure, adc_temperature;
__ASSERT_NO_MSG(channel == SENSOR_CHAN_ALL);
err = ms5607_get_measurement(data,
&adc_pressure,
data->pressure_conv_cmd,
data->pressure_conv_delay);
if (err < 0) {
return err;
}
err = ms5607_get_measurement(data,
&adc_temperature,
data->temperature_conv_cmd,
data->temperature_conv_delay);
if (err < 0) {
return err;
}
ms5607_compensate(data, adc_temperature, adc_pressure);
return 0;
}
static int ms5607_channel_get(struct device *dev, enum sensor_channel chan,
struct sensor_value *val)
{
const struct ms5607_data *data = dev->driver_data;
switch (chan) {
case SENSOR_CHAN_AMBIENT_TEMP:
val->val1 = data->temperature / 100;
val->val2 = data->temperature % 100 * 10000;
break;
case SENSOR_CHAN_PRESS:
val->val1 = data->pressure / 100;
val->val2 = data->pressure % 100 * 10000;
break;
default:
return -EINVAL;
}
return 0;
}
static int ms5607_attr_set(struct device *dev, enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
struct ms5607_data *data = dev->driver_data;
uint8_t p_conv_cmd, t_conv_cmd, conv_delay;
if (attr != SENSOR_ATTR_OVERSAMPLING) {
return -ENOTSUP;
}
switch (val->val1) {
case 4096:
p_conv_cmd = MS5607_CMD_CONV_P_4096;
t_conv_cmd = MS5607_CMD_CONV_T_4096;
conv_delay = 9U;
break;
case 2048:
p_conv_cmd = MS5607_CMD_CONV_P_2048;
t_conv_cmd = MS5607_CMD_CONV_T_2048;
conv_delay = 5U;
break;
case 1024:
p_conv_cmd = MS5607_CMD_CONV_P_1024;
t_conv_cmd = MS5607_CMD_CONV_T_1024;
conv_delay = 3U;
break;
case 512:
p_conv_cmd = MS5607_CMD_CONV_P_512;
t_conv_cmd = MS5607_CMD_CONV_T_512;
conv_delay = 2U;
break;
case 256:
p_conv_cmd = MS5607_CMD_CONV_P_256;
t_conv_cmd = MS5607_CMD_CONV_T_256;
conv_delay = 1U;
break;
default:
LOG_ERR("invalid oversampling rate %d", val->val1);
return -EINVAL;
}
switch (chan) {
case SENSOR_CHAN_ALL:
data->pressure_conv_cmd = p_conv_cmd;
data->temperature_conv_cmd = t_conv_cmd;
data->temperature_conv_delay = conv_delay;
data->pressure_conv_delay = conv_delay;
break;
case SENSOR_CHAN_PRESS:
data->pressure_conv_cmd = p_conv_cmd;
data->pressure_conv_delay = conv_delay;
break;
case SENSOR_CHAN_AMBIENT_TEMP:
data->temperature_conv_cmd = t_conv_cmd;
data->temperature_conv_delay = conv_delay;
break;
default:
return -ENOTSUP;
}
return 0;
}
static const struct ms5607_config ms5607_config = {
.ms5607_device_name = DT_INST_BUS_LABEL(0),
};
static int ms5607_init(struct device *dev)
{
const struct ms5607_config *const config = dev->config_info;
struct ms5607_data *data = dev->driver_data;
struct sensor_value val;
int err;
data->ms5607_device = device_get_binding(config->ms5607_device_name);
if (!data->ms5607_device) {
LOG_ERR("master not found: %s", config->ms5607_device_name);
return -EINVAL;
}
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
ms5607_spi_init(dev);
#else
BUILD_ASSERT(1, "I2c interface not implemented yet");
#endif
data->pressure = 0;
data->temperature = 0;
val.val1 = MS5607_PRES_OVER_DEFAULT;
err = ms5607_attr_set(dev, SENSOR_CHAN_PRESS, SENSOR_ATTR_OVERSAMPLING,
&val);
if (err < 0) {
return err;
}
val.val1 = MS5607_TEMP_OVER_DEFAULT;
err = ms5607_attr_set(dev, SENSOR_CHAN_AMBIENT_TEMP,
SENSOR_ATTR_OVERSAMPLING, &val);
if (err < 0) {
return err;
}
err = data->tf->reset(data);
if (err < 0) {
return err;
}
k_sleep(K_MSEC(2));
err = ms5607_read_prom(data, MS5607_CMD_CONV_READ_OFF_T1,
&data->off_t1);
if (err < 0) {
return err;
}
LOG_DBG("OFF_T1: %d", data->off_t1);
err = ms5607_read_prom(data, MS5607_CMD_CONV_READ_SENSE_T1,
&data->sens_t1);
if (err < 0) {
return err;
}
LOG_DBG("SENSE_T1: %d", data->sens_t1);
err = ms5607_read_prom(data, MS5607_CMD_CONV_READ_T_REF, &data->t_ref);
if (err < 0) {
return err;
}
LOG_DBG("T_REF: %d", data->t_ref);
err = ms5607_read_prom(data, MS5607_CMD_CONV_READ_TCO, &data->tco);
if (err < 0) {
return err;
}
LOG_DBG("TCO: %d", data->tco);
err = ms5607_read_prom(data, MS5607_CMD_CONV_READ_TCS, &data->tcs);
if (err < 0) {
return err;
}
LOG_DBG("TCS: %d", data->tcs);
err = ms5607_read_prom(data, MS5607_CMD_CONV_READ_TEMPSENS,
&data->tempsens);
if (err < 0) {
return err;
}
LOG_DBG("TEMPSENS: %d", data->tempsens);
return 0;
}
static const struct sensor_driver_api ms5607_api_funcs = {
.attr_set = ms5607_attr_set,
.sample_fetch = ms5607_sample_fetch,
.channel_get = ms5607_channel_get,
};
static struct ms5607_data ms5607_data;
DEVICE_AND_API_INIT(ms5607,
DT_INST_LABEL(0),
ms5607_init,
&ms5607_data,
&ms5607_config,
POST_KERNEL,
CONFIG_SENSOR_INIT_PRIORITY,
&ms5607_api_funcs);