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.

TM4C1294NCPDT: GPTM Timer 0 problem

Part Number: TM4C1294NCPDT

I'm having an issue with the way I'm using Timer 0.  The document attached below goes into details about the issue that I'm seeing. 

When I try to run the debugger, the process will run for a few seconds and then produce an Error -2062 which will prevent a Halt to the operation.

Thanks for the help,

Joe

GPTM_Timer0_Issue.docx

  • Hello Joe,

    Given the setup it may take us a little back and forth to figure this out, not having debug on one hand is going to be a small obstacle, but there are ways to help narrow this down.

    From a software standpoint, the only portion I am a little hesitant about is the DRM calls to TAV. Have you tried the TimerLoadGet and TimerLoadSet APIs before? That would be recommended usually.

    That comment said, given you think the issue is in those functions, and you lose debug, let's do a simple test (requires an o-scope or LSA).

    Set both the Enable and Disable Timer functions to toggle a GPIO high on entry, and low on exit.

    This would allow us to see two things.

    1) Does Enable Timer only get called after Disable Timer is called, so you are never writing the TAV with a running timer

    2) Which, if either, of the two API's is where the hang occurs, because if the processor runs into the weeds during one of them then we'd see that GPIO not go low.

    Plus you can check the processing time for each API too.

    Also as a sanity check, you may want to increase your stack size just to see if stack overflow could also explain this (unlikely, but never a bad check to make).
  • Hi Ralph,

    Thank you for the response.

    The first thing I thought of when this error was occur was a stack over flow as well.  I originally had the stack set to 512 but changed it to 1024 and this didn't help.  Under normal operation, the stack wouldn't make it to 5% when entering the Enable/Disable routines.

    I changed the code as you suggested and included a picture below. 

    Channel 4 is the Synch pulse.

    Channel 2 is the I/O that toggles high when the Disable_MeasTimer() is entered and toggles low before returning.

    Channel 3 is the I/O that toggles high when the Enable_MeasTimer() is entered and toggles low before returning.

    Channel 1 is the CAN message being transmitted.

    (NOTE:  If you follow Channel 3, you will see one cycle where it looks like the Enable_MeasTimer() routine is missed.  I think this missed pulse is due to the sampling in my oscilloscope.  I'll plan to add some code that validates this theory but when I change the time scale and turn off a couple of channels, I don't see a missed signal)

    Something odd that I've found is if I use this code snippet, the code runs much longer before locking up.  If I comment out the Main_delay(12) routine, it locks up within 5 seconds.

    //Ensure peripheral is enabled

    if(ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0))

    {

    // Reset the Timer Value

     Main_delay(12);

    HWREG(MEASUREMENT_TIMER + TIMER_O_TAV) = 0x00000001;

    // Determine if Interrupt needs to be enabled.

    if(dwTimerIntStatus == MEASTIMER_INT_ON)

    {

    //Enable Timer0A interrupt

    IntEnable(INT_TIMER0A);

    }

    //Enables Timer0A

    TimerEnable(MEASUREMENT_TIMER,TIMER_A);

  • Hi Ralph,

    I wanted to give you an update on what I have found and I also need some guidance as far as using this timer properly.

    What I have found is it looks like the lock-up issue is cause by the line of code that reinitializes the TAV value.

    HWREG(MEASUREMENT_TIMER + TIMER_O_TAV) = 0x00000001;

    I've removed this line of code and have been running for hours.  Do you know why this operation would cause problems?

    Ideally I would like to reinitialize this timer count value right before it is enabled so the timer delay is consistent.  Without this line of code, the TAV value is somewhat inconsistent (based on code path and interrupts).   I've used a similar procedure with other processors, including the MSP430 and have not seen this type of problem.  Could you provide some guidance for either resetting the TAV value or the recommended operating procedure for these timers based on my desired operation?

    Thanks for the help,

    Joe

  • Hello Joe,

    Interesting, that is odd for sure. Okay given what you've said, I wonder if we could track this down like it were a fault. Can you try some of the debug methods in this document and see if you can track down the peripheral or possibly even the function that is causing the lock up? www.ti.com/.../spma043.pdf

    Also, is the CAN transmission required to make this occur? I don't have a CAN transceiver myself (one of my colleagues at another TI site is the CAN specialist with all the hardware :) ) but if you could take the CAN portion out and send me a CCS project that I could debug, that would go the quickest. Not sure how feasible that is, but if this is on a LaunchPad and isn't part of a massive project that would be helpful.
  • Hi Ralph,

    I think your reply appeared about the same time that I sent my update so I wasn't sure if you have been able to look at what I found...  The problem with the lock-up looks like it occurs when trying to write to the TAV register and reset the timer.  I don't know if this only occurs with Timer0 or other timers but after this line of code was removed, I haven't seen a lock-up condition since.

    I would, however, like to understand how I can properly reset a timer.  I'm using other timers in my code as sort of a WDT.  For certain operational functions, I'll start a timer as an error checker.  If the timer expires before the operation is complete, this likely indicates an error.  If the operation is successful, the timer should never expire and the timer is disabled.  Upon the next operation, I would like to reset the count value of the timer and re-enable it similar to what I was doing with Timer0 and the code snippets I sent. 

    Could you recommend a procedure for resetting the count value?

    Thank you,

    Joe

  • Hello Joe,

    If by resetting you just mean clearing the value, then you can just use TimerLoadSet for that. You can set the Timer count value to whatever you need with that and then re-enable it.
  • Hi Ralph,

    I tried using the TimerLoadGet() followed by the TimerLoadSet() both when the timer was enabled and disabled but I couldn't see the count value in the TAV  & TAR register restart at 0.  After the interval value was reloaded, the timer resumed counting from the value already in the TAR register.  If I have the Stall bit set and try code stepping, should I see the TAR/TAV value reset?

    Thanks,

    Joe

  • Hello Joe,

    Can you check what the TAILD bit inside of the GPTMTAMR (or GPTMTBMR) register is set to?

    Also note that for GPTMTAR, when the timer is disabled, it will not update from TimerLoadSet until the timer is enabled again.

  • Hello Joe,

    Did my prior tips help with resolving this?

  • Hi Ralph,

    I was redirected for a few day.  I will take a look at the TAILD bit and let you know.  When a new value is loaded using the TimerLoadSet() operation, how many clock cycles does it take where you see the TAV value return to 0?  Also, I have the STALL bit set so the timer doesn't increment using the debugger.  Is this a problem?

    JC

  • Hello Joe,

    I don't think the STALL bit would have caused the original lockup and also it wouldn't make sense to me that it would prevent you from seeing the clearing of the registers as all it should do is stop the timer from ticking, but that would occur after you are breaking to see the registers clear right? So it would run again before breaking to check that the value is reset?

    By the end of the TimerLoadSet API, it should already have the right value in TAV.

  • Hi Ralph,

    I've included some screen shot from an emulation that I conducted that shows you how Timer0 is not being RESET.  If you look in the code, I commented out the code where I was writing to the TAV register and replaced it with the TimerLoadGet() followed by the TimerLoadSet() instruction.  I set a break point right before the timer is re-enabled.  On the right you will see the Timer0 registers.

    The program I am running is starting Timer0, running an operation, and then stopping Timer0.  If you remember, I'm using it like a WatchDog.  If the timer expires, it indicates an error.  When I enable the Timer, I'm expecting the Count to be RESET.

    If you look at the screen shots, you can see where the TimerLoadGet() pulls the TAILR value and Sets is back to the same value.  You can also see the TAR and TAV values as they change.  What I'm expecting to see is the TAV and TAR values be somewhere close to 0 but as you can see, it continues to increase until it reaches the TAILR value.

    For this operation to run properly, does the timer need to be enabled?  If the timer is disabled, how can I reset the count value?  The code that I commented out where I was writing to the TAV value works but I think this was causing the problems I mentioned in the previous posts.

    [NEW UPDATE]  I reran this same test where I kept the Timer running to see it the TAV value gets RESET properly and it had no effect.  If you don't mind can you send me some code that resets the timers correctly?  I think I have the timers setup correctly but I may have missed something.

    Thanks,

    JCTimerRESET.docx

  • Hello Joe,

    Speaking of setup, I was wondering you could share the code snippets for the initial timer configuration? I want to check that the TAILD bit is being set properly.

    Regarding code to reset the timers, do you basically want code that does what you have shown where the timer is disabled, reset, and then enabled again?

  • I'm using 4 different timers but they are all initialized in the same manner.  In the code below, I only included one of the Case statements that shows how the peripheral is enabled. (The other 3 are the same). The bottom part of the code shows the actual initialization.  Looking at the screen shots I sent you, the TAILD bit is set to 0 so I would expect to see the clock being reset on the next timing cycle.

    As I mentioned in my last post, I tried keeping the timer enabled but I still didn't see the count value reset as I would expect.  The only method I have found that has worked somewhat effective is by writing the TIMER_O_TAV value to 0x00000001 and looping until it changes.

    For the timer reset code, I'd like to implement the best practices for this processor so the timer can remain enabled or disabled.

    Thanks again for the help,

    Joe

    //== Measurement Timer [TIMER3 A] ==

    //This timer is used to indicate when the ISO_SPARE1 line should be toggled.

    //This timer sets the measurement duty cycle of the sensors.

    case MEASUREMENT_TIMER:

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER3);

    //-- Make sure the Timer3 peripheral is Ready

    while( !(ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER3) || g_dwEventHandler.s_dwEventHandler.ERROR_TimeoutOp) )

    {

    }

    break;

    default:

        return;

    }

    // Configure Timer A as a 32-bit periodic timer.

    TimerConfigure(dwBaseAddress, TIMER_CFG_PERIODIC_UP);

    //Set Timer to run off of the Precision Internal Oscillator (16MHz)

    TimerClockSourceSet(dwBaseAddress, 0x00000000 | TIMER_CLOCK_PIOSC );

    //Set Timer A interval

    TimerLoadSet(dwBaseAddress, TIMER_A, dwTimerValue);

    //Ensure the Timer Interrupt Flag is cleared.

    TimerIntClear(dwBaseAddress, TIMER_TIMA_TIMEOUT);

     

    #if DIRECTIVE_REMOVE_MSG_TIMER == TIMER_ON

    HWREG(dwBaseAddress + TIMER_O_CTL) |= TASTALL;

    #endif

     

    //Configure Timer A interrupt for timer timeout.

    TimerIntEnable(dwBaseAddress,TIMER_TIMA_TIMEOUT);

  • Hello Joe,

    Alright I figured out a couple things. One, there is fine print on the datasheet expressing that the TAILD bit does not impact UP Count mode...

    So the means to reset it, would be what you tried originally:

        HWREG(TIMER0_BASE + TIMER_O_TAV) = 0;

    Now then, regarding that, I wrote some code to test the reset and I was observing that the debugger isn't correctly reflecting the register values properly. My program is set with two timers, one that runs at double the speed of another. Each should flash an LED, but the faster timer is using the above API to clear the TAV register of the slower Timer. As a result, the slower Timer never fires. This was done with minor tweaks to the timers example on TivaWare for the LaunchPad:

    //*****************************************************************************
    //
    // 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-TM4C1294XL Firmware Package.
    //
    //*****************************************************************************
    
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_timer.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.
        //
        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)
    {
        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);
    
        HWREG(TIMER0_BASE + TIMER_O_TAV) = 0;
    
        //
        // 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();
    
        TimerClockSourceSet(TIMER0_BASE, TIMER_CLOCK_PIOSC);
        TimerClockSourceSet(TIMER1_BASE, TIMER_CLOCK_PIOSC);
        //
        // Configure the two 32-bit periodic timers.
        //
        ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC_UP);
        ROM_TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC_UP);
        ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, 16000000);
        ROM_TimerLoadSet(TIMER1_BASE, TIMER_A, 16000000 / 2);
    
        ROM_TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
        ROM_TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
        //
        // 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)
        {
        }
    }
    

  • Hi Ralph,

    Thank you for taking a look at this and providing this example.  I see that you did not need the while() loop that I had implemented where I was reading the TAV register and writing it until it was reset.  Now that you pointed out that the debugger was not showing this value correctly makes sense.  I think I was seeing this first hand.

    I'll implement what you have shown and let you know.

    Thanks again,

    JC