cancel
Showing results for 
Search instead for 
Did you mean: 

[2 serious bugs in Cube library] ADC interrupt on STM32F302x8 is continously fired

Posted on November 26, 2014 at 19:05

I have transferred code for ADC using an interrupt from STM32F405 to STM32F302 but it seems that the interrupt is probably fired again immediatelly after return. I see it by a permanent lit of a LED and on scope at LED signal, too.

If I add HAL_ADC_Start_IT(&hadc1); at the end of the interrupt handler, the interrupt is not fired next. How to clear an interrupt flag or so?

// main.h
#include ''stm32f3xx_hal.h''
#include ''stm32f302x8.h''
#include <
stdbool.h
>
// Macro -------------------------------------------------------------
#define SETPIN(port,pin) (port->BSRRL = pin)
#define CLRPIN(port,pin) (port->BSRRH = pin)
#define TSTPIN(port,pin) (port->IDR & pin)
#define TGLPIN(port,pin) (port->ODR ^= pin)
// Pin definitions
#define LED_PIN GPIO_PIN_15
#define LED_PORT GPIOA
// Function prototypes
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);

#include ''main.h''
ADC_HandleTypeDef hadc1;
extern volatile bool adc1done;
//------------------------------------------------------------------------------
int main(void)
{
HAL_Init();
SystemClock_Config();
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC1_Init();
SETPIN(LED_PORT,LED_PIN);
HAL_Delay(1000);
CLRPIN(LED_PORT,LED_PIN);
HAL_Delay(1000);
HAL_ADC_Start_IT(&hadc1);
while (1)
{
if (adc1done)
{
// process data
adc1done = false;
}
}
}
//------------------------------------------------------------------------------
// System Clock Configuration
void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
__SYSCFG_CLK_ENABLE();
}
//------------------------------------------------------------------------------
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__GPIOA_CLK_ENABLE();
/*Configure GPIO pin : PA15 for LED */
GPIO_InitStruct.Pin = GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
//------------------------------------------------------------------------------
/* ADC1 init function */
void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
//Common config
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION12b;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.NbrOfDiscConversion = 1;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.Overrun = OVR_DATA_OVERWRITTEN;
HAL_ADC_Init(&hadc1);
//Configure Regular Channel
sConfig.Channel = ADC_CHANNEL_10; // OpAmp2 output
sConfig.Rank = 1;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.SamplingTime = ADC_SAMPLETIME_601CYCLES_5;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

#include ''main.h''
extern ADC_HandleTypeDef hadc1;
volatile uint32_t ticks;
volatile bool adc1done;
//------------------------------------------------------------------------------
void SysTick_Handler(void)
{
ticks++;
HAL_IncTick();
}
//------------------------------------------------------------------------------
void ADC1_IRQHandler(void)
{
uint16_t data;
SETPIN(LED_PORT,LED_PIN);
NVIC_ClearPendingIRQ(ADC1_IRQn);
if (__HAL_ADC_GET_FLAG(&hadc1, ADC_FLAG_EOC))
{
data = ADC1->DR;
// preprocess and store data
adc1done = true;
__HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_EOC);
}
CLRPIN(LED_PORT,LED_PIN);
}

// stm32f3xx_hal_msp.c
#include ''stm32f3xx_hal.h''
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
if(hadc->Instance==ADC1)
{
/* Peripheral clock enable */
__ADC1_CLK_ENABLE();
__HAL_RCC_ADC1_CONFIG(RCC_ADC1PLLCLK_DIV4);
/* Peripheral interrupt init*/
/* Sets the priority grouping field */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
HAL_NVIC_SetPriority(ADC1_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(ADC1_IRQn);
}
}

4 REPLIES 4
Posted on November 26, 2014 at 19:38

If it keeps re-entering you're qualifying the wrong flag. Reading the DR should be sufficient to satiate an ADC EOC interrupt.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on November 30, 2014 at 23:06

Yes, ADC->DR resets EOC flag.

I have found the first bug in stm32f3xx_hal_adc_ex.c, in function HAL_ADC_ConfigChannel: line 4280 must be

if (sConfig->Channel >= ADC_CHANNEL_10) // i.e. also equal

without it my setting of a rather long sample time for Chan10 was written into wrong register so the shortest sample time was used. The second bug must be in function HAL_ADC_Start_IT(&hadc1) because it does not work (interrupt is continuously fired) but

__HAL_ADC_ENABLE(&hadc1);
while (__HAL_ADC_GET_FLAG(&hadc1, ADC_FLAG_RDY) == RESET);
__HAL_ADC_ENABLE_IT(&hadc1, ADC_IT_EOC);
ADC1->CR |= ADC_CR_ADSTART;

works. Unfortunatelly, such errorneous STMCube library rather than useful is infuriating (I am not sure about suitable English expression :-))
Posted on January 15, 2015 at 09:41

Hi,

Regarding the two bugs you mention:

  1. Sampling time of ADC_CHANNEL_10: you are right, this is a bug. It has already been corrected and will be available in the next STM32F3 HAL driver release.(Fix: replacement of ''if (sConfig->Channel > ADC_CHANNEL_10)'' by ''if (sConfig->Channel >= ADC_CHANNEL_10)'' )
  2. Function ''HAL_ADC_Start_IT()'': The function is working correctly. Please find attached an example using ADC continuous mode with ADC IT (derived from HAL package ''STM32Cube_FW_F3_V1.1.0'' example ''ADC_AnalogWatchdog''), running on board STM32F302R8 Nucleo.In this example, you can compare ADC running with IT and with transfer by DMA (selection by switch in file “main.h�?). ADC_CHANNEL_10)''
A few comments in your code:

  • Into function ''void ADC1_IRQHandler(void) {...}'', you should use the HAL ADC IRQ handler: “HAL_DMA_IRQHandler(AdcHandle.DMA_Handle);�?
  • You have migrated your code from STM32F4 to STM32F3, some ADC initialization structure parameters must be tuned: For example, adding ''AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START;''
  • Generally, the recommended configuration is use ADC with transfer by DMA. It is more efficient by avoiding CPU processing to go through the IRQ handler at each ADC conversion. This is particularly true in your setup: ADC in continuous mode induces a constant data flow to be transferred. Transfer by DMA would be more suitable to your use case.

Regards,

Heisenberg.

________________

Attachments :

Example_ADC_ContinuousOrTIM_ITorDMA_STM32F302R8-Nucleo.zip : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I1MA&d=%2Fa%2F0X0000000blo%2FkoiOFXY.F8OOgqKLm5.c8XQwvmss1sVjYAdIOCG2EOs&asPdf=false
Posted on January 16, 2015 at 13:08

Hello, Heisenberg,

Thank you for a response and the example. I will study it.

Ragarding the channel 10 sampling time, you see, that I corrected the code myself.

Regarding ADC, I normally use DMA but I need to switch an external AMUX between the ADC conversions in this application.