fix LPC812 PWM
Fork of mbed-dev by
Diff: targets/cmsis/TARGET_STM/TARGET_STM32L0/stm32l0xx_hal_adc.c
- Revision:
- 113:b3775bf36a83
- Parent:
- 0:9b334a45a8ff
--- a/targets/cmsis/TARGET_STM/TARGET_STM32L0/stm32l0xx_hal_adc.c Sun Apr 17 17:45:10 2016 +0100 +++ b/targets/cmsis/TARGET_STM/TARGET_STM32L0/stm32l0xx_hal_adc.c Tue Apr 19 11:15:15 2016 +0100 @@ -2,8 +2,8 @@ ****************************************************************************** * @file stm32l0xx_hal_adc.c * @author MCD Application Team - * @version V1.2.0 - * @date 06-February-2015 + * @version V1.5.0 + * @date 8-January-2016 * @brief This file provides firmware functions to manage the following * functionalities of the Analog to Digital Convertor (ADC) * peripheral: @@ -11,101 +11,228 @@ * ++ Initialization and Configuration of ADC * + Operation functions * ++ Start, stop, get result of conversions of regular - * groups, using 3 possible modes : polling, interruption or DMA. - * ++ Calibration feature + * group, using 3 possible modes : polling, interruption or DMA. * + Control functions + * ++ Channels configuration on regular group * ++ Analog Watchdog configuration - * ++ Regular Channels Configuration * + State functions * ++ ADC state machine management * ++ Interrupts and flags management + * Other functions (extended functions) are available in file + * "stm32l0xx_hal_adc_ex.c". * @verbatim ============================================================================== - ##### ADC specific features ##### + ##### ADC peripheral features ##### ============================================================================== [..] - (#) 12-bit, 10-bit, 8-bit or 6-bit configurable resolution. - - (#) A built-in hardware oversampler allows to improve analog performances - while off-loading the related computational burden from the CPU. + (+) 12-bit, 10-bit, 8-bit or 6-bit configurable resolution - (#) Interrupt generation at the end of conversion and in case of analog - watchdog or overrun events. - - (#) Single and continuous conversion modes. - - (#) Scan or discontinuous mode conversion of channel 0 to channel 18. + (+) A built-in hardware oversampler can handle multiple conversions and average + them into a single data with increased data width, up to 16-bit. + + (+) Interrupt generation at the end of regular conversion and in case of + analog watchdog or overrun events. - (#) Configurable scan direction (Upward from channel 0 to 18 or Backward from - channel 18 to channel 0) + (+) Single and continuous conversion modes. + + (+) Scan mode for conversion of several channels sequentially. - (#) Data alignment with in-built data coherency. + (+) Data alignment with in-built data coherency. + + (+) Programmable sampling time (common for all channels) - (#) Channel-wise programmable sampling time. - - (#) External trigger option with configurable polarity. + (+) ADC conversion of regular group. + + (+) External trigger (timer or EXTI) with configurable polarity - (#) DMA request generation during regular channel conversion. - - (#) ADC supply requirements: 2.4 V to 3.6 V at full speed and down to 1.8 V at + (+) DMA request generation for transfer of conversions data of regular group. + + (+) ADC calibration + + (+) ADC supply requirements: 2.4 V to 3.6 V at full speed and down to 1.8 V at slower speed. - (#) ADC input range: VREF- =VIN =VREF+. - - (#) ADC self-calibration. - - (#) ADC is automatically powered off (AutoOff mode) except during the active - conversion phase. This dramatically reduces the power consumption of the - ADC. - - (#) Wait mode to prevent ADC overrun in applications with low frequency. + (+) ADC input range: from Vref- (connected to Vssa) to Vref+ (connected to + Vdda or to an external voltage reference). ##### How to use this driver ##### ============================================================================== [..] + *** Configuration of top level parameters related to ADC *** + ============================================================ + [..] + (#) Enable the ADC interface - As prerequisite, into HAL_ADC_MspInit(), ADC clock must be configured - at RCC top level. + (++) As prerequisite, ADC clock must be configured at RCC top level. + Caution: On STM32L0, ADC clock frequency max is 16MHz (refer + to device datasheet). + Therefore, ADC clock prescaler must be configured in + function of ADC clock source frequency to remain below + this maximum frequency. + + (++) Two clock settings are mandatory: + (+++) ADC clock (core clock, also possibly conversion clock). - Depending on both possible clock sources: PCLK clock or ADC asynchronous - clock. - __HAL_RCC_ADC1_CLK_ENABLE(); + (+++) ADC clock (conversions clock). + Two possible clock sources: synchronous clock derived from APB clock + or asynchronous clock derived from ADC dedicated HSI RC oscillator + 16MHz. + If asynchronous clock is selected, parameter "HSIState" must be set either: + - to "...HSIState = RCC_HSI_ON" to maintain the HSI16 oscillator + always enabled: can be used to supply the main system clock. + (+++) Example: + Into HAL_ADC_MspInit() (recommended code location) or with + other device clock parameters configuration: + (+++) __HAL_RCC_ADC1_CLK_ENABLE(); (mandatory) + + HSI16 enable : (optional: if asynchronous clock selected) + (+++) RCC_OscInitTypeDef RCC_OscInitStructure; + (+++) RCC_OscInitStructure.OscillatorType = RCC_OSCILLATORTYPE_HSI; + (+++) RCC_OscInitStructure.HSI16CalibrationValue = RCC_HSICALIBRATION_DEFAULT; + (+++) RCC_OscInitStructure.HSIState = RCC_HSI_ON; + (+++) RCC_OscInitStructure.PLL... (optional if used for system clock) + (+++) HAL_RCC_OscConfig(&RCC_OscInitStructure); + + (++) ADC clock source and clock prescaler are configured at ADC level with + parameter "ClockPrescaler" using function HAL_ADC_Init(). (#) ADC pins configuration - (++) Enable the clock for the ADC GPIOs using the following function: - __HAL_RCC_GPIOx_CLK_ENABLE(); - (++) Configure these ADC pins in analog mode using HAL_GPIO_Init(); - - (#) Configure the ADC parameters (conversion resolution, oversampler, - data alignment, continuous mode,...) using the HAL_ADC_Init() function. + (++) Enable the clock for the ADC GPIOs + using macro __HAL_RCC_GPIOx_CLK_ENABLE() + (++) Configure these ADC pins in analog mode + using function HAL_GPIO_Init() + + (#) Optionally, in case of usage of ADC with interruptions: + (++) Configure the NVIC for ADC + using function HAL_NVIC_EnableIRQ(ADCx_IRQn) + (++) Insert the ADC interruption handler function HAL_ADC_IRQHandler() + into the function of corresponding ADC interruption vector + ADCx_IRQHandler(). + + (#) Optionally, in case of usage of DMA: + (++) Configure the DMA (DMA channel, mode normal or circular, ...) + using function HAL_DMA_Init(). + (++) Configure the NVIC for DMA + using function HAL_NVIC_EnableIRQ(DMAx_Channelx_IRQn) + (++) Insert the ADC interruption handler function HAL_ADC_IRQHandler() + into the function of corresponding DMA interruption vector + DMAx_Channelx_IRQHandler(). + + *** Configuration of ADC, group regular, channels parameters *** + ================================================================ + [..] + + (#) Configure the ADC parameters (resolution, data alignment, oversampler, continuous mode, ...) + and regular group parameters (conversion trigger, sequencer, ...) + using function HAL_ADC_Init(). + + (#) Configure the channels for regular group parameters (channel number, + channel rank into sequencer, ..., into regular group) + using function HAL_ADC_ConfigChannel(). + + (#) Optionally, configure the analog watchdog parameters (channels + monitored, thresholds, ...) + using function HAL_ADC_AnalogWDGConfig(). + + + (#) When device is in mode low-power (low-power run, low-power sleep or stop mode), + function "HAL_ADCEx_EnableVREFINT()" must be called before function HAL_ADC_Init(). + In case of internal temperature sensor to be measured: + function "HAL_ADCEx_EnableVREFINTTempSensor()" must be called similarilly - (#) Activate the ADC peripheral using one of the start functions: - HAL_ADC_Start(), HAL_ADC_Start_IT() or HAL_ADC_Start_DMA() + *** Execution of ADC conversions *** + ==================================== + [..] + + (#) Optionally, perform an automatic ADC calibration to improve the + conversion accuracy + using function HAL_ADCEx_Calibration_Start(). + + (#) ADC driver can be used among three modes: polling, interruption, + transfer by DMA. + + (++) ADC conversion by polling: + (+++) Activate the ADC peripheral and start conversions + using function HAL_ADC_Start() + (+++) Wait for ADC conversion completion + using function HAL_ADC_PollForConversion() + (+++) Retrieve conversion results + using function HAL_ADC_GetValue() + (+++) Stop conversion and disable the ADC peripheral + using function HAL_ADC_Stop() + + (++) ADC conversion by interruption: + (+++) Activate the ADC peripheral and start conversions + using function HAL_ADC_Start_IT() + (+++) Wait for ADC conversion completion by call of function + HAL_ADC_ConvCpltCallback() + (this function must be implemented in user program) + (+++) Retrieve conversion results + using function HAL_ADC_GetValue() + (+++) Stop conversion and disable the ADC peripheral + using function HAL_ADC_Stop_IT() + + (++) ADC conversion with transfer by DMA: + (+++) Activate the ADC peripheral and start conversions + using function HAL_ADC_Start_DMA() + (+++) Wait for ADC conversion completion by call of function + HAL_ADC_ConvCpltCallback() or HAL_ADC_ConvHalfCpltCallback() + (these functions must be implemented in user program) + (+++) Conversion results are automatically transferred by DMA into + destination variable address. + (+++) Stop conversion and disable the ADC peripheral + using function HAL_ADC_Stop_DMA() - *** Channels configuration *** - =============================== [..] - (+) To configure the ADC channels group, use HAL_ADC_ConfigChannel() function. - (+) To read the ADC converted values, use the HAL_ADC_GetValue() function. - *** DMA feature configuration *** - ================================= + (@) Callback functions must be implemented in user program: + (+@) HAL_ADC_ErrorCallback() + (+@) HAL_ADC_LevelOutOfWindowCallback() (callback of analog watchdog) + (+@) HAL_ADC_ConvCpltCallback() + (+@) HAL_ADC_ConvHalfCpltCallback + + *** Deinitialization of ADC *** + ============================================================ [..] - (+) To enable the DMA mode, use the HAL_ADC_Start_DMA() function. - (+) To enable the generation of DMA requests continuously at the end of - the last DMA transfer, set .Init.DMAContinuousRequests to ENABLE and - call HAL_ADC_Init() function. + + (#) Disable the ADC interface + (++) ADC clock can be hard reset and disabled at RCC top level. + (++) Hard reset of ADC peripherals + using macro __ADCx_FORCE_RESET(), __ADCx_RELEASE_RESET(). + (++) ADC clock disable + using the equivalent macro/functions as configuration step. + (+++) Example: + Into HAL_ADC_MspDeInit() (recommended code location) or with + other device clock parameters configuration: + (+++) RCC_OscInitStructure.OscillatorType = RCC_OSCILLATORTYPE_HSI; + (+++) RCC_OscInitStructure.HSIState = RCC_HSI_OFF; (if not used for system clock) + (+++) HAL_RCC_OscConfig(&RCC_OscInitStructure); + (#) ADC pins configuration + (++) Disable the clock for the ADC GPIOs + using macro __HAL_RCC_GPIOx_CLK_DISABLE() + + (#) Optionally, in case of usage of ADC with interruptions: + (++) Disable the NVIC for ADC + using function HAL_NVIC_EnableIRQ(ADCx_IRQn) + + (#) Optionally, in case of usage of DMA: + (++) Deinitialize the DMA + using function HAL_DMA_Init(). + (++) Disable the NVIC for DMA + using function HAL_NVIC_EnableIRQ(DMAx_Channelx_IRQn) + + [..] @endverbatim ****************************************************************************** * @attention * - * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * <h2><center>© COPYRIGHT(c) 2016 STMicroelectronics</center></h2> * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -139,12 +266,16 @@ * @{ */ +#ifdef HAL_ADC_MODULE_ENABLED + /** @addtogroup ADC * @brief ADC driver modules * @{ */ -#ifdef HAL_ADC_MODULE_ENABLED +/** @addtogroup ADC_Private + * @{ + */ /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ @@ -158,25 +289,32 @@ /* Maximum delay is 10us (refer to device datasheet, parameter tSTART). */ /* Unit: us */ #define ADC_TEMPSENSOR_DELAY_US ((uint32_t) 10) +/** + * @} + */ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/ +/** @addtogroup ADC_Private + * @{ + */ static HAL_StatusTypeDef ADC_Enable(ADC_HandleTypeDef* hadc); +static HAL_StatusTypeDef ADC_Disable(ADC_HandleTypeDef* hadc); +static HAL_StatusTypeDef ADC_ConversionStop(ADC_HandleTypeDef* hadc); static void ADC_DMAConvCplt(DMA_HandleTypeDef *hdma); static void ADC_DMAHalfConvCplt(DMA_HandleTypeDef *hdma); static void ADC_DMAError(DMA_HandleTypeDef *hdma); -static HAL_StatusTypeDef ADC_ConversionStop(ADC_HandleTypeDef* hadc, uint32_t ConversionGroup); -static HAL_StatusTypeDef ADC_Disable(ADC_HandleTypeDef* hadc); static void ADC_DelayMicroSecond(uint32_t microSecond); +/** + * @} + */ -/* Private functions ---------------------------------------------------------*/ - -/** @defgroup ADC_Private_Functions +/** @addtogroup ADC_Exported_Functions * @{ */ -/** @defgroup ADC_Group1 Initialization/de-initialization functions +/** @addtogroup ADC_Exported_Functions_Group1 * @brief Initialization and Configuration functions * @verbatim @@ -193,32 +331,40 @@ /** - * @brief Initializes the ADCx peripheral according to the specified parameters - * in the ADC_InitStruct. - * @note This function is used to configure the global features of the ADC - * (ClockPrescaler, Resolution, Data Alignment and number of conversion), however, - * the rest of the configuration parameters are specific to the regular - * channels group (scan mode activation, continuous mode activation, - * External trigger source and edge, DMA continuous request after the - * last transfer and End of conversion selection). - * - * As prerequisite, into HAL_ADC_MspInit(), ADC clock must be - * configured at RCC top level. - * See commented example code below that can be copied - * and uncommented into HAL_ADC_MspInit(). - * - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. + * @brief Initializes the ADC peripheral and regular group according to + * parameters specified in structure "ADC_InitTypeDef". + * @note As prerequisite, ADC clock must be configured at RCC top level + * depending on both possible clock sources: APB clock of HSI clock. + * See commented example code below that can be copied and uncommented + * into HAL_ADC_MspInit(). + * @note Possibility to update parameters on the fly: + * This function initializes the ADC MSP (HAL_ADC_MspInit()) only when + * coming from ADC state reset. Following calls to this function can + * be used to reconfigure some parameters of ADC_InitTypeDef + * structure on the fly, without modifying MSP configuration. If ADC + * MSP has to be modified again, HAL_ADC_DeInit() must be called + * before HAL_ADC_Init(). + * The setting of these parameters is conditioned to ADC state. + * For parameters constraints, see comments of structure + * "ADC_InitTypeDef". + * @note This function configures the ADC within 2 scopes: scope of entire + * ADC and scope of regular group. For parameters details, see comments + * of structure "ADC_InitTypeDef". + * @note When device is in mode low-power (low-power run, low-power sleep or stop mode), + * function "HAL_ADCEx_EnableVREFINT()" must be called before function HAL_ADC_Init() + * (in case of previous ADC operations: function HAL_ADC_DeInit() must be called first). + * In case of internal temperature sensor to be measured: + * function "HAL_ADCEx_EnableVREFINTTempSensor()" must be called similarilly. + * @param hadc: ADC handle * @retval HAL status */ HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef* hadc) { - uint32_t tickstart = 0x00; - + /* Check ADC handle */ if(hadc == NULL) { - return HAL_ERROR; + return HAL_ERROR; } /* Check the parameters */ @@ -231,42 +377,79 @@ assert_param(IS_FUNCTIONAL_STATE(hadc->Init.ContinuousConvMode)); assert_param(IS_FUNCTIONAL_STATE(hadc->Init.DiscontinuousConvMode)); assert_param(IS_ADC_EXTTRIG_EDGE(hadc->Init.ExternalTrigConvEdge)); - assert_param(IS_ADC_EXTERNAL_TRIG_CONV(hadc->Init.ExternalTrigConv)); + assert_param(IS_ADC_EXTTRIG(hadc->Init.ExternalTrigConv)); assert_param(IS_FUNCTIONAL_STATE(hadc->Init.DMAContinuousRequests)); - assert_param(IS_ADC_EOC_SELECTION(hadc->Init.EOCSelection)); assert_param(IS_ADC_OVERRUN(hadc->Init.Overrun)); assert_param(IS_FUNCTIONAL_STATE(hadc->Init.LowPowerAutoWait)); assert_param(IS_FUNCTIONAL_STATE(hadc->Init.LowPowerFrequencyMode)); assert_param(IS_FUNCTIONAL_STATE(hadc->Init.LowPowerAutoPowerOff)); assert_param(IS_FUNCTIONAL_STATE(hadc->Init.OversamplingMode)); + /* As prerequisite, into HAL_ADC_MspInit(), ADC clock must be configured */ + /* at RCC top level depending on both possible clock sources: */ + /* APB clock or HSI clock. */ + /* Refer to header of this file for more details on clock enabling procedure*/ + + /* Actions performed only if ADC is coming from state reset: */ + /* - Initialization of ADC MSP */ + /* - ADC voltage regulator enable */ if(hadc->State == HAL_ADC_STATE_RESET) { + /* Initialize ADC error code */ + ADC_CLEAR_ERRORCODE(hadc); + + /* Allocate lock resource and initialize it */ + hadc->Lock = HAL_UNLOCKED; + /* Init the low level hardware */ HAL_ADC_MspInit(hadc); } /* Configuration of ADC parameters if previous preliminary actions are */ /* correctly completed. */ - /* and if there is no conversion on going (ADC can be enabled anyway, */ - /* in case of call of this function to update a parameter */ + /* and if there is no conversion on going on regular group (ADC can be */ + /* enabled anyway, in case of call of this function to update a parameter */ /* on the fly). */ - if ((hadc->State == HAL_ADC_STATE_ERROR) || - (ADC_IS_CONVERSION_ONGOING(hadc) != RESET) ) + if (HAL_IS_BIT_SET(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL) || + (ADC_IS_CONVERSION_ONGOING_REGULAR(hadc) != RESET) ) { /* Update ADC state machine to error */ - hadc->State = HAL_ADC_STATE_ERROR; + SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL); + /* Process unlocked */ __HAL_UNLOCK(hadc); return HAL_ERROR; } - /* Initialize the ADC state */ - hadc->State = HAL_ADC_STATE_BUSY; - - /* Configuration of ADC clock: clock source PCLK or asynchronous with - selectable prescaler */ - __HAL_ADC_CLOCK_PRESCALER(hadc); + /* Set ADC state */ + ADC_STATE_CLR_SET(hadc->State, + HAL_ADC_STATE_REG_BUSY, + HAL_ADC_STATE_BUSY_INTERNAL); + + /* Parameters update conditioned to ADC state: */ + /* Parameters that can be updated only when ADC is disabled: */ + /* - ADC clock mode */ + /* - ADC clock prescaler */ + /* - ADC Resolution */ + if (ADC_IS_ENABLE(hadc) == RESET) + { + /* Some parameters of this register are not reset, since they are set */ + /* by other functions and must be kept in case of usage of this */ + /* function on the fly (update of a parameter of ADC_InitTypeDef */ + /* without needing to reconfigure all other ADC groups/channels */ + /* parameters): */ + /* - internal measurement paths: Vbat, temperature sensor, Vref */ + /* (set into HAL_ADC_ConfigChannel() ) */ + + /* Configuration of ADC clock: clock source PCLK or asynchronous with + selectable prescaler */ + __HAL_ADC_CLOCK_PRESCALER(hadc); + + /* Configuration of ADC: */ + /* - Resolution */ + hadc->Instance->CFGR1 &= ~( ADC_CFGR1_RES); + hadc->Instance->CFGR1 |= hadc->Init.Resolution; + } /* Set the Low Frequency mode */ ADC->CCR &= (uint32_t)~ADC_CCR_LFMEN; @@ -275,47 +458,6 @@ /* Enable voltage regulator (if disabled at this step) */ if (HAL_IS_BIT_CLR(hadc->Instance->CR, ADC_CR_ADVREGEN)) { - /* Disable the ADC (if not already disabled) */ - if (ADC_IS_ENABLE(hadc) != RESET ) - { - /* Check if conditions to disable the ADC are fulfilled */ - if (ADC_DISABLING_CONDITIONS(hadc) != RESET) - { - __HAL_ADC_DISABLE(hadc); - } - else - { - hadc->State= HAL_ADC_STATE_ERROR; - - /* Process unlocked */ - __HAL_UNLOCK(hadc); - - return HAL_ERROR; - } - - /* Get timeout */ - tickstart = HAL_GetTick(); - - /* Wait for disabling completion */ - while(HAL_IS_BIT_SET(hadc->Instance->CR, ADC_CR_ADEN)) - { - /* Check for the Timeout */ - if(ADC_ENABLE_TIMEOUT != HAL_MAX_DELAY) - { - if((HAL_GetTick() - tickstart ) > ADC_DISABLE_TIMEOUT) - { - hadc->State= HAL_ADC_STATE_TIMEOUT; - - /* Process unlocked */ - __HAL_UNLOCK(hadc); - - return HAL_TIMEOUT; - } - } - } - - } - /* Set ADVREGEN bit */ hadc->Instance->CR |= ADC_CR_ADVREGEN; } @@ -323,7 +465,7 @@ /* Configuration of ADC: */ /* - Resolution */ /* - Data alignment */ - /* - Scan direction */ + /* - Scan direction */ /* - External trigger to start conversion */ /* - External trigger polarity */ /* - Continuous conversion mode */ @@ -331,8 +473,7 @@ /* - Overrun */ /* - AutoDelay feature */ /* - Discontinuous mode */ - hadc->Instance->CFGR1 &= ~( ADC_CFGR1_RES | - ADC_CFGR1_ALIGN | + hadc->Instance->CFGR1 &= ~(ADC_CFGR1_ALIGN | ADC_CFGR1_SCANDIR | ADC_CFGR1_EXTSEL | ADC_CFGR1_EXTEN | @@ -343,27 +484,45 @@ ADC_CFGR1_AUTOFF | ADC_CFGR1_DISCEN); - hadc->Instance->CFGR1 |= ( hadc->Init.Resolution | - hadc->Init.DataAlign | + hadc->Instance->CFGR1 |= (hadc->Init.DataAlign | ADC_SCANDIR(hadc->Init.ScanConvMode) | - hadc->Init.ExternalTrigConvEdge | ADC_CONTINUOUS(hadc->Init.ContinuousConvMode) | ADC_DMACONTREQ(hadc->Init.DMAContinuousRequests) | - hadc->Init.Overrun | - __HAL_ADC_CFGR1_AutoDelay(hadc->Init.LowPowerAutoWait) | + hadc->Init.Overrun | + __HAL_ADC_CFGR1_AutoDelay(hadc->Init.LowPowerAutoWait) | __HAL_ADC_CFGR1_AUTOFF(hadc->Init.LowPowerAutoPowerOff)); - /* Configure the external trigger only if Conversion edge is not "NONE" */ - if (hadc->Init.ExternalTrigConvEdge != ADC_EXTERNALTRIGCONVEDGE_NONE) + /* Enable external trigger if trigger selection is different of software */ + /* start. */ + /* Note: This configuration keeps the hardware feature of parameter */ + /* ExternalTrigConvEdge "trigger edge none" equivalent to */ + /* software start. */ + if (hadc->Init.ExternalTrigConv != ADC_SOFTWARE_START) { - hadc->Instance->CFGR1 |= hadc->Init.ExternalTrigConv; + hadc->Instance->CFGR1 |= hadc->Init.ExternalTrigConv | + hadc->Init.ExternalTrigConvEdge; } /* Enable discontinuous mode only if continuous mode is disabled */ - if ((hadc->Init.DiscontinuousConvMode == ENABLE) && (hadc->Init.ContinuousConvMode == DISABLE)) - { - /* Enable the selected ADC discontinuous mode */ - hadc->Instance->CFGR1 |= ( ADC_CFGR1_DISCEN); + if (hadc->Init.DiscontinuousConvMode == ENABLE) + { + if (hadc->Init.ContinuousConvMode == DISABLE) + { + /* Enable the selected ADC group regular discontinuous mode */ + hadc->Instance->CFGR1 |= (ADC_CFGR1_DISCEN); + } + else + { + /* ADC regular group discontinuous was intended to be enabled, */ + /* but ADC regular group modes continuous and sequencer discontinuous */ + /* cannot be enabled simultaneously. */ + + /* Update ADC state machine to error */ + SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG); + + /* Set ADC error code to ADC IP internal error */ + SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL); + } } if (hadc->Init.OversamplingMode == ENABLE) @@ -390,8 +549,11 @@ } else { - /* Disable OverSampling mode */ - hadc->Instance->CFGR2 &= ~ADC_CFGR2_OVSE; + if(HAL_IS_BIT_SET(hadc->Instance->CFGR2, ADC_CFGR2_OVSE)) + { + /* Disable OverSampling mode if needed */ + hadc->Instance->CFGR2 &= ~ADC_CFGR2_OVSE; + } } /* Clear the old sampling time */ @@ -400,30 +562,34 @@ /* Set the new sample time */ hadc->Instance->SMPR |= hadc->Init.SamplingTime; - - /* Set ADC error code to none */ - hadc->ErrorCode = HAL_ADC_ERROR_NONE; - - /* Initialize the ADC state */ - hadc->State = HAL_ADC_STATE_READY; - + /* Clear ADC error code */ + ADC_CLEAR_ERRORCODE(hadc); + + /* Set the ADC state */ + ADC_STATE_CLR_SET(hadc->State, + HAL_ADC_STATE_BUSY_INTERNAL, + HAL_ADC_STATE_READY); + + /* Return function status */ return HAL_OK; } /** - * @brief Deinitialize the ADC peripheral registers to its default reset values. - * @note To not impact other ADCs, reset of common ADC registers have been - * left commented below. - * If needed, the example code can be copied and uncommented into - * function HAL_ADC_MspDeInit(). - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. + * @brief Deinitialize the ADC peripheral registers to their default reset + * values, with deinitialization of the ADC MSP. + * @note For devices with several ADCs: reset of ADC common registers is done + * only if all ADCs sharing the same common group are disabled. + * If this is not the case, reset of these common parameters reset is + * bypassed without error reporting: it can be the intended behaviour in + * case of reset of a single ADC while the other ADCs sharing the same + * common group is still running. + * @param hadc: ADC handle * @retval HAL status */ HAL_StatusTypeDef HAL_ADC_DeInit(ADC_HandleTypeDef* hadc) { - uint32_t tickstart = 0; + HAL_StatusTypeDef tmp_hal_status = HAL_OK; /* Check ADC handle */ if(hadc == NULL) @@ -434,112 +600,120 @@ /* Check the parameters */ assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); - /* Change ADC state */ - hadc->State = HAL_ADC_STATE_BUSY; + /* Set ADC state */ + SET_BIT(hadc->State, HAL_ADC_STATE_BUSY_INTERNAL); - /* Stop potential conversion ongoing */ - if (HAL_IS_BIT_SET(hadc->Instance->CR, ADC_CR_ADSTART) && HAL_IS_BIT_CLR(hadc->Instance->CR, ADC_CR_ADDIS)) - { - /* Stop regular conversion */ - hadc->Instance->CR |= ADC_CR_ADSTP; - } - - /* Disable ADC: Solution to recover from an unknown ADC state (for example, */ - /* in case of forbidden action on register bits) */ - /* Procedure to disable the ADC peripheral: wait for conversions */ - /* effectively stopped, then disable ADC */ - /* 1. Wait until ADSTART = 0 */ - - /* Get timeout */ - tickstart = HAL_GetTick(); + /* Stop potential conversion on going, on regular group */ + tmp_hal_status = ADC_ConversionStop(hadc); - while(HAL_IS_BIT_SET(hadc->Instance->CR, ADC_CR_ADSTART)) + /* Disable ADC peripheral if conversions are effectively stopped */ + if (tmp_hal_status == HAL_OK) + { + /* Disable the ADC peripheral */ + tmp_hal_status = ADC_Disable(hadc); + + /* Check if ADC is effectively disabled */ + if (tmp_hal_status != HAL_ERROR) + { + /* Change ADC state */ + hadc->State = HAL_ADC_STATE_READY; + } + } + + + /* Configuration of ADC parameters if previous preliminary actions are */ + /* correctly completed. */ + if (tmp_hal_status != HAL_ERROR) { - /* Check for the Timeout */ - if(ADC_STOP_CONVERSION_TIMEOUT != HAL_MAX_DELAY) - { - if((HAL_GetTick() - tickstart ) > ADC_STOP_CONVERSION_TIMEOUT) - { - hadc->State= HAL_ADC_STATE_TIMEOUT; + + /* ========== Reset ADC registers ========== */ + /* Reset register IER */ + __HAL_ADC_DISABLE_IT(hadc, (ADC_IT_AWD | ADC_IT_OVR | ADC_IT_EOCAL | ADC_IT_EOS | \ + ADC_IT_EOC | ADC_IT_RDY | ADC_IT_EOSMP )); + - /* Process unlocked */ - __HAL_UNLOCK(hadc); - - return HAL_TIMEOUT; - } - } - } - - /* 2. Disable the ADC peripheral */ - __HAL_ADC_DISABLE(hadc); + /* Reset register ISR */ + __HAL_ADC_CLEAR_FLAG(hadc, (ADC_FLAG_AWD | ADC_FLAG_EOCAL | ADC_FLAG_OVR | ADC_FLAG_EOS | \ + ADC_FLAG_EOC | ADC_FLAG_EOSMP | ADC_FLAG_RDY)); - /* Reset ADC registers****************/ - /* Reset register IER */ - __HAL_ADC_DISABLE_IT(hadc, (ADC_IT_AWD | ADC_IT_OVR | ADC_IT_EOCAL | ADC_IT_EOS | \ - ADC_IT_EOC | ADC_IT_RDY | ADC_IT_EOSMP )); - - /* Reset register ISR */ - __HAL_ADC_CLEAR_FLAG(hadc, (ADC_FLAG_AWD | ADC_FLAG_EOCAL | ADC_FLAG_OVR | ADC_FLAG_EOS | \ - ADC_FLAG_EOC | ADC_FLAG_EOSMP | ADC_FLAG_RDY)); + /* Reset register CR */ + /* Disable voltage regulator */ + /* Note: Regulator disable useful for power saving */ + /* Reset ADVREGEN bit */ + hadc->Instance->CR &= ~ADC_CR_ADVREGEN; + + /* Bits ADC_CR_ADSTP, ADC_CR_ADSTART are in access mode "read-set": no direct reset applicable */ + /* No action */ + + /* Reset register CFGR1 */ + hadc->Instance->CFGR1 &= ~(ADC_CFGR1_AWDCH | ADC_CFGR1_AWDEN | ADC_CFGR1_AWDSGL | \ + ADC_CFGR1_DISCEN | ADC_CFGR1_AUTOFF | ADC_CFGR1_AUTDLY | \ + ADC_CFGR1_CONT | ADC_CFGR1_OVRMOD | ADC_CFGR1_EXTEN | \ + ADC_CFGR1_EXTSEL | ADC_CFGR1_ALIGN | ADC_CFGR1_RES | \ + ADC_CFGR1_SCANDIR| ADC_CFGR1_DMACFG | ADC_CFGR1_DMAEN); - /* Reset register CR */ - /* Disable voltage regulator */ - /* Note: Regulator disable useful for power saving */ - /* Reset ADVREGEN bit */ - hadc->Instance->CR &= ~ADC_CR_ADVREGEN; + /* Reset register CFGR2 */ + hadc->Instance->CFGR2 &= ~(ADC_CFGR2_TOVS | ADC_CFGR2_OVSS | ADC_CFGR2_OVSR | \ + ADC_CFGR2_OVSE | ADC_CFGR2_CKMODE ); - /* Bits ADC_CR_ADSTP, ADC_CR_ADSTART are in access mode "read-set": no direct reset applicable */ - /* No action */ + + /* Reset register SMPR */ + hadc->Instance->SMPR &= ~(ADC_SMPR_SMPR); + + /* Reset register TR */ + hadc->Instance->TR &= ~(ADC_TR_LT | ADC_TR_HT); + + /* Reset register CALFACT */ + hadc->Instance->CALFACT &= ~(ADC_CALFACT_CALFACT); + + + - /* Reset register CFGR1 */ - hadc->Instance->CFGR1 &= ~(ADC_CFGR1_AWDCH | ADC_CFGR1_AWDEN | ADC_CFGR1_AWDSGL | \ - ADC_CFGR1_DISCEN | ADC_CFGR1_AUTOFF | ADC_CFGR1_AUTDLY | \ - ADC_CFGR1_CONT | ADC_CFGR1_OVRMOD | ADC_CFGR1_EXTEN | \ - ADC_CFGR1_EXTSEL | ADC_CFGR1_ALIGN | ADC_CFGR1_RES | \ - ADC_CFGR1_SCANDIR| ADC_CFGR1_DMACFG | ADC_CFGR1_DMAEN); - - /* Reset register CFGR2 */ - hadc->Instance->CFGR2 &= ~(ADC_CFGR2_TOVS | ADC_CFGR2_OVSS | ADC_CFGR2_OVSR | \ - ADC_CFGR2_OVSE | ADC_CFGR2_CKMODE ); + + /* Reset register DR */ + /* bits in access mode read only, no direct reset applicable*/ + + /* Reset register CALFACT */ + hadc->Instance->CALFACT &= ~(ADC_CALFACT_CALFACT); + + /* ========== Hard reset ADC peripheral ========== */ + /* Performs a global reset of the entire ADC peripheral: ADC state is */ + /* forced to a similar state after device power-on. */ + /* If needed, copy-paste and uncomment the following reset code into */ + /* function "void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)": */ + /* */ + /* __HAL_RCC_ADC1_FORCE_RESET() */ + /* __HAL_RCC_ADC1_RELEASE_RESET() */ - /* Reset register SMPR */ - hadc->Instance->SMPR &= ~(ADC_SMPR_SMPR); - - /* Reset register TR */ - hadc->Instance->TR &= ~(ADC_TR_LT | ADC_TR_HT); + /* DeInit the low level hardware */ + HAL_ADC_MspDeInit(hadc); + + /* Set ADC error code to none */ + ADC_CLEAR_ERRORCODE(hadc); + + /* Set ADC state */ + hadc->State = HAL_ADC_STATE_RESET; + } - /* Reset register CALFACT */ - hadc->Instance->CALFACT &= ~(ADC_CALFACT_CALFACT); - - /* Reset register DR */ - /* bits in access mode read only, no direct reset applicable*/ + /* Process unlocked */ + __HAL_UNLOCK(hadc); - /* Reset register CALFACT */ - hadc->Instance->CALFACT &= ~(ADC_CALFACT_CALFACT); + /* Return function status */ + return tmp_hal_status; +} - /* DeInit the low level hardware */ - HAL_ADC_MspDeInit(hadc); - - /* Set ADC error code to none */ - hadc->ErrorCode = HAL_ADC_ERROR_NONE; - - /* Change ADC state */ - hadc->State = HAL_ADC_STATE_RESET; - - /* Return function status */ - return HAL_OK; -} - /** * @brief Initializes the ADC MSP. - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. + * @param hadc: ADC handle * @retval None */ __weak void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc) { + /* Prevent unused argument(s) compilation warning */ + UNUSED(hadc); + /* NOTE : This function Should not be modified, when the callback is needed, the HAL_ADC_MspInit could be implemented in the user file */ @@ -547,14 +721,16 @@ /** * @brief DeInitializes the ADC MSP. - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. + * @param hadc: ADC handle * @retval None */ __weak void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc) { - /* NOTE : This function Should not be modified, when the callback is needed, - the HAL_ADC_MspDeInit could be implemented in the user file + /* Prevent unused argument(s) compilation warning */ + UNUSED(hadc); + + /* NOTE : This function should not be modified. When the callback is needed, + function HAL_ADC_MspDeInit must be implemented in the user file. */ } @@ -562,7 +738,7 @@ * @} */ -/** @defgroup ADC_Group2 I/O operation functions +/** @addtogroup ADC_Exported_Functions_Group2 * @brief I/O operation functions * @verbatim @@ -570,118 +746,126 @@ ##### IO operation functions ##### =============================================================================== [..] This section provides functions allowing to: - (+) Start conversion. - (+) Stop conversion. - (+) poll for conversion complete. + (+) Start conversion of regular group. + (+) Stop conversion of regular group. + (+) Poll for conversion complete on regular group. (+) poll for conversion event. - (+) Start conversion and enable interrupt. - (+) Stop conversion and disable interrupt. - (+) handle ADC interrupt request. - (+) Start conversion of regular channel and enable DMA transfer. - (+) Stop conversion of regular channel and disable DMA transfer. (+) Get result of regular channel conversion. - (+) Handle ADC interrupt request. - + (+) Start conversion of regular group and enable interruptions. + (+) Stop conversion of regular group and disable interruptions. + (+) Handle ADC interrupt request + (+) Start conversion of regular group and enable DMA transfer. + (+) Stop conversion of regular group and disable ADC DMA transfer. @endverbatim * @{ */ /** - * @brief Enables ADC and starts conversion of the regular channels. - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. + * @brief Enables ADC, starts conversion of regular group. + * Interruptions enabled in this function: None. + * @param hadc: ADC handle * @retval HAL status */ HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc) { - HAL_StatusTypeDef tmpHALStatus = HAL_OK; + HAL_StatusTypeDef tmp_hal_status = HAL_OK; /* Check the parameters */ assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); /* Perform ADC enable and conversion start if no conversion is on going */ - if (ADC_IS_CONVERSION_ONGOING(hadc) == RESET) + if (ADC_IS_CONVERSION_ONGOING_REGULAR(hadc) == RESET) { /* Process locked */ __HAL_LOCK(hadc); - /* Change ADC state */ - hadc->State = HAL_ADC_STATE_BUSY_REG; - - /* Set ADC error code to none */ - hadc->ErrorCode = HAL_ADC_ERROR_NONE; - /* Enable the ADC peripheral */ /* If low power mode AutoPowerOff is enabled, power-on/off phases are */ /* performed automatically by hardware. */ if (hadc->Init.LowPowerAutoPowerOff != ENABLE) { - tmpHALStatus = ADC_Enable(hadc); + tmp_hal_status = ADC_Enable(hadc); } /* Start conversion if ADC is effectively enabled */ - if (tmpHALStatus != HAL_ERROR) + if (tmp_hal_status == HAL_OK) { - /* ADC start conversion command */ + /* Set ADC state */ + /* - Clear state bitfield related to regular group conversion results */ + /* - Set state bitfield related to regular operation */ + ADC_STATE_CLR_SET(hadc->State, + HAL_ADC_STATE_READY | HAL_ADC_STATE_REG_EOC | HAL_ADC_STATE_REG_OVR | HAL_ADC_STATE_REG_EOSMP, + HAL_ADC_STATE_REG_BUSY); + + /* Reset ADC all error code fields */ + ADC_CLEAR_ERRORCODE(hadc); + + /* Process unlocked */ + /* Unlock before starting ADC conversions: in case of potential */ + /* interruption, to let the process to ADC IRQ Handler. */ + __HAL_UNLOCK(hadc); + + /* Clear regular group conversion flag and overrun flag */ + /* (To ensure of no unknown state from potential previous ADC */ + /* operations) */ + __HAL_ADC_CLEAR_FLAG(hadc, (ADC_FLAG_EOC | ADC_FLAG_EOS | ADC_FLAG_OVR)); + + /* Enable conversion of regular group. */ + /* If software start has been selected, conversion starts immediately. */ + /* If external trigger has been selected, conversion will start at next */ + /* trigger event. */ hadc->Instance->CR |= ADC_CR_ADSTART; } - - /* Process unlocked */ - __HAL_UNLOCK(hadc); } else { - tmpHALStatus = HAL_BUSY; + tmp_hal_status = HAL_BUSY; } /* Return function status */ - return tmpHALStatus; + return tmp_hal_status; } /** - * @brief Stop ADC conversion of regular channels, disable ADC peripheral. - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. - * @retval None + * @brief Stop ADC conversion of regular group, disable ADC peripheral. + * @param hadc: ADC handle + * @retval HAL status. */ HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef* hadc) { - HAL_StatusTypeDef tmpHALStatus = HAL_OK; + HAL_StatusTypeDef tmp_hal_status = HAL_OK; + + /* Check the parameters */ + assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); /* Process locked */ __HAL_LOCK(hadc); - /* 1. Stop potential conversion ongoing (regular conversion) */ - tmpHALStatus = ADC_ConversionStop(hadc, ADC_REGULAR_GROUP); + /* 1. Stop potential conversion on going, on regular group */ + tmp_hal_status = ADC_ConversionStop(hadc); - /* 2. Disable ADC peripheral if conversions are effectively stopped */ - if (tmpHALStatus != HAL_ERROR) + /* Disable ADC peripheral if conversions are effectively stopped */ + if (tmp_hal_status == HAL_OK) { - /* Disable the ADC peripheral */ - tmpHALStatus = ADC_Disable(hadc); + /* 2. Disable the ADC peripheral */ + tmp_hal_status = ADC_Disable(hadc); /* Check if ADC is effectively disabled */ - if ((hadc->State != HAL_ADC_STATE_ERROR) && (tmpHALStatus != HAL_ERROR)) - { - /* Change ADC state */ - hadc->State = HAL_ADC_STATE_READY; - } - else + if (tmp_hal_status == HAL_OK) { - return HAL_ERROR; + /* Set ADC state */ + ADC_STATE_CLR_SET(hadc->State, + HAL_ADC_STATE_REG_BUSY, + HAL_ADC_STATE_READY); } - } - else - { - return HAL_ERROR; } /* Process unlocked */ __HAL_UNLOCK(hadc); /* Return function status */ - return HAL_OK; + return tmp_hal_status; } /** @@ -696,18 +880,20 @@ * parameter "EOCSelection" set to ADC_EOC_SINGLE_CONV). * In this case, DMA resets the flag EOC and polling cannot be * performed on each conversion. Nevertheless, polling can still - * be performed on the complete sequence. + * be performed on the complete sequence (ADC init + * parameter "EOCSelection" set to ADC_EOC_SEQ_CONV). * @param hadc: ADC handle * @param Timeout: Timeout value in millisecond. * @retval HAL status */ HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout) { - uint32_t tickstart = 0; + uint32_t tickstart; uint32_t tmp_Flag_EOC; /* Check the parameters */ assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); + assert_param(IS_ADC_EOC_SELECTION(hadc->Init.EOCSelection)); /* If end of conversion selected to end of sequence */ if (hadc->Init.EOCSelection == ADC_EOC_SEQ_CONV) @@ -726,7 +912,7 @@ if (HAL_IS_BIT_SET(hadc->Instance->CFGR1, ADC_CFGR1_DMAEN)) { /* Update ADC state machine to error */ - hadc->State = HAL_ADC_STATE_ERROR; + SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG); /* Process unlocked */ __HAL_UNLOCK(hadc); @@ -739,7 +925,7 @@ } } - /* Get tick */ + /* Get tick count */ tickstart = HAL_GetTick(); /* Wait until End of Conversion flag is raised */ @@ -751,7 +937,7 @@ if((Timeout == 0) || ((HAL_GetTick()-tickstart) > Timeout)) { /* Update ADC state machine to timeout */ - hadc->State = HAL_ADC_STATE_TIMEOUT; + SET_BIT(hadc->State, HAL_ADC_STATE_TIMEOUT); /* Process unlocked */ __HAL_UNLOCK(hadc); @@ -761,6 +947,43 @@ } } + /* Update ADC state machine */ + SET_BIT(hadc->State, HAL_ADC_STATE_REG_EOC); + + /* Determine whether any further conversion upcoming on group regular */ + /* by external trigger, continuous mode or scan sequence on going. */ + if(ADC_IS_SOFTWARE_START_REGULAR(hadc) && + (hadc->Init.ContinuousConvMode == DISABLE) ) + { + /* If End of Sequence is reached, disable interrupts */ + if( __HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS) ) + { + /* Allowed to modify bits ADC_IT_EOC/ADC_IT_EOS only if bit */ + /* ADSTART==0 (no conversion on going) */ + if (ADC_IS_CONVERSION_ONGOING_REGULAR(hadc) == RESET) + { + /* Disable ADC end of single conversion interrupt on group regular */ + /* Note: Overrun interrupt was enabled with EOC interrupt in */ + /* HAL_Start_IT(), but is not disabled here because can be used */ + /* by overrun IRQ process below. */ + __HAL_ADC_DISABLE_IT(hadc, ADC_IT_EOC | ADC_IT_EOS); + + /* Set ADC state */ + ADC_STATE_CLR_SET(hadc->State, + HAL_ADC_STATE_REG_BUSY, + HAL_ADC_STATE_READY); + } + else + { + /* Change ADC state to error state */ + SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG); + + /* Set ADC error code to ADC IP internal error */ + SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL); + } + } + } + /* Clear end of conversion flag of regular group if low power feature */ /* "LowPowerAutoWait " is disabled, to not interfere with this feature */ /* until data register is read using function HAL_ADC_GetValue(). */ @@ -770,24 +993,17 @@ __HAL_ADC_CLEAR_FLAG(hadc, (ADC_FLAG_EOC | ADC_FLAG_EOS)); } - /* Update state machine on conversion status if not in error state */ - if(hadc->State != HAL_ADC_STATE_ERROR) - { - /* Change ADC state */ - hadc->State = HAL_ADC_STATE_EOC; - } - /* Return ADC state */ return HAL_OK; } /** * @brief Poll for conversion event. - * @param hadc: ADC handle. + * @param hadc: ADC handle * @param EventType: the ADC event type. * This parameter can be one of the following values: - * @arg ADC_AWD_EVENT: ADC Analog watchdog event. - * @arg ADC_OVR_EVENT: ADC Overrun event. + * @arg ADC_AWD_EVENT: ADC Analog watchdog event + * @arg ADC_OVR_EVENT: ADC Overrun event * @param Timeout: Timeout value in millisecond. * @retval HAL status */ @@ -799,11 +1015,11 @@ assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); assert_param(IS_ADC_EVENT_TYPE(EventType)); - /* Get timeout */ + /* Get tick count */ tickstart = HAL_GetTick(); /* Check selected event flag */ - while(!(__HAL_ADC_GET_FLAG(hadc,EventType))) + while(__HAL_ADC_GET_FLAG(hadc, EventType) == RESET) { /* Check if timeout is disabled (set to infinite wait) */ if(Timeout != HAL_MAX_DELAY) @@ -811,7 +1027,7 @@ if((Timeout == 0)||((HAL_GetTick() - tickstart ) > Timeout)) { /* Update ADC state machine to timeout */ - hadc->State = HAL_ADC_STATE_TIMEOUT; + SET_BIT(hadc->State, HAL_ADC_STATE_TIMEOUT); /* Process unlocked */ __HAL_UNLOCK(hadc); @@ -823,19 +1039,29 @@ switch(EventType) { - /* Check analog watchdog flag */ + /* Analog watchdog (level out of window) event */ case ADC_AWD_EVENT: - /* Change ADC state */ - hadc->State = HAL_ADC_STATE_AWD; + /* Set ADC state */ + SET_BIT(hadc->State, HAL_ADC_STATE_AWD1); /* Clear ADC analog watchdog flag */ __HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_AWD); break; - /* Case ADC_OVR_EVENT */ - default: - /* Change ADC state */ - hadc->State = HAL_ADC_STATE_ERROR; + /* Overrun event */ + default: /* Case ADC_OVR_EVENT */ + /* If overrun is set to overwrite previous data, overrun event is not */ + /* considered as an error. */ + /* (cf ref manual "Managing conversions without using the DMA and without */ + /* overrun ") */ + if (hadc->Init.Overrun == ADC_OVR_DATA_PRESERVED) + { + /* Set ADC state */ + SET_BIT(hadc->State, HAL_ADC_STATE_REG_OVR); + + /* Set ADC error code to overrun */ + SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_OVR); + } /* Clear ADC Overrun flag */ __HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_OVR); @@ -847,280 +1073,188 @@ } /** - * @brief Enables the interrupt and starts ADC conversion of regular channels. - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. - * @retval HAL status. + * @brief Enables ADC, starts conversion of regular group with interruption. + * Interruptions enabled in this function: + * - EOC (end of conversion of regular group) or EOS (end of + * sequence of regular group) depending on ADC initialization + * parameter "EOCSelection" + * - overrun (if available) + * Each of these interruptions has its dedicated callback function. + * @param hadc: ADC handle + * @retval HAL status */ HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc) { - HAL_StatusTypeDef tmpHALStatus = HAL_OK; + HAL_StatusTypeDef tmp_hal_status = HAL_OK; /* Check the parameters */ assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); /* Perform ADC enable and conversion start if no conversion is on going */ - if (ADC_IS_CONVERSION_ONGOING(hadc) == RESET) + if (ADC_IS_CONVERSION_ONGOING_REGULAR(hadc) == RESET) { /* Process locked */ __HAL_LOCK(hadc); - /* State machine update: Change ADC state */ - hadc->State = HAL_ADC_STATE_BUSY_REG; - - /* Set ADC error code to none */ - hadc->ErrorCode = HAL_ADC_ERROR_NONE; - /* Enable the ADC peripheral */ /* If low power mode AutoPowerOff is enabled, power-on/off phases are */ /* performed automatically by hardware. */ if (hadc->Init.LowPowerAutoPowerOff != ENABLE) { - tmpHALStatus = ADC_Enable(hadc); + tmp_hal_status = ADC_Enable(hadc); } /* Start conversion if ADC is effectively enabled */ - if (tmpHALStatus != HAL_ERROR) + if (tmp_hal_status == HAL_OK) { - /* Enable ADC overrun interrupt */ - __HAL_ADC_ENABLE_IT(hadc, ADC_IT_OVR); + /* Set ADC state */ + /* - Clear state bitfield related to regular group conversion results */ + /* - Set state bitfield related to regular operation */ + ADC_STATE_CLR_SET(hadc->State, + HAL_ADC_STATE_READY | HAL_ADC_STATE_REG_EOC | HAL_ADC_STATE_REG_OVR | HAL_ADC_STATE_REG_EOSMP, + HAL_ADC_STATE_REG_BUSY); + + /* Reset ADC all error code fields */ + ADC_CLEAR_ERRORCODE(hadc); + + /* Process unlocked */ + /* Unlock before starting ADC conversions: in case of potential */ + /* interruption, to let the process to ADC IRQ Handler. */ + __HAL_UNLOCK(hadc); + + /* Clear regular group conversion flag and overrun flag */ + /* (To ensure of no unknown state from potential previous ADC */ + /* operations) */ + __HAL_ADC_CLEAR_FLAG(hadc, (ADC_FLAG_EOC | ADC_FLAG_EOS | ADC_FLAG_OVR)); /* Enable ADC end of conversion interrupt */ + /* Enable ADC overrun interrupt */ + assert_param(IS_ADC_EOC_SELECTION(hadc->Init.EOCSelection)); switch(hadc->Init.EOCSelection) { case ADC_EOC_SEQ_CONV: __HAL_ADC_DISABLE_IT(hadc, ADC_IT_EOC); - __HAL_ADC_ENABLE_IT(hadc, ADC_IT_EOS); + __HAL_ADC_ENABLE_IT(hadc, (ADC_IT_EOS | ADC_IT_OVR)); break; /* case ADC_EOC_SINGLE_CONV */ default: - __HAL_ADC_DISABLE_IT(hadc, ADC_IT_EOS); - __HAL_ADC_ENABLE_IT(hadc, ADC_IT_EOC); + __HAL_ADC_ENABLE_IT(hadc, (ADC_IT_EOC | ADC_IT_EOS | ADC_IT_OVR)); break; } - /* ADC start conversion command */ + /* Enable conversion of regular group. */ + /* If software start has been selected, conversion starts immediately. */ + /* If external trigger has been selected, conversion will start at next */ + /* trigger event. */ hadc->Instance->CR |= ADC_CR_ADSTART; } - - else - { - tmpHALStatus = HAL_ERROR; - } - - /* Process unlocked */ - __HAL_UNLOCK(hadc); } else { - tmpHALStatus = HAL_BUSY; + tmp_hal_status = HAL_BUSY; } /* Return function status */ - return tmpHALStatus; + return tmp_hal_status; } /** - * @brief Stop ADC conversion of regular channels, disable interruptions - * EOC/EOS/OVR, disable ADC peripheral. - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. - * @retval None + * @brief Stop ADC conversion of regular group, disable interruption of + * end-of-conversion, disable ADC peripheral. + * @param hadc: ADC handle + * @retval HAL status. */ HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef* hadc) { - HAL_StatusTypeDef tmpHALStatus = HAL_OK; + HAL_StatusTypeDef tmp_hal_status = HAL_OK; + + /* Check the parameters */ + assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); /* Process locked */ __HAL_LOCK(hadc); - /* 1. Stop potential conversion ongoing (regular conversion) */ - tmpHALStatus = ADC_ConversionStop(hadc, ADC_REGULAR_GROUP); + /* 1. Stop potential conversion on going, on regular group */ + tmp_hal_status = ADC_ConversionStop(hadc); - /* 2. Disable ADC peripheral if conversions are effectively stopped */ - if (tmpHALStatus != HAL_ERROR) + /* Disable ADC peripheral if conversions are effectively stopped */ + if (tmp_hal_status == HAL_OK) { - /* Disable ADC interrupts */ + /* Disable ADC end of conversion interrupt for regular group */ + /* Disable ADC overrun interrupt */ __HAL_ADC_DISABLE_IT(hadc, (ADC_IT_EOC | ADC_IT_EOS | ADC_IT_OVR)); - /* Disable the ADC peripheral */ - tmpHALStatus = ADC_Disable(hadc); + /* 2. Disable the ADC peripheral */ + tmp_hal_status = ADC_Disable(hadc); /* Check if ADC is effectively disabled */ - if ((hadc->State != HAL_ADC_STATE_ERROR) && (tmpHALStatus != HAL_ERROR)) + if (tmp_hal_status == HAL_OK) { - /* Change ADC state */ - hadc->State = HAL_ADC_STATE_READY; - } - else - { - return HAL_ERROR; + /* Set ADC state */ + ADC_STATE_CLR_SET(hadc->State, + HAL_ADC_STATE_REG_BUSY, + HAL_ADC_STATE_READY); } } - else - { - return HAL_ERROR; - } - /* Process unlocked */ __HAL_UNLOCK(hadc); /* Return function status */ - return HAL_OK; + return tmp_hal_status; } /** - * @brief Handles ADC interrupt request - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. - * @retval None - */ -void HAL_ADC_IRQHandler(ADC_HandleTypeDef* hadc) -{ - /* Check the parameters */ - assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); - assert_param(IS_ADC_EOC_SELECTION(hadc->Init.EOCSelection)); - - - /* Check End of Conversion flag for regular channels */ - if( (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC) && __HAL_ADC_GET_IT_SOURCE(hadc, ADC_IT_EOC)) || \ - (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS) && __HAL_ADC_GET_IT_SOURCE(hadc, ADC_IT_EOS)) ) - { - /* Change ADC state */ - hadc->State = HAL_ADC_STATE_EOC; - - - /* Disable interruption if no further conversion upcoming by continuous mode or external trigger */ - if((hadc->Init.ContinuousConvMode == DISABLE) && \ - (hadc->Init.ExternalTrigConvEdge == ADC_EXTERNALTRIGCONVEDGE_NONE) - ) - { - /* Allowed to modify bits ADC_IT_EOC/ADC_IT_EOS only if bit ADSTART==0 (no conversion on going) */ - if (HAL_IS_BIT_CLR(hadc->Instance->CR, ADC_CR_ADSTART)) - { - /* Cases of interruption after each conversion or after each sequence */ - /* If interruption after each sequence */ - if (hadc->Init.EOCSelection == ADC_EOC_SEQ_CONV) - { - /* Allowed to modify bits ADC_IT_EOC/ADC_IT_EOS/ADC_IT_OVR only if bit*/ - /* ADSTART==0 (no conversion on going) */ - if (ADC_IS_CONVERSION_ONGOING(hadc) == RESET) - { - /* If End of Sequence is reached, disable interrupts */ - if( __HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS) ) - { - /* DISABLE ADC end of sequence conversion interrupt */ - /* DISABLE ADC overrun interrupt */ - __HAL_ADC_DISABLE_IT(hadc, ADC_IT_EOC | ADC_IT_EOS | ADC_IT_OVR); - } - } - else - { - /* Change ADC state to error state */ - hadc->State = HAL_ADC_STATE_ERROR; - /* Set ADC error code to ADC IP internal error */ - hadc->ErrorCode |= HAL_ADC_ERROR_INTERNAL; - } - } - /* If interruption after each conversion */ - else - { - /* DISABLE ADC end of single conversion interrupt */ - /* DISABLE ADC overrun interrupt */ - __HAL_ADC_DISABLE_IT(hadc, ADC_IT_EOC | ADC_IT_OVR); - } - } - else - { - /* Change ADC state to error state */ - hadc->State = HAL_ADC_STATE_ERROR; - } - } - - /* Conversion complete callback */ - /* Note: into callback, to determine if callback has been triggered from EOC or EOS, */ - /* it is possible to use: if( __HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS)) */ - HAL_ADC_ConvCpltCallback(hadc); - - /* Clear regular channels conversion flag */ - if (hadc->Init.LowPowerAutoWait != ENABLE) - { - __HAL_ADC_CLEAR_FLAG(hadc, (ADC_FLAG_EOC | ADC_FLAG_EOS) ); - } - } - - - /* Check Analog watchdog flags */ - if( (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_AWD) && __HAL_ADC_GET_IT_SOURCE(hadc, ADC_IT_AWD))) - { - /* Change ADC state */ - hadc->State = HAL_ADC_STATE_AWD; - - /* Level out of window callback */ - HAL_ADC_LevelOutOfWindowCallback(hadc); - - /* Clear ADC Analog watchdog flag */ - __HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_AWD); - } - - /* Check Overrun flag */ - if(__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_OVR) && __HAL_ADC_GET_IT_SOURCE(hadc, ADC_IT_OVR)) - { - /* Change ADC state to overrun state */ - hadc->State = HAL_ADC_STATE_ERROR; - - /* Set ADC error code to overrun */ - hadc->ErrorCode |= HAL_ADC_ERROR_OVR; - - /* Clear the Overrun flag */ - __HAL_ADC_CLEAR_FLAG(hadc,ADC_FLAG_OVR); - - /* Error callback */ - HAL_ADC_ErrorCallback(hadc); - } -} - -/** - * @brief Enables ADC DMA request after last transfer (Single-ADC mode) and enables ADC peripheral - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. + * @brief Enables ADC, starts conversion of regular group and transfers result + * through DMA. + * Interruptions enabled in this function: + * - DMA transfer complete + * - DMA half transfer + * - overrun + * Each of these interruptions has its dedicated callback function. + * @param hadc: ADC handle * @param pData: The destination Buffer address. * @param Length: The length of data to be transferred from ADC peripheral to memory. * @retval None */ HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length) { - HAL_StatusTypeDef tmpHALStatus = HAL_OK; + HAL_StatusTypeDef tmp_hal_status = HAL_OK; /* Check the parameters */ assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); /* Perform ADC enable and conversion start if no conversion is on going */ - if (ADC_IS_CONVERSION_ONGOING(hadc) == RESET) + if (ADC_IS_CONVERSION_ONGOING_REGULAR(hadc) == RESET) { /* Process locked */ __HAL_LOCK(hadc); - /* Change ADC state */ - hadc->State = HAL_ADC_STATE_BUSY_REG; - - /* Set ADC error code to none */ - hadc->ErrorCode = HAL_ADC_ERROR_NONE; - - /* Enable the ADC peripheral */ + /* Enable the ADC peripheral */ /* If low power mode AutoPowerOff is enabled, power-on/off phases are */ /* performed automatically by hardware. */ if (hadc->Init.LowPowerAutoPowerOff != ENABLE) { - tmpHALStatus = ADC_Enable(hadc); + tmp_hal_status = ADC_Enable(hadc); } /* Start conversion if ADC is effectively enabled */ - if (tmpHALStatus != HAL_ERROR) + if (tmp_hal_status == HAL_OK) { - /* Enable ADC DMA mode */ - hadc->Instance->CFGR1 |= ADC_CFGR1_DMAEN; + /* Set ADC state */ + /* - Clear state bitfield related to regular group conversion results */ + /* - Set state bitfield related to regular operation */ + ADC_STATE_CLR_SET(hadc->State, + HAL_ADC_STATE_READY | HAL_ADC_STATE_REG_EOC | HAL_ADC_STATE_REG_OVR | HAL_ADC_STATE_REG_EOSMP, + HAL_ADC_STATE_REG_BUSY); + + /* Reset ADC all error code fields */ + ADC_CLEAR_ERRORCODE(hadc); + + /* Process unlocked */ + /* Unlock before starting ADC conversions: in case of potential */ + /* interruption, to let the process to ADC IRQ Handler. */ + __HAL_UNLOCK(hadc); /* Set the DMA transfer complete callback */ hadc->DMA_Handle->XferCpltCallback = ADC_DMAConvCplt; @@ -1131,155 +1265,311 @@ /* Set the DMA error callback */ hadc->DMA_Handle->XferErrorCallback = ADC_DMAError; - /* Manage ADC and DMA start: ADC overrun interruption, DMA start, - ADC start (in case of SW start) */ + + /* Manage ADC and DMA start: ADC overrun interruption, DMA start, ADC */ + /* start (in case of SW start): */ + + /* Clear regular group conversion flag and overrun flag */ + /* (To ensure of no unknown state from potential previous ADC */ + /* operations) */ + __HAL_ADC_CLEAR_FLAG(hadc, (ADC_FLAG_EOC | ADC_FLAG_EOS | ADC_FLAG_OVR)); /* Enable ADC overrun interrupt */ __HAL_ADC_ENABLE_IT(hadc, ADC_IT_OVR); - /* Enable the DMA Stream */ + /* Enable ADC DMA mode */ + hadc->Instance->CFGR1 |= ADC_CFGR1_DMAEN; + + /* Start the DMA channel */ HAL_DMA_Start_IT(hadc->DMA_Handle, (uint32_t)&hadc->Instance->DR, (uint32_t)pData, Length); - /* ADC start conversion command */ + /* Enable conversion of regular group. */ + /* If software start has been selected, conversion starts immediately. */ + /* If external trigger has been selected, conversion will start at next */ + /* trigger event. */ hadc->Instance->CR |= ADC_CR_ADSTART; } - - /* Process unlocked */ - __HAL_UNLOCK(hadc); } else { - tmpHALStatus = HAL_BUSY; + tmp_hal_status = HAL_BUSY; } /* Return function status */ - return tmpHALStatus; + return tmp_hal_status; } /** - * @brief Disable ADC DMA (Single-ADC mode), disable ADC peripheral - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. - * @retval None + * @brief Stop ADC conversion of regular group, disable ADC DMA transfer, disable + * ADC peripheral. + * Each of these interruptions has its dedicated callback function. + * @param hadc: ADC handle + * @retval HAL status. */ HAL_StatusTypeDef HAL_ADC_Stop_DMA(ADC_HandleTypeDef* hadc) { - HAL_StatusTypeDef tmpHALStatus = HAL_OK; + HAL_StatusTypeDef tmp_hal_status = HAL_OK; + + /* Check the parameters */ + assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); /* Process locked */ __HAL_LOCK(hadc); - /* 1. Stop potential conversion ongoing (regular conversion) */ - tmpHALStatus = ADC_ConversionStop(hadc, ADC_REGULAR_GROUP); + /* 1. Stop potential conversion on going, on regular group */ + tmp_hal_status = ADC_ConversionStop(hadc); - /* 2. Disable ADC peripheral if conversions are effectively stopped */ - if (tmpHALStatus != HAL_ERROR) + /* Disable ADC peripheral if conversions are effectively stopped */ + if (tmp_hal_status == HAL_OK) { /* Disable ADC DMA (ADC DMA configuration ADC_CFGR_DMACFG is kept) */ hadc->Instance->CFGR1 &= ~ADC_CFGR1_DMAEN; - /* Disable the DMA Stream */ - if (HAL_DMA_Abort(hadc->DMA_Handle) != HAL_OK) + /* Disable the DMA channel (in case of DMA in circular mode or stop while */ + /* while DMA transfer is on going) */ + tmp_hal_status = HAL_DMA_Abort(hadc->DMA_Handle); + + /* Check if DMA channel effectively disabled */ + if (tmp_hal_status != HAL_OK) { /* Update ADC state machine to error */ - hadc->State = HAL_ADC_STATE_ERROR; - - /* Process unlocked */ - __HAL_UNLOCK(hadc); - - return HAL_ERROR; + SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_DMA); } /* Disable ADC overrun interrupt */ __HAL_ADC_DISABLE_IT(hadc, ADC_IT_OVR); - /* Disable the ADC peripheral */ - tmpHALStatus = ADC_Disable(hadc); - - /* Check if ADC is effectively disabled */ - if ((hadc->State != HAL_ADC_STATE_ERROR) && (tmpHALStatus != HAL_ERROR)) + /* 2. Disable the ADC peripheral */ + /* Update "tmp_hal_status" only if DMA channel disabling passed, to keep */ + /* in memory a potential failing status. */ + if (tmp_hal_status == HAL_OK) { - /* Change ADC state */ - hadc->State = HAL_ADC_STATE_READY; + tmp_hal_status = ADC_Disable(hadc); } else { - return HAL_ERROR; + ADC_Disable(hadc); } - } - else - { - return HAL_ERROR; + + /* Check if ADC is effectively disabled */ + if (tmp_hal_status == HAL_OK) + { + /* Set ADC state */ + ADC_STATE_CLR_SET(hadc->State, + HAL_ADC_STATE_REG_BUSY, + HAL_ADC_STATE_READY); + } } /* Process unlocked */ __HAL_UNLOCK(hadc); /* Return function status */ - return HAL_OK; + return tmp_hal_status; } /** - * @brief Gets the converted value from data register of regular channel. - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. + * @brief Get ADC regular group conversion result. + * @note Reading DR register automatically clears EOC (end of conversion of + * regular group) flag. + * @note This function does not clear ADC flag EOS + * (ADC group regular end of sequence conversion). + * Occurrence of flag EOS rising: + * - If sequencer is composed of 1 rank, flag EOS is equivalent + * to flag EOC. + * - If sequencer is composed of several ranks, during the scan + * sequence flag EOC only is raised, at the end of the scan sequence + * both flags EOC and EOS are raised. + * To clear this flag, either use function: + * in programming model IT: @ref HAL_ADC_IRQHandler(), in programming + * model polling: @ref HAL_ADC_PollForConversion() + * or @ref __HAL_ADC_CLEAR_FLAG(&hadc, ADC_FLAG_EOS). + * @param hadc: ADC handle * @retval Converted value */ uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc) { - /* Return the selected ADC converted value */ + /* Check the parameters */ + assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); + + /* Note: EOC flag is not cleared here by software because automatically */ + /* cleared by hardware when reading register DR. */ + + /* Return ADC converted value */ return hadc->Instance->DR; } /** - * @brief Regular conversion complete callback in non blocking mode - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. + * @brief Handles ADC interrupt request. + * @param hadc: ADC handle + * @retval None + */ +void HAL_ADC_IRQHandler(ADC_HandleTypeDef* hadc) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); + assert_param(IS_FUNCTIONAL_STATE(hadc->Init.ContinuousConvMode)); + + /* ========== Check End of Conversion flag for regular group ========== */ + if( (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC) && __HAL_ADC_GET_IT_SOURCE(hadc, ADC_IT_EOC)) || + (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS) && __HAL_ADC_GET_IT_SOURCE(hadc, ADC_IT_EOS)) ) + { + /* Update state machine on conversion status if not in error state */ + if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL)) + { + /* Set ADC state */ + SET_BIT(hadc->State, HAL_ADC_STATE_REG_EOC); + } + + /* Determine whether any further conversion upcoming on group regular */ + /* by external trigger, continuous mode or scan sequence on going. */ + if(ADC_IS_SOFTWARE_START_REGULAR(hadc) && + (hadc->Init.ContinuousConvMode == DISABLE) ) + { + /* If End of Sequence is reached, disable interrupts */ + if( __HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS) ) + { + /* Allowed to modify bits ADC_IT_EOC/ADC_IT_EOS only if bit */ + /* ADSTART==0 (no conversion on going) */ + if (ADC_IS_CONVERSION_ONGOING_REGULAR(hadc) == RESET) + { + /* Disable ADC end of single conversion interrupt on group regular */ + /* Note: Overrun interrupt was enabled with EOC interrupt in */ + /* HAL_Start_IT(), but is not disabled here because can be used */ + /* by overrun IRQ process below. */ + __HAL_ADC_DISABLE_IT(hadc, ADC_IT_EOC | ADC_IT_EOS); + + /* Set ADC state */ + ADC_STATE_CLR_SET(hadc->State, + HAL_ADC_STATE_REG_BUSY, + HAL_ADC_STATE_READY); + } + else + { + /* Change ADC state to error state */ + SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG); + + /* Set ADC error code to ADC IP internal error */ + SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL); + } + } + } + + /* Conversion complete callback */ + /* Note: into callback, to determine if conversion has been triggered */ + /* from EOC or EOS, possibility to use: */ + /* " if( __HAL_ADC_GET_FLAG(&hadc, ADC_FLAG_EOS)) " */ + HAL_ADC_ConvCpltCallback(hadc); + + + /* Clear regular group conversion flag */ + /* Note: in case of overrun set to ADC_OVR_DATA_PRESERVED, end of */ + /* conversion flags clear induces the release of the preserved data.*/ + /* Therefore, if the preserved data value is needed, it must be */ + /* read preliminarily into HAL_ADC_ConvCpltCallback(). */ + __HAL_ADC_CLEAR_FLAG(hadc, (ADC_FLAG_EOC | ADC_FLAG_EOS) ); + } + + /* ========== Check Analog watchdog flags ========== */ + if(__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_AWD) && __HAL_ADC_GET_IT_SOURCE(hadc, ADC_IT_AWD)) + { + /* Set ADC state */ + SET_BIT(hadc->State, HAL_ADC_STATE_AWD1); + + /* Level out of window callback */ + HAL_ADC_LevelOutOfWindowCallback(hadc); + + /* Clear ADC Analog watchdog flag */ + __HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_AWD); + + } + + + /* ========== Check Overrun flag ========== */ + if(__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_OVR) && __HAL_ADC_GET_IT_SOURCE(hadc, ADC_IT_OVR)) + { + /* If overrun is set to overwrite previous data (default setting), */ + /* overrun event is not considered as an error. */ + /* (cf ref manual "Managing conversions without using the DMA and without */ + /* overrun ") */ + /* Exception for usage with DMA overrun event always considered as an */ + /* error. */ + if ((hadc->Init.Overrun == ADC_OVR_DATA_PRESERVED) || + HAL_IS_BIT_SET(hadc->Instance->CFGR1, ADC_CFGR1_DMAEN) ) + { + /* Set ADC error code to overrun */ + SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_OVR); + + /* Clear ADC overrun flag */ + __HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_OVR); + + /* Error callback */ + HAL_ADC_ErrorCallback(hadc); + } + + /* Clear the Overrun flag */ + __HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_OVR); + } +} + +/** + * @brief Conversion complete callback in non blocking mode + * @param hadc: ADC handle * @retval None */ __weak void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { - /* NOTE : This function Should not be modified, when the callback is needed, - the HAL_ADC_ConvCpltCallback could be implemented in the user file + /* Prevent unused argument(s) compilation warning */ + UNUSED(hadc); + + /* NOTE : This function should not be modified. When the callback is needed, + function HAL_ADC_ConvCpltCallback must be implemented in the user file. */ } /** - * @brief Regular conversion half DMA transfer callback in non blocking mode - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. + * @brief Conversion DMA half-transfer callback in non blocking mode + * @param hadc: ADC handle * @retval None */ __weak void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc) { - /* NOTE : This function Should not be modified, when the callback is needed, - the HAL_ADC_ConvHalfCpltCallback could be implemented in the user file + /* Prevent unused argument(s) compilation warning */ + UNUSED(hadc); + + /* NOTE : This function should not be modified. When the callback is needed, + function HAL_ADC_ConvHalfCpltCallback must be implemented in the user file. */ } /** - * @brief Analog watchdog callback in non blocking mode - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. + * @brief Analog watchdog callback in non blocking mode. + * @param hadc: ADC handle * @retval None */ __weak void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef* hadc) { - /* NOTE : This function Should not be modified, when the callback is needed, - the HAL_ADC_LevelOoutOfWindowCallback could be implemented in the user file + /* Prevent unused argument(s) compilation warning */ + UNUSED(hadc); + + /* NOTE : This function should not be modified. When the callback is needed, + function HAL_ADC_LevelOoutOfWindowCallback must be implemented in the user file. */ } /** - * @brief Error ADC callback. - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. + * @brief ADC error callback in non blocking mode + * (ADC conversion with interruption or transfer by DMA) + * @param hadc: ADC handle * @retval None */ __weak void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc) { - /* NOTE : This function Should not be modified, when the callback is needed, - the HAL_ADC_ErrorCallback could be implemented in the user file + /* Prevent unused argument(s) compilation warning */ + UNUSED(hadc); + + /* NOTE : This function should not be modified. When the callback is needed, + function HAL_ADC_ErrorCallback must be implemented in the user file. */ } @@ -1287,7 +1577,7 @@ * @} */ -/** @defgroup ADC_Group3 Peripheral Control functions +/** @addtogroup ADC_Exported_Functions_Group3 * @brief Peripheral Control functions * @verbatim @@ -1295,8 +1585,8 @@ ##### Peripheral Control functions ##### =============================================================================== [..] This section provides functions allowing to: - (+) Configure channels. - (+) Configure the analog watch dog. + (+) Configure channels on regular group + (+) Configure the analog watchdog @endverbatim * @{ @@ -1304,11 +1594,27 @@ /** - * @brief Configures the selected ADC regular channel: sampling time, - * offset,. - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. - * @param sConfig: ADC regular channel configuration structure. + * @brief Configures the the selected channel to be linked to the regular + * group. + * @note In case of usage of internal measurement channels: + * VrefInt/Vlcd(STM32L0x3xx only)/TempSensor. + * Sampling time constraints must be respected (sampling time can be + * adjusted in function of ADC clock frequency and sampling time + * setting). + * Refer to device datasheet for timings values, parameters TS_vrefint, + * TS_vlcd (STM32L0x3xx only), TS_temp (values rough order: 5us to 17us). + * These internal paths can be be disabled using function + * HAL_ADC_DeInit(). + * @note Possibility to update parameters on the fly: + * This function initializes channel into regular group, following + * calls to this function can be used to reconfigure some parameters + * of structure "ADC_ChannelConfTypeDef" on the fly, without reseting + * the ADC. + * The setting of these parameters is conditioned to ADC state. + * For parameters constraints, see comments of structure + * "ADC_ChannelConfTypeDef". + * @param hadc: ADC handle + * @param sConfig: Structure of ADC channel for regular group. * @retval HAL status */ HAL_StatusTypeDef HAL_ADC_ConfigChannel(ADC_HandleTypeDef* hadc, ADC_ChannelConfTypeDef* sConfig) @@ -1316,51 +1622,85 @@ /* Check the parameters */ assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); assert_param(IS_ADC_CHANNEL(sConfig->Channel)); + assert_param(IS_ADC_RANK(sConfig->Rank)); /* Process locked */ __HAL_LOCK(hadc); /* Parameters update conditioned to ADC state: */ /* Parameters that can be updated when ADC is disabled or enabled without */ - /* conversion on going : */ + /* conversion on going on regular group: */ /* - Channel number */ /* - Management of internal measurement channels: Vbat/VrefInt/TempSensor */ - if (ADC_IS_CONVERSION_ONGOING(hadc) != RESET) + if (ADC_IS_CONVERSION_ONGOING_REGULAR(hadc) != RESET) { /* Update ADC state machine to error */ - hadc->State = HAL_ADC_STATE_ERROR; + SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG); /* Process unlocked */ __HAL_UNLOCK(hadc); return HAL_ERROR; } - /* Enable selected channels */ - hadc->Instance->CHSELR |= (uint32_t)(sConfig->Channel & ADC_CHANNEL_MASK); - - /* Management of internal measurement channels: Vlcd/VrefInt/TempSensor */ - /* internal measurement paths enable: If internal channel selected, enable */ - /* dedicated internal buffers and path. */ - - /* If Temperature sensor channel is selected, then enable the internal */ - /* buffers and path */ - if (((sConfig->Channel & ADC_CHANNEL_MASK) & ADC_CHANNEL_TEMPSENSOR ) == (ADC_CHANNEL_TEMPSENSOR & ADC_CHANNEL_MASK)) + if (sConfig->Rank != ADC_RANK_NONE) { - ADC->CCR |= ADC_CCR_TSEN; + /* Enable selected channels */ + hadc->Instance->CHSELR |= (uint32_t)(sConfig->Channel & ADC_CHANNEL_MASK); + + /* Management of internal measurement channels: Vlcd (STM32L0x3xx only)/VrefInt/TempSensor */ + /* internal measurement paths enable: If internal channel selected, enable */ + /* dedicated internal buffers and path. */ + + /* If Temperature sensor channel is selected, then enable the internal */ + /* buffers and path */ + if (((sConfig->Channel & ADC_CHANNEL_MASK) & ADC_CHANNEL_TEMPSENSOR ) == (ADC_CHANNEL_TEMPSENSOR & ADC_CHANNEL_MASK)) + { + ADC->CCR |= ADC_CCR_TSEN; + + /* Delay for temperature sensor stabilization time */ + ADC_DelayMicroSecond(ADC_TEMPSENSOR_DELAY_US); + } + + /* If VRefInt channel is selected, then enable the internal buffers and path */ + if (((sConfig->Channel & ADC_CHANNEL_MASK) & ADC_CHANNEL_VREFINT) == (ADC_CHANNEL_VREFINT & ADC_CHANNEL_MASK)) + { + ADC->CCR |= ADC_CCR_VREFEN; + } - /* Delay for temperature sensor stabilization time */ - ADC_DelayMicroSecond(ADC_TEMPSENSOR_DELAY_US); +#if defined (STM32L053xx) || defined (STM32L063xx) || defined (STM32L073xx) || defined (STM32L083xx) + /* If Vlcd channel is selected, then enable the internal buffers and path */ + if (((sConfig->Channel & ADC_CHANNEL_MASK) & ADC_CHANNEL_VLCD) == (ADC_CHANNEL_VLCD & ADC_CHANNEL_MASK)) + { + ADC->CCR |= ADC_CCR_VLCDEN; + } +#endif } - - /* If VRefInt channel is selected, then enable the internal buffers and path */ - if (((sConfig->Channel & ADC_CHANNEL_MASK) & ADC_CHANNEL_VREFINT) == (ADC_CHANNEL_VREFINT & ADC_CHANNEL_MASK)) + else { - ADC->CCR |= ADC_CCR_VREFEN; - } - - /* If Vlcd channel is selected, then enable the internal buffers and path */ - if (((sConfig->Channel & ADC_CHANNEL_MASK) & ADC_CHANNEL_VLCD) == (ADC_CHANNEL_VLCD & ADC_CHANNEL_MASK)) - { - ADC->CCR |= ADC_CCR_VLCDEN; + /* Regular sequence configuration */ + /* Reset the channel selection register from the selected channel */ + hadc->Instance->CHSELR &= ~((uint32_t)(sConfig->Channel & ADC_CHANNEL_MASK)); + + /* Management of internal measurement channels: VrefInt/TempSensor/Vbat */ + /* internal measurement paths disable: If internal channel selected, */ + /* disable dedicated internal buffers and path. */ + if (((sConfig->Channel & ADC_CHANNEL_MASK) & ADC_CHANNEL_TEMPSENSOR ) == (ADC_CHANNEL_TEMPSENSOR & ADC_CHANNEL_MASK)) + { + ADC->CCR &= ~ADC_CCR_TSEN; + } + + /* If VRefInt channel is selected, then enable the internal buffers and path */ + if (((sConfig->Channel & ADC_CHANNEL_MASK) & ADC_CHANNEL_VREFINT) == (ADC_CHANNEL_VREFINT & ADC_CHANNEL_MASK)) + { + ADC->CCR &= ~ADC_CCR_VREFEN; + } + +#if defined (STM32L053xx) || defined (STM32L063xx) || defined (STM32L073xx) || defined (STM32L083xx) + /* If Vlcd channel is selected, then enable the internal buffers and path */ + if (((sConfig->Channel & ADC_CHANNEL_MASK) & ADC_CHANNEL_VLCD) == (ADC_CHANNEL_VLCD & ADC_CHANNEL_MASK)) + { + ADC->CCR &= ~ADC_CCR_VLCDEN; + } +#endif } /* Process unlocked */ @@ -1372,14 +1712,22 @@ /** * @brief Configures the analog watchdog. - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. - * @param AnalogWDGConfig : pointer to an ADC_AnalogWDGConfTypeDef structure - * that contains the configuration information of ADC analog watchdog. + * @note Possibility to update parameters on the fly: + * This function initializes the selected analog watchdog, following + * calls to this function can be used to reconfigure some parameters + * of structure "ADC_AnalogWDGConfTypeDef" on the fly, without reseting + * the ADC. + * The setting of these parameters is conditioned to ADC state. + * For parameters constraints, see comments of structure + * "ADC_AnalogWDGConfTypeDef". + * @param hadc: ADC handle + * @param AnalogWDGConfig: Structure of ADC analog watchdog configuration * @retval HAL status */ HAL_StatusTypeDef HAL_ADC_AnalogWDGConfig(ADC_HandleTypeDef* hadc, ADC_AnalogWDGConfTypeDef* AnalogWDGConfig) { + HAL_StatusTypeDef tmp_hal_status = HAL_OK; + uint32_t tmpAWDHighThresholdShifted; uint32_t tmpAWDLowThresholdShifted; @@ -1389,75 +1737,83 @@ assert_param(IS_ADC_CHANNEL(AnalogWDGConfig->Channel)); assert_param(IS_FUNCTIONAL_STATE(AnalogWDGConfig->ITMode)); + /* Verify if threshold is within the selected ADC resolution */ assert_param(IS_ADC_RANGE(ADC_GET_RESOLUTION(hadc), AnalogWDGConfig->HighThreshold)); assert_param(IS_ADC_RANGE(ADC_GET_RESOLUTION(hadc), AnalogWDGConfig->LowThreshold)); + if(AnalogWDGConfig->WatchdogMode == ADC_ANALOGWATCHDOG_SINGLE_REG) + { + assert_param(IS_ADC_CHANNEL(AnalogWDGConfig->Channel)); + } + /* Process locked */ __HAL_LOCK(hadc); /* Parameters update conditioned to ADC state: */ /* Parameters that can be updated when ADC is disabled or enabled without */ - /* conversion on going : */ + /* conversion on going on regular group: */ /* - Analog watchdog channels */ /* - Analog watchdog thresholds */ - if (ADC_IS_CONVERSION_ONGOING(hadc) != RESET) + if (ADC_IS_CONVERSION_ONGOING_REGULAR(hadc) == RESET) { - /* Update ADC state machine to error */ - hadc->State = HAL_ADC_STATE_ERROR; - /* Process unlocked */ - __HAL_UNLOCK(hadc); - return HAL_ERROR; - } - - /* Configure ADC Analog watchdog interrupt */ - if(AnalogWDGConfig->ITMode == ENABLE) - { - /* Enable the ADC Analog watchdog interrupt */ - __HAL_ADC_ENABLE_IT(hadc, ADC_IT_AWD); + /* Configure ADC Analog watchdog interrupt */ + if(AnalogWDGConfig->ITMode == ENABLE) + { + /* Enable the ADC Analog watchdog interrupt */ + __HAL_ADC_ENABLE_IT(hadc, ADC_IT_AWD); + } + else + { + /* Disable the ADC Analog watchdog interrupt */ + __HAL_ADC_DISABLE_IT(hadc, ADC_IT_AWD); + } + + /* Configuration of analog watchdog: */ + /* - Set the analog watchdog mode */ + /* - Set the Analog watchdog channel (is not used if watchdog */ + /* mode "all channels": ADC_CFGR1_AWD1SGL=0) */ + hadc->Instance->CFGR1 &= ~( ADC_CFGR1_AWDSGL | + ADC_CFGR1_AWDEN | + ADC_CFGR1_AWDCH); + + hadc->Instance->CFGR1 |= ( AnalogWDGConfig->WatchdogMode | + (AnalogWDGConfig->Channel & ADC_CHANNEL_AWD_MASK)); + + + /* Shift the offset in function of the selected ADC resolution: Thresholds */ + /* have to be left-aligned on bit 11, the LSB (right bits) are set to 0 */ + tmpAWDHighThresholdShifted = ADC_AWD1THRESHOLD_SHIFT_RESOLUTION(hadc, AnalogWDGConfig->HighThreshold); + tmpAWDLowThresholdShifted = ADC_AWD1THRESHOLD_SHIFT_RESOLUTION(hadc, AnalogWDGConfig->LowThreshold); + + /* Clear High & Low high thresholds */ + hadc->Instance->TR &= (uint32_t) ~ (ADC_TR_HT | ADC_TR_LT); + + /* Set the high threshold */ + hadc->Instance->TR = ADC_TRX_HIGHTHRESHOLD (tmpAWDHighThresholdShifted); + /* Set the low threshold */ + hadc->Instance->TR |= tmpAWDLowThresholdShifted; } else { - /* Disable the ADC Analog watchdog interrupt */ - __HAL_ADC_DISABLE_IT(hadc, ADC_IT_AWD); - } - - /* Configuration of analog watchdog: */ - /* - Set the analog watchdog mode */ - /* - Set the Analog watchdog channel (is not used if watchdog */ - /* mode "all channels": ADC_CFGR1_AWD1SGL=0) */ - hadc->Instance->CFGR1 &= ~( ADC_CFGR1_AWDSGL | - ADC_CFGR1_AWDEN | - ADC_CFGR1_AWDCH); + /* Update ADC state machine to error */ + SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG); - hadc->Instance->CFGR1 |= ( AnalogWDGConfig->WatchdogMode | - (AnalogWDGConfig->Channel & ADC_CHANNEL_AWD_MASK)); - + tmp_hal_status = HAL_ERROR; + } - /* Shift the offset in function of the selected ADC resolution: Thresholds */ - /* have to be left-aligned on bit 11, the LSB (right bits) are set to 0 */ - tmpAWDHighThresholdShifted = ADC_AWD1THRESHOLD_SHIFT_RESOLUTION(hadc, AnalogWDGConfig->HighThreshold); - tmpAWDLowThresholdShifted = ADC_AWD1THRESHOLD_SHIFT_RESOLUTION(hadc, AnalogWDGConfig->LowThreshold); - - /* Clear High & Low high thresholds */ - hadc->Instance->TR &= (uint32_t) ~ (ADC_TR_HT | ADC_TR_LT); - - /* Set the high threshold */ - hadc->Instance->TR = ADC_TRX_HIGHTHRESHOLD (tmpAWDHighThresholdShifted); - /* Set the low threshold */ - hadc->Instance->TR |= tmpAWDLowThresholdShifted; /* Process unlocked */ __HAL_UNLOCK(hadc); /* Return function status */ - return HAL_OK; + return tmp_hal_status; } /** * @} */ -/** @defgroup ADC_Group4 ADC Peripheral State functions +/** @addtogroup ADC_Exported_Functions_Group4 * @brief ADC Peripheral State functions * @verbatim @@ -1475,20 +1831,21 @@ /** * @brief return the ADC state - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. + * @param hadc: ADC handle * @retval HAL state */ -HAL_ADC_StateTypeDef HAL_ADC_GetState(ADC_HandleTypeDef* hadc) +uint32_t HAL_ADC_GetState(ADC_HandleTypeDef* hadc) { + /* Check the parameters */ + assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); + /* Return ADC state */ return hadc->State; } /** * @brief Return the ADC error code - * @param hadc: pointer to a ADC_HandleTypeDef structure that contains - * the configuration information for the specified ADC. + * @param hadc: ADC handle * @retval ADC Error Code */ uint32_t HAL_ADC_GetError(ADC_HandleTypeDef *hadc) @@ -1502,6 +1859,15 @@ */ /** + * @} + */ + + +/** @addtogroup ADC_Private + * @{ + */ + +/** * @brief Enable the selected ADC. * @note Prerequisite condition to use this function: ADC must be disabled * and voltage regulator must be enabled (done into HAL_ADC_Init()). @@ -1528,10 +1894,10 @@ if (ADC_ENABLING_CONDITIONS(hadc) == RESET) { /* Update ADC state machine to error */ - hadc->State = HAL_ADC_STATE_ERROR; + SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL); /* Set ADC error code to ADC IP internal error */ - hadc->ErrorCode |= HAL_ADC_ERROR_INTERNAL; + SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL); return HAL_ERROR; } @@ -1542,31 +1908,24 @@ /* Delay for ADC stabilization time. */ ADC_DelayMicroSecond(ADC_STAB_DELAY_US); - /* Wait for ADC effectively enabled */ - /* Get timeout */ + /* Get tick count */ tickstart = HAL_GetTick(); - /* Skip polling for RDY ADRDY when AutoOFF is enabled */ - if (hadc->Init.LowPowerAutoPowerOff != ENABLE) - { + /* Wait for ADC effectively enabled */ while(__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_RDY) == RESET) { - /* Check for the Timeout */ - if(ADC_ENABLE_TIMEOUT != HAL_MAX_DELAY) - { if((HAL_GetTick() - tickstart ) > ADC_ENABLE_TIMEOUT) { /* Update ADC state machine to error */ - hadc->State = HAL_ADC_STATE_ERROR; + SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL); /* Set ADC error code to ADC IP internal error */ - hadc->ErrorCode |= HAL_ADC_ERROR_INTERNAL; + SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL); return HAL_ERROR; } } - } - } + } /* Return HAL status */ @@ -1576,7 +1935,7 @@ /** * @brief Disable the selected ADC. * @note Prerequisite condition to use this function: ADC conversions must be - * stopped to disable the ADC. + * stopped. * @param hadc: ADC handle * @retval HAL status. */ @@ -1585,7 +1944,7 @@ uint32_t tickstart = 0; /* Verification if ADC is not already disabled: */ - /* forbidden to disable ADC (set bit ADC_CR_ADDIS) if ADC is already */ + /* Note: forbidden to disable ADC (set bit ADC_CR_ADDIS) if ADC is already */ /* disabled. */ if (ADC_IS_ENABLE(hadc) != RESET ) { @@ -1598,36 +1957,32 @@ else { /* Update ADC state machine to error */ - hadc->State = HAL_ADC_STATE_ERROR; + SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL); - /* Set ADC error code to ADC internal error */ - hadc->ErrorCode |= HAL_ADC_ERROR_INTERNAL; + /* Set ADC error code to ADC IP internal error */ + SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL); return HAL_ERROR; } /* Wait for ADC effectively disabled */ - /* Get timeout */ + /* Get tick count */ tickstart = HAL_GetTick(); while(HAL_IS_BIT_SET(hadc->Instance->CR, ADC_CR_ADEN)) { - /* Check for the Timeout */ - if(ADC_ENABLE_TIMEOUT != HAL_MAX_DELAY) - { if((HAL_GetTick() - tickstart ) > ADC_DISABLE_TIMEOUT) { /* Update ADC state machine to error */ - hadc->State = HAL_ADC_STATE_ERROR; + SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL); - /* Set ADC error code to ADC internal error */ - hadc->ErrorCode |= HAL_ADC_ERROR_INTERNAL; + /* Set ADC error code to ADC IP internal error */ + SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL); return HAL_ERROR; } } } - } /* Return HAL status */ return HAL_OK; @@ -1638,66 +1993,47 @@ * @note Prerequisite condition to use this function: ADC conversions must be * stopped to disable the ADC. * @param hadc: ADC handle - * @param ConversionGroup: Only ADC group regular. - * This parameter can be one of the following values: - * @arg ADC_REGULAR_GROUP: ADC regular conversion type. * @retval HAL status. */ -static HAL_StatusTypeDef ADC_ConversionStop(ADC_HandleTypeDef* hadc, uint32_t ConversionGroup) +static HAL_StatusTypeDef ADC_ConversionStop(ADC_HandleTypeDef* hadc) { - uint32_t tickstart = 0 ; + uint32_t tickstart = 0; /* Check the parameters */ assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance)); - assert_param(IS_ADC_CONVERSION_GROUP(ConversionGroup)); - - /* Parameters update conditioned to ADC state: */ - /* Parameters that can be updated when ADC is disabled or enabled without */ - /* conversion on going : */ - if (ADC_IS_CONVERSION_ONGOING(hadc) != RESET) + + /* Verification if ADC is not already stopped on regular group to bypass */ + /* this function if not needed. */ + if (ADC_IS_CONVERSION_ONGOING_REGULAR(hadc)) { - /* Update ADC state machine to error */ - hadc->State = HAL_ADC_STATE_ERROR; - /* Process unlocked */ - return HAL_ERROR; - } - - /* Verification: if ADC is not already stopped, bypass this function */ - if (HAL_IS_BIT_SET(hadc->Instance->CR, ADC_CR_ADSTART)) - { - /* Stop potential conversion on regular group */ - if (ConversionGroup == ADC_REGULAR_GROUP) + + /* Stop potential conversion on going on regular group */ + /* Software is allowed to set ADSTP only when ADSTART=1 and ADDIS=0 */ + if (HAL_IS_BIT_SET(hadc->Instance->CR, ADC_CR_ADSTART) && + HAL_IS_BIT_CLR(hadc->Instance->CR, ADC_CR_ADDIS) ) { - /* Software is allowed to set ADSTP only when ADSTART=1 and ADDIS=0 */ - if (HAL_IS_BIT_SET(hadc->Instance->CR, ADC_CR_ADSTART) && \ - HAL_IS_BIT_CLR(hadc->Instance->CR, ADC_CR_ADDIS) ) - { - /* Stop conversions on regular group */ - hadc->Instance->CR |= ADC_CR_ADSTP; - } + /* Stop conversions on regular group */ + hadc->Instance->CR |= ADC_CR_ADSTP; } /* Wait for conversion effectively stopped */ - /* Get timeout */ + /* Get tick count */ tickstart = HAL_GetTick(); while((hadc->Instance->CR & ADC_CR_ADSTART) != RESET) { - /* Check for the Timeout */ - if(ADC_STOP_CONVERSION_TIMEOUT != HAL_MAX_DELAY) + if((HAL_GetTick() - tickstart) > ADC_STOP_CONVERSION_TIMEOUT) { - if((HAL_GetTick() - tickstart ) > ADC_STOP_CONVERSION_TIMEOUT) - { - /* Update ADC state machine to error */ - hadc->State = HAL_ADC_STATE_ERROR; - - /* Set ADC error code to ADC IP internal error */ - hadc->ErrorCode |= HAL_ADC_ERROR_INTERNAL; - - return HAL_ERROR; - } + /* Update ADC state machine to error */ + SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL); + + /* Set ADC error code to ADC IP internal error */ + SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL); + + return HAL_ERROR; } - } + } + } /* Return HAL status */ @@ -1711,13 +2047,59 @@ */ static void ADC_DMAConvCplt(DMA_HandleTypeDef *hdma) { + /* Retrieve ADC handle corresponding to current DMA handle */ ADC_HandleTypeDef* hadc = ( ADC_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; - /* Change ADC state */ - hadc->State = HAL_ADC_STATE_EOC; + /* Update state machine on conversion status if not in error state */ + if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL | HAL_ADC_STATE_ERROR_DMA)) + { + /* Set ADC state */ + SET_BIT(hadc->State, HAL_ADC_STATE_REG_EOC); + /* Determine whether any further conversion upcoming on group regular */ + /* by external trigger, continuous mode or scan sequence on going. */ + if(ADC_IS_SOFTWARE_START_REGULAR(hadc) && + (hadc->Init.ContinuousConvMode == DISABLE) ) + { + /* If End of Sequence is reached, disable interrupts */ + if( __HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS) ) + { + /* Allowed to modify bits ADC_IT_EOC/ADC_IT_EOS only if bit */ + /* ADSTART==0 (no conversion on going) */ + if (ADC_IS_CONVERSION_ONGOING_REGULAR(hadc) == RESET) + { + /* Disable ADC end of single conversion interrupt on group regular */ + /* Note: Overrun interrupt was enabled with EOC interrupt in */ + /* HAL_Start_IT(), but is not disabled here because can be used */ + /* by overrun IRQ process below. */ + __HAL_ADC_DISABLE_IT(hadc, ADC_IT_EOC | ADC_IT_EOS); + + /* Set ADC state */ + ADC_STATE_CLR_SET(hadc->State, + HAL_ADC_STATE_REG_BUSY, + HAL_ADC_STATE_READY); + } + else + { + /* Change ADC state to error state */ + SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG); + + /* Set ADC error code to ADC IP internal error */ + SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL); + } + } + } + + /* Conversion complete callback */ HAL_ADC_ConvCpltCallback(hadc); } + else + { + /* Call DMA error callback */ + hadc->DMA_Handle->XferErrorCallback(hdma); + } + +} /** * @brief DMA half transfer complete callback. @@ -1726,9 +2108,10 @@ */ static void ADC_DMAHalfConvCplt(DMA_HandleTypeDef *hdma) { + /* Retrieve ADC handle corresponding to current DMA handle */ ADC_HandleTypeDef* hadc = ( ADC_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; - /* Conversion complete callback */ + /* Half conversion callback */ HAL_ADC_ConvHalfCpltCallback(hadc); } @@ -1739,11 +2122,17 @@ */ static void ADC_DMAError(DMA_HandleTypeDef *hdma) { - ADC_HandleTypeDef* hadc = ( ADC_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; - hadc->State= HAL_ADC_STATE_ERROR; + /* Retrieve ADC handle corresponding to current DMA handle */ + ADC_HandleTypeDef* hadc = ( ADC_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; + + /* Set ADC state */ + SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_DMA); + /* Set ADC error code to DMA error */ - hadc->ErrorCode |= HAL_ADC_ERROR_DMA; - HAL_ADC_ErrorCallback(hadc); + SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_DMA); + + /* Error callback */ + HAL_ADC_ErrorCallback(hadc); } /** @@ -1766,11 +2155,11 @@ * @} */ -#endif /* HAL_ADC_MODULE_ENABLED */ /** * @} */ +#endif /* HAL_ADC_MODULE_ENABLED */ /** * @} */