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 June 12, 2017 at 10:19

Hey Scott

Thanks for the response, yeah this is pretty much what I ended up doing as well. I got notified that this has been reported as a bug so I hope it gets fixed soon.

Nathan

Posted on June 26, 2017 at 14:22

Hi Scott

STM are reporting this is fixed in 4.20, and im using 4.21 and still having issues.

Specifically, ADC_EOC_SINGLE_SEQ_CONV is still being generated from CubeMX. What is worse, is that cubeMX still allows you to select 'End of single or sequence of conversion' in the ADC parameters.

Scott, what version are you using?

Posted on June 26, 2017 at 15:03

On top of this, I have attempted your approached to use 

ADC_EOC_SINGLE_CONV and to call 

HAL_ADC_Start_IT within 

HAL_ADC_ConvCpltCallback and it works, but only for 3 channels and I have 6. The other ADC channels values remain 0. Playing around with the debugger and to my surprise 5 of the 6 channels in the array managed to get data, but not the 6th. Tired playing around with debugger again and i still only to get 3 channels with data.

Posted on June 27, 2017 at 11:17

Hi,

'End of single or sequence of conversion' value for 'End Of Conversion Selection' parameter will be removed in coming release of CubeMX.

So, the 'End Of Conversion Selection' parameter will be with the following possible values: - End of Single conversion - End of sequence of conversion

Regards

Imen
When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
Marvin Thorell
Associate
Posted on July 27, 2017 at 19:42

You need to use discontinuous mode. Using other modes, the channels all get read very quickly and EOS bit gets set. You need to use interrupts to catch them before they get overwritten. By using discontinuous mode, you can start ADC and wait for completion, then read one channel. Only EOC bit will be set. Next pass, read next channel, etc. When you have read all channels, EOS bit will be set.

Marv

Posted on July 29, 2017 at 09:20

Hi

  Sorry for taking so long in getting back to you, I have been away for a good while, and recently got back. I updated to the latest version, and cant remember what version I was running.  Have you now solved the issue?

Scott

Posted on July 30, 2017 at 20:08

Yes, all running. Thanks.

Marv

Marvin D. Thorell, P.E.

Creative Engineering, LLC

3716 Sheridan Road

Racine, WI 53403

mdthorell@gmail.com

Posted on July 31, 2017 at 02:53

Yes

Using the latest HAL and CubeMX versions:

// Variables:

unsigned int ADC_raw[6];

unsigned char index1 = 0;

unsigned short int ADC_Busy = 0;

// ConvCpltCallback function as follows:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)

{

   ADC_Busy = 1;

   if(__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC))

   {

      ADC_raw[index1] = HAL_ADC_GetValue(hadc);

      index1++;

   }

   if (index1 > 5)

   {

      index1 = 0;

      ADC_Busy = 0;

   }

}

// infinite loop:

while (1)

{

   if(ADC_Busy == 0)

   {

      ADC_Busy = 1;

      HAL_ADC_Start_IT(&hadc);

   }

}

The key thing to know is to make sure you slow down the ADC clock so that when the interrupt

ConvCpltCallback 

is called it has time to process. Also using variable index does not work, so I had to change to index1
Posted on December 28, 2017 at 15:35

 ,

 ,

Hello,

 , , As @Marvin Thorell said, you should use discontinuous mode. , ADC hardware is fast and interrupt software rutines are pretty slow, you will miss some channels even if you increase the 'Sampling Time'. , So you need to stop ADC sampling for the next channel, check below code. But i offer you to use DMA transfer.

/* USER CODE BEGIN 0 */

 ,

int ADC_index,

 ,

uint32_t ADC_Raw[3],

 ,

 ,

 ,

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)

 ,

{

 ,

 , ,  ,if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC))

 ,

 , ,  ,{

 ,

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

 ,

 , ,  , , ,  ,hadc->,Instance->,CR |= (uint32_t)ADC_CR_ADSTART,

 ,

 , ,  ,}

 ,

 , ,  ,if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS))

 ,

 , ,  ,{

 ,

 , ,  , , ,  ,if (ADC_index != 3)

 ,

 , ,  , , ,  ,{

 ,

 , ,  , , ,  , , ,  ,/* Something is wrong! We may receive overrun error */

 ,

 , ,  , , ,  , , ,  ,__asm volatile('bkpt ♯ 0\n'),

 ,

 , ,  , , ,  ,}

 ,

 , ,  , , ,  ,ADC_index = 0,

 ,

 , ,  ,}

 ,

}

 ,

 ,

 ,

void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)

 ,

{

 ,

 , , , if (HAL_ADC_GetError(hadc) &, HAL_ADC_ERROR_OVR)

 ,

 , ,  , , ,  ,__asm volatile('bkpt ♯ 0\n'),

 ,

}

 ,

 ,

 ,

/* USER CODE END 0 */

 ,

 ,

 ,

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_ADC_Init(),

 ,

 ,

 ,

 , /* USER CODE BEGIN 2 */

 ,

 ,

 ,

 , /* USER CODE END 2 */

 ,

 ,

 ,

 , /* Infinite loop */

 ,

 , /* USER CODE BEGIN WHILE */

 ,

 , ADC_index = 0,

 ,

 , HAL_ADC_Start_IT(&,hadc),

 ,

 , while (1)

 ,

 , {

 ,

 , /* USER CODE END WHILE */

 ,

 ,

 ,

 , /* USER CODE BEGIN 3 */

 ,

 ,

 ,

 , }

 ,

 , /* USER CODE END 3 */

 ,

 ,

 ,

}

 ,

 ,

 ,

 ,

 ,

/* ADC init function */

 ,

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.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1,

 ,

 , hadc.Init.Resolution = ADC_RESOLUTION_12B,

 ,

 , hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT,

 ,

 , hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD,

 ,

 , hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV,

 ,

 , hadc.Init.LowPowerAutoWait = DISABLE,

 ,

 , hadc.Init.LowPowerAutoPowerOff = DISABLE,

 ,

 , hadc.Init.ContinuousConvMode = DISABLE,

 ,

 , hadc.Init.DiscontinuousConvMode = ENABLE,

 ,

 , hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START,

 ,

 , hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE,

 ,

 , hadc.Init.DMAContinuousRequests = DISABLE,

 ,

 , hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED,

 ,

 , if (HAL_ADC_Init(&,hadc) != HAL_OK)

 ,

 , {

 ,

 , , , _Error_Handler(__FILE__, __LINE__),

 ,

 , }

 ,

 ,

 ,

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

 ,

 , , , */

 ,

 , sConfig.Channel = ADC_CHANNEL_0,

 ,

 , sConfig.Rank = ADC_RANK_CHANNEL_NUMBER,

 ,

 , sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5,

 ,

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

 ,

 , {

 ,

 , , , _Error_Handler(__FILE__, __LINE__),

 ,

 , }

 ,

 ,

 ,

 , , , /**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(__FILE__, __LINE__),

 ,

 , }

 ,

 ,

 ,

 , , , /**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(__FILE__, __LINE__),

 ,

 , }

 ,

 ,

 ,

}