cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 Nucleo Continuous ADC mode only converts once

balintbujtor
Associate

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 */

}
1 ACCEPTED SOLUTION

Accepted Solutions
SofLit
ST Employee

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;

 

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

View solution in original post

8 REPLIES 8
SofLit
ST Employee

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;

 

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
TDK
Guru

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.

If you feel a post has answered your question, please click "Accept as Solution".

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.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

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.

If you feel a post has answered your question, please click "Accept as Solution".

@TDK wrote:

If we're going to get technical, it is not a must to use interrupts either. 


I didn't say it is a must. The OP is using interrupt mode, so I think he's hoping to get an answer regarding this config.

@balintbujtor + increase also the sampling time time (sConfig.Sampling) to the max value.

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Hello @SofLit, 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.

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)

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Can someone from ST, an employee actually tell me where in the documentation that you provided states that setting this will correct the issue?    AdcHandle.Init.EOCSelection = DISABLE;

I have tested this and it does fix the issue, however, the documentation that was posted as the reference for the solution doesn't seem to show this.  So, I'm curious as to how the solution was actually found?

Looking at example code doesn't actually tie back to a document that states how the behaviour is expected. I do see that the example does DISABLE this param, but where is the documentation that supports this?