14
\$\begingroup\$

I am trying to learn how to use "new" HAL library from stm32.
When I try to do simple ADC conversion it works just one time, but then it stops converting. I suppose End of conversion flag does not get set. I am using STM32f429I Discovery board, which has STM32f429ZI on board.
Note that I know about sprintf being bad practice and making adc with interrupt is better, I know that, please don't point it out, this is not relevant to the question, I am just testing HAL here.
So the question is why EOC flag is not set or what could I do to make it work? Googling is not helping much since very few good materials about HAL out there.

Here is the code:

__IO uint16_t ADCValue=0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc);

int main(void)
{
  char str[15];

  /* Various initializations */

  HAL_ADC_Start(&hadc1);
  while (1)
  {

        if (HAL_ADC_PollForConversion(&hadc1, 1000000) == HAL_OK)
        {
            ADCValue = HAL_ADC_GetValue(&hadc1);
            sprintf(str, "%d", ADCValue);
            BSP_LCD_DisplayStringAt(130,30, (uint8_t*)str, LEFT_MODE);
        }

  }

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    ADCValue = HAL_ADC_GetValue(&hadc1);
}

I also created the project with CubeMX, adc configuration is the following: enter image description here

EDIT 1
I tried to debug everything and it seems that program gets stuck into checking for EOC flag - it sees that it is not shown and therefore issues timer waiting for EOC to show up(but it never gets set) Here is the code where it gets stuck in debugger:

/* Check End of conversion flag */
  while(!(__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC)))
  {
    /* Check for the Timeout */
    if(Timeout != HAL_MAX_DELAY)
    {
      if((Timeout == 0)||((HAL_GetTick() - tickstart ) > Timeout))
      {
        hadc->State= HAL_ADC_STATE_TIMEOUT;
        /* Process unlocked */
        __HAL_UNLOCK(hadc);
        return HAL_TIMEOUT;
      }
    }
\$\endgroup\$

5 Answers 5

8
\$\begingroup\$

In your original code, set the End of Conversion Selection to disabled.

 hadc1.Init.EOCSelection = DISABLE;

It turned out that #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000) value is equal to DISABLE. So actually the EOCSelection should be configured as: enter image description here
to be able to poll the ADC multiple times.

Then you can read the ADC continously without stopping and starting the ADC:

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    ConfigureADC();

    HAL_ADC_Start(&hadc1);
    while(1)
    {
        if (HAL_ADC_PollForConversion(&hadc1, 1000000) == HAL_OK)
        {
            ADCValue = HAL_ADC_GetValue(&hadc1);
        }
    }
}

This way it worked fine for me.

Since HAL is a quite new library there are not a lot of resources to be find but not impossible. I learned a lot from this tutorial, it demonstrates all possible ADC useage step by step; from simple polling, to using interrupts and DMA.

\$\endgroup\$
4
  • \$\begingroup\$ hm... disabling EOCSelection makes it work, but from the definition of it it says - Specifies whether the EOC flag is set at the end of single channel conversion or at the end of all conversions. Disabling this should not help by definition.. but it helps.... confusing. Do you know why exactly disabling this makes it work? thanks for the answer anyway \$\endgroup\$ Commented Nov 26, 2015 at 23:13
  • \$\begingroup\$ I am just learning HAL too, so I do not know the reason yet. It is just an experience. I found that HAL can be consfuing so many times. \$\endgroup\$ Commented Nov 26, 2015 at 23:25
  • \$\begingroup\$ I have checked the define values and #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000) which is same as disabled, so disabled is actually ADC_EOC_SEQ_CONV. \$\endgroup\$ Commented Nov 26, 2015 at 23:43
  • 1
    \$\begingroup\$ oh, ok, so it is not literally disabled. It makes sense, previously it was ADC_EOC_SINGLE_CONV which probably means just that - it converts just one time, and ADC_EOC_SEQ_CONV is continuous conversion. One more mystery solved :) Thanks! \$\endgroup\$ Commented Nov 26, 2015 at 23:49
5
\$\begingroup\$

I would like to add that for my setup (nucleo-h743) it was not enough to set:

hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;

I also had to enable the overrun setting as well:

hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

Without this the HAL_ADC_PollForConversion was still blocking. I do not fully understand why this was necessary but it does allow me to poll in continuous mode.

\$\endgroup\$
3
\$\begingroup\$

Hm... I found couple of tutorials that used HAL_ADC_Stop(&hadc1) to end the convertion... I was looking at these tutorials before and thought that this is rather barbaric way, seems it disables ADC completely, so I though there should be different method. But it seems, that this actually works well.
Be welcome to post answer if there is more elegant way of doing this, since I think using HAL_ADC_Stop() is pretty awful, but can be used for learning purposes.

while (1)
  {
        HAL_ADC_Start(&hadc1);
        if (HAL_ADC_PollForConversion(&hadc1, 1000000) == HAL_OK)
        {
            ADCValue = HAL_ADC_GetValue(&hadc1);
                        sprintf(str, "%d", ADCValue);
                        BSP_LCD_DisplayStringAt(130,30, (uint8_t*)str, LEFT_MODE);
        }
        HAL_ADC_Stop(&hadc1);

  }
\$\endgroup\$
1
  • \$\begingroup\$ Hi, i found an issue with this method, it restricts the maximum sample rate you can achieve by A LOT, it is not recommended to use this method if you need quick ADC conversions. \$\endgroup\$
    – r0k1m
    Commented Feb 28, 2020 at 10:17
1
\$\begingroup\$

This works for me, hope it will help:

if (HAL_ADC_Start(&hadc) != HAL_OK)
{
    /* Start Conversation Error */
    // Error_Handler();
}
if (HAL_ADC_PollForConversion(&hadc, 500) != HAL_OK)
{
    /* End Of Conversion flag not set on time */
    // Error_Handler();
    ADCValue=-1;
}
else
{
    /* ADC conversion completed */
    /*##-5- Get the converted value of regular channel ########################*/
    ADCValue = HAL_ADC_GetValue(&hadc);
}
HAL_ADC_Stop(&hadc);
\$\endgroup\$
0
\$\begingroup\$

I have encountered the same problem. By reading this post and I found the comments in the supplied driver. It could clarify a little more.

/*
         *< Specifies what EOC (End Of Conversion) flag is used for conversion by polling and interruption:
         *< end of conversion of each rank or complete sequence.
         *  This parameter can be a value of @ref ADC_EOCSelection.
         *  Note: For injected group, end of conversion (flag&IT) is raised only at the end of the sequence.
         *  Therefore, if end of conversion is set to end of each conversion, injected group should not be used
         *  with interruption (HAL_ADCEx_InjectedStart_IT) or polling (HAL_ADCEx_InjectedStart and
         *  HAL_ADCEx_InjectedPollForConversion). By the way, polling is still possible since driver will use
         *  an estimated timing for end of injected conversion.
         *  Note: If overrun feature is intended to be used, use ADC in mode 'interruption' (function HAL_ADC_Start_IT() )
         *  with parameter EOCSelection set to end of each conversion or in mode 'transfer by DMA'
         *  (function HAL_ADC_Start_DMA()).
         *  If overrun feature is intended to be bypassed, use ADC in mode 'polling' or 'interruption' with
         *  parameter EOCSelection must be set to end of sequence
         */
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.