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