1 /*
2 * Copyright (c) 2021 Eug Krashtan
3 * Copyright (c) 2022 Wouter Cappelle
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/device.h>
9 #include <zephyr/devicetree.h>
10 #include <zephyr/drivers/sensor.h>
11 #include <zephyr/drivers/adc.h>
12 #include <zephyr/logging/log.h>
13 #include <zephyr/pm/device_runtime.h>
14 #include <stm32_ll_adc.h>
15 #if defined(CONFIG_SOC_SERIES_STM32H5X)
16 #include <stm32_ll_icache.h>
17 #endif /* CONFIG_SOC_SERIES_STM32H5X */
18
19 LOG_MODULE_REGISTER(stm32_temp, CONFIG_SENSOR_LOG_LEVEL);
20
21 #define CAL_RES 12
22 #define MAX_CALIB_POINTS 2
23
24 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_temp)
25 #define DT_DRV_COMPAT st_stm32_temp
26 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_temp_cal)
27 #define DT_DRV_COMPAT st_stm32_temp_cal
28 #define HAS_DUAL_CALIBRATION 1
29 #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32c0_temp_cal)
30 #define DT_DRV_COMPAT st_stm32c0_temp_cal
31 #define HAS_SINGLE_CALIBRATION 1
32 #else
33 #error "No compatible devicetree node found"
34 #endif
35
36 #if defined(HAS_SINGLE_CALIBRATION) || defined(HAS_DUAL_CALIBRATION)
37 #define HAS_CALIBRATION 1
38 #endif
39
40 struct stm32_temp_data {
41 const struct device *adc;
42 const struct adc_channel_cfg adc_cfg;
43 ADC_TypeDef *adc_base;
44 struct adc_sequence adc_seq;
45 struct k_mutex mutex;
46 int16_t sample_buffer;
47 int16_t raw; /* raw adc Sensor value */
48 };
49
50 struct stm32_temp_config {
51 #if !defined(HAS_CALIBRATION)
52 float average_slope; /** Unit: mV/°C */
53 int v25; /** Unit: mV */
54 #else /* HAS_CALIBRATION */
55 unsigned int calib_vrefanalog; /** Unit: mV */
56 unsigned int calib_data_shift;
57 const void *ts_cal1_addr;
58 int ts_cal1_temp; /** Unit: °C */
59 #if defined(HAS_SINGLE_CALIBRATION)
60 float average_slope; /** Unit: mV/°C */
61 #else /* HAS_DUAL_CALIBRATION */
62 const void *ts_cal2_addr;
63 int ts_cal2_temp; /** Unit: °C */
64 #endif
65 #endif /* HAS_CALIBRATION */
66 bool is_ntc;
67 };
68
adc_enable_tempsensor_channel(ADC_TypeDef * adc)69 static inline void adc_enable_tempsensor_channel(ADC_TypeDef *adc)
70 {
71 const uint32_t path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(adc));
72
73 LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(adc),
74 path | LL_ADC_PATH_INTERNAL_TEMPSENSOR);
75
76 k_usleep(LL_ADC_DELAY_TEMPSENSOR_STAB_US);
77 }
78
adc_disable_tempsensor_channel(ADC_TypeDef * adc)79 static inline void adc_disable_tempsensor_channel(ADC_TypeDef *adc)
80 {
81 const uint32_t path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(adc));
82
83 LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(adc),
84 path & ~LL_ADC_PATH_INTERNAL_TEMPSENSOR);
85 }
86
87 #if defined(HAS_CALIBRATION)
fetch_mfg_data(const void * addr)88 static uint32_t fetch_mfg_data(const void *addr)
89 {
90 /* On all STM32 series, the calibration data is stored
91 * as 16-bit data in the manufacturing flash region
92 */
93 return sys_read16((mem_addr_t)addr);
94 }
95
96 /**
97 * @returns TS_CAL1 in calib_data[0]
98 * TS_CAL2 in calib_data[1] if applicable
99 */
read_calibration_data(const struct stm32_temp_config * cfg,uint32_t calib_data[MAX_CALIB_POINTS])100 static void read_calibration_data(const struct stm32_temp_config *cfg,
101 uint32_t calib_data[MAX_CALIB_POINTS])
102 {
103 #if defined(CONFIG_SOC_SERIES_STM32H5X)
104 /* Disable the ICACHE to ensure all memory accesses are non-cacheable.
105 * This is required on STM32H5, where the manufacturing flash must be
106 * accessed in non-cacheable mode - otherwise, a bus error occurs.
107 */
108 LL_ICACHE_Disable();
109 #endif /* CONFIG_SOC_SERIES_STM32H5X */
110
111 calib_data[0] = fetch_mfg_data(cfg->ts_cal1_addr);
112 #if defined(HAS_DUAL_CALIBRATION)
113 calib_data[1] = fetch_mfg_data(cfg->ts_cal2_addr);
114 #endif
115
116
117 #if defined(CONFIG_SOC_SERIES_STM32H5X)
118 /* Re-enable the ICACHE (unconditonally - it should always be turned on) */
119 LL_ICACHE_Enable();
120 #endif /* CONFIG_SOC_SERIES_STM32H5X */
121 }
122 #endif /* HAS_CALIBRATION */
123
convert_adc_sample_to_temperature(const struct device * dev)124 static float convert_adc_sample_to_temperature(const struct device *dev)
125 {
126 struct stm32_temp_data *data = dev->data;
127 const struct stm32_temp_config *cfg = dev->config;
128 const uint16_t vdda_mv = adc_ref_internal(data->adc);
129 float temperature;
130
131 #if !defined(HAS_CALIBRATION)
132 /**
133 * Series without calibration (STM32F1/F2):
134 * Tjunction = ((Dividend) / Avg_Slope) + 25
135 *
136 * where Dividend is:
137 * - (V25 - Vsense) on STM32F1 series ("ntc")
138 * - (Vsense - V25) on STM32F2 series
139 * and Vsense = (ADC raw data) / ADC_MAX_VALUE * Vdda
140 * and ADC_MAX_VALUE = 4095 (12-bit ADC resolution)
141 *
142 * References:
143 * - RM0008 §11.10 "Temperature sensor" (STM32F100)
144 * - RM0041 §10.9 "Temperature sensor" (STM32F101/F102/F103/F105/F107)
145 * - RM0033 §10.10 "Temperature sensor" (STM32F2)
146 */
147 /* Perform multiplication first for higher accuracy */
148 const int vsense = ((int)data->raw * vdda_mv) / 4095;
149
150 if (cfg->is_ntc) {
151 temperature = (float)(cfg->v25 - vsense);
152 } else {
153 temperature = (float)(vsense - cfg->v25);
154 }
155 temperature /= cfg->average_slope;
156 temperature += 25.0f;
157 #else /* HAS_CALIBRATION */
158 uint32_t calib[MAX_CALIB_POINTS];
159
160 read_calibration_data(cfg, calib);
161
162 const float sense_data = ((float)vdda_mv / cfg->calib_vrefanalog) * data->raw;
163
164 #if defined(HAS_SINGLE_CALIBRATION)
165 /**
166 * Series with one calibration point (STM32C0,STM32F030/F070):
167 * Tjunction = ((Dividend) / Avg_Slope_Code) + TS_CAL1_TEMP
168 *
169 * where Dividend is:
170 * - (TS_CAL1 - Sense_Data) on STM32F030/STM32F070 ("ntc")
171 * - (Sense_Data - TS_CAL1) on STM32C0 series
172 *
173 * and Avg_SlopeCode = (Avg_Slope * 4096 / calibration Vdda)
174 *
175 * References:
176 * - RM0360 §12.8 "Temperature sensor" (STM32F030/STM32F070)
177 * - RM0490 §14.10 "Temperature sensor and internal reference voltage" (STM32C0)
178 */
179 const float avg_slope_code =
180 (cfg->average_slope / cfg->calib_vrefanalog) * 4096.f;
181 float dividend;
182
183 if (cfg->is_ntc) {
184 dividend = ((float)(calib[0] >> cfg->calib_data_shift) - sense_data);
185 } else {
186 dividend = (sense_data - (calib[0] >> cfg->calib_data_shift));
187 }
188
189 temperature = (dividend / avg_slope_code) + cfg->ts_cal1_temp;
190 #else /* HAS_DUAL_CALIBRATION */
191 /**
192 * Series with two calibration points:
193 * Tjunction = (Slope * (Sense_Data - TS_CAL1)) + TS_CAL1_TEMP
194 *
195 * (TS_CAL2_TEMP - TS_CAL1_TEMP)
196 * where Slope = -----------------------------
197 * (TS_CAL2 - TS_CAL1)
198 */
199 const float slope = ((float)(cfg->ts_cal2_temp - cfg->ts_cal1_temp))
200 / ((calib[1] - calib[0]) >> cfg->calib_data_shift);
201
202 temperature = (slope * (sense_data - (calib[0] >> cfg->calib_data_shift)))
203 + cfg->ts_cal1_temp;
204 #endif /* HAS_SINGLE_CALIBRATION */
205 #endif /* HAS_CALIBRATION */
206
207 return temperature;
208 }
209
stm32_temp_sample_fetch(const struct device * dev,enum sensor_channel chan)210 static int stm32_temp_sample_fetch(const struct device *dev, enum sensor_channel chan)
211 {
212 struct stm32_temp_data *data = dev->data;
213 struct adc_sequence *sp = &data->adc_seq;
214 int rc;
215
216 if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) {
217 return -ENOTSUP;
218 }
219
220 k_mutex_lock(&data->mutex, K_FOREVER);
221 pm_device_runtime_get(data->adc);
222
223 rc = adc_channel_setup(data->adc, &data->adc_cfg);
224 if (rc) {
225 LOG_DBG("Setup AIN%u got %d", data->adc_cfg.channel_id, rc);
226 goto unlock;
227 }
228
229 adc_enable_tempsensor_channel(data->adc_base);
230
231 rc = adc_read(data->adc, sp);
232 if (rc == 0) {
233 data->raw = data->sample_buffer;
234 }
235
236 adc_disable_tempsensor_channel(data->adc_base);
237
238 unlock:
239 pm_device_runtime_put(data->adc);
240 k_mutex_unlock(&data->mutex);
241
242 return rc;
243 }
244
stm32_temp_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)245 static int stm32_temp_channel_get(const struct device *dev, enum sensor_channel chan,
246 struct sensor_value *val)
247 {
248 if (chan != SENSOR_CHAN_DIE_TEMP) {
249 return -ENOTSUP;
250 }
251
252 const float temp = convert_adc_sample_to_temperature(dev);
253
254 return sensor_value_from_float(val, temp);
255 }
256
257 static DEVICE_API(sensor, stm32_temp_driver_api) = {
258 .sample_fetch = stm32_temp_sample_fetch,
259 .channel_get = stm32_temp_channel_get,
260 };
261
stm32_temp_init(const struct device * dev)262 static int stm32_temp_init(const struct device *dev)
263 {
264 struct stm32_temp_data *data = dev->data;
265 struct adc_sequence *asp = &data->adc_seq;
266
267 k_mutex_init(&data->mutex);
268
269 if (!device_is_ready(data->adc)) {
270 LOG_ERR("Device %s is not ready", data->adc->name);
271 return -ENODEV;
272 }
273
274 *asp = (struct adc_sequence){
275 .channels = BIT(data->adc_cfg.channel_id),
276 .buffer = &data->sample_buffer,
277 .buffer_size = sizeof(data->sample_buffer),
278 .resolution = 12U,
279 };
280
281 return 0;
282 }
283
284 /**
285 * Verify that the ADC instance which this driver uses to measure temperature
286 * is enabled. On STM32 MCUs with more than one ADC, it is possible to compile
287 * this driver even if the ADC used for measurement is disabled. In such cases,
288 * fail build with an explicit error message.
289 */
290 #if !DT_NODE_HAS_STATUS_OKAY(DT_INST_IO_CHANNELS_CTLR(0))
291
292 /* Use BUILD_ASSERT to get preprocessing on the message */
293 BUILD_ASSERT(0, "ADC '" DT_NODE_FULL_NAME(DT_INST_IO_CHANNELS_CTLR(0)) "' needed by "
294 "temperature sensor '" DT_NODE_FULL_NAME(DT_DRV_INST(0)) "' is not enabled");
295
296 /* To reduce noise in the compiler error log, do not attempt
297 * to instantiate device if the sensor's ADC is not enabled.
298 */
299 #else
300
301 static struct stm32_temp_data stm32_temp_dev_data = {
302 .adc = DEVICE_DT_GET(DT_INST_IO_CHANNELS_CTLR(0)),
303 .adc_base = (ADC_TypeDef *)DT_REG_ADDR(DT_INST_IO_CHANNELS_CTLR(0)),
304 .adc_cfg = {
305 .gain = ADC_GAIN_1,
306 .reference = ADC_REF_INTERNAL,
307 .acquisition_time = ADC_ACQ_TIME_MAX,
308 .channel_id = DT_INST_IO_CHANNELS_INPUT(0),
309 .differential = 0
310 },
311 };
312
313 static const struct stm32_temp_config stm32_temp_dev_config = {
314 #if defined(HAS_CALIBRATION)
315 .ts_cal1_addr = (const void *)DT_INST_PROP(0, ts_cal1_addr),
316 .ts_cal1_temp = DT_INST_PROP(0, ts_cal1_temp),
317 #if defined(HAS_SINGLE_CALIBRATION)
318 .average_slope = ((float)DT_INST_STRING_UNQUOTED(0, avgslope)),
319 #else /* HAS_DUAL_CALIBRATION */
320 .ts_cal2_addr = (const void *)DT_INST_PROP(0, ts_cal2_addr),
321 .ts_cal2_temp = DT_INST_PROP(0, ts_cal2_temp),
322 #endif
323 .calib_data_shift = (DT_INST_PROP(0, ts_cal_resolution) - CAL_RES),
324 .calib_vrefanalog = DT_INST_PROP(0, ts_cal_vrefanalog),
325 #else
326 .average_slope = ((float)DT_INST_STRING_UNQUOTED(0, avgslope)),
327 .v25 = DT_INST_PROP(0, v25),
328 #endif
329 .is_ntc = DT_INST_PROP_OR(0, ntc, false)
330 };
331
332 SENSOR_DEVICE_DT_INST_DEFINE(0, stm32_temp_init, NULL,
333 &stm32_temp_dev_data, &stm32_temp_dev_config,
334 POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,
335 &stm32_temp_driver_api);
336
337 #endif /* !DT_NODE_HAS_STATUS_OKAY(DT_INST_IO_CHANNELS_CTLR(0)) */
338