This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Trying to Synchronize Two Wide Timers

Other Parts Discussed in Thread: TM4C123BE6PM

Hi,

I am trying to synchronize two wide timers on a Tiva (TM4C123BE6PM) in PWM mode.  The functions used to initialize and synchronize the two timers are shown below (the functions are also called in the order given below):

void init50KHzPWM_Wide(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER1);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
    GPIOPinConfigure(GPIO_PC6_WT1CCP0);
    GPIOPinTypeTimer(GPIO_PORTC_BASE, GPIO_PIN_6);
    TimerConfigure(WTIMER1_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);
    TimerLoadSet(WTIMER1_BASE, TIMER_A, 1600);  //Count for 50KHz at 80MHz clock.
    TimerMatchSet(WTIMER1_BASE, TIMER_A, 800);  //50% duty cycle at init
    TimerEnable(WTIMER1_BASE, TIMER_A);
}

void init25KHzPWM_Wide(void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
    GPIOPinConfigure(GPIO_PC4_WT0CCP0);
    GPIOPinTypeTimer(GPIO_PORTC_BASE, GPIO_PIN_4);
    TimerConfigure(WTIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);
    TimerLoadSet(WTIMER0_BASE, TIMER_A, 3200);  //Count for 25KHz at 80MHz clock.
    TimerMatchSet(WTIMER0_BASE, TIMER_A, 1600);  //50% duty cycle at init
    TimerEnable(WTIMER0_BASE, TIMER_A);
}

void syncTimers(void)
{
    TimerSynchronize(WTIMER0_BASE, WTIMER_0A_SYNC | WTIMER_1A_SYNC);
}

This seems to be what the manual suggests (section 11.3.4).  I have tried a quiet a few other things, (for example to make a HWREG write to the GPTMSYNC register) in the syncTimers function, but I just can't get the two timers to synchronize.

Any help is appreciated.

Regards,

