cancel
Showing results for 
Search instead for 
Did you mean: 

Frequency Capture Issue - missing pulses

paul23
Associate II
Posted on December 11, 2014 at 03:32

Hi,

I ma currently trying to use the timer capture to measure a burst pulse but it always seems to miss a couple of signals. I have measured it on an oscilloscope and I can see 10 pulses but from my frequency measurement using the timer capture, I only can measure 7 to 8 pulses. The timer capture code is shown below and stores the capture value into a ringbuffer (from kargs.net). In the main code, it checks if the ring buffer has any data and transmit to a serial terminal via usart dma. Any ideas why the pulses are missing? Have I set this up correctly? Cheers Paul

unsigned char FreqCounter::IC2Value = 0;
RingBufAdaptor *FreqCounter::p_buffer;
FreqCounter::FreqCounter()
{
RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
p_buffer = &ring_buffer;
/* TIM2 configuration: PWM Input mode ------------------------
The external signal is connected to TIM2 CH2 pin (PA.01),
The Rising edge is used as active edge,
The TIM2 CCR2 is used to compute the frequency value
------------------------------------------------------------ */
TIM_ICInitTypeDef 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 = 0x0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
// /* Select the TIM2 Input Trigger: TI2FP2 */
TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);
/* Select the slave Mode: Reset Mode */
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);
/* Enable the Master/Slave Mode */
TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);
/* TIM enable counter */
TIM_Cmd(TIM2, ENABLE);
/* Enable the CC2 Interrupt Request */
TIM_ITConfig(TIM2, TIM_IT_CC2, ENABLE);
}
unsigned int FreqCounter::get_last_frequency()
{
if (ring_buffer.is_empty())
return 0;
return system_clock / ring_buffer.pop_front();
}
void FreqCounter::RCC_Configuration()
{
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* GPIOA clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
}
void FreqCounter::GPIO_Configuration()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void FreqCounter::NVIC_Configuration()
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the TIM2 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void FreqCounter::TIM2_IRQHandler()
{
if (TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET)
{
/* Clear TIM2 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
// /* Get the Input Capture value */
IC2Value = TIM_GetCapture2(TIM2);
p_buffer->put(&IC2Value);
}
}

8 REPLIES 8
paul23
Associate II
Posted on December 11, 2014 at 03:36

My system clock is 36 MHz and have output to the MCO pin and measured it with a scope. The burst pulse consists of two frequencies; 147 kHz and 150 kHz. The number of pulses varies.

Posted on December 11, 2014 at 04:43

Do you have other interrupts with higher priority which could be pulling down a few hundred machine cycles? Couldn't you use DMA to fill the ring buffer?

If you didn't continuously reset the counter you might be able to determine if the timer's missing the the pulse, or your interrupt.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
paul23
Associate II
Posted on December 11, 2014 at 04:55

We don't have any other high priority interrupts. The other interrupt in the system is the systick. We have found your example code for DMA and going to try it out. As for removing the counter reset, the measurement is inaccurate.

paul23
Associate II
Posted on December 11, 2014 at 04:56

Below is our systick code.

#include ''stm32f10x.h''
#include <
string.h
>
#include ''timer.h''
#define MAX_SYS_TICK_HANDLERS 20
/*-------------------------------Global Variables-----------------------------*/
static uint64_t currentTime;
static tSysTickHandler sysTickHandlers[MAX_SYS_TICK_HANDLERS];
static int sysTickHandlerIndex;
/*--------------------------------Module Setup--------------------------------*/
// Called before the main loop
void initialise_timer(void)
{
currentTime = 0;
sysTickHandlerIndex = 0;
// Set the systick for 10us interrupts.
SysTick_Config(SystemCoreClock / 100000);
}
/*------------------------------External Functions----------------------------*/
// Make sure you register your tick handlers in the module Init function. This will
// make sure it gets registered before the mainloop and interrupts are enabled.
void register_sys_tick_handler(tSysTickHandler sysTickHandler)
{
if (sysTickHandlerIndex < MAX_SYS_TICK_HANDLERS)
{
sysTickHandlers[sysTickHandlerIndex++] = sysTickHandler;
}
else
{
// This is an unrecorverable error. We have run out of allocated sysTickHandlers.
// Increase the define MAX_SYS_TICK_HANDLERS.
assert_param(0);
}
}
uint64_t get_current_time(void)
{
uint64_t tempTime;
// Make sure we disable interrupts and create a local copy of the time. This
// will ensure the sysTick interrupt will not modify currentTime while we
// are reading it.
__disable_irq();
tempTime = currentTime;
__enable_irq();
return tempTime;
}
void master_sys_tick_handler(void)
{
int i;
for (i = 0; i < sysTickHandlerIndex; i++)
{
if (sysTickHandlers[i] != NULL)
{
sysTickHandlers[i]();
}
}
__disable_irq();
currentTime++;
__enable_irq();
}

Posted on December 11, 2014 at 05:12

As for removing the counter reset, the measurement is inaccurate.

Why would it be inaccurate, you're either latching values on a continuous timebase properly or you're not. The delta measurements should be as viable as the reset ones, but you can figure out which pulse you're not seeing.

How are you synchronizing the pulse train you see on the scope vs the one you're recording in the buffer?
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
paul23
Associate II
Posted on December 11, 2014 at 21:14

The pulse is generated using a timer from a separate micro board. The pulse train is generated when a button is pressed on the board and the oscilloscope is triggered using the rising edge. The same for the timer capture module as seen in the above code.

We have tested with 20kHz pulse train and we can detect all the pulses using the timer capture module but not for the 150kHz pulse train.

We have used the RCC_GetClocksFreq to ensure our APB1 bus is running at 36MHz.

paul23
Associate II
Posted on December 12, 2014 at 04:43

Triggered 11 pulse train using GPIO interrupt but only detected 9 pulses. I wonder if it is a speed issue. Currently using g++. Trying using gcc with some optimization turned on.

paul23
Associate II
Posted on December 12, 2014 at 05:00

Ok got it working. It was too slow so set the optimization flag to O2 and now all the pulses are detected.