2015-07-04 10:33 AM
Hello all,
i am trying to capture a ppm signal, for the moment i use a steady fixed widith signal of 740hz, with 1050us on period, and 300us off period. The signal going to PA0 and PA1 of my STM32F4 I have several questions: I noticed if i use as trigger TIM_TS_TI1FP1 , the event interupt ocures at the specific frequency of the signal wich i have it on the input of mcu, this somehow overides my timebase period/prescale setings. Is this true? When performing a readout of the counter register, it is reseted just by reading it? The counter registers are automaticly cleard when a new rise/fall it event ocurrs? I am afraid i did not understand exactly the corelation between timer clock and the counting register... With the code bellow my raw values for the given 740hz signal are Capture1 = 4430 Capture2 = 1890 Is there a specific formula for calculate the ''ON'' period in microseconds? My timer settings are like in the following codeRCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA , ENABLE); //Enable the GPIOx AHB clock
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_TIM2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_TIM2);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure Timer2 timebase */
TIM_TimeBaseStructure.TIM_Prescaler = 9;
TIM_TimeBaseStructure.TIM_Period = 6999;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* configure Timer2 Channel 1 */
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; /*Capture performed each time an edge is detected on the capture input. */
TIM_ICInitStructure.TIM_ICFilter = 0x00;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
/* configure Timer2 Channel 2 */
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x00;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
/* Configure Timer2 Interupt Sources */
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE); // enable Channel 1 capture interupt
TIM_ITConfig(TIM2, TIM_IT_CC2, ENABLE);// enable Channel 2 capture interupt
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //enable interupt events
TIM_SelectInputTrigger(TIM2,TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset); /* Rising edge of the selected trigger input
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2, ENABLE); // Start the Timer
Bellow are the Interupts
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_CC1) == 1)// If compare capture has occured
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
capture1 = TIM_GetCapture1(TIM2); // Get timer counts for Period
GPIO_ToggleBits(GPIOD,GPIO_Pin_5); // just some toggle for logic analyzer
GPIO_ToggleBits(GPIOD,GPIO_Pin_5);
}
if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == 1)// If compare capture has occured
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
capture2= TIM_GetCapture2(TIM2);
GPIO_ToggleBits(GPIOD,GPIO_Pin_9); // just some toggle for logic analyzer
GPIO_ToggleBits(GPIOD,GPIO_Pin_9);
}
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // Counter overflow, reset interrupt
GPIO_ToggleBits(GPIOD,GPIO_Pin_12);
}
}
2015-07-04 01:32 PM
The prescaler and timer act as dividers.
A Prescale of 9 (10-1) is DIV10 of the source clock. Nominally APB1 is at 42 MHz (DIV4) the TIMCLK is DIV2 (ie APB1 * 2), 84 MHz. Your timebase is ticking at 8.4 MHz (84 MHz / 10), so figure 119 ns PER TICK. You have set the counter to 6999 (7000-1), it's going to tick modulo 7000, this is going to make your math VERY difficult, wrap every 83.33 ms and thus practically limited to 1200 Hz. TIM2 is a 32-BIT count, use the maximal 32-bit value, and the math works itself out if you use 32-bit unsigned math. You'd also have finer granularity of measurements if you set the prescaler as ZERO (DIV1), the counter will then tick a 84MHz (11.9 ns ticks) In Input Capture, the value in CNT is latched into CCRx at each event. CNT wraps at the Period, and counts at the TIMCLK/(Prescaler + 1). The functionality here is not overly complex.2015-07-04 02:45 PM
Thank you clive for your response.
So suposing i have my prescale =0 and my period = That would mean 84mhz/period value , wich means by the math 84 000 000 / 83 = 1 MHZ . That means that my timer is ticking at 1 uS . And if i have a signal of lets say 1500 us between two rise edges , that means in my routine bellow that every 1500us i have a event, and when reading the counter i should have 1500 ticks?if(TIM_GetITStatus(TIM2, TIM_IT_CC1) == 1)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
capture1 = TIM_GetCapture1(TIM2);
}
2015-07-04 03:11 PM
No, that would set the update period to 1us (1MHz), and you can't interrupt at that rate.
You'd want to set Prescale = 83, and Period = 0xFFFFFFFF; and not interrupt on the Update If you are measuring a 1 KHz signal, you'd expect a delta of 1000 ticks; uint32_t SamplePointA = TIM2->CCR1; .. uint32_t SamplePointB = TIM2->CCR1; uint32_t Delta = SamplePointB - SamplePointA; // Count in 1us (1MHz) ticks. For 1 KHz ~1000 ticks2015-07-05 01:58 AM
Hmm, i am confused now.
And despite these, now i have the corect value in my count register, namely my signal is composed of Ton period of 1050 uS and Toff period of 300us, totalizing 1350us per cycle. And my counter register constantly measures 1350-1358 wich is fairly good So in the end wich is the corect timer clock definition? I am asking because with the settings of prescale 83 and period FFFFFFFF i get a very low frequency (0.000232hz) Is there a corelation between update event frequency and the timer ticking frequency? By the way, the Delta measurement is done in two consecutive interupt events, or in the same event at once?2015-07-05 04:52 AM
Ok, lets recap this, again,
With my settings of Prescaler = 83; TIM2->CNT++; // Occurs at 1 MHz (1us) Or more specifically TIM2->CNT = (TIM2->CNT + 1) % (Period + 1); TIM2->CNT wraps at Period, ie 0xFFFFFFFF->0x00000000 Update occurs when TIM2->CNT == 0, it's a long time, you DON'T CARE, you're NOT measuring it. At CC1 Event TIM2->CCR1 = TIM2->CNT Each Event occurs at a different time, and you are comparing the count, IN TICKS AT 1 MHz, between the events. Events A and B are separated in time, you're measuring the time as B-A You use a LARGE value for the Period so a) it DOESN'T wrap within your desired timing window, and b) the math is simple, and not complicated by weird modulo values2015-07-05 05:08 AM
2015-07-05 05:44 AM
Yes, it loads the value of CNT into CCR1, and then interrupts you to tell you that occurred. The loading occurs at the hardware level, so is immune to whatever your interrupt latency is, up to the point the measured frequency exceeds the rate you can process it.
2015-07-05 05:49 AM
If i still talk about timers, i was wondering of a better solution to synchronize my pulse indexes.
I have put a picture bellow. My ppm signal is composed of 8 pulses with ranges from (500 to 2000uS) and pause between 8 pulses of aprox 300uS. The ppm pulse frames are sent with a rate of 50hz between each frame. and i thinked to declare a array like uint32_t pchan[8], and to asign to each pchan the number of the pulse index, example pchan[0] = pulse1, pchan[1]=pulse2 and so on... I was thinking of measure the time between the last falling edge of the current frame and the first rising edge of the next frame, and if the period is greater than a maximum pulse width (2000us), then consider for the next pulse, index should be 0. I am asking if there is a best solution for achiveing thisvoid TIM2_IRQHandler(void)
{ if(TIM_GetITStatus(TIM2, TIM_IT_CC1) == 1)// If compare capture has occured { TIM_ClearITPendingBit(TIM2, TIM_IT_CC1); capture1 = TIM_GetCapture1(TIM2); // Get timer counts for Period capture1 = capture1 -capture2 ; // get the Toff value between pulses if (capture1 >2000){ uu=7;} //if we detect the ''dead pulse'' reset pulse index if (uu>7) { uu=0;} // if the index reached maximum allowed index, reset it ! } if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == 1) {// If compare capture has occured TIM_ClearITPendingBit(TIM2, TIM_IT_CC2); capture2 = TIM_GetCapture2(TIM2); pchan[uu]=capture2 ; }2015-07-05 06:03 AM
I'm familiar with PPM signals, and it's a topic that's been covered here before, several times.
You'd want to save the delta values into an array, along with code to confirm an ~20ms repetition rate, and to resynchronize the table. With thought DMA could be used to decimate the interrupt loading. Your code appears missing an uu++