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_adc_dma_transfer; /* Note: Variable not declared as volatile because register read is already declared as volatile */
110 uint32_t calibration_index;
111 uint32_t calibration_factor_accumulated = 0;
112 uint32_t tickstart;
113
114 /* Check the parameters */
115 assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
116
117 /* Process locked */
118 __HAL_LOCK(hadc);
119
120 /* Calibration prerequisite: ADC must be disabled. */
121
122 /* Disable the ADC (if not already disabled) */
123 tmp_hal_status = ADC_Disable(hadc);
124
125 /* Check if ADC is effectively disabled */
126 if (LL_ADC_IsEnabled(hadc->Instance) == 0UL)
127 {
128 /* Set ADC state */
129 ADC_STATE_CLR_SET(hadc->State,
130 HAL_ADC_STATE_REG_BUSY,
131 HAL_ADC_STATE_BUSY_INTERNAL);
132
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_adc_dma_transfer = READ_BIT(hadc->Instance->CFGR1, ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG);
140 CLEAR_BIT(hadc->Instance->CFGR1, ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG);
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 /* Apply calibration factor */
171 LL_ADC_Enable(hadc->Instance);
172 LL_ADC_SetCalibrationFactor(hadc->Instance, calibration_factor_accumulated);
173 LL_ADC_Disable(hadc->Instance);
174
175 /* Wait for ADC effectively disabled before changing configuration */
176 /* Get tick count */
177 tickstart = HAL_GetTick();
178
179 while (LL_ADC_IsEnabled(hadc->Instance) != 0UL)
180 {
181 if ((HAL_GetTick() - tickstart) > ADC_DISABLE_TIMEOUT)
182 {
183 /* New check to avoid false timeout detection in case of preemption */
184 if (LL_ADC_IsEnabled(hadc->Instance) != 0UL)
185 {
186 /* Update ADC state machine to error */
187 SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);
188
189 /* Set ADC error code to ADC peripheral internal error */
190 SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);
191
192 return HAL_ERROR;
193 }
194 }
195 }
196
197 /* Restore ADC DMA transfer request after calibration */
198 SET_BIT(hadc->Instance->CFGR1, backup_setting_adc_dma_transfer);
199
200 /* Set ADC state */
201 ADC_STATE_CLR_SET(hadc->State,
202 HAL_ADC_STATE_BUSY_INTERNAL,
203 HAL_ADC_STATE_READY);
204 }
205 else
206 {
207 SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);
208
209 /* Note: No need to update variable "tmp_hal_status" here: already set */
210 /* to state "HAL_ERROR" by function disabling the ADC. */
211 }
212
213 /* Process unlocked */
214 __HAL_UNLOCK(hadc);
215
216 /* Return function status */
217 return tmp_hal_status;
218 }
219
220 /**
221 * @brief Get the calibration factor.
222 * @param hadc ADC handle.
223 * @retval Calibration value.
224 */
HAL_ADCEx_Calibration_GetValue(ADC_HandleTypeDef * hadc)225 uint32_t HAL_ADCEx_Calibration_GetValue(ADC_HandleTypeDef *hadc)
226 {
227 /* Check the parameters */
228 assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
229
230 /* Return the selected ADC calibration value */
231 return ((hadc->Instance->CALFACT) & 0x0000007FU);
232 }
233
234 /**
235 * @brief Set the calibration factor to overwrite automatic conversion result.
236 * ADC must be enabled and no conversion is ongoing.
237 * @param hadc ADC handle
238 * @param CalibrationFactor Calibration factor (coded on 7 bits maximum)
239 * @retval HAL state
240 */
HAL_ADCEx_Calibration_SetValue(ADC_HandleTypeDef * hadc,uint32_t CalibrationFactor)241 HAL_StatusTypeDef HAL_ADCEx_Calibration_SetValue(ADC_HandleTypeDef *hadc, uint32_t CalibrationFactor)
242 {
243 HAL_StatusTypeDef tmp_hal_status = HAL_OK;
244 uint32_t tmp_adc_is_conversion_on_going_regular;
245
246 /* Check the parameters */
247 assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
248 assert_param(IS_ADC_CALFACT(CalibrationFactor));
249
250 /* Process locked */
251 __HAL_LOCK(hadc);
252
253 /* Verification of hardware constraints before modifying the calibration */
254 /* factors register: ADC must be enabled, no conversion on going. */
255 tmp_adc_is_conversion_on_going_regular = LL_ADC_REG_IsConversionOngoing(hadc->Instance);
256
257 if ((LL_ADC_IsEnabled(hadc->Instance) != 0UL)
258 && (tmp_adc_is_conversion_on_going_regular == 0UL)
259 )
260 {
261 hadc->Instance->CALFACT &= ~ADC_CALFACT_CALFACT;
262 hadc->Instance->CALFACT |= CalibrationFactor;
263 }
264 else
265 {
266 /* Update ADC state machine */
267 SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
268 /* Update ADC error code */
269 SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);
270
271 /* Update ADC state machine to error */
272 tmp_hal_status = HAL_ERROR;
273 }
274
275 /* Process unlocked */
276 __HAL_UNLOCK(hadc);
277
278 /* Return function status */
279 return tmp_hal_status;
280 }
281
282 /**
283 * @brief Analog watchdog 2 callback in non-blocking mode.
284 * @param hadc ADC handle
285 * @retval None
286 */
HAL_ADCEx_LevelOutOfWindow2Callback(ADC_HandleTypeDef * hadc)287 __weak void HAL_ADCEx_LevelOutOfWindow2Callback(ADC_HandleTypeDef *hadc)
288 {
289 /* Prevent unused argument(s) compilation warning */
290 UNUSED(hadc);
291
292 /* NOTE : This function should not be modified. When the callback is needed,
293 function HAL_ADCEx_LevelOutOfWindow2Callback must be implemented in the user file.
294 */
295 }
296
297 /**
298 * @brief Analog watchdog 3 callback in non-blocking mode.
299 * @param hadc ADC handle
300 * @retval None
301 */
HAL_ADCEx_LevelOutOfWindow3Callback(ADC_HandleTypeDef * hadc)302 __weak void HAL_ADCEx_LevelOutOfWindow3Callback(ADC_HandleTypeDef *hadc)
303 {
304 /* Prevent unused argument(s) compilation warning */
305 UNUSED(hadc);
306
307 /* NOTE : This function should not be modified. When the callback is needed,
308 function HAL_ADCEx_LevelOutOfWindow3Callback must be implemented in the user file.
309 */
310 }
311
312
313 /**
314 * @brief End Of Sampling callback in non-blocking mode.
315 * @param hadc ADC handle
316 * @retval None
317 */
HAL_ADCEx_EndOfSamplingCallback(ADC_HandleTypeDef * hadc)318 __weak void HAL_ADCEx_EndOfSamplingCallback(ADC_HandleTypeDef *hadc)
319 {
320 /* Prevent unused argument(s) compilation warning */
321 UNUSED(hadc);
322
323 /* NOTE : This function should not be modified. When the callback is needed,
324 function HAL_ADCEx_EndOfSamplingCallback must be implemented in the user file.
325 */
326 }
327
328 /**
329 * @brief ADC channel configuration ready callback in non-blocking mode.
330 * @param hadc ADC handle
331 * @retval None
332 */
HAL_ADCEx_ChannelConfigReadyCallback(ADC_HandleTypeDef * hadc)333 __weak void HAL_ADCEx_ChannelConfigReadyCallback(ADC_HandleTypeDef *hadc)
334 {
335 /* Prevent unused argument(s) compilation warning */
336 UNUSED(hadc);
337
338 /* NOTE : This function should not be modified. When the callback is needed,
339 function HAL_ADCEx_ChannelConfigReadyCallback must be implemented in the user file.
340 */
341 }
342
343 /**
344 * @}
345 */
346
347 /**
348 * @brief Disable ADC voltage regulator.
349 * @note Disabling voltage regulator allows to save power. This operation can
350 * be carried out only when ADC is disabled.
351 * @note To enable again the voltage regulator, the user is expected to
352 * resort to HAL_ADC_Init() API.
353 * @param hadc ADC handle
354 * @retval HAL status
355 */
HAL_ADCEx_DisableVoltageRegulator(ADC_HandleTypeDef * hadc)356 HAL_StatusTypeDef HAL_ADCEx_DisableVoltageRegulator(ADC_HandleTypeDef *hadc)
357 {
358 HAL_StatusTypeDef tmp_hal_status;
359
360 /* Check the parameters */
361 assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
362
363 /* Setting of this feature is conditioned to ADC state: ADC must be ADC disabled */
364 if (LL_ADC_IsEnabled(hadc->Instance) == 0UL)
365 {
366 LL_ADC_DisableInternalRegulator(hadc->Instance);
367 tmp_hal_status = HAL_OK;
368 }
369 else
370 {
371 tmp_hal_status = HAL_ERROR;
372 }
373
374 return tmp_hal_status;
375 }
376
377 /**
378 * @}
379 */
380
381 /**
382 * @}
383 */
384
385 #endif /* HAL_ADC_MODULE_ENABLED */
386 /**
387 * @}
388 */
389
390 /**
391 * @}
392 */
393