cancel
Showing results for 
Search instead for 
Did you mean: 

STM32f103 Counter (EXTI/Timer)

amir_lm35
Associate II
Posted on August 04, 2016 at 20:09

Hi there.

i want to make a pulse counter with stm32f103RB. at first time i using EXTI to count the pulses means configure one of EXTI in falling or rising edge and in the IRQ_hander routine increase a variable. it works good in frequency lower than 100Hz !!!! when my frequency higher than 100Hz my counting lower than real pulses. i think this maybe because of EXTI low speed and go to use timer/counter but with channel capture i have same results :( my sample code like blow. could you please help me where is the problem?

void Configure_PA(void) {
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//IPU;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10 | GPIO_Pin_9 | GPIO_Pin_8;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA , GPIO_PinSource11);
EXTI_InitStruct.EXTI_Line = EXTI_Line11; // EXTI15_10_IRQn
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
/* Triggers on rising and falling edge */
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStruct);
/* Configure one bit for preemption priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStruct.NVIC_IRQChannel = EXTI15_10_IRQn; 
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
/* Set sub priority */
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* PD0 is connected to EXTI_Line0, which has EXTI0_IRQn vector */
NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn; 
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA , GPIO_PinSource10); 
EXTI_InitStruct.EXTI_Line = EXTI_Line10;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStruct);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA , GPIO_PinSource9); 
EXTI_InitStruct.EXTI_Line = EXTI_Line9;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStruct);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA , GPIO_PinSource8); 
EXTI_InitStruct.EXTI_Line = EXTI_Line8;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStruct);
}
/* Handle Digital Input interrupts */
void EXTI15_10_IRQHandler(void) { 
if (EXTI_GetITStatus(EXTI_Line11) != RESET) { 
CounterCh[1]++;
EXTI_ClearITPendingBit(EXTI_Line11); 
} 
if (EXTI_GetITStatus(EXTI_Line10) != RESET) {
CounterCh[2]++; 
EXTI_ClearITPendingBit(EXTI_Line10);
}
}
void EXTI9_5_IRQHandler(void) { 
if (EXTI_GetITStatus(EXTI_Line9) != RESET) {
CounterCh[3]++;
EXTI_ClearITPendingBit(EXTI_Line9); 
} 
if (EXTI_GetITStatus(EXTI_Line8) != RESET) {
CounterCh[4]++;
EXTI_ClearITPendingBit(EXTI_Line8); 
}
}

10 REPLIES 10
troy1818
Senior
Posted on August 08, 2016 at 11:44

Should work. What is triggering the interrupt ? HW schematics ? any capacitor anywhere near the input ?

I suggest to get an oscilloscope and look at the input to confirm that it is correct.

What freq is the mcu running at ?

You could also try and using pull up for the input pin to see if you get any changed behavior.

amir_lm35
Associate II
Posted on August 20, 2016 at 17:41

i guess it should be work too.

but i test it with 3 different hardware (different PCB) and with all of them i have same problem.

I using another micro controller to triggering the interrupt and the output port set to Push Pull. and in interrupt program i test In_Floating_mode and IPU mode but results are same. 

i using a uVision Keil 5.14 and STM32f103RBT

thanks a lot.

Posted on August 20, 2016 at 17:48

What frequencies are we talking about, be specific, it helps understand the issue.

Losing 50-60 count over what observation period?

What speed is the chip running at?

What else is it doing? How are you outputting the results during the tests?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
amir_lm35
Associate II
Posted on August 20, 2016 at 19:17

thanks for your reply clive1.

my St running at 72MHz and the pulses have 1KHz speed but the results in a 30 sec has been different about 100 count. 

i configure another timer (TIM2) for printing results every 2 seconds with serial port.

it read some analog channel, 1wire, and answered to CAN bus(with high priority) but in most of time the mail loop is in delay. 

thansk.

Posted on August 20, 2016 at 23:46

I'd suggest creating a clock source locally with a timer and looping that back into the EXTI for a sanity check.

Also consider using a TIM in External Clock mode, and use that for counting cycles, and confirming if that sees the same number of pulses.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
amir_lm35
Associate II
Posted on August 21, 2016 at 05:51

i using this code for another test but the result not changed more.

