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.

TM4C123GH6PM: How to "restart" a General Purpose Timer?

Part Number: TM4C123GH6PM

I am trying to use a General Purpose Timer peripheral to respond to a timeout condition. That is, in the absence of a certain event in a given length of time, the timer should trigger an interrupt.

The way I've always done this on other MCUs is to set up a Timer to generate a periodic interrupt. So for example if the event is expected to occur every 950 uS, I might configure a periodic timer to trigger an interrupt every 1 ms. But I never allow that interrupt to trigger: Every time the event in question occurs, the event handler restarts the timer (sets its counter back to 0 or maximum depending on count direction). If the event does not occur, the timer "times out" and triggers the interrupt, which handles the lack of event.

I'm trying to do this with TivaWare. My line of thought is to restart the timer (and therefore prevent triggering the interrupt) by loading the start value into GPTMTAV every time the event occurs.

My questions:

1. Is this the correct way to "restart" the timer back to the beginning?

2. If so, TivaWare provides a function TimerValueGet() but does not provide a function TimerValueSet(). Is there a TivaWare function that accomplishes what I want?

  • Wouldn't one shot mode make more sensefor this?

    Robert

    Or better, a proper system event timer system?
  • twelve12pm said:
    ...TivaWare provides a function TimerValueGet() but does not provide a function TimerValueSet().    Is there a TivaWare function that accomplishes what I want?

    I believe so - yet due to your experience & savvy - it is troubling that you (appear) to have "missed" this.     (Note: my firm employs (only) past StellarisWare 9453 (which was believed to be "bullet-proof" - newer incarnations - "Not so much!")    Perhaps this (answering) function - resident w/in StellarisWare - did not "pass thru" to your "newer" API.

    I submit, "TimerLoadSet()" - as excellent (and intended) to satisfy your requirement.    

    Follows the detailed description of this function.     (hopefully this function "did" survive into the newer API...)

    27.2.2.17 TimerLoadSet
    Sets the timer load value.

    Prototype:
    void
    TimerLoadSet(unsigned long ulBase, unsigned long ulTimer, unsigned long ulValue)

    Parameters:
    ulBase is the base address of the timer module.
    ulTimer specifies the timer(s) to adjust; must be one of TIMER_A, TIMER_B, or TIMER_BOTH. Only TIMER_A should be used when the timer is configured for full-width operation.
    ulValue is the load value.

    Description:
    This function configures the timer load value; if the timer is running then the value is immediately loaded into the timer.     (i.e.  "just as you desired" - mais oui?)

    Note:
    This function can be used for both full- and half-width modes of 16/32-bit timers and for half-width modes of 32/64-bit timers.    Use TimerLoadSet64() for full-width modes of 32/64-bit timers.

    Returns:
    None.

  • Cannot "get back in" to my post (just above) - due to: "forum upgrade(?); wrist-sprain causing "one-hand" typing; diminshed server number/quality due to "late" hour...

    Revealed here - the essence of the, "TimerLoadSet()" function - do note that it operates upon (NOT) "GPTMTAV" (Register you noted) - instead upon "GPTMTAILR" (or GPTMTBILR).     

    Register "GPTMTAV" to my understanding - reveals the Timer's current, free-running value.    (which is NOT what you require!)    

    Register "GPTMTAILR" (or its "B" version) loads the Timer's "Starting Count Value" - which IS what you seek.   (IMO)

    Review of "timer.c" source - w/in StellarisWare 9453 reveals:

    // Set the timer A load value if requested.
    //
    if(ulTimer & TIMER_A)
    {
    HWREG(ulBase + TIMER_O_TAILR) = ulValue;
    }

    //
    // Set the timer B load value if requested.
    //
    if(ulTimer & TIMER_B)
    {
    HWREG(ulBase + TIMER_O_TBILR) = ulValue;
    }

    Again - while firm/I have long migrated to another's Cortex M7 (>200MHz & Graphic HW Accelerator) I do believe "TimerLoadSet()" proves, "Good for Gov't (or your) Work!"

  • Dear cb1_mobile,

    Thanks so much for your help as always.

    I was under the impression that the GTPMxILR register (and thus TimerLoadSet()) sets the count that gets loaded into the counter when the clock starts a new cycle. I think (but I am not sure) that this will result in the clock passing through 0 and triggering its interrupt, which is not what I intend. But I'm a TM4C n00b so I'm going to test this and I'll be back here soon with the outcome...

    Sorry to hear about your wrist.

  • Robert, Under most circumstances I would use a software event timer system as you suggest. I always implement a "low resolution" tick timer used for non-critical timing and timeouts, where a bit of skew is acceptable. In this particular case, though, the event in question is periodic and each time it does not occur it must be compensated for by our alternate event in a deterministic amount of time.
  • Hello twelve12pm,

    Perhaps I can help clarify a bit on the expected behavior if using the TimerLoadSet (which, by the way cb1, does indeed function the same in TivaWare!)

    From Section 11.3.2.1 of the device Datasheet:

    If software updates the GPTMTnILR or the GPTMTnPR register while the counter is counting down, the counter loads the new value on the next clock cycle and continues counting from the new value if the TnILD bit in the GPTMTnMR register is clear. If the TnILD bit is set, the counter loads the new value after the next timeout.

    The key here is the TnILD bit. If you ensure the bit is clear, yes it will make one more clock cycle to apply the new value, but at that point the counting will occur from the new value and thus should not trigger your interrupt (unless that singular clock cycle was the tipping point for the interrupt to occur which it sounds like you avoid by adding buffer time per your initial description). However, if you were to have the TnILD bit set, then it would indeed continue on counting until triggering an, in this case undesired, interrupt. So you should find that so long as the TnILD bit is cleared, you would get your intended behavior.

    Let us know how the testing goes to verify this.

  • Before I tested TimerLoadSet() (which I will do shortly) I performed another search for TimerValueSet() through all files in the TivaWare installation directory. I found something interesting...

    There is a file C:\ti\TivaWare_C_Series-2.1.4.178\nfclib\directmode.c

    It contains this code:

    //*****************************************************************************

    //

    // Set timer value.

    // This function is missing from the StellarisWare timer API, so here it is

    // as a macro

    //

    //*****************************************************************************

    #define TimerValueSet(ulBase, ulTimer, ulValue)                               \

       HWREG((ulBase) + ((ulTimer)==TIMER_A ? TIMER_O_TAV : TIMER_O_TBV)) =      \

           (ulValue)

    So this appears to confirm my earlier thinking that this function is missing from TivaWare...

  • This makes sense. The datasheet makes more sense now, having read your explanation. Unfortunately, that section of the datasheet is difficult to understand because so many different explanations are commingled together.

    I have a further question: I am using a 80 MHz system clock and setting the timer period to 1 ms, which translates to 80,000 clock ticks, or 0x13880, which requires a 24-bit value. When I configure the timer at startup, the 0x01 is written to GPTMTAPR by a call to TimerPrescaleSet() and the 0x3880 is written to GPTMTAILR by a call to TimerLoadSet(). When I wish to restart the timer, is it necessary to set both GPTMTAPR and GPTMTAILR (i.e., call both functions to restart the timer) or is it enough to only set GPTMTAILR by calling only TimerLoadSet()?
  • I experimented further. It appears necessary, because of the 24-bit count, to load both GPTMTAPR and GPTMTAILR.

    Thanks very much to cb1_mobile, Ralph, and Robert for all your help.

  • May I suggest a means (fitting w/in KISS - Always) to speed/simplify/enhance?

    Your selection of a "32 bit" Timer would avoid the complications added by any prescale.    (and while LIKE (newly banned here) and KISS (forever banned here) stand rejected by vendor - they have enabled "thousands" to, "systematically drive toward success!"

    Thanks for your kind "reward" - PITY that the "encouraging, peer-affirming LIKE" has (unjustifiably) departed this "Vale of Tears!"

    KISS and StellarisWare 9453 (only "bullet-proof"API version supporting: LM3S, LX4F, TM4C123) RULE...       (Note: TM4C123 supported w/in Ver 9453 via simple addition w/in pin_map.h)

  • You're right. 32-bit would solve that. Or, I could continue using a 16-bit timer but switch to Periodic rather than PWM mode. I'm not outputting the waveform on a pin; rather, I'm only using this timer to generate the interrupt. If my understanding is correct, in Periodic mode when counting down, the prescaler is a true prescaler and therefore I would only need to use TimerLoadSet(). I'll try this next and let you know how it goes.

    I was wondering what happened to that LIKE button. :-(
  • twelve12pm said:
    I was wondering what happened to that LIKE button. :-(

    I generated a protesting/questioning post - w/in Day 2 of the "Banning" - and was presented, "Neophyte users (those most unlikely to (ever) employ "LIKE") were "confused" - thus "LIKE" suffered beheading."   (Vendor language - tiny bit more - "corp speak" than my own...)   

    Famed Forum Posters "Robert & (even) Jens" attended the "viewing" (organized by moi) and equally "documented their protest!"     We are gathered here not to mourn "LIKE" but to PRAISE "LIKE!"      Say - did the "coffin lid" just (bit) raise?     (while the "lights went down" - in Dallas...)

    I believe that you've NO Need for PWM Mode - your existing Periodic (or Robert's "One Shot") will work - although I believe the function TimerLoadSet() - especially if you employ "Down Count" - proves the best (most eased) satisfaction of your requirement...

  • That's funny considering that just about all the popular websites have "like" buttons.
  • cb1_mobile said:

    I believe that you've NO Need for PWM Mode - your existing Periodic (or Robert's "One Shot") will work - although I believe the function TimerLoadSet() - especially if you employ "Down Count" - proves the best (most eased) satisfaction of your requirement...

    Ok! Periodic mode is working like a charm. To restart the timer I need only call TimerLoadSet() now. No need to also call TimerPrescaleSet(). And I'm still working with only half the timer (16-bit mode) to preserve more timers for other things.

    Just for reference and to help anyone who might need it in the future, I setup the timer as follows:

    Periodic mode, split timer (16-bit, Timer B in this case), count down to get true prescaler, TnILD bit in GPTMTnMR register is clear to make TimerLoadSet() work as desired, prescaler set once at system initialization, period (GPTMTnILR) set at system initialization and set again whenever we wish to restart the timer.

    Some defines that appear in the following code:

    #define SYSTEM_CLOCK_FREQ_HZ       80000000

    #define M_TMR_FREQ_HZ              1000

    #define M_TMR_PRESCALER            10

    #define M_TMR_INPUT_FREQ_HZ        ((SYSTEM_CLOCK_FREQ_HZ) / (M_TMR_PRESCALER))

    #define M_TMR_PERIOD               ((M_TMR_INPUT_FREQ_HZ) / (M_TMR_FREQ_HZ))

    #define M_TMR_INTERRUPT_PRIORITY   3

    Initialization of the timer:

    SysCtlPeripheralDisable(SYSCTL_PERIPH_TIMER1);

    SysCtlPeripheralReset(SYSCTL_PERIPH_TIMER1);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);

    while (SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER1) != true) {

    // Wait for peripheral to activate

    }

    // Configure half timer as periodic

    TimerConfigure(TIMER1_BASE, (TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PERIODIC));

    // Very important: Make sure call to TimerLoadSet() will restart timer on next clock

    TimerUpdateMode(TIMER1_BASE, TIMER_B, TIMER_UP_LOAD_IMMEDIATE);

    // Set prescaler

    TimerPrescaleSet(TIMER1_BASE, TIMER_B, (M_TMR_PRESCALER - 1));

    // Set period

    TimerLoadSet(TIMER1_BASE, TIMER_B, M_TMR_PERIOD);

    // Set interrupt priority

    IntPrioritySet(INT_TIMER1B, M_TMR_INTERRUPT_PRIORITY);

    // Enable interrupt

    TimerIntEnable(TIMER1_BASE, TIMER_TIMB_TIMEOUT);

    IntEnable(INT_TIMER1B);

    // Enable Timer

    TimerEnable(TIMER1_BASE, TIMER_B);

    When I want to restart the timer, preventing timeout interrupt:

    TimerLoadSet(TIMER1_BASE, TIMER_B, M_TMR_PERIOD);

    I agree they should bring back the Like button. It should also function like a bookmark so that you can go back and easily find posts you've liked, to refer to them later.

  • Good for you - and the care, effort & detail w/in your post is "sure" to multiply its value!
    Vendor's Ralph raised a good point re: "TnILD" - I cannot recall if our (older) API included the function you (alone) found & deployed, "TimerUpdateMode()" - it is "very Kool" when the "student over-takes the teacher!"   (and does NOT "rub it in" - too badly!)

    Your bookmark idea displays "great" creativity - in my firm's case - we "Copy/Paste" such "enhanced code blocks and/or operating tips" into a shared Word file - with each new entry tightly organized by subject. (we note vendor's "tags" (primarily advertising) prove woeful - thus my frequent creations - which better represent "tech-aid reality.")

    The ability to quickly/easily "find key tech data" - so vital to the success & growth of small tech business - appears (almost) "lost in space" here - while uber useful (not) "Blogs, Groups, Video" enjoy "beach-front location" - to (near) zero visitors!    (hiding vital tech data may NOT make great sense - user knowledge would be greatly enhanced if vendor's "style guide could mature - include most all Tech DATA - up top (w/in the pristine Red-Stripe (beach-front) real estate."    (just another outrage practiced by the "LIKE-less crüe!")

  • It is difficult to find the right tech data. Searches often turn information either too basic or too advanced. Forums like this one are very important for exchange of the right information.