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