cancel
Showing results for 
Search instead for 
Did you mean: 

why does ADC_FLAG_EOS get called after each channel?

Scott Dev
Senior
Posted on April 06, 2017 at 12:22

Hi

I am trying to use the ADC in the STM32L07 as a multichannel scan. I have set up Cube for 3 analogue channels, AN0, Temperature and VRef Int. I have set it up for single scan usign the HAL_ADC_Start_IT(&hadc); command. Within the interupt routine I am checking the ADC_FLAG_EOC for after each channel completed, and the ADC_FLAG_EOS for after the complete scan is completed. When the HAL_ADC_Start_IT is called, I see the first channel with ADC_FLAG_EOC, but straight away the ADC_FLAG_EOS is also called. I am new to the chip, and not sure what I am doing wrong, can anyone advice me? My code is below, and attached is snap shot of the cube setting

Many Thanks

Scott

unsigned ADC_Raw[3];

unsigned char ADC_index=0;

#define AD_VCCINT 2

#define AD_TEMP 1

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)

{

if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC))

{

ADC_Raw[ADC_index++]=HAL_ADC_GetValue(hadc);

ADC_raw = HAL_ADC_GetValue(hadc);

}

if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS))

{ <<gets called straight after first conversion...

ADC_index=0;

Vdd = 3000 * (*VREFINT_CAL_ADDR)/ADC_Raw[AD_VCCINT];

temperature=(((int32_t)ADC_Raw[AD_TEMP]*Vdd/3000)-(int32_t)*TEMP30_CAL_ADDR);

temperature*=(int32_t)(130-30);

temperature/=(int32_t)(*TEMP130_CAL_ADDR - *TEMP30_CAL_ADDR);

temperature+=30;

}

}

static void MX_ADC_Init(void)

{

ADC_ChannelConfTypeDef sConfig;

/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)

*/

hadc.Instance = ADC1;

hadc.Init.OversamplingMode = DISABLE;

hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;

hadc.Init.Resolution = ADC_RESOLUTION_12B;

hadc.Init.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;

hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;

hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;

hadc.Init.ContinuousConvMode = DISABLE;

hadc.Init.DiscontinuousConvMode = DISABLE;

hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;

hadc.Init.DMAContinuousRequests = DISABLE;

hadc.Init.EOCSelection = ADC_EOC_SINGLE_SEQ_CONV;

hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;

hadc.Init.LowPowerAutoWait = DISABLE;

hadc.Init.LowPowerFrequencyMode = DISABLE;

hadc.Init.LowPowerAutoPowerOff = DISABLE;

if (HAL_ADC_Init(&hadc) != HAL_OK)

{

Error_Handler();

}

/**Configure for the selected ADC regular channel to be converted.

*/

sConfig.Channel = ADC_CHANNEL_0;

sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;

if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)

{

Error_Handler();

}

/**Configure for the selected ADC regular channel to be converted.

*/

sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;

if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)

{

Error_Handler();

}

/**Configure for the selected ADC regular channel to be converted.

*/

sConfig.Channel = ADC_CHANNEL_VREFINT;

if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)

{

Error_Handler();

}

}

Note: this post was migrated and contained many threaded conversations, some content may be missing.
28 REPLIES 28
Posted on April 06, 2017 at 18:11

Its a strange one. I have also tried what you suggested, just set ADC_EOC_SINGLE_CONV and it just carried out one conversion. Also tried ranking 1,2,3.  I only called HAL_ADC_Start_IT(&hadc) once. So looks like for some reason its not sampling the other 2 channels.

Scott

Posted on April 06, 2017 at 19:17

Does changing

hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;

to

hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD | ADC_SCAN_ENABLE;

fix it?

Scott Dev
Senior
Posted on April 07, 2017 at 16:12

Hi

 Anyone had the same issue? I have went through the example many times and still get the same result.

Regards

Scott

egarcia
Associate
Posted on April 07, 2017 at 20:18

Hi Scott:

I was also doing development, actually following the same example you are, and had the same issue!

On the debugger, I was following your same steps. When you hit your first breakpoint, do you also get an OVR flag set on the ISR register? I noticed I was, which I believe it means that the ADC is going faster than the interrupt can handle it. Maybe the interrupt overhead of CubeMX's code?

Anyway, I changed the clock to 'Synchronous Clock Mode / 4' and tried it again. If I put the breakpoint on the 'if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS))' code block I can get the values of the three channels. However a breakpoint on the other 'if' block will make the ADC overrun.

Let me know if this helps, I hope it does!

Thanks,

-Eduardo

Posted on April 09, 2017 at 18:47

Hi Eduardo

  Thanks for your reply, and a great help, cheers.

What you said is exactly what i am seeing. I am new to the STM32 , so still learning .I would have never throught of that one,as I always assumed as I was using the debugger everything would stop between breakpoints and wouldnt get OVR set. I have set the same as you with the clock mode /4 . But also had to slow down the ADC sample rate or still wouldnt work. I thought this was the speed between the each sample period, and nothing to do with each channel. 

I like the CubeMX, but maybe its becasue I am new to this , but does save a lot of time. I might try setting the ADC up without using the CubeMX to see if this works without changing these settings.

Thanks Again

Scott

Posted on April 10, 2017 at 18:43

Hi

devlin.scott

,

Regarding

ADC_EOC_SINGLE_SEQ_CONV use, this is already answered by

Joly.Jeanne

in

https://community.st.com/0D50X00009Xkf0fSAB

For your second point regarding

ADC_EOC_SINGLE_SEQ_CONV, it is a feature possible on HW side but, since a couple of years, we did not findany use case in SW in the HAL driver. We use eitherADC_EOC_SINGLE_CONV orADC_EOC_SEQ_CONV. With your post, as this variable is not use, we decided to delete this variable. It will be as well available in the nextCubeMX release.

Hope this helps you.

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
Posted on April 13, 2017 at 19:15

Hi Imen

  Thanks for your replies. I have set the ADC to only convert 1 channel at a time, and call HAL_ADC_Start_IT(&hadc); to start the convertion.  What I am seeing is that the

ADC_EOC_SINGLE_CONV

does get called after each channel ,and I call HAL_ADC_Start_IT(&hadc); to start the next channel. Then when all 3 have been converted, the

ADC_EOC_SEQ_CONV does get called. Mind, as I probably dont need it as after the each

ADC_EOC_SINGLE_CONV

I can work out when all convertions are comlpeted.

Scott

gates.nathan
Associate III
Posted on June 07, 2017 at 20:30

Hi

devlin.scott

‌ have made any progress on this it?

I have tearing my hair out trying to get read multiple channels using interrupts.

Im getting the same behaviour that you got: EOC flag followed directly after EOS flag.

Thanks

Nathan

Posted on June 08, 2017 at 19:09

Hi Nathan,

 I never really got around the issue, but I dont the following:

I have 2 a/d channels and started sampling within my main() appliction with a HAL_ADC_Start_IT(hadc); and set ADC_index=0. When I get a EOC, I simply call HAL_ADC_Start_IT() again until all channels are read.

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)

{

    if (__HAL_ADC_GET_FLAG(hadc, ADC_IT_EOC))  //received EOC

       {

            ADC_Raw[ADC_index++]=HAL_ADC_GetValue(hadc); //store value and increase channel

   

            if(ADC_index<3) //while not all channels read, start another interupt

                HAL_ADC_Start_IT(hadc);

        }

        if (__HAL_ADC_GET_FLAG(hadc, ADC_IT_EOS))

        {

         /.......

        }

    }

Regards

Scott

Posted on June 08, 2017 at 23:41

Ooops, typo error. I meant to say,' I do the following'.  Instead of starting the interupt and end on a ADC_IT_EOS, I simply keep starting an interupt within the ADC_IT_EOC until all the channels are sampled. It would be great if someone managed to get this working.

Scott