forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstm32_temp.c
144 lines (120 loc) · 3.34 KB
/
stm32_temp.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
* 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)