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.

CCS/EK-TM4C129EXL: Default timers.c is not working as expected

Part Number: EK-TM4C129EXL

Tool/software: Code Composer Studio

Hi All,

I am tasked to write a timer based interrupt code (I am a beginner to this). As for a start, I tried compiling the timers.c code provided by TI for TM4c129exl.

However, it seems the timer IntHandlers are not triggered (added few printf lines to debug on this).  I wonder do I need to do any jumper settings or rework for this (my jumpers are in default settings).

Attached the terminal output and code:

//*****************************************************************************
//
// timers.c - Timers example.
//
// Copyright (c) 2013-2017 Texas Instruments Incorporated.  All rights reserved.
// Software License Agreement
//
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
//
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
//
// This is part of revision 2.1.4.178 of the EK-TM4C129EXL Firmware Package.
//
//*****************************************************************************

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"

//*****************************************************************************
//
//! \addtogroup example_list
//! <h1>Timer (timers)</h1>
//!
//! This example application demonstrates the use of the timers to generate
//! periodic interrupts.  One timer is set up to interrupt once per second and
//! the other to interrupt twice per second; each interrupt handler will toggle
//! its own indicator throught the UART.
//!
//! UART0, connected to the Virtual Serial Port and running at 115,200, 8-N-1,
//! is used to display messages from this application.
//
//*****************************************************************************

//****************************************************************************
//
// System clock rate in Hz.
//
//****************************************************************************
uint32_t g_ui32SysClock;

//*****************************************************************************
//
// Flags that contain the current value of the interrupt indicator as displayed
// on the UART.
//
//*****************************************************************************
uint32_t g_ui32Flags;

//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif

//*****************************************************************************
//
// The interrupt handler for the first timer interrupt.
//
//*****************************************************************************
void
Timer0IntHandler(void)
{
	UARTprintf("DEBUG: Entered timer0\n");
    char cOne, cTwo;

    //
    // Clear the timer interrupt.
    //
    ROM_TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    //
    // Toggle the flag for the first timer.
    //
    HWREGBITW(&g_ui32Flags, 0) ^= 1;

    //
    // Use the flags to Toggle the LED for this timer
    //
    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, g_ui32Flags);

    //
    // Update the interrupt status.
    //
    ROM_IntMasterDisable();
    cOne = HWREGBITW(&g_ui32Flags, 0) ? '1' : '0';
    cTwo = HWREGBITW(&g_ui32Flags, 1) ? '1' : '0';
    UARTprintf("\rT1: %c  T2: %c", cOne, cTwo);
    ROM_IntMasterEnable();
}

//*****************************************************************************
//
// The interrupt handler for the second timer interrupt.
//
//*****************************************************************************
void
Timer1IntHandler(void)
{
	UARTprintf("DEBUG: Entered timer1\n");
    char cOne, cTwo;

    //
    // Clear the timer interrupt.
    //
    ROM_TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);

    //
    // Toggle the flag for the second timer.
    //
    HWREGBITW(&g_ui32Flags, 1) ^= 1;

    //
    // Use the flags to Toggle the LED for this timer
    //
    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, g_ui32Flags);

    //
    // Update the interrupt status.
    //
    ROM_IntMasterDisable();
    cOne = HWREGBITW(&g_ui32Flags, 0) ? '1' : '0';
    cTwo = HWREGBITW(&g_ui32Flags, 1) ? '1' : '0';
    UARTprintf("\rT1: %c  T2: %c", cOne, cTwo);
    ROM_IntMasterEnable();
}

//*****************************************************************************
//
// Configure the UART and its pins.  This must be called before UARTprintf().
//
//*****************************************************************************
void
ConfigureUART(void)
{
    //
    // Enable the GPIO Peripheral used by the UART.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    //
    // Enable UART0.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    //
    // Configure GPIO Pins for UART mode.
    //
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    //
    // Initialize the UART for console I/O.
    //
    UARTStdioConfig(0, 115200, g_ui32SysClock);
}

