Skip to main content
Graduate
September 18, 2024
Solved

STM32 Nucleo Continuous ADC mode only converts once

  • September 18, 2024
  • 2 replies
  • 2024 views

Hello Forum,

I have an issue performing continuous conversions with the ADC on my STM Nucleo board. I want to continuously convert once the ADC is initialized and started and do something with the data afterwards (what is irrelevant to the problem). However, for some reason, if I place the HAL_ADC_Start_IT function call outside the while loop the HAL_ADC_ConvCpltCallback function is only called once. I would expect that in continuous mode I don't need to Start the ADC every time I want to make a conversion.

Board: STM32 Nucleo F446RE
STM32 IDE version: 1.14.0


The main:

ADC_HandleTypeDef hadc2;

UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */
uint16_t adc_val;
uint16_t counter = 0;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_ADC2_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{

/* USER CODE BEGIN 1 */


/* USER CODE END 1 */

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_ADC2_Init();
/* USER CODE BEGIN 2 */
HAL_ADC_Start_IT(&hadc2);
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

The ADC conversion complete callback:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
adc_val = HAL_ADC_GetValue(&hadc2);
counter++;
}


The ADC init function (generated by CubeMX):

static void MX_ADC2_Init(void)
{

/* USER CODE BEGIN ADC2_Init 0 */

/* USER CODE END ADC2_Init 0 */

ADC_ChannelConfTypeDef sConfig = {0};

/* USER CODE BEGIN ADC2_Init 1 */

/* USER CODE END ADC2_Init 1 */

/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc2.Instance = ADC2;
hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc2.Init.Resolution = ADC_RESOLUTION_12B;
hadc2.Init.ScanConvMode = DISABLE;
hadc2.Init.ContinuousConvMode = ENABLE;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.NbrOfConversion = 1;
hadc2.Init.DMAContinuousRequests = DISABLE;
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc2) != HAL_OK)
{
Error_Handler();
}

/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC2_Init 2 */

/* USER CODE END ADC2_Init 2 */

}
    This topic has been closed for replies.
    Best answer by mƎALLEm

    Hello,

    Comparing your code to what provided as example in https://github.com/STMicroelectronics/STM32CubeF4/blob/master/Projects/STM324xG_EVAL/Examples/ADC/ADC_RegularConversion_Interrupt/Src/main.c

    I see this difference:

    In your code:

    hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

    while in the Cube example:

    AdcHandle.Init.EOCSelection = DISABLE;

     

     

    2 replies

    mƎALLEmAnswer
    Technical Moderator
    September 18, 2024

    Hello,

    Comparing your code to what provided as example in https://github.com/STMicroelectronics/STM32CubeF4/blob/master/Projects/STM324xG_EVAL/Examples/ADC/ADC_RegularConversion_Interrupt/Src/main.c

    I see this difference:

    In your code:

    hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

    while in the Cube example:

    AdcHandle.Init.EOCSelection = DISABLE;

     

     

    Graduate
    September 19, 2024

    Hello @mƎALLEm, thank you for the answer, your suggestion solved my problem! Can you provide me documentation (or explain if you know) where the meaning and use of this flag are written down? Thank you! In the HAL documentation there is no explanation.

    Technical Moderator
    September 19, 2024

    Hello @balintbujtor ,


    @balintbujtor wrote:

    Can you provide me documentation (or explain if you know) where the meaning and use of this flag are written down? 


    The reference manual of the product RM0390 / Section 13 Analog-to-digital converter (ADC)

    Super User
    September 18, 2024

    You have to use DMA to convert more than one channel, or a single channel continuously. Code can't keep up with the rate of conversions.

    Technical Moderator
    September 18, 2024

    It's not a must to use DMA for continuous mode. It can be also managed by interrupt. But better to use DMA for perf reasons and to prevent loosing samples.

    Super User
    September 18, 2024

    If we're going to get technical, it is not a must to use interrupts either. But good luck running code that can keep up with a conversion every 15 ADC ticks.