zephyr/drivers/sensor/stm32_temp/stm32_temp.c

145 lines
3.3 KiB
C

/*
* Copyright (c) 2021 Eug Krashtan
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <device.h>
#include <drivers/sensor.h>
#include <drivers/adc.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(stm32_temp, CONFIG_SENSOR_LOG_LEVEL);
#define DT_DRV_COMPAT st_stm32_temp
struct stm32_temp_data {
const struct device *adc;
uint8_t channel;
struct adc_channel_cfg adc_cfg;
struct adc_sequence adc_seq;
struct k_mutex mutex;
int16_t sample_buffer;
int32_t mv; /* Sensor value in millivolts */
};
struct stm32_temp_config {
int avgslope;
int v25_mv;
int tsv_mv;
bool is_ntc;
};
static int stm32_temp_sample_fetch(const struct device *dev,
enum sensor_channel chan)
{
const struct stm32_temp_config *cfg = dev->config;
struct stm32_temp_data *data = dev->data;
struct adc_sequence *sp = &data->adc_seq;
int rc;
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) {
return -ENOTSUP;
}
k_mutex_lock(&data->mutex, K_FOREVER);
rc = adc_read(data->adc, sp);
sp->calibrate = false;
if (rc == 0) {
data->mv = data->sample_buffer * cfg->tsv_mv / 0x0FFF;
}
k_mutex_unlock(&data->mutex);
return 0;
}
static int stm32_temp_channel_get(const struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
struct stm32_temp_data *data = dev->data;
const struct stm32_temp_config *cfg = dev->config;
float temp;
if (chan != SENSOR_CHAN_DIE_TEMP) {
return -ENOTSUP;
}
if (cfg->is_ntc) {
temp = (float)(cfg->v25_mv - data->mv);
} else {
temp = (float)(data->mv - cfg->v25_mv);
}
temp = (temp/cfg->avgslope)*10;
temp += 25;
sensor_value_from_double(val, temp);
return 0;
}
static const struct sensor_driver_api stm32_temp_driver_api = {
.sample_fetch = stm32_temp_sample_fetch,
.channel_get = stm32_temp_channel_get,
};
static int stm32_temp_init(const struct device *dev)
{
struct stm32_temp_data *data = dev->data;
struct adc_channel_cfg *accp = &data->adc_cfg;
struct adc_sequence *asp = &data->adc_seq;
int rc;
k_mutex_init(&data->mutex);
if (!device_is_ready(data->adc)) {
LOG_ERR("Device %s is not ready", data->adc->name);
return -ENODEV;
}
*accp = (struct adc_channel_cfg){
.gain = ADC_GAIN_1,
.reference = ADC_REF_INTERNAL,
.acquisition_time = ADC_ACQ_TIME_MAX,
.channel_id = data->channel,
.differential = 0
};
rc = adc_channel_setup(data->adc, accp);
LOG_DBG("Setup AIN%u got %d", data->channel, rc);
*asp = (struct adc_sequence){
.channels = BIT(data->channel),
.buffer = &data->sample_buffer,
.buffer_size = sizeof(data->sample_buffer),
.resolution = 12,
.calibrate = true,
};
return 0;
}
#define STM32_TEMP_INST(idx) \
static struct stm32_temp_data inst_##idx##_data = { \
.adc = DEVICE_DT_GET(DT_IO_CHANNELS_CTLR( \
DT_INST(idx, st_stm32_temp))), \
.channel = DT_IO_CHANNELS_INPUT( \
DT_INST(idx, st_stm32_temp)) \
}; \
static const struct stm32_temp_config inst_##idx##_config = { \
.avgslope = DT_INST_PROP(idx, avgslope), \
.v25_mv = DT_INST_PROP(idx, v25), \
.tsv_mv = DT_INST_PROP(idx, ts_voltage_mv), \
.is_ntc = DT_INST_PROP(idx, ntc) \
}; \
DEVICE_DT_INST_DEFINE(idx, \
stm32_temp_init, \
NULL, \
&inst_##idx##_data, \
&inst_##idx##_config, \
POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, \
&stm32_temp_driver_api);
DT_INST_FOREACH_STATUS_OKAY(STM32_TEMP_INST)