/* * Copyright (c) 2019 Thomas Schmid * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT meas_ms5607 #include #include #include #include #include #include "ms5607.h" #define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL #include 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 - ((int32_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_config *config, uint8_t cmd, uint16_t *val) { int err; err = config->tf->read_prom(config, cmd, val); if (err < 0) { LOG_ERR("Error reading prom"); return err; } return 0; } static int ms5607_get_measurement(const struct ms5607_config *config, uint32_t *val, uint8_t cmd, uint8_t delay) { int err; *val = 0U; err = config->tf->start_conversion(config, cmd); if (err < 0) { return err; } k_msleep(delay); err = config->tf->read_adc(config, val); if (err < 0) { return err; } return 0; } static int ms5607_sample_fetch(const struct device *dev, enum sensor_channel channel) { const struct ms5607_config *config = dev->config; struct ms5607_data *data = dev->data; int err; uint32_t adc_pressure, adc_temperature; __ASSERT_NO_MSG(channel == SENSOR_CHAN_ALL); err = ms5607_get_measurement(config, &adc_pressure, data->pressure_conv_cmd, data->pressure_conv_delay); if (err < 0) { return err; } err = ms5607_get_measurement(config, &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(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { const struct ms5607_data *data = dev->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 -ENOTSUP; } return 0; } static int ms5607_attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, const struct sensor_value *val) { struct ms5607_data *data = dev->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 int ms5607_init(const struct device *dev) { const struct ms5607_config *const config = dev->config; struct ms5607_data *data = dev->data; struct sensor_value val; int err; err = config->tf->bus_check(config); if (err < 0) { return err; } 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 = config->tf->reset(config); if (err < 0) { return err; } k_sleep(K_MSEC(2)); err = ms5607_read_prom(config, 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(config, 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(config, 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(config, MS5607_CMD_CONV_READ_TCO, &data->tco); if (err < 0) { return err; } LOG_DBG("TCO: %d", data->tco); err = ms5607_read_prom(config, MS5607_CMD_CONV_READ_TCS, &data->tcs); if (err < 0) { return err; } LOG_DBG("TCS: %d", data->tcs); err = ms5607_read_prom(config, MS5607_CMD_CONV_READ_TEMPSENS, &data->tempsens); if (err < 0) { return err; } LOG_DBG("TEMPSENS: %d", data->tempsens); return 0; } static DEVICE_API(sensor, ms5607_api_funcs) = { .attr_set = ms5607_attr_set, .sample_fetch = ms5607_sample_fetch, .channel_get = ms5607_channel_get, }; #define MS5607_SPI_OPERATION (SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | \ SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_TRANSFER_MSB) /* Initializes a struct ms5607_config for an instance on a SPI bus. */ #define MS5607_CONFIG_SPI(inst) \ { \ .tf = &ms5607_spi_transfer_function, \ .bus_cfg.spi = SPI_DT_SPEC_INST_GET(inst, \ MS5607_SPI_OPERATION, \ 0), \ } /* Initializes a struct ms5607_config for an instance on a I2C bus. */ #define MS5607_CONFIG_I2C(inst) \ { \ .tf = &ms5607_i2c_transfer_function, \ .bus_cfg.i2c = I2C_DT_SPEC_INST_GET(inst), \ } /* * Main instantiation macro, which selects the correct bus-specific * instantiation macros for the instance. */ #define MS5607_DEFINE(inst) \ static struct ms5607_data ms5607_data_##inst; \ static const struct ms5607_config ms5607_config_##inst = \ COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ (MS5607_CONFIG_SPI(inst)), \ (MS5607_CONFIG_I2C(inst))); \ SENSOR_DEVICE_DT_INST_DEFINE(inst, \ ms5607_init, \ NULL, \ &ms5607_data_##inst, \ &ms5607_config_##inst, \ POST_KERNEL, \ CONFIG_SENSOR_INIT_PRIORITY, \ &ms5607_api_funcs); /* Create the struct device for every status "okay" node in the devicetree. */ DT_INST_FOREACH_STATUS_OKAY(MS5607_DEFINE)