cancel
Showing results for 
Search instead for 
Did you mean: 

Counting frequency of input signal - timer counter gives double frequency than external pin interrupt counting

rnd7
Associate II
Posted on June 10, 2016 at 11:45

Hi Guys,

Want to ask for a quick bit of advice please. I have a STM32F407 running on a board that has been configured to count frequency (number of pulses per second - period and duty cycle are variable). I had it set up to use the pin that the frequency input was connected to, to trigger an external interrupt and then in the interrupt I would increment a counter. Every 1s the difference between the current counter value and the previous counter value would be output as the frequency during that particular 1s interval. I recently ran into a problem with the above when presented with very high frequency input signal. The processor was spending too much time interrupting. I recently changed my code to use the timer with my frequency input signal as external clock signal for the counter. The problem I am having now is that the new code which uses a timer to count the frequency outputs roughly double the frequency that the previous code based on counting number of external interrupts did. Could anybody help me understand why this is? I checked in DM00031020 STM32 reference manual p5 From what I understand, using ETR external clock only either rising or falling edge can be used, not both. Is there possibly a problem with my previous code that counts on pin external interrupts? Obviously I'm missing something here, I thought that what I was doing in Old code vs New code should give me the same output. Old previous code for counting external pin interrupts:

GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOD, EXTI_PinSource2);
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
void EXTI0_IRQHandler(void)
{
u32Total_Counts_C1++;
EXTI_ClearITPendingBit(EXTI_Line0);
return;
}

New (problematic) code for counting frequency with timer:

GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_TIM3);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 0; //i tried 1 here also, which then gives me ~same frequency as interrupt counting.
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ETRClockMode2Config(TIM3, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted, 0x00);
TIM_Cmd(TIM3, ENABLE);

Any help/advice appreciated. Thanks for reading.
5 REPLIES 5
Posted on June 10, 2016 at 12:01

So use a scope or a known frequency source to benchmark the methods and make a determination.

You don't show the code that processes the measurement or define the integration time or results/frequencies. I would use a 32-bit counter to ensure I wasn't getting a counter overflow between measurements.

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

I will look into getting a source for a fixed frequency input as then I will know which version of the code is ''correct''.

Currently I am using the same frequency input source (minor variations are possible and expected - in the order of ~+/-5%) and comparing the outputs of the two versions of code, the timer based counting output is very close (2% out at last measurement) to double the interrupt based counting. Integration time is 1 second. I am testing with low frequency (<1kHz) for now. Using the timer based counting I measured a frequency of 5 Using the external pin interrupt based counting I measured a frequency of The board is already in production so I am limited to the pin already in use PD2 which as I understand limits me to use the TIM3 timer which is only 16-bit. In future revisions of the board I will propose to the team that alternative pins be used to enable 32-bit counters. The following code is called in main loop to read from the 16-bit timer and increment a 32-bit counter with the difference between the current read and the previous read:

u16 u16Difference = 0;
//get 16-bit counter value
u16TIM3_Counter = (u16)TIM_GetCounter(TIM3);
//find difference between current counter and previous counter
u16Difference = (u16TIM3_Counter - u16TIM3_Counter_Previous);
//increment 32-bit counter variable with difference value above
u32Total_Counts_C2 = u32Total_Counts_C2 + u16Difference;
//save current 16-bit counter value to be used as previous value in next iteration
u16TIM3_Counter_Previous = u16TIM3_Counter;

This code is called every 1s and is generic to both new and old methods:

u32Counts_C2 = u32Total_Counts_C2 - u32Total_Counts_C2_Previous;
u32Total_Counts_C2_Previous = u32Total_Counts_C2;

rnd7
Associate II
Posted on June 10, 2016 at 13:44

Got a frequency simulator and plugged it in for testing.

Using external interrupt counting I simulated a 9600Hz signal and measured exactly 9600Hz as the output from software.

Using a very, very old frequency counter (+/- 5% specified accuracy) I measured ~10153Hz and dropping frequency to 2600Hz simulated I measured ~2500Hz, so it seems that signal simulator is working as expected. (could not verify with scope, it broke 3days ago).

Repeating test with 9600Hz output from frequency simulator and using timer 3 counter as set up in code from previous posts, I get 19200Hz output from software. (9600 * 2 = 19200Hz) exactly.

Perhaps I should completely de-initialize the timer before I do the setup?

rnd7
Associate II
Posted on June 10, 2016 at 14:01

OK this is weird...

I have access to the same frequency input signal via both pin PD2 and PE0. PD2 can route to timer 3 ETR and PE0 can route to timer 4 ETR. I set up timer 3 as below:

GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_TIM3);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 0; //i tried 1 here also, which then gives me ~same frequency as interrupt counting.
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ETRClockMode2Config(TIM3, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted, 0x00);
TIM_Cmd(TIM3, ENABLE);

I set up timer 4 as below:

GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource0, GPIO_AF_TIM4);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
TIM_ETRClockMode2Config(TIM4, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted, 0x00);
TIM_Cmd(TIM4, ENABLE);

Reading of values is the same method as before. in main loop:

u16 u16Difference = 0;
u16TIM3_Counter = (u16)TIM_GetCounter(TIM3);
u16TIM4_Counter = (u16)TIM_GetCounter(TIM4);
u16Difference = (u16TIM3_Counter - u16TIM3_Counter_Previous);
u32Total_Counts_C2 = u32Total_Counts_C2 + u16Difference;
u16Difference = (u16TIM4_Counter - u16TIM4_Counter_Previous);
u32Total_Counts_C1 = u32Total_Counts_C1 + u16Difference;
u16TIM3_Counter_Previous = u16TIM3_Counter;
u16TIM4_Counter_Previous = u16TIM4_Counter;

called once a second:

u32Counts_C1 = u32Total_Counts_C1 - u32Total_Counts_C1_Previous;
u32Counts_C2 = u32Total_Counts_C2 - u32Total_Counts_C2_Previous;
u32Total_Counts_C1_Previous = u32Total_Counts_C1;
u32Total_Counts_C2_Previous = u32Total_Counts_C2;

So far as I can see, both timers etc setup is identical, both methods of reading values, etc are identical (in same functions called from same place etc). BUT: value read from TIM3 counter is double that from TIM4 counter. Anybody see something I have missed or any ideas?
Posted on June 10, 2016 at 21:37

Covered external counting via CH1 here

[DEAD LINK /public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/STM32Discovery/STM32F4%20Timer%20External%20Pulse%20counting&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F&currentviews=921]https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/STM32Discovery/STM32F4%20Timer%20External%20Pulse%20counting&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F¤tviews=921

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