2012-04-22 11:52 AM
Hi,
working with the STM32F103 processor, I`m searching for a solution to sychronize a STM32 timer to an external input signal. This signal has a constant frequency of e.g. 24Hz or 30Hz. Using a input capture timer I`m able with the help of ''clive1'' to receive every piece of this input signal. Now I want to transmit this received signal again. Unfortunately not with the same frequency as the input signal frequency. The frequency of the output signal is 8x the input frequency, which means I need another timer to generate this frequency. This timer must be synchronized to the input capture timer. At the moment I start a second timer for the output frequency with the 8x frequency of the input signal. I know the input frequency from the input capture timer (delay between two received pkts). If I receive the first pkt after the initialization the second timer, I reset the second timer TIM2->CNT register to acchieve a synchronization. But this dosen`t work, because after a short time (about 5mins) the input signal is no longer synchronize to the output signal. In my main routine: while(1) { /*syncFlag is at startup = 1 to sync the second timer to the input capture timer. If I recvd a new pkt the flag ''captureFlag'' will be set to one in the ISR */ if((syncFlag) && (captureFlag)) { /* received a new input pkt -> get this pkt */ GetRcvdInputSignal(); /* reset timer2 */ TIM2->CNT = 0; /* clear all flags */ captureFlag = syncFlag= 0; } else if(captureFlag ) { GetRcvdInputSignal(); captureFlag = 0; } /* timer2Flag is the flag from the second timer which will be set in the ISR */ if(timer2Flag) { TxdSignal(); if(SignalOutofSync()) { /* input signal no longer in sync with the output signal */ //error } timer2Flag = 0; } } I hope you can give me some hints to acchieve a proper synchronization between the input & output signal. Because I think I didn`t use the right way at the moment. best regards Hans2012-04-22 01:07 PM
I'm not sure if the ''loss of synchronization'' you are describing is just clock drift.
Clocks generated from different sources are notoriously difficult to keep in sync because they all have their own error and drift, this accumulates as a bias as one signal walks away for the other. This is compounded by the granularity by which you can control the generation of the output signal, and the fact the STM32 only provides you with integer division. Basically you need handle the fractional error, and how it accumulates. Say the counter typically cycles 0 thru 999, over some update periods you might want a 0..998 or a 0..1000 to account of the accumulating error. If you measure the output you might expect a saw-tooth where the period increases, and then snaps back by the granularity. At 72 MHz this jump is 13.889 ns, with a drift of 1 nanosecond per second, you have to correct every ~14 seconds to keep the output from walking away from the desired frequency output, this will introduce phase noise, which you should be able to see as jitter in the duty cycle on a scope. Depending on the application this also might be undesirable. Ideally you want all the clocks derived from this single 72 MHz (or whatever it is in actuality, figure error, aging, thermal drift, etc), that way at least you have chance of the remaining in sync over the long haul without continually having to discipline them.2012-04-22 01:31 PM
The loss of synchronization is the clock drift and maybe the synchronization at startup. I don`t know if it`s the right way to reset the CNR register of the timer if the first input signal is received. Or if there`s a much better synchronization method.
According to the clock drift: If the input signal has the frequency 30Hz, then the timer period for the second timer is [0, 2399]. I can read out the CNT register if a new pkt is recvd and I will notice that the CNT register value isn`t 2399 or 0. For example the CNT register value is 0x15 which means that the timer2 is too fast. So is it correct if I reset the CNT register (TIM2->CNT = 0;)? Or is there another algorithm to accumulate the error? while(1) { /*synchronization init phase */ if((syncFlag) && (captureFlag)) { /* received a new input pkt -> get this pkt */ GetRcvdInputSignal(); /* reset timer2 */ TIM2->CNT = 0; /* clear all flags */ captureFlag = syncFlag= 0; } else if(captureFlag ) { /* @30Hz * 8 -> timervalue = [0, 2399] */ unsigned short timervalue = TIM2->CNT; /* reset CNT register */ TIM2->CNT = 0; GetRcvdInputSignal(); captureFlag = 0; } /* timer2Flag is the flag from the second timer which will be set in the ISR */ if(timer2Flag) { TxdSignal(); if(SignalOutofSync()) { /* input signal no longer in sync with the output signal */ //error } timer2Flag = 0; } }2012-04-23 06:10 AM
I suggest the following:
After the second input signal interrupt (when you know the frequency), start TIM2 to generate 8 pulses, then disable it. Then for each input signal interrupt, repeat the frequency calculation and start TIM2 again.There will be a small delay between input and TIM2 first pulse, but there should be no long term drift. Cheers, Hal2012-04-23 10:01 AM
Hi Hal,
could you explain your idea a little bit closer to me? I don`t understand the meaning of it. The frequency of the input signal is always 24Hz or 30Hz. I noticed only that the signal has a big jitter of round about 0.5ms. while(1) { /*syncFlag is at startup = 1 to sync the second timer to the input capture timer. If I recvd a new pkt the flag ''captureFlag'' will be set to one in the ISR */ if((syncFlag) && (captureFlag)) { /* received a new input pkt -> get this pkt */ GetRcvdInputSignal(); /* reset timer2 */ TIM2->CNT = 0; /* clear all flags */ captureFlag = syncFlag= 0; } else if(captureFlag ) { GetRcvdInputSignal(); captureFlag = 0; } /* timer2Flag is the flag from the second timer which will be set in the ISR */ if(timer2Flag) { TxdSignal(); if(SignalOutofSync()) { /* input signal no longer in sync with the output signal */ unsigned int timervalue = TIM2->CNT; if(timervalue < 30) { TIM2->CNT--; } else if (timervalue > (MAX_CNTRVALUE - 30) { TIM2->CNT++; } else { /* timervalue = 0; */ } } timer2Flag = 0; } }2012-04-24 05:49 AM
Perhaps this rewording will be more clear:
After the second input signal interrupt (when you know the frequency), start TIM2 to generate 8 pulses, then disable TIM2 when the 8 pulses complete. Then for the third and following input signal interrupts, repeat the frequency calculation and start TIM2 again, disabling it after 8 pulses.There will be a small delay between input and TIM2 first pulse, but there should be no long term drift, since TIM2 is started each time in sync with the input. But now you mention you have .5 ms jitter on the signal. My recommended method will also have that jitter at the start of each group of 8. You will have to decide if that is acceptable. If it is not acceptable, you have a design challenge to filter this input jitter. Cheers, Hal2012-04-24 07:53 AM
Hi Hal,
alright, now I understand your approach to be in sync with the input signal by starting and stopping the timer after every 8x input pkts. If I want to reduce the jitter. Is it possible by software? Or do I need to add additional hardware components?2012-04-25 10:59 AM
Removing the jitter at the source will fix the problem. You will have to decide if that is possible.
Software filtering is not simple. A Kahlman filter on the input signal period capture count will determine (after some captures) when the signal should arrive jitter free. Then you need to adjust when TIM2 is enabled to resync with each filter update. To avoid the impossible task of a negative time adjustment, delay the TIM2 enable by one output pulse. Other forum viewers may have a simpler solution. Cheers, Hal2012-08-24 02:58 PM
''start TIM2 to generate 8 pulses, then disable TIM2 when the 8 pulses complete.''
How exactly do you do this? When I try to do something like this with an interrupt handler (and a counter), I overshoot and get a few extra lagging pulses that sneak out before I've had the chance to completely shut down the timer in the interrupt.2012-08-24 04:26 PM
What kind of frequency are you talking about?
In PWM mode you can pull the width to zero so it latches on the next update, to effectively turn off a clock output without killing the timer completely, and turn it back on in a similar fashion. Your on/off points will be at the update interval, having finer granularity would take some work. Now admittedly the period needs to be longer than the interrupt latency, but I suspect KHz is doable. For higher frequency the repetition count looks to be the way to go.