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.

Daisy-Chaining Timers Wait-on-trigger



I need a little help figuring out how to setup daisy-chaining timers.

I have an LM4F232 eval kit with a LM4F232H5QD microcontroller, and
I am trying to setup two timers. Timer 0 is setup to timeout at
1us. Timer 1 is setup to wait for Timer 0 trigger and count for 15.682ms.

Timer 1 does not wait for Timer 0 trigger and immediately starts
counting. I purposely disable Timer 0 in code but Timer 1 still
starts counting, so regardless of whether Timer 0 is disabled or
enabled, Timer 1 immediately starts counting. Please offer any
suggestions of my code or anything that I am missing to setup.

I have also checked the errats but no mention of daisy-chaining timers
other than making sure the timers are not in PWM mode.

Thanks in advance.


---------------------------------------------------------------------
//Clocking is set to run from the Main at 16 MHz.

//Enable Timer Peripherals
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);

//Configure Timer 0 - Periodic Count up for 1us
ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC_UP);
ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, 16);
ROM_TimerEnable(TIMER0_BASE, TIMER_A);

//Configure Timer 1 - Periodic Count up and wait for Timer 0 trigger
//Timer 1 set to 15.682ms timeout
ROM_TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC_UP);
ROM_TimerLoadSet(TIMER1_BASE, TIMER_A, 15682);
ROM_TimerControlWaitOnTrigger(TIMER1_BASE, TIMER_A, true);
ROM_TimerEnable(TIMER1_BASE, TIMER_A);
---------------------------------------------------------------------

  • Hello,

    I notice that you're enabling Timer 0 before Timer 1 is configured and enabled itself. Generally it is good practice to configure the timer that is being triggered before the timer that is doing the triggering. 

    In your case specifically, Timer 0 is set up to count to 16 clock cycles. The configuration steps for Timer 1 can take as many as ~40 clock cycles to execute. So before you even finish configuring Timer 1, Timer 0 has counted to 16 and has triggered Timer 1. By the time you enable Timer 1, it already has the trigger signal, and therefore starts counting immediately.

    My recommendation would be to order your configuration in this manner:

    [Configure Timer 1]
    [Configure Timer 0]
    [Enable Timer 1]
    [Enable Timer 0] 

    -David

  • David,

    I re-ordered my code per your suggestion. Here it is.

    //Enable Timer Peripherals
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);

    //Configure Timer 1 - Periodic Count up and wait for Timer 0 trigger
    //Timer 1 set to 15.682ms timeout
    ROM_TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC_UP);
    ROM_TimerLoadSet(TIMER1_BASE, TIMER_A, 15682);
    ROM_TimerControlWaitOnTrigger(TIMER1_BASE, TIMER_A, true);

    //Configure Timer 0 - Periodic Count up for 1us
    ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC_UP);
    ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, 16);

    //Enable the timers.
    ROM_TimerEnable(TIMER1_BASE, TIMER_A);
    ROM_TimerEnable(TIMER0_BASE, TIMER_A);

    The results are the same. In fact I comment out Timer 0 enable like below but Timer 1 still continues to start counting immediately.

    //ROM_TimerEnable(TIMER0_BASE, TIMER_A);

    Any other ideas?

  • How are you measuring/monitoring when the timers start counting?

    -David

  • Hi David,

    First of all - this is my understanding.

    Timer 0 counts at a rate of the 62.5ns which is the system clock cycle.
    Therefore, with a load value of 16 for Timer 0 it should generate a trigger event every 1us for Timer 1.

    I have an timeout interrupt handler installed on Timer 1 where it toggles a gpio pin and I monitor the output with a scope.
    If it is correctly triggered by Timer 0, Timer 1 should have a count rate of 1us.
    Therefore, with a load value of 15682 for Timer 1 it should produce a 15.682ms pulse width but it is not.

    In the case where I do not enable Timer 0, the output of the gpio pin should not be toggling - but it is. This tells me that Timer 1 is running.
    In the case where both timers are enabled, Timer 1 produces a pulse width of 0.98ms which is ruffly 15682 * 62.5ns and therefore is counting at the same rate as Timer 0 rather than waiting for the trigger event from Timer 0.

    Please correct me if I am incorrect on my explination or implementation.

    Thanks.

  • Note: Took quite awhile for me to come to good conclusion - please "skim" till you reach A-HA moment (below) for "real solution!"

    I'm wondering if your use of a "single" timer - employing TWO Timers (known as Split Pair - "A" and "B") might better achieve your goal? 

    I propose this change as I suspect that there may be higher odds of the daisy-chain "connectivity" you seek - w/in the same timer.  (and 16 bits - which each Split Timer provides - appears adequate for your needs)

    TIMER_CFG_PERIODIC = Full Width, periodic Timer ...  what you've done - creates just a single Timer

    TIMER_CFG_SPLIT_PAIR = TWO, Half Width Timers ...  my suggested alternative - creates TWO Independent Timers

    and then:  TIMER_CFG_A_PERIODIC ... configs one such timer  and TIMER_CFG_B_PERIODIC ... configs its "twin"

    I am uncomfortable with the use of a toggling bit/Led as "proof positive" that Timer1 is running.  We're not shown the code - thus are unable to comment.  What is the frequency of Timer1 when Timer0 is disabled?  (we're not told - thus far)  Might this provide a good clue?

    Suspect that your IDE's "monitoring" of key Timer1 Register values - would be far more effective measure of Timer1's operation.  IIRC - most ARM MCUs do not "bring out" a timer output pin.  (many simpler MCUs past - did)  Thus any output pin wiggle may be linked to effects beyond this timer...

    A-HA moment - think I see it: from SW-DRL-UG - Daisy Chain:   " Note:This functionality is not available on all parts. This function should not be used for Timer 0A or Wide Timer 0A."  This advisory w/in the TimerControlWaitOnTrigger() function.  You may be better advised to thus use/try Timers1 and 2 - avoid Timer0 for this daisy-chain mode...  (how could you have known?  I had to really dig...)

    And from my LX4F MCU Datasheet (not same as yours - check!) - "WAIT for TRIGGER MODE:  Wait-for-Trigger mode is enabled by setting the TnWOT bit in the GPTMTnMR register. When the TnWOT bit is set, Timer N+1 does not begin counting until the timer in the previous position in the daisy chain (Timer N) reaches its time-out event. The daisy chain is configured such that GPTM1 always follows GPTM0, GPTM2 follows GPTM1, and so on.  Thus I am more convinced that my advice to avoid Timer0 (from above) and instead use Timer1 and Timer2 - will solve your problem.  You also must insure that the TnWOT bit - as indicated herein - is set.

    Your kindness in awarding "Verified Answer" gratefully appreciated.  (believe this one - well earned)

     

  • cb1- said:

    A-HA moment - think I see it: from SW-DRL-UG - Daisy Chain:   " Note:This functionality is not available on all parts. This function should not be used for Timer 0A or Wide Timer 0A."  This advisory w/in the TimerControlWaitOnTrigger() function.  You may be better advised to thus use/try Timers1 and 2 - avoid Timer0 for this daisy-chain mode...  (how could you have known?  I had to really dig...)

    And from my LX4F MCU Datasheet (not same as yours - check!) - "WAIT for TRIGGER MODE:  Wait-for-Trigger mode is enabled by setting the TnWOT bit in the GPTMTnMR register. When the TnWOT bit is set, Timer N+1 does not begin counting until the timer in the previous position in the daisy chain (Timer N) reaches its time-out event. The daisy chain is configured such that GPTM1 always follows GPTM0, GPTM2 follows GPTM1, and so on.  Thus I am more convinced that my advice to avoid Timer0 (from above) and instead use Timer1 and Timer2 - will solve your problem.  You also must insure that the TnWOT bit - as indicated herein - is set.

    The TimerControlWaitOnTrigger() function sets the TnWOT bit for the specified timer. So calling it like Jaime does above should be setting the bit for Timer1. For sanity, it is a good idea to check the register anyway.

    The statement "This fucntion should not be used for Timer 0A or Wide Timer 0A" does not imply that Timer 0 should be avoided. It only means that Timer 0A can't "Wait on Trigger" since it is the first timer. It can definitely trigger Timer 1, like Jaime is trying to do.

    Jaime,

    What I think may be happening, at least for the scenario where both timers are enabled, is that you're repeatedly triggering Timer 1 before it ever finishes counting. You have Timer 0 set to periodically count to 16. Every 16 counts it triggers Timer 1. Timer 1 is set to count to 15682, but it only gets as far as 16 before another trigger signal comes in from Timer 0. I'm not sure how the internals work with the timer (I would have to pin down one of the designers) but I would bet that an incoming trigger before Timer 1 is finished will just restart the count.

    Try making your Timer 0 count larger than your Timer 1 count and look to see if the behavior matches what you'd expect. 

    Also, unless you are disabling the timers in your interrupt handlers, the timer will continue to count. Even if you do disable the timers, the function/interrupt entry cost in system clocks is approximately 7 clocks in and 7 clocks out. 16 ticks on your timer is VERY close to the 14 required to enter and exit a function call, so I don't think you're measuring the timer activity accurately. 

    My suggestion is to increase the counts to at least verify the proper behavior.

    -David

  • Stellaris David said:
    does not imply that Timer 0 should be avoided.

    While I accept your position - cannot agree that the "implication" does not exist.  And my suggestion of Timer1 & Timer2 is quick/easy to set-up and test/verify.

    Believe that you do not address the stated fact that Timer1 does appear to, "complete its count" - and toggle!  If - as you suggest - this timer continually "restarts its count" - NO such toggling would occur.

    Further (fm. Jamie's intiial post) - " I purposely disable Timer 0 in code but Timer 1 still starts counting..." seems to significantly undercut the, "repeated restart' theory - does it not?  (i.e. with Timer0 disabled - no such "restart trigger" could be generated - yet poster reports Timer1 still counting...)

    I'm jammed right now - would attempt this w/ Timer1 & Timer2 - perhaps later unless we can resolve.

    Yours are good, thoughtful points - but clearly the datasheets (both SW-DRL-UG and MCU) should better detail and address this issue.  Forcing such "extra effort" upon motivated users is less than ideal...  (of course - you had nothing to do with this - but some clarity is needed...)

    Disappointing that earlier "official" post received, "suggested answer" tick - yet mine (crafted w/equal effort/imagination) remain relegated to, "wasteland."

  • Thanks for all the suggestions.

    I have taken all the suggestions but Timer N+1 always starts running.
    I have used Timers 2 and 3, Timers 4 and 5, and also different pairs of Wide Timers. I've also configured them in both individual and concatenated modes. Used one-shot or periodic (up/down). Used larger per-loaded values in Timer N than in Timer N+1. The results is still the same. It doesn't matter which Timer N+1 I set to wait on Timer N, Timer N+1 never waits on trigger from Timer N. I have even left Timer N disabled, but Timer N+1 still starts to count. To verify that Timer N+1 is counting, I setup a time-out interrupt which toggles a gpio pin and it is always toggling.

    What I don't get is - why does Timer N+1 start counting when its TnWOT bit is set and Timer N is disabled?

    Perhaps I am leaving some setup out which I don't know about.

    Thanks again for all your inputs.

  • Ratz!   (strong message to follow)   You've tried hard - presented detail - and we know this daisy-chaining to work well w/far simpler MCUs.

    May I suggest that you (temporarily) break the Timer N+1 "daisy chain LINK" to Timer N - and then check to see if Timer N+1 still runs.  Suspect it will be insightful to get one higher order (Not T0) Timer properly responding/commanded - and then return to the battle of daisy-chaining.

    With the weekend coming - I'm sure to have time (will make sure) to replicate your code on our LX4F (64 pin) - and see if I can resolve this.

    Do thank you for attempting w/the higher order timers - absolutely hate it when time/effort are "blown up" due to strange, "anomaly" - and you've now removed that from our, "field of play."

    One item of interest (to me - at least) still open - please explain how you "know" that Timer N+1 is indeed toggling.  It may be that we're not looking in the right area - based upon complex assessments - which are possibly incomplete or suffer some error.  (earlier I suggested use of the IDE's Register View - to observe the Timer's "Action.")  Suggest that this, "toggle rate" be slowed - so as to be more visible to both the IDE and human observer...

  •     Latest interesting update.
        Below is some timer code using Timer 3 where A and B are individual 16bit timers.   

        First I selecting Mode 1 where Timer 3-B is periodic up counter.
        I load this code using IAR Workbench and set a break point on the While(1) loop.
        You will notice that the Timer 3 TAR, TBR, TAV, and TBV registers are all zeros.
        By clicking repeatedly on the run button you will see that TAV increments while TBV does not. (So far so good).
        When TAV reaches its load value of 60 and resets to 0, TBV then starts incrementing. (So far so good).
        While TAV continues to increment, TBV reaches its load value of 10 and resets to 0; however, TBV
        continues to increment and does not stop and wait for TAV to reach its load value again to trigger B.
        Since TAV has not reached its load value of 60 when TBV resets to 0, I would expect TBV to stop and
        wait for the trigger from timer A.

        Second I select Mode 2 where Timer 3-B is a One-Shot up counter.
        Code is loaded and a break point is set on the While(1) loop.
        Clicking on the run button repeatedly, everything works exactly as describes above except when
        TBV reaches its load value and resets to 0, it never counts again even though TAV reaches its
        load value and resets to 0 several times. I would expect that TBV would trigger again once TAV
        reaches its load value and resets to 0 again.

        I suppose these results are correct, otherwise what would be the difference between
        periodic and one-shot - if they both reached their load value, reset, and where triggered again.
        However, an interesting question does come to mind, how do I reset Timer B to trigger again in
        One-Shot mode or if I wanted to use it again in periodic mode? Do I disable it and then enable it or is there a
        register somewhere that I need to clear?


        //Configure Timer 3 Peripheral
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER3);
        ROM_IntMasterEnable();
        //
        // Configure for two 16-bit timers.
        //
        //Disable Timers
        TimerDisable(TIMER3_BASE, TIMER_A);
        TimerDisable(TIMER3_BASE, TIMER_B);
        //Clear the A and B value registers so they start at zero
        TIMER3_TAV_R = 0;
        TIMER3_TBV_R = 0;

        //Choose the mode for Timer B by removing the // in fron of TimerConfigure(...)
       
        //Mode 1
        //Timer B is Periodic Up counter
        //TimerConfigure(TIMER3_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC_UP | TIMER_CFG_B_PERIODIC_UP);

        //Mode 2
        //Timer B is One Shot Up counter
        //TimerConfigure(TIMER3_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC_UP | TIMER_CFG_B_ONE_SHOT_UP);

        //Timer B   
        TimerLoadSet(TIMER3_BASE, TIMER_B, 10);
        TimerControlWaitOnTrigger(TIMER3_BASE, TIMER_B, true);
        TimerControlStall(TIMER3_BASE, TIMER_B, true);  
     
        //Timer A
        TimerLoadSet(TIMER3_BASE, TIMER_A, 60);
        TimerControlStall(TIMER3_BASE, TIMER_A, true);
       
        //Enable Timers
        TimerEnable(TIMER3_BASE, TIMER_B);
        TimerEnable(TIMER3_BASE, TIMER_A);
        while(1);

  • Thanks for this - also have IAR so will include pertinent, "screen caps" should my efforts bear fruit.

    I'm going to do full search (daisy chain) w/in SW-DRL-UG & my LX4F MCU Datasheet.  Also will review past success w/daisy chain using Zilog MCU.  (how delightful)

    Have other commitments now - will try to post here prior to this evening...

  • Greetings - afraid not the best news.  Essentially duplicated your findings - modifying only the Timer pins - on our custom (64 pin LX4F pcb).  (other usage confined my investigation to PF_3 and PF_4 - where PF_4 is T2CCP0 and PF_3 is T1CCP1)  My MCU datasheet indicates that Timer B (T1CCP1) can  trigger Timer A (T2CCP0) 

    Here's the confirming quote from my datasheet, "If Timer A is configured as a 16-bit (16/32-bit mode) or 32-bit (32/64-bit wide mode) timer, it triggers Timer B in the same module, and Timer B triggers Timer A in the next module."  Again I did this due to HW constraints on my custom board.

    I sought to eliminate interrupts - and their handling - as a source of error/added complexity.  That same datasheet page goes on, "This function is valid for one-shot, periodic, and PWM modes."  Both quotes are contained w/in 10.3.3 "Wait-for-Trigger Mode."  Now I seized on PWM mode - as I've used that w/great success for fast/eased PWM generation via the Timer.  And - as it quickly/easily enables direct timer output to the targeted timer pin.  (thus - no interrupt required)

    And - after multiple tests - with Timer N loaded with both larger and smaller values than N+1 - no success what-so-ever in achieving anything approximating either a cascade or daisy-chain.  Here's my code - note I commented many functions "in/out" extensively - could find no combination which worked...

    However - I tried repeatedly - with your exact code too (w/Timers translated to be compatible w/my board) - and failed just as you noted!

    void
    daisy_timer_setup(void)
    {

            HWREG(GPIO_PORTF_BASE + GPIO_O_AFSEL) &= ~0x18;  // 0x18 = PX_3,4

            HWREG(GPIO_PORTF_BASE + GPIO_O_DIR)   |= 0x18;   // bits 3,4 OUT
           
            HWREG(GPIO_PORTF_BASE + GPIO_O_DEN)   |= 0x18;   // bits 3,4 enabled
       
            HWREG(GPIO_PORTF_BASE + GPIO_O_DR8R)  |= 0x18;   // 8mA drive i
    }


    void
    timer_test(void)
    {
     
       ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
       ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);

       ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

       ROM_GPIOPinConfigure(GPIO_PF4_T2CCP0);

      ROM_GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_4);
     
      ROM_GPIOPinConfigure(GPIO_PF3_T1CCP1);

      ROM_GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_3); 

    //Configure Timer 2 - PWM - direct output to PF_4
    //Timer 2 set to 200uS timeout
     ROM_TimerConfigure(TIMER2_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);
     ROM_TimerLoadSet(TIMER2_BASE, TIMER_A, 10000);
     ROM_TimerMatchSet(TIMER2_BASE,TIMER_A, 5000);
     ROM_TimerControlWaitOnTrigger(TIMER2_BASE, TIMER_A, true);

    //Configure Timer 1 - PWM - direct output to PF_3
    //Timer 1 set to 10uS timeout
     ROM_TimerConfigure(TIMER1_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PWM);
     ROM_TimerLoadSet(TIMER1_BASE, TIMER_B, 500);
     ROM_TimerMatchSet(TIMER1_BASE,TIMER_B, 200);

    //Enable the timers.
      ROM_TimerEnable(TIMER1_BASE, TIMER_B);
      ROM_TimerEnable(TIMER2_BASE, TIMER_A);

    }

    Without use of "TimerMatchSet()" - I could not get either timer to sustain.  As you reported - commenting out the "Enable" of lower order Timer N - had no effect on the N+1 Timer in the chain - it continued merrily along!   TimerControlWaitOnTrigger() produced no linkage between Timers - despite my best efforts.

    I would submit that some, slight, further, explanation/detail is indicated so that average user may utilize this, "Wait for Trigger" Timer function.  The 8 or so sentences w/in the datasheet have failed both you and I...