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