1 /**
2 ******************************************************************************
3 * @file stm32wlxx_hal_adc_ex.c
4 * @author MCD Application Team
5 * @brief This file provides firmware functions to manage the following
6 * functionalities of the Analog to Digital Converter (ADC)
7 * peripheral:
8 * + Peripheral Control functions
9 * Other functions (generic functions) are available in file
10 * "stm32wlxx_hal_adc.c".
11 *
12 ******************************************************************************
13 * @attention
14 *
15 * Copyright (c) 2020 STMicroelectronics.
16 * All rights reserved.
17 *
18 * This software is licensed under terms that can be found in the LICENSE file
19 * in the root directory of this software component.
20 * If no LICENSE file comes with this software, it is provided AS-IS.
21 *
22 ******************************************************************************
23 @verbatim
24 [..]
25 (@) Sections "ADC peripheral features" and "How to use this driver" are
26 available in file of generic functions "stm32wlxx_hal_adc.c".
27 [..]
28 @endverbatim
29 */
30
31 /* Includes ------------------------------------------------------------------*/
32 #include "stm32wlxx_hal.h"
33
34 /** @addtogroup STM32WLxx_HAL_Driver
35 * @{
36 */
37
38 /** @defgroup ADCEx ADCEx
39 * @brief ADC Extended HAL module driver
40 * @{
41 */
42
43 #ifdef HAL_ADC_MODULE_ENABLED
44
45 /* Private typedef -----------------------------------------------------------*/
46 /* Private define ------------------------------------------------------------*/
47
48 /** @defgroup ADCEx_Private_Constants ADC Extended Private Constants
49 * @{
50 */
51
52 /* Fixed timeout value for ADC calibration. */
53 /* Values defined to be higher than worst cases: maximum ratio between ADC */
54 /* and CPU clock frequencies. */
55 /* Example of profile low frequency : ADC frequency at 31.25kHz (ADC clock */
56 /* source PLL 8MHz, ADC clock prescaler 256), CPU frequency 48MHz. */
57 /* Calibration time max = 116 / fADC (refer to datasheet) */
58 /* = 178 176 CPU cycles */
59 #define ADC_CALIBRATION_TIMEOUT (178176UL) /*!< ADC calibration time-out value (unit: CPU cycles) */
60 #define ADC_DISABLE_TIMEOUT (2UL)
61
62 /**
63 * @}
64 */
65
66 /* Private macro -------------------------------------------------------------*/
67 /* Private variables ---------------------------------------------------------*/
68 /* Private function prototypes -----------------------------------------------*/
69 /* Exported functions --------------------------------------------------------*/
70
71 /** @defgroup ADCEx_Exported_Functions ADC Extended Exported Functions
72 * @{
73 */
74
75 /** @defgroup ADCEx_Exported_Functions_Group1 Extended Input and Output operation functions
76 * @brief Extended IO operation functions
77 *
78 @verbatim
79 ===============================================================================
80 ##### IO operation functions #####
81 ===============================================================================
82 [..] This section provides functions allowing to:
83
84 (+) Perform the ADC self-calibration.
85 (+) Get calibration factors.
86 (+) Set calibration factors.
87
88 @endverbatim
89 * @{
90 */
91
92 /**
93 * @brief Perform an ADC automatic self-calibration
94 * Calibration prerequisite: ADC must be disabled (execute this
95 * function before HAL_ADC_Start() or after HAL_ADC_Stop() ).
96 * @note Calibration factor can be read after calibration, using function
97 * HAL_ADC_GetValue() (value on 7 bits: from DR[6;0]).
98 * @param hadc ADC handle
99 * @retval HAL status
100 */
HAL_ADCEx_Calibration_Start(ADC_HandleTypeDef * hadc)101 HAL_StatusTypeDef HAL_ADCEx_Calibration_Start(ADC_HandleTypeDef *hadc)
102 {
103 HAL_StatusTypeDef tmp_hal_status;
104 __IO uint32_t wait_loop_index = 0UL;
105 uint32_t backup_setting_cfgr1;
106 uint32_t calibration_index;
107 uint32_t calibration_factor_accumulated = 0;
108 uint32_t tickstart;
109
110 /* Check the parameters */
111 assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
112
113 __HAL_LOCK(hadc);
114
115 /* Calibration prerequisite: ADC must be disabled. */
116
117 /* Disable the ADC (if not already disabled) */
118 tmp_hal_status = ADC_Disable(hadc);
119
120 /* Check if ADC is effectively disabled */
121 if (LL_ADC_IsEnabled(hadc->Instance) == 0UL)
122 {
123 /* Set ADC state */
124 ADC_STATE_CLR_SET(hadc->State,
125 HAL_ADC_STATE_REG_BUSY,
126 HAL_ADC_STATE_BUSY_INTERNAL);
127
128 /* Manage settings impacting calibration */
129 /* - Disable ADC mode auto power-off */
130 /* - Disable ADC DMA transfer request during calibration */
131 /* Note: Specificity of this STM32 series: Calibration factor is */
132 /* available in data register and also transferred by DMA. */
133 /* To not insert ADC calibration factor among ADC conversion data */
134 /* in array variable, DMA transfer must be disabled during */
135 /* calibration. */
136 backup_setting_cfgr1 = READ_BIT(hadc->Instance->CFGR1, ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG | ADC_CFGR1_AUTOFF);
137 CLEAR_BIT(hadc->Instance->CFGR1, ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG | ADC_CFGR1_AUTOFF);
138
139 /* ADC calibration procedure */
140 /* Note: Perform an averaging of 8 calibrations for optimized accuracy */
141 for (calibration_index = 0UL; calibration_index < 8UL; calibration_index++)
142 {
143 /* Start ADC calibration */
144 LL_ADC_StartCalibration(hadc->Instance);
145
146 /* Wait for calibration completion */
147 while (LL_ADC_IsCalibrationOnGoing(hadc->Instance) != 0UL)
148 {
149 wait_loop_index++;
150 if (wait_loop_index >= ADC_CALIBRATION_TIMEOUT)
151 {
152 /* Update ADC state machine to error */
153 ADC_STATE_CLR_SET(hadc->State,
154 HAL_ADC_STATE_BUSY_INTERNAL,
155 HAL_ADC_STATE_ERROR_INTERNAL);
156
157 __HAL_UNLOCK(hadc);
158
159 return HAL_ERROR;
160 }
161 }
162
163 calibration_factor_accumulated += LL_ADC_GetCalibrationFactor(hadc->Instance);
164 }
165 /* Compute average */
166 calibration_factor_accumulated /= calibration_index;
167 /* Apply calibration factor */
168 LL_ADC_Enable(hadc->Instance);
169 LL_ADC_SetCalibrationFactor(hadc->Instance, calibration_factor_accumulated);
170 LL_ADC_Disable(hadc->Instance);
171
172 /* Wait for ADC effectively disabled before changing configuration */
173 /* Get tick count */
174 tickstart = HAL_GetTick();
175
176 while (LL_ADC_IsEnabled(hadc->Instance) != 0UL)
177 {
178 if ((HAL_GetTick() - tickstart) > ADC_DISABLE_TIMEOUT)
179 {
180 /* New check to avoid false timeout detection in case of preemption */
181 if (LL_ADC_IsEnabled(hadc->Instance) != 0UL)
182 {
183 /* Update ADC state machine to error */
184 SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);
185
186 /* Set ADC error code to ADC peripheral internal error */
187 SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);
188
189 return HAL_ERROR;
190 }
191 }
192 }
193
194 /* Restore configuration after calibration */
195 SET_BIT(hadc->Instance->CFGR1, backup_setting_cfgr1);
196
197 /* Set ADC state */
198 ADC_STATE_CLR_SET(hadc->State,
199 HAL_ADC_STATE_BUSY_INTERNAL,
200 HAL_ADC_STATE_READY);
201 }
202 else
203 {
204 SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);
205
206 /* Note: No need to update variable "tmp_hal_status" here: already set */
207 /* to state "HAL_ERROR" by function disabling the ADC. */
208 }
209
210 __HAL_UNLOCK(hadc);
211
212 return tmp_hal_status;
213 }
214
215 /**
216 * @brief Get the calibration factor.
217 * @param hadc ADC handle.
218 * @retval Calibration value.
219 */
HAL_ADCEx_Calibration_GetValue(ADC_HandleTypeDef * hadc)220 uint32_t HAL_ADCEx_Calibration_GetValue(ADC_HandleTypeDef *hadc)
221 {
222 /* Check the parameters */
223 assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
224
225 /* Return the selected ADC calibration value */
226 return ((hadc->Instance->CALFACT) & 0x0000007FU);
227 }
228
229 /**
230 * @brief Set the calibration factor to overwrite automatic conversion result.
231 * ADC must be enabled and no conversion is ongoing.
232 * @param hadc ADC handle
233 * @param CalibrationFactor Calibration factor (coded on 7 bits maximum)
234 * @retval HAL state
235 */
HAL_ADCEx_Calibration_SetValue(ADC_HandleTypeDef * hadc,uint32_t CalibrationFactor)236 HAL_StatusTypeDef HAL_ADCEx_Calibration_SetValue(ADC_HandleTypeDef *hadc, uint32_t CalibrationFactor)
237 {
238 HAL_StatusTypeDef tmp_hal_status = HAL_OK;
239 uint32_t tmp_adc_is_conversion_on_going_regular;
240
241 /* Check the parameters */
242 assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
243 assert_param(IS_ADC_CALFACT(CalibrationFactor));
244
245 __HAL_LOCK(hadc);
246
247 /* Verification of hardware constraints before modifying the calibration */
248 /* factors register: ADC must be enabled, no conversion on going. */
249 tmp_adc_is_conversion_on_going_regular = LL_ADC_REG_IsConversionOngoing(hadc->Instance);
250
251 if ((LL_ADC_IsEnabled(hadc->Instance) != 0UL)
252 && (tmp_adc_is_conversion_on_going_regular == 0UL)
253 )
254 {
255 hadc->Instance->CALFACT &= ~ADC_CALFACT_CALFACT;
256 hadc->Instance->CALFACT |= CalibrationFactor;
257 }
258 else
259 {
260 /* Update ADC state machine */
261 SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
262 /* Update ADC error code */
263 SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);
264
265 /* Update ADC state machine to error */
266 tmp_hal_status = HAL_ERROR;
267 }
268
269 __HAL_UNLOCK(hadc);
270
271 return tmp_hal_status;
272 }
273
274 /**
275 * @brief Analog watchdog 2 callback in non-blocking mode.
276 * @param hadc ADC handle
277 * @retval None
278 */
HAL_ADCEx_LevelOutOfWindow2Callback(ADC_HandleTypeDef * hadc)279 __weak void HAL_ADCEx_LevelOutOfWindow2Callback(ADC_HandleTypeDef *hadc)
280 {
281 /* Prevent unused argument(s) compilation warning */
282 UNUSED(hadc);
283
284 /* NOTE : This function should not be modified. When the callback is needed,
285 function HAL_ADCEx_LevelOutOfWindow2Callback must be implemented in the user file.
286 */
287 }
288
289 /**
290 * @brief Analog watchdog 3 callback in non-blocking mode.
291 * @param hadc ADC handle
292 * @retval None
293 */
HAL_ADCEx_LevelOutOfWindow3Callback(ADC_HandleTypeDef * hadc)294 __weak void HAL_ADCEx_LevelOutOfWindow3Callback(ADC_HandleTypeDef *hadc)
295 {
296 /* Prevent unused argument(s) compilation warning */
297 UNUSED(hadc);
298
299 /* NOTE : This function should not be modified. When the callback is needed,
300 function HAL_ADCEx_LevelOutOfWindow3Callback must be implemented in the user file.
301 */
302 }
303
304
305 /**
306 * @brief End Of Sampling callback in non-blocking mode.
307 * @param hadc ADC handle
308 * @retval None
309 */
HAL_ADCEx_EndOfSamplingCallback(ADC_HandleTypeDef * hadc)310 __weak void HAL_ADCEx_EndOfSamplingCallback(ADC_HandleTypeDef *hadc)
311 {
312 /* Prevent unused argument(s) compilation warning */
313 UNUSED(hadc);
314
315 /* NOTE : This function should not be modified. When the callback is needed,
316 function HAL_ADCEx_EndOfSamplingCallback must be implemented in the user file.
317 */
318 }
319
320 /**
321 * @brief ADC channel configuration ready callback in non-blocking mode.
322 * @param hadc ADC handle
323 * @retval None
324 */
HAL_ADCEx_ChannelConfigReadyCallback(ADC_HandleTypeDef * hadc)325 __weak void HAL_ADCEx_ChannelConfigReadyCallback(ADC_HandleTypeDef *hadc)
326 {
327 /* Prevent unused argument(s) compilation warning */
328 UNUSED(hadc);
329
330 /* NOTE : This function should not be modified. When the callback is needed,
331 function HAL_ADCEx_ChannelConfigReadyCallback must be implemented in the user file.
332 */
333 }
334
335 /**
336 * @}
337 */
338
339 /**
340 * @brief Disable ADC voltage regulator.
341 * @note Disabling voltage regulator allows to save power. This operation can
342 * be carried out only when ADC is disabled.
343 * @note To enable again the voltage regulator, the user is expected to
344 * resort to HAL_ADC_Init() API.
345 * @param hadc ADC handle
346 * @retval HAL status
347 */
HAL_ADCEx_DisableVoltageRegulator(ADC_HandleTypeDef * hadc)348 HAL_StatusTypeDef HAL_ADCEx_DisableVoltageRegulator(ADC_HandleTypeDef *hadc)
349 {
350 HAL_StatusTypeDef tmp_hal_status;
351
352 /* Check the parameters */
353 assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
354
355 /* Setting of this feature is conditioned to ADC state: ADC must be ADC disabled */
356 if (LL_ADC_IsEnabled(hadc->Instance) == 0UL)
357 {
358 LL_ADC_DisableInternalRegulator(hadc->Instance);
359 tmp_hal_status = HAL_OK;
360 }
361 else
362 {
363 tmp_hal_status = HAL_ERROR;
364 }
365
366 return tmp_hal_status;
367 }
368
369 /**
370 * @}
371 */
372
373 /**
374 * @}
375 */
376
377 #endif /* HAL_ADC_MODULE_ENABLED */
378 /**
379 * @}
380 */
381
382 /**
383 * @}
384 */
385