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.

EK-TM4C123GXL: TM4C123GXL- Timer seems to run twice fast

Part Number: EK-TM4C123GXL
Other Parts Discussed in Thread: ENERGIA

Hey everyone, I am trying to learn timers. I saw an example code on the internet and checked it against datasheet and values choosen for configuration seems fine.

Expected result: 1 second red led on, 1 second led off

Actual result: 0.5 sec red led on, 0.5 sec led off

Here is the code I build and load to TM4C. Code is developed on Keil Uvision. From Manage Runtime Environment, choose CMSIS->Core and Device->Startup software components.

#include "TM4C123.h"                    // Device header

void delay_Microsecond(uint32_t time);

int main()
{
  
  SYSCTL->RCGCGPIO |= 0x20;     // Unlock clock for Port F
  GPIOF->DIR = 0x02;            // Set PF1(RED) LED pin as output
  GPIOF->DEN = 0x02;            // Digital Enable PF1(RED) LED
  
  while(1)
  {
    delay_Microsecond(1000000); // Wait 1 sec
    GPIOF->DATA ^= 0x02;        // Toggle output value of PF1(RED LED)
  }
}

void delay_Microsecond(uint32_t time)
{
  SYSCTL->RCGCTIMER |= 0x02;    // Enable and provide a clock to TIMER1
  TIMER1->CTL = 0x00;           // Timer 1-A is disabled.
  TIMER1->CFG = 0x04;           // Select 16 bit timer
  TIMER1->TAMR = 0x2;           // Set periodic timer mode
  TIMER1->TAILR = 16 - 1;       // 0 to 15 = 16 ticks for 1 microsecond
  TIMER1->ICR = 0x1;            // Clear interrupts from TIMER1(Unnecessary here?)
  TIMER1->CTL = 0x01;           // Timer 1-A enabled
  for(int i = 0;i < time; i++){
    while((TIMER1->RIS & 0x1) == 0x00);
    TIMER1->ICR = 0x1;          // Clear Timer 1-A interrupt every 16 ticks
  }
}

  • May I complement you on the,  "Very nice job" you did w/your posting?     Clearly described - sufficiently detailed - and (even) reveals  "format-correct" code.    (keeps the forum Gods (somewhat) happy ... although (even) they - are "UNABLE TO **LIKE** your post!')     SO wonderfully poetic...

    Mehmet Kose said:
    I saw an example code on the internet and checked it against datasheet

    Not quite awake staff & I  (it is 05:55 in Chicago - on Saturday) love the fact that you made the (extra) time & effort to review the MCU Manual - likely probing the key Timer Registers.     And of course - both "you and my small tech group" - always & only - "believe every word noted on the internet."    (ok - at least every (other) word...)

    While your code method "DRM" is generally NOT deemed effective (by hallowed vendor - and few  "opinionated" outsiders (never moi)) you have, "Commented the heck out of it" - making DRM (almost) bearable!    Yet (another) "Point in your favor!"    (there were/are MANY!)

    Two areas "jump out" after quick examination of your well organized & presented code:

    • there appears  "NO/ZERO"  setting of the MCU's System Clock - can it be "relied upon" to,  "Always run @ the same (known) rate" - even from "Uninitialized Start-Up?"    Unless the Timers are ordered to be clocked by the "PIOSC" - knowing the System Clock is (usually) required.    From your  code's comment, "16 ticks = 1µS" it proves (reasonably) certain that your "intent" was for the MCU to run @ 16MHz.   Yet beware - "intent" does not always insure "Device Compliance."     As you are questioning the Timer - "Knowing the Actual MCU clock rate" - IS mandatory.   (perhaps CMSIS manages this...)
    • unseen (by my eyes) is any, "Set-Up or Config." of your Timer's various Interrupts.    Yet your  (for loop)  "spins" - based upon the "presence/absence" of the, "Raw Interrupt!"    You must carefully check to note if such interrupt can occur - w/out the requirement to "Set-Up and/or Configure."

    The fact that your code runs - toggling the Led at "twice" your desired rate - confirms that (even) DRM code may (sometimes) ... (almost)  succeed!     Employing the "tips herein" - or via other means - you must search out the reason for your (apparent) "Doubled MCU's Timer "Clock Rate."    Again - you are 95%+ "home" - NICE JOB...

  • loved the CMSIS-styled approach. I actually wrote a set of routines around that myself (github.com/.../CMSIS-framework-for-TM4-devices). the struct-based approach is infinitely better than what Luminary / TI offers, in my view.

    your code is also well documented. Keep doing it.

    As to your problem, you may want to check the clock source for the timer and see if there is a unexpected divide-by-2 somewhere. I usually track SystemCoreClock (available if the CMSIS framework is used) to be sure.

    Also, 16-tick per interrupt may be a little bit too dicey. try to see if your code works if you load ILR to something larger, like 160-1 or 1600-1.

    I would also use 1000000ul in calling that delay routine, just to maintain code portability - it is a good habit.
  • BTW, your comment about whether it is necessary to turn off the ICR at beginning of the code. it is. As you don't turn off the timer at end of the delay routine, the timer will continue to roll and may overflow - not here but it may.

    so not clearing your ICR will run cut the execution by 1 round / microsecond, in those cases.
  • Thanks for the encouragement! My original code that I worked on was not so clear like this(admitting while being ashamed), I know how "unformatted-uncommented" code can be exhausting to understand.
    There is also love-hate relationship between me and TI products because developing simple programs for them is highly detailed, sometimes tiring for fast prototyping, compared to Arduino developing(I am aware of Energia IDE). But i decided to advance my career on IoT and Texas Instruments has both fine educational materials and wide variety of IoT products. Therefore, I decided to learn about internal organs of their MCU with as little abstraction as possible. For this reason, I am checking datasheet frequently for each topic I learn.
  • For the purpose of lean execution, I tried to stop and disable the clock at the end of delay function below. Is this best practice to "free" a timer once we are done with it?

    void delay_millisecond(uint32_t time)
    {
      ...
      // Original function body is not copied here to prevent clutter
      TIMER1->CTL = 0x00;           // Timer 1-A is disabled.
      SYSCTL->RCGCTIMER &= ~0x02;   // Disable clock to TIMER1
    }

  • My mistake was assuming system core clock would be 16 Mhz by default since I have not written any code to modify it.Thanks to Danny F. and cb1_mobile, I investigated the issue more. Here are the results.

    When I added startup software component through Manage Run-time Environment->Device->Startup in Keil UVision, it added "system_TM4C123.c" file into the project under Project->Target->Device(in Project Explorer window).  This file has clock configuration definitions and SystemInit() function in it. Here are some of definitions;

    #define CLOCK_SETUP 1            // This causes to clock configuration at initialization with SystemInit() function
    #define CFG_RCC_SYSDIV 4         // This causes 50 Mhz system core clock speed(Check TM4C123GH6PM Datasheet)
    #define CFG_RCC_USESYSDIV 1      // Enables System Clock Divider(The value "4" above) 
    #define CFG_RCC_PWRDN 0          // Do NOT disable PLL
    #define CFG_RCC_BYPASS 0         // Do NOT bypass PLL
    #define PLL_CLK    (400000000UL) // PLL Clock is 400 Mhz 

    As we can see PLL is not disabled/bypassed, clock setup is enabled and SYSDIV is choosen to be 4. According to the values above and information in the datasheet(Page 223- "Using the SYSDIV and SYSDIV2 Fields"),  expected system clock is 400 MHz / 2 /4 = 50 MHz. Division by 2 is predivision before divisor 4 is applied. To prevent clock configuration at start, I simply set CLOCK_SETUP to 0;

    #define CLOCK_SETUP 0 // Disable clock configuration within SystemInit() function

    Since there was no external clock configurations, MCU had 16 MHz system core clock speed happily after that.

    Note: I marked this post as "resolving one". Do I have to mark other helper posts leading to the solution?

  • I loaded ILR register with 16000 - 1 this time as you suggested. It became more accuracte since then. Before doing that, I was having 50 LED blinks in 53 seconds, not I am having 50 LED blinks in 50 seconds. Is this because of overhead of loops spevificly?
  • "Is this best practice to "free" a timer once we are done with it?"

    I don't think a generic "best" practice exists for all applications.

    with that said, I typically keep a free running clock in my applications. that clock can be either systick, or any timer. the 2nd approach is especially useful when lots of delays of unequal length can be created from unused compare channels.

    if you wish to stick to your current approach, I would initialize the timer out of the delay routine, and reset the counter / flag within the delay routine.
  • Good for you - as you have noted - my (first response) "honed in upon a "difference" between original program's clock setting and your own."

    Poster Danny make a good point as to the, "Over-involvement of Interrupts" - brought on my your use of the (far too small value) of 16.    For your 16 bit timer - that may be increased to 16,000 - or even 64,000 - should you be willing to "Tweak your math."      (16 bit maxes out around 65.5K)      Raising that value will indeed (drastically) reduce your "loop overhead."

    To the "This Resolved" Issue - proper rewarding should target your Responders - in the case here it is believed that poster Danny & I should both be so awarded...

    You may note that "FEW here" employ Keil AND CMSIS - and their combined operation - "behind the scenes" - HIDES key program info from your "Helper Crüe."