1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2011-02-22 onelife Initial creation for EFM32
9 * 2011-07-27 onelife Modify according to ADC driver changes
10 */
11
12 /***************************************************************************//**
13 * @addtogroup efm32
14 * @{
15 ******************************************************************************/
16
17 /* Includes ------------------------------------------------------------------*/
18 #include "board.h"
19 #include "drv_adc.h"
20
21 #if defined(RT_USING_MISC)
22 /* Private typedef -----------------------------------------------------------*/
23 /* Private define ------------------------------------------------------------*/
24 /* Private macro -------------------------------------------------------------*/
25 #ifdef RT_MISC_DEBUG
26 #define misc_debug(format,args...) rt_kprintf(format, ##args)
27 #else
28 #define misc_debug(format,args...)
29 #endif
30
31 /* Private constants ---------------------------------------------------------*/
32 static rt_device_t adc0;
33 static struct efm32_adc_control_t control = \
34 {ADC_MODE_SINGLE, {}, {0, (rt_uint8_t)EFM32_NO_DMA}};
35
36 /* Private variables ---------------------------------------------------------*/
37 /* Private function prototypes -----------------------------------------------*/
38 rt_int32_t efm32_misc_getCelsius(rt_uint32_t adcSample);
39
40 /* Private functions ---------------------------------------------------------*/
41 /***************************************************************************//**
42 * @brief
43 * Get current temperature value in degree celsius
44 *
45 * @details
46 *
47 * @note
48 *
49 * @return
50 * Temperature value (signed integer) in degree celsius times 100
51 *
52 ******************************************************************************/
rt_hw_get_temp(void)53 rt_int32_t rt_hw_get_temp(void)
54 {
55 ADC_InitSingle_TypeDef singleInit = ADC_INITSINGLE_DEFAULT;
56 struct efm32_adc_result_t result;
57 rt_uint32_t temp;
58
59 /* Set input to temperature sensor. Acquisition time must be 256 cycles.
60 Reference must be 1.25V */
61 singleInit.acqTime = adcAcqTime32;
62 singleInit.reference = adcRef1V25;
63 singleInit.input = adcSingleInpTemp;
64
65 control.single.init = &singleInit;
66 adc0->control(adc0, RT_DEVICE_CTRL_ADC_MODE, &control);
67 result.mode = control.mode;
68 result.buffer = (void *)&temp;
69 adc0->control(adc0, RT_DEVICE_CTRL_RESUME, &result);
70 adc0->control(adc0, RT_DEVICE_CTRL_ADC_RESULT, &result);
71
72 return efm32_misc_getCelsius(temp);
73 }
74
75 /***************************************************************************//**
76 * @brief
77 * Get current VDD value in volt
78 *
79 * @details
80 *
81 * @note
82 *
83 * @return
84 * VDD value (unsigned integer) in volt times 100
85 *
86 ******************************************************************************/
rt_hw_get_vdd(void)87 rt_uint32_t rt_hw_get_vdd(void)
88 {
89 ADC_InitSingle_TypeDef singleInit = ADC_INITSINGLE_DEFAULT;
90 struct efm32_adc_result_t result;
91 rt_uint32_t vdd;
92
93 /* Set input to temperature sensor. Reference must be 1.25V */
94 singleInit.acqTime = adcAcqTime32;
95 singleInit.reference = adcRef1V25;
96 singleInit.input = adcSingleInpVDDDiv3;
97
98 control.single.init = &singleInit;
99 adc0->control(adc0, RT_DEVICE_CTRL_ADC_MODE, &control);
100 result.mode = control.mode;
101 result.buffer = (void *)&vdd;
102 adc0->control(adc0, RT_DEVICE_CTRL_RESUME, &result);
103 adc0->control(adc0, RT_DEVICE_CTRL_ADC_RESULT, &result);
104
105 return (vdd * 125 * 3) / 4096;
106 }
107
108 /***************************************************************************//**
109 * @brief
110 * Initialize all the miscellaneous drivers
111 *
112 * @details
113 *
114 * @note
115 *
116 * @return
117 * Error code
118 ******************************************************************************/
rt_hw_misc_init(void)119 rt_err_t rt_hw_misc_init(void)
120 {
121 do
122 {
123 /* Find ADC device */
124 adc0 = rt_device_find(RT_ADC0_NAME);
125 if (adc0 == RT_NULL)
126 {
127 misc_debug("Misc err: Can't find device: %s!\n", RT_ADC0_NAME);
128 break;
129 }
130 misc_debug("Misc: Find device %s\n", RT_ADC0_NAME);
131
132 return RT_EOK;
133 } while (0);
134
135 misc_debug("Misc err: Init failed!\n");
136 return -RT_ERROR;
137 }
138
139 /***************************************************************************//**
140 * @brief
141 * Convert ADC result to degree celsius.
142 *
143 * @details
144 *
145 * @note
146 * See section 2.3.4 in the reference manual for details on this calculatoin
147 *
148 * @param adcResult
149 * Raw value from ADC to be converted to celsius
150 *
151 * @return
152 * The temperature value (signed integer) in degrees celsius times 100
153 *
154 ******************************************************************************/
efm32_misc_getCelsius(rt_uint32_t adcResult)155 rt_int32_t efm32_misc_getCelsius(rt_uint32_t adcResult)
156 {
157 /* Factory calibration temperature from device information page. */
158 rt_int32_t cal_temp = ((DEVINFO->CAL & _DEVINFO_CAL_TEMP_MASK) \
159 >> _DEVINFO_CAL_TEMP_SHIFT) * 100;
160
161 /* Factory calibration value from device information page. */
162 rt_int32_t cal_value = ((DEVINFO->ADC0CAL2 & _DEVINFO_ADC0CAL2_TEMP1V25_MASK) \
163 >> _DEVINFO_ADC0CAL2_TEMP1V25_SHIFT) * 10000;
164
165 /* Temperature gradient (from datasheet) in (ADC unit / degree celsius * 100) */
166 rt_int32_t t_grad = -385;
167
168 return (cal_temp - (cal_value - (rt_int32_t)adcResult * 10000) / t_grad);
169 }
170
171 /*******************************************************************************
172 * Export to FINSH
173 ******************************************************************************/
174 #ifdef RT_USING_FINSH
175 #include <finsh.h>
176
list_temp(void)177 void list_temp(void)
178 {
179 rt_int32_t temp = rt_hw_get_temp();
180
181 rt_kprintf("Temperature is %2d.%02d C\n", temp / 100, temp % 100);
182 }
183 FINSH_FUNCTION_EXPORT(list_temp, list current temperature value.)
184
list_vdd(void)185 void list_vdd(void)
186 {
187 rt_uint32_t vdd = rt_hw_get_vdd();
188
189 rt_kprintf("VDD is %1d.%02d V\n", vdd / 100, vdd % 100);
190 }
191 FINSH_FUNCTION_EXPORT(list_vdd, list current VDD value.)
192
193 #endif /* RT_USING_FINSH */
194
195 #endif /* defined(RT_USING_MISC) */
196 /***************************************************************************//**
197 * @}
198 ******************************************************************************/
199