Anand

  • When all else fails - time to visit the driverlb - specifically timer.c, "TimerSynchronize()."

    Now - our group uses StellarisWare - not its replacement - and:

     void
    TimerSynchronize(unsigned long ulBase, unsigned long ulTimers)
    {
        //
        // Check the arguments.
        //
        ASSERT(ulBase == TIMER0_BASE);   // and you used "reasonable" WTIMER0!

        //
        // Synchronize the specified timers.
        //
        HWREG(ulBase + TIMER_O_SYNC) = ulTimers;
    }

    Do not know if your assertion is now "LEGAL" - your SW.  But quickly/easily tested/verified... 

    At the frequencies you employ - use of wide timers seems unnecessary - perhaps wasteful...

    Appears, "TIMER_O_SYNC" is a superior target for your desire...

    And note: timer.c lists this timer sync as, "not available - all parts..."

  • Hello Anand,

    As cb1 pointed out, the use of "WTIMER0_BASE" is illegal and should be "TIMER0_BASE". You can still synchronize the timers "WTIMER_0A_SYNC" and "WTIMER_0B_SYNC" (assuming this is what you are trying to do by looking at your code) but the base has to be "TIMER0_BASE".

    The description for GPTMSYNC  register (under section 11.6), in the datasheet, clearly states that "This register is only implemented on GPTM module 0" i.e. "TIMER0_BASE" in StellarisWare/TivaWare.

    Hope this clears any confusion!

    Regards,
    Sai
  • Hello cb1,

    Thank you so much for your reply.

    I verified the timer.c in the driverlib.  Indeed, the Tivaware also has the assertion.  And I did change the function call to:

    TimerSynchronize(TIMER0_BASE, WTIMER_0A_SYNC | WTIMER_1A_SYNC);

    and there is no effect.  I also tried synchronizing other timers (after the required initialization), both, wide and normal-width to check if the synchronizing works in general.  However, I could not achieve synchronizing between any two timers.

    Could someone from TI please verify that synchronization is possible across timer modules (wide and normal-width) on the TM4C123BE6PM?

    Some other points:

    1. The timer frequency values in my example code seem unnecessary, however, the frequency will be modified later in the application scenario.  It will drop to as low as 50Hz and 25Hz at some point in the application.  These values don't "fit" into a 16-bit width.  Hence the choice of wide timers.

    2. I didn't understand the "TIMER_O_SYNC" comment.  However, I tried using a "HWREG" to access "TIMER0_BASE+0x010" instead of the TimerSynchronize(..) function.  Still no effect.

    3. I did see the "not available - all parts" comment in the timer.c.  However, the TM4C123BE6PM datasheet specifies a GPTMSYNC register which means that this functionality must be present on the TM4C123BE6PM.

    Lastly, I would like to point-out a confusing aspect.  The CCS debugger shows a SYNC register for all the GPTM timers!  It even updates these values when a write is performed to these locations.  I don't know how this is possible.  Isn't the debugger suppose to read out the actual values from the registers using the JTAG chain?  How does it reflect something that is not supposed to be there!

    Thanks to cb1 and everyone who is patiently reading this post.

    Regards,

    Anand

  • ...just to update the post....

    I forgot to mention that the TIMER0 is enabled when the function -

      TimerSynchronize(TIMER0_BASE, WTIMER_0A_SYNC | WTIMER_1A_SYNC);

    is called.  I saw other posts on this topic:

        http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/p/258102/927211.aspx
        http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/258102.aspx

    and realized that TIMER0 needs to enabled even if it is unused in the application scenario.

    Hope to hear something on this post soon.  Just a simple mention that synchronization between GPTMs on TM4C123BE6PM has been successfully implemented by someone else will do.


    Thanks,

    Anand

  • Lights, Camera, SYNC!  (after a mere 50 minute battle...)

    Cannot comment upon your specific - nor any rebrand device - LX4F has attained your desired Sync.  Will post scope caps to confirm.  (shortly)  Did note several "unexpected" function handling requirements - checking now to see if these pass, "sanity check."

    Update: uh-oh - thrill of victory - not so much...  Appears to sync "randomly" - maybe 1 out of 5 scope caps.  Due to custom board routings - other signal demands - have tested just w/2 wide Timers.  Will shift to normal Timers - see if results improve.  (doubtful this can be completed - tonight... sorry...)

    Update_2: 22:27 CST - Have again been able to achieve Sync (2 Timers) - even w/one Wide_Timer @ 50Hz.  But - in this specific test case/methodology - restrictions are present.  Results are unexpected - will detail tomorrow for those interested - most likely later in the day...

     

  • Anand / cb1,

    Have you referred Page 21 of the errata for TM4C123x microcontrollers?

    I am able to synchronize the PWM signals of the WideTimer0/1 using a code similar to the one posted by Anand. The only modification (to cover the erratum) was to enable TIMER0 (using SysCtlPeripheralEnable()) and call TimerSynchronize() a second time by passing a "0" to the parameter ui32Timers.

    Hope this fixes the problem!

    Regards,
    Sai
  • @Stellaris Sai,

    We have no rebrand devices - all work done w/LX4F - as stated.  And - have tried "back to back" calls to TimerSync() - w/out notable success. 

    Update: just read - then applied your errata guidance - exact same "loss of sync quickly w/time continues." (as described in detail - below...)  And - disturbingly - we note that, "TIMER_SYNC_SYNCWT5" which our pre-errata addition had properly set to 0x03 is now set to 0x0 - thus should be, "out of sync!"  Again - ours is LX4F under StellarisWare_9453...

    I'd hazard the guess that you are not looking at the "edges" of each PWM signal - w/timebase set at/around 1uS/Div.  This should quickly/convincingly reveal that "sync" is - at best - transient.  We trigger our scope on the rising edge of the lower frequency PWM signal.  (we are testing @ 50 & 250Hz PWM frequencies - the eventual target of poster and other of our client interests)  Break from sync is fast - almost furious - even w/purported, errata claimed "fix!"

    That said - believe once again, "devil in the details" as regards Timer Sync.  Refer to Timer Section - our LX4F manual:

    10.3.4 Synchronizing GP Timer Blocks
    The GPTM Synchronizer Control (GPTMSYNC) register in the GPTM0 block can be used to synchronize selected timers to begin counting at the same time.

    So - multiple reports (not just here) of NO SYNC may in fact be, "imprecise definition" of the MCU's SYNC capability/performance.  Should there even be slight deviation in the frequency ratio between Timers - would not any reported, "loss of Sync" in fact be, "normal/expected?"  SW-DRL-UGxxxx and MCU manuals, "do not touch this issue/concern..." 

    Do note that boldface - after a serious review - we've found that the "Timer synchronization" will not "maintain" - and that even the slightest difference in frequency - or their integral multiple - will cause that synchronization to be lost with passage of time.  If you apply sync to Timers set @ 2X or 4X frequency ratio (and of course beyond) - my belief is that you will note that the sync is short-lived. This issue disappears when the same frequency is employed - @ each timer - but that appears to be too limiting for most.

    Suspect (know) you'll doubt - if you change the period even by 1 or 2 counts for one of the "Sync'ed Timers" - you'll immediately note our findings... 

    I'm gathering many scope traces - which support these findings - along w/StellarisWare codes which were employed during our testing.  Believe that we have "work-around" in the "works" - and that requires more time...

    One of our "attempts" involves periodic "recalls" of the SyncTimers function - unsuccessful thus far.

  • And - at long last - victory at hand.

    Credit Stellaris Sai for his errata identification - but note that the errata fails to detail the necessary, "How, Why and Where..."

    To that errata:

    Description: The GPTM Synchronize (GPTMSYNC) register allows software to synchronize a number of timers. The bits in this register should be self-clearing after setting bits to synchronize selected timers, but they are not.

    Workaround(s): When bits in the GPTMSYNC register are set, software must clear the bits prior to setting them for a subsequent update. When using TivaWare™ APIs, instead of just calling the TimerSynchronize() function once, software should call the function a second time with 0 as a parameter, as shown below:

    TimerSynchronize(TIMER0_BASE, TIMER_0A_SYNC | TIMER_1A_SYNC);
    TimerSynchronize(TIMER0_BASE, 0);

    And - adding this code alone - as shown above - "defeats" rather than corrects this SYNC Timer issue!

    Always unstated - (my read, > 10 MCU manuals + SW-DRL-UG9453) is the likely requirement to periodically call (thus updating) the TimerSynchronize() function.  This is nowhere mentioned!  And - the order shown above (directly from the published errata) is backwards - will surely "break" any/all Sync!

    And - adding to our fun - the frequency of these calls to, "TimerSynchronize()" must be carefully considered - and then test/verified.  Done improperly - the PWM frequency, duty cycle or both - may be altered!  Appears safest to make these calls at a frequency 1/2 or 1/4 of your lowest PWM frequency - but do test/verify...

    My suggestion - tested extensively now over the past 15 minutes - is to initially employ:

    TimerSynchronize(TIMER0_BASE, TIMER_0A_SYNC | TIMER_1A_SYNC);  // at tail-end of timer set-up

    and then to periodically make the call to:

                ROM_SysCtlDelay(333333);   // have placed delay here to facilitate testing
                TimerSynchronize(TIMER0_BASE, 0);
                TimerSynchronize(TIMER0_BASE, TIMER_0A_SYNC | TIMER_1A_SYNC);

    Again - this order is crucial - and is not that shown in vendor's errata.  Ending in "TIMER0_BASE, 0" will always break any SYNC!   Note that I've called that function before making the call to proper Sync.

    Have tested this now for > 30 minutes on LX4F - under StellarisWare 9453 - and Sync is Dead-On - no sign of earlier "drift" as past noted...

    In summary - the errata report - and the recognition/understanding of the periodic requirement to, "update Sync" - in the order shown here (not that w/in the errata) will enable Sync across multiple Timers even when (especially when) frequencies differ.  The requirement to periodically "recall" TimerSync() may not be intuitive - and minus that periodic recall - the initial Sync may often be lost...  (unless frequencies are precisely matched)

  • Hi,

    I don't actually remember how I ended up reading this, but I did anyway. I read through all the participants' comments and there's something I think you all might have missed (or then I'm just plain wrong).

    Thing is, I understand the timer counts beginning at the load value (1600 / 3200 in this case) and counts down all the way to zero (assuming count down-mode). This is inclusive both ends, so in fact it takes 1601 / 3201 clock cycles, respectively. Thus, the timer periods are no longer exact integer multiples of each other. With that kind of frequency, it doesn't take long for the "out of sync" to get substantial. Try setting 3201 as the load value for the 25 kHz PWM? That should result in 3202 clock cycles per period ( == 2 * 1601), and hopefully solve this.

    Best regards,

    Veikko

  • Indeed - without the proper sequence of calls to TimerSync() - loss of sync will occur.  That is why I made the time/effort to describe an exact procedure - differing from vendor poster and vendor's errata (and in fact correcting each) - after I physically confirmed the correctness of my theory and test methods.

    The proper rate of calling to TimerSync() does indeed overcome the issue you raise.  This is a necessary "evil" - required to insure Sync maintains.  All vendor manuals I've read make no mention of this proper, periodic recall necessity...

    Employing the technique I described - I was able to precisely sink signals @ 2:1, 3:1, 5:1, 10:1.  And then 5.5:1 - that being the real "proof" of sync.  Those signals are absolutely "locked" - when the Sync is correctly timed and provided.   (method you describe - not so much...)

    I would have posted detailed scope caps - but interest was so lacking/pathetic - I've moved on...  (even the originating poster abandoned...)  Other concrete structures beckon - welcome my (somewhat) hard head...

  • I fail to see how you would need to call TimerSynchronize() repeatedly. From an LM4F datasheet:

    "Setting a bit in the GPTMSYNC register causes the associated timer to perform the actions of a timeout event."

    Thus, every timer asked to do so, will reset it's value to either 0 or the load value (depending on the count mode) and then go on from there. The timers should then maintain synchronization, provided that:

    • They're being clocked from the same source (this should be obvious)
    • Their periods are EXACT integer multiples of each other - including the "roll-over cycle" from 0 to the load value or vice versa. For example, load values of 100 and 200 will not produce an exact multiple, but 99 and 199 will.

    On the other hand, if the periods are not exact multiples of each other, how are you supposed to maintain synchronization even in theory? Triggering on one signal will absolutely ruin other signals if the periods are not exact multiples.

    In addition, I think your statement about the order of calls to TimerSynchronize() is wrong. Calling it with a zero parameter does not have any effect on any timer, but it does clear the register. I think the errata is correct on that count.

  • My statements about vendor poster and vendor's errata are very much correct!

    You'd do well to "hook-up" make some experimental effort - as I did - over hours.

    Your "failure to see" indicates that you've not well read the detail - earlier supplied...

    Your "thoughts" (guesses!) versus hard work/thought - on actual hardware.  Not the fairest match...

  • Well guess what, I did hook up. A ye olde Stellaris Launchpad with LX4F120H5QR on board, and a Saleae Logic analyzer.

    Using Anand's code from post #1, I can easily see the waveforms shifting over time.

    However, changing the load values from 1600 to 1599 and from 3200 to 3199, the shift disappeared completely. Dead stable, without any subsequent synchronization needed.

    The other change I did to Anand's code is the syncTimers function:

    void syncTimers(void)
    {
        SysCtlPeripheralEnable(TIMER0_BASE);
        TimerSynchronize(TIMER0_BASE, WTIMER_0A_SYNC | WTIMER_1A_SYNC);
        TimerSynchronize(TIMER0_BASE, 0);
    }

    Fair enough?

    Edit:

    I also tested the 5.5:1 period ratio you state as being the "real proof of sync". Using otherwise identical code, but load values of 5499 and 999 (thus 5500 and 1000 clock cycles, thus a 5.5:1 ratio) the signals stay in perfect sync, without any subsequent calls to TimerSynchronize.