2024-09-18 09:56 AM
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 */
}
Solved! Go to Solution.
2024-09-18 10:04 AM
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;
2024-09-18 10:04 AM
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;
2024-09-18 11:03 AM
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.
2024-09-18 11:17 AM
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.
2024-09-18 11:44 AM
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.
2024-09-18 11:53 AM - edited 2024-09-18 12:07 PM
@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.
2024-09-18 11:40 PM
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.
2024-09-19 12:40 AM
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)
2024-10-21 11:36 PM
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?