//*****************************************************************************
//
// This example application demonstrates the use of the timers to generate
// periodic interrupts.
//
//*****************************************************************************
int
main(void)
{
    //
    // Set the clocking to run directly from the crystal at 120MHz.
    //
    g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                             SYSCTL_OSC_MAIN |
                                             SYSCTL_USE_PLL |
                                             SYSCTL_CFG_VCO_480), 120000000);

    //
    // Initialize the UART and write status.
    //
    ConfigureUART();

    UARTprintf("\033[2JTimers example\n");
    UARTprintf("T1: 0  T2: 0");

    //
    // Enable the GPIO port that is used for the on-board LEDs.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);

    //
    // Enable the GPIO pins for the LEDs (PN0 & PN1).
    //
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0 | GPIO_PIN_1);


    //
    // Enable the peripherals used by this example.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);

    //
    // Enable processor interrupts.
    //
    ROM_IntMasterEnable();

    //
    // Configure the two 32-bit periodic timers.
    //
    ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    ROM_TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC);
    ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, g_ui32SysClock);
    ROM_TimerLoadSet(TIMER1_BASE, TIMER_A, g_ui32SysClock / 2);

    //
    // Setup the interrupts for the timer timeouts.
    //
    ROM_IntEnable(INT_TIMER0A);
    ROM_IntEnable(INT_TIMER1A);
    ROM_TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    ROM_TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);

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

    //
    // Loop forever while the timers run.
    //
    while(1)
    {
    }
}

  • We do not use the '129 family - yet is your use of:

    ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);

    compatible w/your (later) use of:

    ROM_IntEnable(INT_TIMER0A);       Note too that you've carried this "Half-Timer" targeting throughout the rest of your Timer Code!

    Does not the "TimerConfigure" target the "Entire Timer" while your "IntEnable" and all other Timer coding - targets (just) the half/sub Timer?

    It is expected that your change from parameter, "TIMER_CFG_PERIODIC" to "TIMER_CFG_A_PERIODIC" w/in both of your two TimerConfigure functions - will resolve your issue!

  • I just retried the timers project and verified it worked correctly on my EK-TM4C129EXL launchpad. Then I replaced my timers.c file with the one you posted, and it also worked correctly.  Just to double check that it is not an issue with the build, would you program the attached .out file to see if it works?

    /cfs-file/__key/communityserver-discussions-components-files/908/timers.out

  • Bob,

    Would you be so good as to review my posting (bit earlier) than your own - in which (I believe) a mistake was identified & corrected?

    There is a clear "clash" between the Timer Configuration (both timers) as "Full Width Timers" and all subsequent references to them as "Half-Width Timers!"       Such is (unlikely) to be "normal/customary" API usage - is it?

  • Hi CB1,

    On my launchpad the code works as originally written and also works with the correction you provided. It just so happens that the two defines are equal:

    #define TIMER_CFG_PERIODIC       0x00000022  // Full-width periodic timer
    #define TIMER_CFG_A_PERIODIC     0x00000022  // Timer A periodic timer
    

    That being said, using "TIMER_CFG_A_PERIODIC" would be more clear. This is a deficiency in the TI example code, not the fault of the original poster. It is a good catch but does not explain why the example is not working on the original poster's launch pad. As always, thank you for your careful eye.

  • Greetings Bob, (it is Friday!)

    Indeed - you ARE correct - NEVER would I have expected this!

    Along w/Not being at all intuitive - or clear - does this not lead one to the "Identical loose expectation" - when configuring the "B" Half-Timer?     And - in that case - there is no (fortunate) "Saving define Duplication" - to rescue the unwary!     They WILL crash/burn!     Thus the (expected) "parallelism between Half Timers A & B" has been (unexpectedly/unwantedly) breached!     And that's NOT good!

    As a long-term user (going back to LMI days) I checked 7-8 year old versions of StellarisWare - and they too - identically defined "CFG_PERIODIC and CFG_A_PERIODIC."     Thus - this is NOT "newly arrived" - and while may "excuse" the "less than attentive users of "Timer-A" - is SURE to plunge the hapless users of "Timer_B" into darkness - which is (unfortunately) prompted (even encouraged) by this define's duplication...

    Thanks for your assistance in "digging up" this detail - not all "long duration" efforts are fully attentive ones - and I'm (sad to say) "proof" of that...

  • Hi Bob,

    A question, how do I burn your binary file to my 129exl. For MSP430, we can do this with FET-Pro430 (refer: www.youtube.com/watch. Are there any similar software for 129exl, or I can easily do this with using only CCS (without compiling my current code and only burn your binary file to the launchpad).

    Attached also my project file for your cross check (i have replaced timers.c into hello.c).

    https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/908/5707.hello.7z

  • This can be easily done with CCS. Once you have connected to the target, select "Run", then "Load", then "Load Program". Select "Browse" and locate the file I sent, "timers.out". Then select "OK". That should program the code I wrote into your LaunchPad.
  • Hi Bob and cb1_mobile,

    I think now I know what was the problem. It seems previousy I didnt define the timer handlers inside the vector table at startup_ccs.c. It works as usual now.  Aternatively, we can also use static allocation of timer interrupt handlers as in the example below. Works as well. I really appreciate your help guys. Thank you : )

    //*****************************************************************************
    //
    // timers.c - Timers example.
    //
    // Copyright (c) 2013-2017 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    //
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    //
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    //
    // This is part of revision 2.1.4.178 of the EK-TM4C129EXL Firmware Package.
    //
    //*****************************************************************************
    
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/timer.h"
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"
    
    //*****************************************************************************
    //
    //! \addtogroup example_list
    //! <h1>Timer (timers)</h1>
    //!
    //! This example application demonstrates the use of the timers to generate
    //! periodic interrupts.  One timer is set up to interrupt once per second and
    //! the other to interrupt twice per second; each interrupt handler will toggle
    //! its own indicator throught the UART.
    //!
    //! UART0, connected to the Virtual Serial Port and running at 115,200, 8-N-1,
    //! is used to display messages from this application.
    //
    //*****************************************************************************
    
    //****************************************************************************
    //
    // System clock rate in Hz.
    //
    //****************************************************************************
    uint32_t g_ui32SysClock;
    
    //*****************************************************************************
    //
    // Flags that contain the current value of the interrupt indicator as displayed
    // on the UART.
    //
    //*****************************************************************************
    uint32_t g_ui32Flags;
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
    }
    #endif
    
    //*****************************************************************************
    //
    // The interrupt handler for the first timer interrupt.
    //
    //*****************************************************************************
    void
    Timer0IntHandler(void)
    {
        char cOne, cTwo;
    
        //
        // Clear the timer interrupt.
        //
        TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    
        //
        // Toggle the flag for the first timer.
        //
        HWREGBITW(&g_ui32Flags, 0) ^= 1;
    
        //
        // Use the flags to Toggle the LED for this timer
        //
        GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, g_ui32Flags);
    
        //
        // Update the interrupt status.
        //
        IntMasterDisable();
        cOne = HWREGBITW(&g_ui32Flags, 0) ? '1' : '0';
        cTwo = HWREGBITW(&g_ui32Flags, 1) ? '1' : '0';
        UARTprintf("\rT1: %c  T2: %c", cOne, cTwo);
        IntMasterEnable();
    }
    
    //*****************************************************************************
    //
    // The interrupt handler for the second timer interrupt.
    //
    //*****************************************************************************
    void
    Timer1IntHandler(void)
    {
        char cOne, cTwo;
    
        //
        // Clear the timer interrupt.
        //
        TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
    
        //
        // Toggle the flag for the second timer.
        //
        HWREGBITW(&g_ui32Flags, 1) ^= 1;
    
        //
        // Use the flags to Toggle the LED for this timer
        //
        GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, g_ui32Flags);
    
        //
        // Update the interrupt status.
        //
        IntMasterDisable();
        cOne = HWREGBITW(&g_ui32Flags, 0) ? '1' : '0';
        cTwo = HWREGBITW(&g_ui32Flags, 1) ? '1' : '0';
        UARTprintf("\rT1: %c  T2: %c", cOne, cTwo);
        IntMasterEnable();
    }
    
    //*****************************************************************************
    //
    // Configure the UART and its pins.  This must be called before UARTprintf().
    //
    //*****************************************************************************
    void
    ConfigureUART(void)
    {
        //
        // Enable the GPIO Peripheral used by the UART.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
        //
        // Enable UART0.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
        //
        // Configure GPIO Pins for UART mode.
        //
        GPIOPinConfigure(GPIO_PA0_U0RX);
        GPIOPinConfigure(GPIO_PA1_U0TX);
        GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
        //
        // Initialize the UART for console I/O.
        //
        UARTStdioConfig(0, 115200, g_ui32SysClock);
    }
    
    //*****************************************************************************
    //
    // This example application demonstrates the use of the timers to generate
    // periodic interrupts.
    //
    //*****************************************************************************
    int
    main(void)
    {
        //
        // Set the clocking to run directly from the crystal at 120MHz.
        //
        g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                                 SYSCTL_OSC_MAIN |
                                                 SYSCTL_USE_PLL |
                                                 SYSCTL_CFG_VCO_480), 120000000);
    
        //
        // Initialize the UART and write status.
        //
        ConfigureUART();
    
        UARTprintf("\033[2JTimers example\n");
        UARTprintf("T1: 0  T2: 0");
    
        //
        // Enable the GPIO port that is used for the on-board LEDs.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
    
        //
        // Enable the GPIO pins for the LEDs (PN0 & PN1).
        //
        GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
    
        //
        // Enable the peripherals used by this example.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    
        //
        // Enable processor interrupts.
        //
        IntMasterEnable();
    
        //
        // Configure the two 32-bit periodic timers.
        //
        TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
        TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC);
        TimerLoadSet(TIMER0_BASE, TIMER_A, g_ui32SysClock);
        TimerLoadSet(TIMER1_BASE, TIMER_A, g_ui32SysClock / 2);
        TimerIntRegister(TIMER0_BASE, TIMER_A, Timer0IntHandler); //-------------
        TimerIntRegister(TIMER1_BASE, TIMER_A, Timer1IntHandler); //-------------
    
        //
        // Setup the interrupts for the timer timeouts.
        //
        IntEnable(INT_TIMER0A);
        IntEnable(INT_TIMER1A);
        TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
        TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
    
        //
        // Enable the timers.
        //
        TimerEnable(TIMER0_BASE, TIMER_A);
        TimerEnable(TIMER1_BASE, TIMER_A);
    
        //
        // Loop forever while the timers run.
        //
        while(1)
        {
        }
    }
    

  • I will submit this is a reason to use weak definials for interrupts.

    Robert
  • Hi Robert,
    Sorry I couldn't understand what you meant. Could you elaborate more ?
  • Copied From e2e.ti.com/.../2215479 definials#2215479

    Since the original post is locked this may not maintain full fidelity

    The approach is general. Almost every compiler supports it. The details are compiler specific. Since it involves startup and interrupts it's not portable in any case so the fact that it's compiler specific is not of great significance.

    I'll use IAR for example

    The idea is to set each vector to a known routine something like

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void (* const __vector_table[155])(void) =
    {
        top_of_mem,                         /* The initial stack pointer (defined by linker)*/
        Reset_ISR,                          /* The reset handler */
        NMI_ISR,                /* The NMI handler */
        Fault_ISR,                          /* The hard fault handler */
        MPUFault_ISR,                   /* The MPU fault handler */
        BusFault_ISR,                       /* The bus fault handler */
        UsageFault_ISR,                     /* The usage fault handler */

    Define a default routine

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void IntDefaultHandler(void)
    {
        unsigned int psr_contents;
        volatile int i;
            /*  Program Status Register contains the current exception vector.*/
        psr_contents=__get_PSR();
        (void)SWO_putc('!',31u);
        SWO_fputhex((char)(psr_contents&0xFF), 31u);

    So far this is usually the same for each compiler. Now come the compiler specifics. In IAR I have the following

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /*lint -e975 allow pragma, this is not quite C.  Need to control placement and
        weak definitions of symbols.                    */
    /*lint -efile(766,startup_wk.h) */
        /* Weakly link vectors to default routines so user can replace. */
    #pragma weak NMI_ISR=IntDefaultHandler
    #pragma weak Fault_ISR=IntDefaultHandler
    #pragma weak BusFault_ISR=IntDefaultHandler
    #pragma weak UsageFault_ISR=IntDefaultHandler
    #pragma weak SVCall_ISR=IntDefaultHandler
    #pragma weak DebugMonitor_ISR=IntDefaultHandler
    #pragma weak MPUFault_ISR=IntDefaultHandler
    #pragma weak PendSV_ISR=IntDefaultHandler
    #pragma weak SysTick_ISR=IntDefaultHandler
    #pragma weak GPIO_A_ISR=IntDefaultHandler               /* GPIO Port A */

    This assigns IntDefaultHandler as the routine for each of the interrupt routines. Think of it as renaming them. The weak pragma makes them weak definials, that is they are temporary assignments. If the user code defines a routine named NMI_ISR it is used in place of IntDefaultHandler. In GCC I would probably use the linker to define the weak definials (I have in the past).

    Now adding a new interrupt is easy, you just define the routine with the appropriate name.

    Upsides:

    • Easy to add or remove interrupts
    • No forgetting to assign interrupts
    • Unused interrupts automatically have a default.
    • Startup is reusable

    Downsides:

    • Missing interrupt routines may not be detected until run time test. Think typo.
    • Interrupt names are public symbols

    Clear as mud?

    Robert