2016-07-17 01:42 PM
I have a micro-controller board based on STM32F030F4P6. I have written a program to read a channel of Analog to Digital converter,
ADC1
at rising edge ofTIM3
timer where I want to read the ADC value as soon as End of Conversion (EOC
) ofADC1
generates an interrupt. Below is the code. The interrupt handler,ADC1_IRQHandler()
, however, is never called. Does anybody know what is wrong with the code?&sharpinclude ''stm32f0xx.h''
&sharpinclude ''stm32f0xx_rcc.h'' &sharpinclude ''stm32f0xx_gpio.h'' &sharpinclude ''stm32f0xx_adc.h'' &sharpinclude ''stm32f0xx_tim.h'' &sharpinclude ''stm32f0xx_misc.h'' int g_adc_value; void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { GPIOx->ODR ^= GPIO_Pin; } void RCC_Config() { RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_ADCCLKConfig(RCC_ADCCLK_HSI14); } void GPIO_Config() { GPIO_InitTypeDef GPIO_InitStruct; /* PinA0 as Analog input */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStruct); /* PinA4 as digital output to drive LED */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_Level_3; GPIO_InitStruct.GPIO_OType = GPIO_OType_OD; // LED has an on-board resistor GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStruct); } void ADC_Config() { NVIC_InitTypeDef NVIC_InitStructure; // Enable the TIM3 global Interrupt NVIC_InitStructure.NVIC_IRQChannel = ADC1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); // ADC1 IT Enable ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE); ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO; ADC_Init(ADC1, &ADC_InitStructure); // Do setup! ADC_ChannelConfig(ADC1,ADC_Channel_0,ADC_SampleTime_1_5Cycles); ADC_GetCalibrationFactor(ADC1); ADC_Cmd(ADC1, ENABLE); // Enable ADC1 while (ADC_GetFlagStatus (ADC1, ADC_FLAG_ADEN) == RESET); while (ADC_GetFlagStatus (ADC1, ADC_FLAG_ADRDY) == RESET); } void TIM3_Config() // Timing of ADC1 { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; /* Time base configuration */ TIM_TimeBaseStructure.TIM_Period = (48000000 / 40000) - 1; // 40 KHz TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); /* TRGO selection */ TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update); // ADC_ExternalTrigConv_T3_TRGO /* enable counter */ TIM_Cmd(TIM3, ENABLE); } void ADC1_IRQHandler(void) { if(ADC_GetITStatus(ADC1,ADC_IT_EOC)) { GPIO_ToggleBits(GPIOA, GPIO_Pin_4); g_adc_value = ADC_GetConversionValue(ADC1); ADC_ClearITPendingBit(ADC1,ADC_IT_EOC); } } int main(void) { SystemInit(); GPIO_Config(); TIM3_Config(); ADC_Config(); ADC_StartOfConversion(ADC1); // Start conversion GPIO_SetBits(GPIOA, GPIO_Pin_4); // LED off while (1) { } } #stm32f030-adc-interrupt2016-07-17 02:24 PM
You need to actually call RCC_Config(), as one of the first things. I would also only enable the IRQ in the ADC after you have the ADC configuration finished.
2016-07-17 02:43 PM
Hi Clive,
Thanks for your hints! I modified the code according to your hints, but there is still no call to theADC1_IRQHandler()
function! Here is the modified code:#include ''stm32f0xx.h''
#include ''stm32f0xx_rcc.h'' #include ''stm32f0xx_gpio.h'' #include ''stm32f0xx_adc.h'' #include ''stm32f0xx_tim.h'' #include ''stm32f0xx_misc.h'' int g_adc_value; void RCC_Config() { RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_ADCCLKConfig(RCC_ADCCLK_HSI14); } void GPIO_Config() { GPIO_InitTypeDef GPIO_InitStruct; /* PinA0 as Analog input */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStruct); /* PinA4 as digital output to drive LED */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_Level_3; GPIO_InitStruct.GPIO_OType = GPIO_OType_OD; // LED has an on-board resistor GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStruct); } void ADC_Config() { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = ADC1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO; ADC_Init(ADC1, &ADC_InitStructure); // Do setup! ADC_ChannelConfig(ADC1,ADC_Channel_0,ADC_SampleTime_1_5Cycles); ADC_GetCalibrationFactor(ADC1); ADC_Cmd(ADC1, ENABLE); // Enable ADC1 while (ADC_GetFlagStatus (ADC1, ADC_FLAG_ADEN) == RESET); while (ADC_GetFlagStatus (ADC1, ADC_FLAG_ADRDY) == RESET); // ADC1 IT EnableADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);
} void TIM3_Config() // Timing of ADC1 { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; /* Time base configuration */ TIM_TimeBaseStructure.TIM_Period = (48000000 / 40000) - 1; // 40 KHz TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); /* TRGO selection */ TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update); // ADC_ExternalTrigConv_T3_TRGO /* enable counter */ TIM_Cmd(TIM3, ENABLE); } void ADC1_IRQHandler(void) { if(ADC_GetITStatus(ADC1,ADC_IT_EOC)) { GPIO_SetBits(GPIOA, GPIO_Pin_4); // LED off
g_adc_value = ADC_GetConversionValue(ADC1); ADC_ClearITPendingBit(ADC1,ADC_IT_EOC); } } int main(void) { SystemInit(); RCC_Config();
GPIO_Config(); TIM3_Config(); ADC_Config(); ADC_StartOfConversion(ADC1); // Start conversion GPIO_ResetBits(GPIOA, GPIO_Pin_4); // LED on
while (1) { } } Edit 1: I realized that the following code makes Timer 3 not to generate Trigger (T3_TRGO)! Any idea?
NVIC_InitStructure.NVIC_IRQChannel = ADC1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
2016-07-20 04:36 AM
I found the problem!
It is because of a strange definition instm32f0xx.h
where for
STM32F030F4P6
chips (and for some non-sense reasons) we have to use the definitionADC1_IRQn
instead of standard definition
ADC1_COMP_IRQn
. This makes the programmer to use the name
ADC1_IRQHandler()
for the interrupt service routine, but the compiler searches for the function
ADC1_COMP_IRQHandler()
. This makes the run of program problematic because the program counter will be lost when
EOC
interrupt is generated. Hope this saves hours of wasting time to find out a non-sense definition as the source of the problem.