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.

Tiva TM4C123GH6PMI General Purpose Timer Interrupts not Triggering



Hi

I seem to be having trouble getting the General Purpose Timers to trigger an interrupt on timeout.  I have configured the vector table, and the assembly correctly points to the Timer interrupt handler.  Issue is, on timeout, the handler is never invoked, even though the Timer RIS register flags a timeout.  My code is below:

#include "LM4F230H5QR.h"
#include <stdint.h>

int main() {
/* System Clock Setup in IAR Start Up */

// Clock Gating
SYSCTL->RCGC1     |= ((1U<<16)); // Enable Timer 0
SYSCTL->RCGC2     |= (1U<<5);    // Enable clock to IO PORTF
SYSCTL->GPIOHBCTL |= (1U<<5);    // Enable high speed periphreal bus for PORTF

// NVIC
NVIC_SetPriorityGrouping(0);
NVIC_EnableIRQ(TIMER0A_IRQn);     // Enable TIMER0A Interrupt
NVIC_SetPriority(TIMER0A_IRQn,1); // Set TIMER0A Priority

// Initialize PORT F
GPIOF_AHB->DIR |= ((1U<<3)|(1U<<2)|(1U<<1));  // PIN 1,2,3 as output
GPIOF_AHB->DEN |= ((1U<<3)|(1U<<2)|(1U<<1));  // Enable PIN 1,2,3

// Timer config
TIMER0->CFG   |= 0x0;        // Set Timer0 to 32 bit
TIMER0->TAMR  |= ((1U<<1));  // Set Timer 0 to periodic
TIMER0->IMR   |= ((1U<<0));  // Enable timeout interrupt
TIMER0->TAILR |= 0xffff;     // Timer 0 autoload value

// START TIMERS
TIMER0->CTL |= ((1U<<0));      // Enable Timer 0


while(1){

}
//return 0;
}

The weird thing is, the first time I compiled and loaded this code onto the Tiva C launch pad, the interrupt triggered.  I then switched Timer0 A to 16 bit mode, and it stopped working.  So, I immediately switched it back to 32 bit mode, and it is still not working...  I have no clue why.  Any tips would be greatly appreciated.  I have found similar threads on the forum, but I am afraid they were of no use to me.  I even tried adding delays to no avail, between each instruction to see if it was a setup/hold time violation.

Other Information:

Tool flow: IAR 7.20.1.7307

