cancel
Showing results for 
Search instead for 
Did you mean: 

ADC1 sample from 2 channels with interrupt for conversion ready

GTanova
Associate II

Hello, 

I have two channels on ADC1 and I want to trigger a s ample separately, every two seconds from first channel and every 10th second from second channel. I am using interrupts so after the adc trigger I get an interrupt when conversion is done. But it seems i only get a sample or read it from the first channel. I am new to stm32 microcontroller so i am not sure what can be wrong. I am configering everything and using an interrupt handler for reading the ready sample. I get the interrupt after each trigger but it seems i am getting the value from the first channel. 

__HAL_RCC_VREF_CLK_ENABLE(); // enable the internal voltage reference

hadc1.Instance = ADC1;

hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;

hadc1.Init.Resolution = ADC_RESOLUTION_12B;

hadc1.Init.GainCompensation = 0;

hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;

hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

hadc1.Init.LowPowerAutoWait = DISABLE;

hadc1.Init.ContinuousConvMode = DISABLE;

hadc1.Init.NbrOfConversion = 1;

hadc1.Init.DiscontinuousConvMode = DISABLE;

hadc1.Init.DMAContinuousRequests = DISABLE;

hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;

hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;

hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;

hadc1.Init.OversamplingMode = DISABLE;

ADC_RegisterHandle(&hadc1);

sConfig.SamplingTime = ADC_SAMPLETIME_391CYCLES_5;

sConfig.SingleDiff = ADC_SINGLE_ENDED;

sConfig.OffsetNumber = ADC_OFFSET_NONE;

sConfig.Offset = 0;

sConfig.Channel = ADC_CHANNEL_5;

sConfig.Rank = ADC_REGULAR_RANK_1;

HAL_ADC_ConfigChannel(&hadc1, &sConfig);

sConfig.Channel = ADC_CHANNEL_6;

sConfig.Rank = ADC_REGULAR_RANK_2;

HAL_ADC_ConfigChannel(&hadc1, &sConfig);



__HAL_ADC_CLEAR_FLAG(&adc1, ADC_FLAG_EOC);

__HAL_ADC_CLEAR_FLAG(&adc1, ADC_FLAG_OVR);

__HAL_ADC_CLEAR_FLAG(&adc1, ADC_FLAG_EOS);



HAL_NVIC_SetPriority(ADC1_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(ADC1_IRQn);



__HAL_ADC_ENABLE_IT(&adc1, ADC_IT_EOC);



if (HAL_ADC_Init(&hadc1) != HAL_OK)

{

Error_Handler();

}

 HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);



Public void ADC_RegisterHandle(ADC_HandleTypeDef *handle)

{

hadc1 = handle;

}

This is my interrupt handler:

Public void ADC1_IRQHandler(void)

{

if (__HAL_ADC_GET_FLAG(adc1, ADC_FLAG_EOS)){ //test code to check set flags



if (NULL != adcValueCB) {

// just for test to see if interrupt is received

}

}

if (__HAL_ADC_GET_FLAG(adc1, ADC_FLAG_EOC)){



if (NULL != adcValueCB) {

// just for test to see if interrupt is received

}

}

if (__HAL_ADC_GET_FLAG(adc1, ADC_FLAG_OVR)){



if (NULL != adcValueCB) {

// just for test to see if interrupt is received

}

}

HAL_ADC_IRQHandler(adc1); //hal library from stm32

}



void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)

{

if (hadc->Instance == ADC1) {

uint32_t ch1 = HAL_ADC_GetValue(hadc); // here I always get the value from first sampled channel, channel 5

adcValueCB(&ch1); // return value to rest of the program

__HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_OVR); // clear flags that are not cleared by getting the value

__HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_EOS);

}

}

In the code loop I trigger the conversion:

Get the number of channel I want a sample from, sent from the rest of the program at different intervals

 
sConfig.Channel = inputChannel;

sConfig.Rank = GetChannelRank(inputChannel);

HAL_ADC_ConfigChannel(&adc1, &sConfig);

SysCtlDelay(10); // delay of 10 ms after changing channels to stabilize

HAL_ADC_Start_IT(&hadc1);



Is there anything I am missing?

 

Best regards,

Gergana

 

Edit by ST Moderator to apply source code formatting. Please see the Posting Tips for how to properly post source code.

1 REPLY 1
Aime
ST Employee

Hello @GTanova ,

Your issue stems from the way the ADC is configured and used to sample multiple channels separately at different intervals, but with only one conversion configured at a time.

 

ADC Channel Configuration Persistence:
HAL_ADC_ConfigChannel() configures the ADC channel in the regular sequence. But the ADC peripheral may not fully update the channel selection immediately or reliably between conversions, especially if the ADC is not fully stopped or if the configuration is not done properly.
 

Rank and Scan Mode:
Since you have ScanConvMode = DISABLE and NbrOfConversion = 1, the ADC expects only one channel configured. Configuring multiple channels with different ranks but scan disabled is inconsistent.
 

Changing Channel on the Fly:
Changing the channel configuration dynamically before each conversion is possible but requires careful handling:

  • Stop ADC completely.
  • Configure the new channel.
  • Start ADC conversion.
  • Wait for conversion complete interrupt.
  • Repeat.

Rank Usage:
If scan mode is disabled, ranks beyond 1 are ignored. Your second channel configuration with rank 2 is not used.

 

Based on your application (You want to sample channel 5 every 2 seconds and channel 6 every 10 seconds separately.) here is how to solve it:

  1. Stop ADC before reconfiguring channel
  2. Configure the desired channel
  3. Small delay if needed (to stabilize)
  4. Start ADC conversion with interrupt
  5. In the conversion complete callback, read the value

Here is a Code Snippet proposal, the argument channel in the requested channel that you want to update the configuration

 

Best regards,

Aime