timer and External Clock is my last idea because i need 4 channel counter at last running in 5KHz and when i use external clock should be use 4 timer and i loss many hardware resources.

void Tim1_init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
/* Enable clock for GPIOA */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* Set pin as input */ 
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; //_AF_OD;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10 | GPIO_Pin_9 | GPIO_Pin_8;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
/* Enable the TIM1 global Interrupt */
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);
TIM_TIxExternalClockConfig(TIM1,TIM_TS_TI1FP1,TIM_ICPolarity_Rising, 0);
TIM_SetCounter(TIM1,0);
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM1, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM1, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM1, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM1, &TIM_ICInitStructure);
/* TIM1 counter enable */
TIM_Cmd(TIM1, ENABLE);
/* TIM1 Main Output(Input) Enable */
//TIM_CtrlPWMOutputs(TIM1, ENABLE);
/* Enable TIM1 channel 2 interrupt source */
// Enable the CCx Interrupt Request
TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);
TIM_ITConfig(TIM1, TIM_IT_CC2, ENABLE);
TIM_ITConfig(TIM1, TIM_IT_CC3, ENABLE);
TIM_ITConfig(TIM1, TIM_IT_CC4, ENABLE);
// assuming PCLK1 ticks at 42[MHz] -> slow down timer to 420 KHz
// because TIM1 is a 16 bit counter, we can expect to be able to measure
// a waveform of up to 156 milliseconds.
// TIM_PrescalerConfig(TIM1, 100, TIM_PSCReloadMode_Immediate) ;
// TIM_ClearFlag(TIM1, TIM_FLAG_CC1||TIM_FLAG_CC2);
// TIM_ITConfig(TIM1,TIM_IT_CC1||TIM_IT_CC2,ENABLE);
// TIM_ARRPreloadConfig(TIM1, ENABLE);
// TIM_CCxCmd(TIM1,TIM_Channel_1||TIM_Channel_2,ENABLE);
}
void InitializeTimer()
{
// TIM_TimeBaseInitTypeDef TIM_TimeBase_InitStructure;
// NVIC_InitTypeDef NVIC_InitStructure;
// >>> OVF = ( Period * Prescaler ) / Clock = 2000 * 18000 / 36000000 ; Clock(APB1) = 36MHz =72MHz/2+> Becuse of APB2 in slow mode <<<
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
TIM_TimeBaseInitTypeDef timerInitStructure; 
timerInitStructure.TIM_Prescaler = 7199;//17999;
timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
timerInitStructure.TIM_Period = 19999;//1999
timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
timerInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &timerInitStructure); 
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
EnableTimerInterrupt();
TIM_Cmd(TIM2, ENABLE);
}
void TIM1_CC_IRQHandler(void)
{
// Capture/Compare interrupt source ?
if (TIM_GetITStatus(TIM1, TIM_IT_CC1) == SET)
{
CounterCh[4]++;
TIM_ClearITPendingBit(TIM1, TIM_IT_CC1) ; 
}
// Capture/Compare interrupt source ?
if (TIM_GetITStatus(TIM1, TIM_IT_CC2) == SET)
{
TIM_ClearITPendingBit(TIM1, TIM_IT_CC2) ;
CounterCh[3]++;
}
if (TIM_GetITStatus(TIM1, TIM_IT_CC3) == SET)
{ 
TIM_ClearITPendingBit(TIM1, TIM_IT_CC3) ; 
CounterCh[2]++;
}
if (TIM_GetITStatus(TIM1, TIM_IT_CC4) == SET)
{ 
TIM_ClearITPendingBit(TIM1, TIM_IT_CC4) ; 
CounterCh[1]++;
}
} 

Posted on August 21, 2016 at 19:32

Yes, there is only one counting element per timer. The point is to validate/confirm the measurements you are seeing with the interrupt method.

With 4x inputs at 5KHz, on an F1, perhaps using the hardware timers will save you from burning a lot of cycles doing unproductive work.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
amir_lm35
Associate II
Posted on August 24, 2016 at 07:38

thanks clive1.

could you please give me a sample program?

Posted on August 24, 2016 at 15:13

could you please give me a sample program?

I'm afraid I can't commit my resources to your project. You'll need to review assorted examples posted to the forum, there should be a couple of External Clock examples.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..