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