1 /*
2 * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdlib.h>
8 #include <zephyr/kernel.h>
9
10 #include "soc/soc_caps.h"
11 #include "esp_private/sar_periph_ctrl.h"
12 #include "esp_log.h"
13
14 #if SOC_TEMP_SENSOR_SUPPORTED
15 #include "hal/temperature_sensor_ll.h"
16 #include "soc/temperature_sensor_periph.h"
17 #include "soc/periph_defs.h"
18 #include "esp_private/periph_ctrl.h"
19 #include "esp_private/adc_share_hw_ctrl.h"
20
21 extern int rtc_spinlock;
22
23 #define RTC_ENTER_CRITICAL() do { rtc_spinlock = irq_lock(); } while(0)
24 #define RTC_EXIT_CRITICAL() irq_unlock(rtc_spinlock);
25
26
27 /*------------------------------------------------------------------------------------------------------------
28 -----------------------------------------Temperature Sensor---------------------------------------------------
29 ------------------------------------------------------------------------------------------------------------*/
30 static const char *TAG_TSENS = "temperature_sensor";
31
32 #define INT_NOT_USED 999999
33
34 static int s_record_min = INT_NOT_USED;
35 static int s_record_max = INT_NOT_USED;
36 static int s_temperature_sensor_power_cnt;
37
38 static uint8_t s_tsens_idx = 2; // Index for temperature attribute, set 2(middle) as default value
39
temperature_sensor_power_acquire(void)40 void temperature_sensor_power_acquire(void)
41 {
42 RTC_ENTER_CRITICAL();
43 s_temperature_sensor_power_cnt++;
44 if (s_temperature_sensor_power_cnt == 1) {
45 adc_apb_periph_claim();
46 periph_module_enable(PERIPH_TEMPSENSOR_MODULE);
47 periph_module_reset(PERIPH_TEMPSENSOR_MODULE);
48 regi2c_saradc_enable();
49 temperature_sensor_ll_clk_enable(true);
50 temperature_sensor_ll_enable(true);
51 }
52 RTC_EXIT_CRITICAL();
53 }
54
temperature_sensor_power_release(void)55 void temperature_sensor_power_release(void)
56 {
57 RTC_ENTER_CRITICAL();
58 s_temperature_sensor_power_cnt--;
59 /* Sanity check */
60 if (s_temperature_sensor_power_cnt < 0) {
61 RTC_EXIT_CRITICAL();
62 ESP_LOGE(TAG_TSENS, "%s called, but s_temperature_sensor_power_cnt == 0", __func__);
63 abort();
64 } else if (s_temperature_sensor_power_cnt == 0) {
65 temperature_sensor_ll_clk_enable(false);
66 temperature_sensor_ll_enable(false);
67 regi2c_saradc_disable();
68 periph_module_disable(PERIPH_TEMPSENSOR_MODULE);
69 adc_apb_periph_free();
70 }
71 RTC_EXIT_CRITICAL();
72 }
73
temperature_sensor_get_raw_value(void)74 static int temperature_sensor_get_raw_value(void)
75 {
76 int raw_value = temperature_sensor_ll_get_raw_value();
77 return (TEMPERATURE_SENSOR_LL_ADC_FACTOR * raw_value - TEMPERATURE_SENSOR_LL_DAC_FACTOR * temperature_sensor_attributes[s_tsens_idx].offset - TEMPERATURE_SENSOR_LL_OFFSET_FACTOR);
78 }
79
temp_sensor_sync_tsens_idx(int tsens_idx)80 void temp_sensor_sync_tsens_idx(int tsens_idx)
81 {
82 s_tsens_idx = tsens_idx;
83 }
84
temp_sensor_get_raw_value(bool * range_changed)85 int16_t temp_sensor_get_raw_value(bool *range_changed)
86 {
87 RTC_ENTER_CRITICAL();
88
89 int degree = temperature_sensor_get_raw_value();
90 uint8_t temperature_dac;
91
92 // 1. Check whether temperature value is in range
93 if (s_record_min != INT_NOT_USED && degree >= s_record_min && degree <= s_record_max) {
94 // If degree is in range, not needed to do any check to save time. Otherwise, choose proper range and record.
95 if (range_changed != NULL) {
96 *range_changed = false;
97 }
98 RTC_EXIT_CRITICAL();
99 return degree;
100 }
101
102 // 2. If temperature value is not in range, adjust to proper range
103 if (degree >= temperature_sensor_attributes[1].range_max) {
104 s_tsens_idx = 0;
105 } else if (degree >= temperature_sensor_attributes[2].range_max && degree < temperature_sensor_attributes[1].range_max) {
106 s_tsens_idx = 1;
107 } else if (degree <= temperature_sensor_attributes[2].range_min && degree > temperature_sensor_attributes[3].range_min) {
108 s_tsens_idx = 3;
109 } else if (degree <= temperature_sensor_attributes[3].range_min) {
110 s_tsens_idx = 4;
111 } else {
112 s_tsens_idx = 2;
113 }
114 ESP_EARLY_LOGD(TAG_TSENS, "range changed, change to index %d", s_tsens_idx);
115 temperature_dac = temperature_sensor_attributes[s_tsens_idx].reg_val;
116 s_record_min = temperature_sensor_attributes[s_tsens_idx].range_min;
117 s_record_max = temperature_sensor_attributes[s_tsens_idx].range_max;
118
119 temperature_sensor_ll_set_range(temperature_dac);
120
121 // 3. Then, read value again
122 // Before reading the temperature value, ticks need to be delayed, otherwise a wrong value will be returned.
123 // As what has been recommended and tested, 300us is a good interval to get the correct value after adjust range.
124 esp_rom_delay_us(300);
125 degree = temperature_sensor_get_raw_value();
126 if (range_changed != NULL) {
127 *range_changed = true;
128 }
129
130 RTC_EXIT_CRITICAL();
131 return degree;
132 }
133
134 #endif
135