Optimizations: Off

  • Hello Eric

    Have you enabled the NVIC Controller by calling IntMasterEnable()?

    Regards

    Amit

  • Hi,

    Does your program compiles OK? I have doubts:

    NVIC_EnableIRQ(TIMER0A_IRQn);     // Enable TIMER0A Interrupt
    NVIC_SetPriority(TIMER0A_IRQn,1); // Set TIMER0A Priority

    because of "IRQn" -try to set up specific timer interrupt, not a generic one.

    Also, you did not enabled global interrupts (Int MasterEnable()) and for setting priorities you need to write

    NVIC_SetPriority(TIMERxxxx, 1<<5) // again, use the right, first parameter; the second one, for priority should use only the upper 3 bits of a byte.

    Petrei

  • The function "NVIC_EnableIRQ( ... )" is part of the core_m4 CMSIS header; it sets the bit corresponding a specific interrupt source in the NVIC ISER register.  I have not used the API you mentioned, but my best guess is that the IntMasterEnable() function simply sets all bits in the NVIC ISER register.  Perhaps I should take a look at the IntMasterEnable() source code; do you happen to have a link to this API?

  • Hi,

    I make observations on "TIMER0A_IRQn" which is defined in CMSIS, but not in driverlib (or at least my computer is not able to find it in driverlib files).

    IntMasterEnable is defined in driverlib/interrupt.h and the source code is in driverlib/interrupt.c file.

    Petrei

  • Hello Eric,

    IntMasterEnable can be found in driverlib/interrupts.c and driverlib/interruots.h

    It enables the Interrupt bit in the Cortex M4 CPU registers, so you would see a cpuise call.

    Regards

    Amit

  • Hello Eric

    From the CMSIS is the equivalent of IntMasterEnable()

    void __enable_irq ( void  )

    Regards

    Amit

  • Thanks for the help Amit

    Unfortunately, the master enable was not my Issue.  I downloaded the API and ran it, and it looks like IntMasterEnable clears the PRIMASK register, which is cleared on reset in my startup assembly.  

    I think I have a tool or hardware issue.  I compiled, downloaded, and debugged 10 different times using the Stellaris flash loader through IAR with the exact same source code.  For 2 out of the 10 trials, the interrupt worked correctly.   The funny thing is, when I configure the exact same timers are a PWM module to blink an LED, everything works fine.  It seems its interrupts that are the issue.  This makes absolute zero sense unless its a hardware issue, a tool issue, or potentially the addresses in my header are incorrect.  Well, at least I have a direction to go =) 

  • Hello Eric,

    I checked your original post. As you mentioned the RIS register bit for timeout is set. Since the IMR bit is set as well in the code, the MIS bit should be set as well. Can you check that?

    Also since you changed the code between 32-bit and 16-bit the CFG register may still hold the 16-bit mode value due to OR operation. Please make sure you write the value as = 0x0 instead of |= 0x0.

    Regards

    Amit

  • Good morning

    First off, I solved my issue.  It turns out that it was the flash loader in IAR 7xxx (or at least I think so).  I downloaded IAR 6xxx from the TI website, which included the flash loaders.  Now the code I posted works exactly I expect it to.  This however does not mean it was actually the flash loader (but it does seem logical), as installing and older version changes a lot things at once.  NOTE that I am using the exact same libraries/source as I was with IAR7xxx.

    However, before I re-downloaded everything, I tried to debug my code a little further.  While it turns out everything I did was correct, I have posted below what I did look at trying to debug the code.

    ***

    I spent some time reviewing all the register bits, and everything looks clean.  Both the RIS and MIS are set on timeout.  If I monitor them in a while loop, I am able to clear them using ICR.

    I made the following changes based on your post to the code to no avail:

    #include "LM4F230H5QR.h"
    #include <stdint.h>

    int main() {
       /* System Clock Setup in IAR Start Up */
       __asm("cpsie i"); // Clear PRIMASK (Global Interrupt Enable)

       // Clock Gating
       SYSCTL->RCGC1 = ((1U<<16)); // Enable Timer 0

       // NVIC
       NVIC_SetPriorityGrouping(0);
       NVIC_EnableIRQ(TIMER0A_IRQn);     // Enable TIMER0A Interrupt
       NVIC_SetPriority(TIMER0A_IRQn,0); // Set TIMER0A Priority

       // Timer config
       TIMER0->CFG   = 0x0;        // Set Timer 0 to 32 bit
       TIMER0->TAMR  = ((1U<<1));  // Set Timer 0 to periodic
       TIMER0->IMR   = ((1U<<0));  // Enable timeout interrupt
       TIMER0->TAILR = 0xffffffff; // Timer 0 autoload value

       // START TIMERS

       TIMER0->CTL   |= ((1U<<0));   // Enable Timer 0


       while(1){

       }
       //return 0;
    }

    Furthermore, I set the Timer to its max value so no interrupt would occur between enabling the clock and me stepping into the infinite loop for a few iterations.  When I monitor the NVIC interrupt pending register (PEND0), I see that it gets set on timeout; however the corresponding NVIC active interrupt register (ACTIVE0) bit is never set.   Therefore, the NVIC controller sees the interrupt, but will not branch.

    As I mentioned, I checked the vector table in the disassembly.  The vector table instructs the NVIC to branch to 0x000002e1.  Looking at the disassembly, my function handler starts at 0x000002e0.  If I am not mistaken, the discrepancy in the lsb has to do with the core using ARM or Thumb2 instructions, as all branch instructions should be even at all times.

    ***

    That's it.  Turns out there was nothing wrong with the above code, but it was a good exercise to look at all those registers =)

  • Hello Eric,

    This is a good read for IAR users. Thanks for detailing.

    Also on a side not the Interrupt Vector as I read it will always point to ADDR+0x1. This I believe is part of the Cortex M4 User Manual on Interrupt Vector structure.

    Regards

    Amit