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