cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L4 - ADC Mulit Channel Interrupt support

ASter.2
Associate II

Hey Guys,

I am working with the STM32L476RG Nucleo board (however my custom board has the L462 chip - I am hoping the solution will work for both chips) and I am trying to get multiple channels ADC interrupts to work without success.

My CubeMX setup is as follows:

0693W00000Hr00oQAB.png 

My Code:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
	p_value[indx] = HAL_ADC_GetValue(hadc);
	indx = (indx + 1) % 2;
	if((indx % 2) == 0) {
		HAL_ADC_Start_IT(&hadc1);
	}
}
 
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_ADC1_Init();
  /* USER CODE BEGIN 2 */
 
  HAL_ADC_Start_IT(&hadc1);
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
         HAL_Delay(5);
         sprintf(msg, "ADC1: %hu\t\tADC2: %hu\r\n", p_value[0], p_value[1]);
         HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
  }
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

I am expecting to see the callback twice for each HAL_ADC_Start_IT() call but for some reason, it only calls it once. I am able to see only the first channel.

Any help is appreciated!

Thanks!

Almog

6 REPLIES 6
ASter.2
Associate II

Update:

I have managed to read the two separate ADC1 channels by removing the HAL_ADC_Start_IT(&hadc1) at line 36 and placing it within the while(1) loop.

This method is semi-working in the way that I can see both channels behaving independently of each other which is what I wanted. However, now there is a different problem:

It looks like it's skipping an iteration.

I have 2 potentiometers connected to PC0 and PC1.

In my program, while changing the potentiometer value I can see that the one connected to PC1 (supposed to be channel 2) is changing p_value[0] and the other potentiometer on pin PC0 (supposed to be channel 1) is changing p_value[1].

CubeMX is configured that Channel 1 is rank 1 and Channel 2 is rank 2. If I understand correctly, the potentiometer connected to PC0 should be read first and placed in p_value[0] while the other potentiometer should be placed in p_value[1].

I can seem to find any resources that can help me configure my ADC to use interrupts with multiple channels.

As I understand it, while the ADC is in scan mode, once I call HAL_ADC_Start_IT(&hadc1), it does not stop until ALL channels have been read and after each channel, the EOC flag is up and an interrupt is called. Is that not the way?

Thanks for your help,

Almog

TDK
Guru

2.5 sampling cycles (plus conversion time) is not enough time for the CPU to interrupt and read out the value before the next conversion completes. Use DMA or a much slower sampling scheme.

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

Hey TDK,

Thanks for the reply.

Changing the sampling cycle count to 47.5 still produces the same results - One callback instead of 2 per HAL_ADC_Start_IT(&hadc1) call.

Is there anything else that needs to be changed?

Thanks

Philippe Cherbonnel
ST Employee

Hi @Community member​ ,

The STM32L4 ADC has only 1 data register (for ADC group regular), therefore when the ADC performs several successive conversions you have to fetch the data quickly enough before next data overwrites data registers.

  • If using polling or IT: the CPU must be fast enough (and not be preempted another higher priority task) to fetch the data. This is the issue in your case, as mentioned by @TDK​ 
  • If using DMA: this

Best regards

Philippe

Philippe Cherbonnel
ST Employee

Hi @ASter.2 (Community Member)​ ,

The STM32L4 ADC has only 1 data register (for ADC group regular), therefore when the ADC performs several successive conversions you have to fetch the data quickly enough before next data overwrites data registers.

  • If using polling or IT: the CPU must be fast enough (and not be preempted another higher priority task) to fetch the data. This is the issue in your case, as mentioned by @TDK (Community Member)​: the CPU has only few tens of cycles to process IRQ handler and get the conversion data.
  • If using DMA: this is the recommended method: DMA will transfer data in RAM after each conversion, therefore CPU is offloaded and you will not miss any conversion data.

You can find some examples in STM32L4 FW package:

Using ADC LL driver:

 ...\Firmware\Projects\NUCLEO-L476RG\Examples_LL\ADC\ADC_MultiChannelSingleConversion

Using ADC HAL driver:

 ...\Firmware\Projects\NUCLEO-L4R5ZI\Examples\ADC\ADC_Sequencer

Best regards

Philippe

Yes, use DMA or a much slower sampling scheme as suggested.

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