2012-11-23 02:03 AM
Hi fellow forum mates,
I am a student working on a new project using stm32f4 eval board. My task is to measure the frequency from 3 different sources ranging from 1000hz to 725khz. I have been trying for days using a function generator to simulate the source. I have no problem measuring the lower frequency however when i am measuring at higher frequency . I notice sometimes the frequency i measure is almostactuallyhalf of the input. Any idea or solution as i am very lost.InitTimer2(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* GPIOA clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Connect TIM pins to AF */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_TIM2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_TIM2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_TIM2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_TIM2);
/* Enable the TIM1 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Time Base configuration */
TIM_TimeBaseStructure.TIM_Prescaler = PRESCALER;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
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 = 0x02;
TIM_ICInit(TIM2, &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 = 0x02;
TIM_ICInit(TIM2, &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 = 0x02;
TIM_ICInit(TIM2, &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 = 0x02;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
/* TIM enable counter */
TIM_Cmd(TIM2, ENABLE);
}
void TIM2_IRQHandler(void) {
GPIO_ToggleBits(GPIOD, GPIO_Pin_12);
if(TIM_GetITStatus(TIM2, TIM_IT_CC1) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
if(CaptureNumber2 == 0)
{
/* Get the Input Capture value */
Timer2Read1 = TIM_GetCapture1(TIM2);
CaptureNumber2 = 1;
}
else if(CaptureNumber2 == 1)
{
/* Get the Input Capture value */
Timer2Read2 = TIM_GetCapture1(TIM2);
/* Capture computation */
if (Timer2Read2 > Timer2Read1)
{
Timer2Diff = (Timer2Read2 - Timer2Read1);
}
else if (Timer2Read2 <
Timer2Read1
)
{
Timer2Diff = ((0xFFFF - Timer2Read1) + Timer2Read2);
}
else
{
Timer2Diff
=
0
;
}
CaptureNumber2
=
0
;//cc2
/* Frequency computation */
Timer2FREQ = (uint32_t) SystemCoreClock/2/ (1+PRESCALER) /Timer2Diff;
//save result into array
setSensorResult(Timer2FREQ);
}
}
else if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
if(CaptureNumber2 == 0)
{
/* Get the Input Capture value */
Timer2Read1
=
TIM_GetCapture2
(TIM2);
CaptureNumber2
=
1
;
}
else if(CaptureNumber2 == 1)
{
/* Get the Input Capture value */
Timer2Read2
=
TIM_GetCapture2
(TIM2);
/* Capture computation */
if (Timer2Read2 > Timer2Read1)
{
Timer2Diff = (Timer2Read2 - Timer2Read1);
}
else if (Timer2Read2 <
Timer2Read1
)
{
Timer2Diff = ((0xFFFF - Timer2Read1) + Timer2Read2);
}
else
{
Timer2Diff
=
0
;
}
CaptureNumber2
=
0
;//cc2
/* Frequency computation */
Timer2FREQ = (uint32_t) SystemCoreClock/2/ (1+PRESCALER) /Timer2Diff;
//save result into array
Sensor::setSensorResult(Timer2FREQ);
}
}
else if(TIM_GetITStatus(TIM2, TIM_IT_CC3) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);
if(CaptureNumber2 == 0)
{
/* Get the Input Capture value */
Timer2Read1
=
TIM_GetCapture3
(TIM2);
CaptureNumber2
=
1
;
}
else if(CaptureNumber2 == 1)
{
/* Get the Input Capture value */
Timer2Read2
=
TIM_GetCapture3
(TIM2);
/* Capture computation */
if (Timer2Read2 > Timer2Read1)
{
Timer2Diff = (Timer2Read2 - Timer2Read1);
}
else if (Timer2Read2 < Timer2Read1)
{
Timer2Diff = ((0xFFFF - Timer2Read1) + Timer2Read2);
}
else
{
Timer2Diff = 0;
}
CaptureNumber2 = 0;
Timer2FREQ = (uint32_t) SystemCoreClock/2/ (1+PRESCALER) /Timer2Diff;
//save result into array
Sensor::setSensorResult(Timer2FREQ);
}
}
GPIO_ToggleBits(GPIOD, GPIO_Pin_12);
}
Appreciate all your help .
2012-11-23 04:54 AM
725 KHz seems a bit on the high side to be measuring periods, I'd have the hardware counting pulses over a defined window.
Your repetitive use of CaptureNumber2 for holding state is problematic. If you are saturating the core, do less in the interrupt.2012-11-23 11:36 PM
2012-11-24 06:03 AM
Ok, so lets analyze some failure modes of the presented code.
What happens if CC1 occurs followed by CC2, what delta are you measuring? You need channel unique variables. What happens if CC1 and CC2 trigger at the same time? The if/else tree ignores this. What happens if the measurement occurs at a 0x10000 tick interval, setting the delta to zero and then dividing by zero? What happens when the timer rolls over? The 16-bit unsigned computation of the delta is wrong, simple 16-bit unsigned math would be easier and provide the correct answer all the time. You'd still need to catch the zero case. The interrupt will not re-enter, if multiple CC1 interrupts occur during servicing only one will be recognized. Avoid unnecessary division where possible, hw division mask some of the cost, but precompute where you can. Consider if PRESCALER allows for the granularity and range required. To integrate over time, you'd count pulses in the TIMx->CNT register (ie one timer per source), and have a secondary timer sample this, at say the 10 ms interval, using DMA. You could use an Update interrupt instead, DMA just has a tighter service window.2012-11-25 05:43 PM
Hi Clive,
I made modification to on only one timer channel at a time and precompute most of the calculations within the interrupt however the same issues with the error in frequency calculation is still observed. I am trying the implementation that you suggested . Do you mind sharing some codes as i am still a little hazy about the method?Regards