2
\$\begingroup\$

I am using STM32F030F4P6. When I call this function my ADC starts successfully and I can read an ADC value in the ADC callback, but my MCU hangs at this function line. What is the problem?

My code is generated by st32mcubemx and my IDE is IAR. I have a problem with this line. My program prints "OK1" and the ADC runs successfully, but my MCU doesn't print "OK2". This is a part of my main code generated by cubeMX:

  /* USER CODE BEGIN 2 */  
  uint8_t ret;
  printf("OK1!\r\n");
  ret = HAL_ADC_Start_IT(&hadc);
  if (ret != HAL_OK) printf("ERROR Start ADC\r\n");
  else printf("ADC start sucess!\r\n");
  printf("OK2!\r\n");
  /* USER CODE END 2 */

And this is my ADC init:

/* Includes ------------------------------------------------------------------*/
#include "adc.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

ADC_HandleTypeDef hadc;

/* ADC init function */
void MX_ADC_Init(void)
{
  ADC_ChannelConfTypeDef sConfig = {0};

  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
  */
  hadc.Instance = ADC1;
  hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc.Init.Resolution = ADC_RESOLUTION_12B;
  hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
  hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc.Init.LowPowerAutoWait = DISABLE;
  hadc.Init.LowPowerAutoPowerOff = DISABLE;
  hadc.Init.ContinuousConvMode = ENABLE;
  hadc.Init.DiscontinuousConvMode = DISABLE;
  hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc.Init.DMAContinuousRequests = DISABLE;
  hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  if (HAL_ADC_Init(&hadc) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel to be converted. 
  */
  sConfig.Channel = ADC_CHANNEL_4;
  sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
  if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

}

void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if (adcHandle->Instance==ADC1)
  {
  /* USER CODE BEGIN ADC1_MspInit 0 */

  /* USER CODE END ADC1_MspInit 0 */
    /* ADC1 clock enable */
    __HAL_RCC_ADC1_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**ADC GPIO Configuration    
    PA4     ------> ADC_IN4 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* ADC1 interrupt Init */
    HAL_NVIC_SetPriority(ADC1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(ADC1_IRQn);
  /* USER CODE BEGIN ADC1_MspInit 1 */

  /* USER CODE END ADC1_MspInit 1 */
  }
}

void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{

  if (adcHandle->Instance==ADC1)
  {
  /* USER CODE BEGIN ADC1_MspDeInit 0 */

  /* USER CODE END ADC1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_ADC1_CLK_DISABLE();
  
    /**ADC GPIO Configuration    
    PA4     ------> ADC_IN4 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4);

    /* ADC1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(ADC1_IRQn);
  /* USER CODE BEGIN ADC1_MspDeInit 1 */

  /* USER CODE END ADC1_MspDeInit 1 */
  }
}

This is my ADC callback:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  if (hadc->Instance == ADC1)
  {
    adc_val = HAL_ADC_GetValue(hadc);
    Vin = adc_val*0.001;
    printf("ADC val:%d Vin:%f\r\n",adc_val,Vin);
  }
}

And this is my error callback. At this, I receive ADC ERR:2 meaning HAL_ADC_ERROR_OVR. I am getting the ADC value in the callback but this happens.

void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
{
  uint32_t adc_error;
  printf("ADC ERR:%d\r\n",hadc->ErrorCode);
}
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Your callback functions are being called from the ADC interrupt. It's almost certain that you can't do printf from an interrupt, and that's what's causing your code to hang. \$\endgroup\$
    – brhans
    Dec 25, 2019 at 7:56
  • \$\begingroup\$ OK, when I comment on the printf and get the result in the live watch window my MCU hangs too. \$\endgroup\$
    – OnlyStar
    Dec 25, 2019 at 9:41
  • 1
    \$\begingroup\$ Time to add some Breakpoints and step through the code? \$\endgroup\$
    – Tyler
    Dec 25, 2019 at 13:54
  • \$\begingroup\$ The ADC implementation in STM32 works perfect with DMA and circular buffer. For this reason any singular conversions make no sense, unless you run out of free DMA channels. Just set up circular buffer, add all your ADC channels to it and start continuous DMA conversions. It will take zero CPU time afterwards and you can simply read converted values from memory as necessary \$\endgroup\$
    – Maple
    Mar 7 at 8:57

1 Answer 1

0
\$\begingroup\$

What happens is that the printf in the conversion completion callback is still printing when the next interrupt happens so it can't execute until printf is done and therefore the result is not read in time and overrun happens. So it is usually not a good idea to call printf in an interrupt context, unless you have written it yourself to make it re-entrant and make it write to a buffer, and still it might be too slow.

\$\endgroup\$
1
  • \$\begingroup\$ OK, when I comment on the printf and get the result in the live watch window my MCU hangs too. \$\endgroup\$
    – OnlyStar
    Dec 25, 2019 at 9:41

Your Answer

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

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