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: Interrupt in Tivaware Timer never runs

Part Number: TM4C123GH6PM
Other Parts Discussed in Thread: TM4C123AH6PM, TM4C129ENCPDT

Hi everyone. I am currently using timer.c from tivaware and built a code to use it for an ultrasound sensor.  My problem is that my interruptions never get called.  I will include part of my code in hope for someone can help me out.  Thanks in advance. 

Information:  I am using TIMER1 so I use PF2 and PF3. The program keeps getting stucked in the while flagB loop and never gets out because the interruption TIMER1BHANDLER never runs and so flagB doesnt update to 1.  

#include "timer.h"
#include <stdint.h>
#include "tm4c123gh6pm.h"
#include "interrupt.h"
#include "sysctl.h"

#define TIMER1 0x40031000
#define PERIODO 62.5

#define ECHO 0x04 //PF2
#define TRIG  0x08  //PF3

uint8_t flagB;

void ConfigGPIO(void){
    SYSCTL_RCGCGPIO_R |= 0x20;
    while(!(SYSCTL_PRGPIO_R & 0x20));

    GPIO_PORTF_DIR_R |= TRIG;
    GPIO_PORTF_DIR_R &= ~(ECHO);

    GPIO_PORTF_AFSEL_R |= (TRIG|ECHO);
    GPIO_PORTF_PCTL_R |= (GPIO_PORTF_PCTL_R & 0xFFFF00FF) | 0x7700;
    GPIO_PORTF_AMSEL_R &= ~(ECHO|TRIG);
    GPIO_PORTF_DEN_R |= (ECHO|TRIG);

}

void ConfigHCSR04(void){

    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER1));

    TimerDisable(TIMER1,TIMER_BOTH);

   // (T1CCP0 connect to ECHO.)
    TimerConfigure(TIMER1,(TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_CAP_TIME|TIMER_CFG_B_ONE_SHOT));
    TimerControlEvent(TIMER1,TIMER_A,TIMER_EVENT_BOTH_EDGES);
    TimerControlEvent(TIMER1,TIMER_B,TIMER_EVENT_NEG_EDGE);

    TimerIntEnable(TIMER1,(TIMER_CAPA_EVENT|TIMER_TIMB_TIMEOUT));
    TimerIntRegister(TIMER1,TIMER_A,&Timer1AHandler);
    TimerIntRegister(TIMER1,TIMER_B,&Timer1BHandler);

    IntMasterEnable();
    IntEnable(INT_TIMER1B);
    IntEnable(INT_TIMER1A);

    //TimerA  24 bits. TimerB  16 bits.
    TimerPrescaleSet(TIMER1,TIMER_A,0xFF);
    TimerLoadSet(TIMER1,TIMER_A,0xFFFF);
    TimerLoadSet(TIMER1,TIMER_B,(10000/PERIODO));  //timeout in 10 uS

    TimerEnable(TIMER1,TIMER_A);

}
 
void Timer1BHandler(void){
    GPIO_PORTF_DATA_R &= ~(TRIG);
    TimerIntClear(TIMER1,TIMER_TIMB_TIMEOUT);
    flagB = 1;
}

void main(void){
    ConfigHCSR04();
    ConfigGPIO();

    while(1){
        if (!(GPIO_PORTF_DATA_R & ECHO)){   //Si no estoy haciendo medicion entonces emito ultrasonido.
            GPIO_PORTF_DATA_R |= TRIG;
            TimerEnable(TIMER1,TIMER_B);
            while(!flagB);
            flagB = 0;
        }
}

  • Hello Richard,

    Given you have a mix of DRM code and TivaWare code, it is a bit hard to say what might all be going on.

    Some things I am seeing at first glance:

    1) I don't see a SysCtlPeripheralEnable call or something akin to it.

    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);

    2) You have TimerIntEnable, but don't have global Interrupt enable calls

    IntMasterEnable();
    IntEnable(INT_TIMER1B);

    3) You have Timer 1A and 1B setup, and interrupts enabled for them both, but I only see one ISR.

    4) It is not clear if you added your ISR correctly to the startup_ccs.c file, so make sure you do that as well.

    5) I don't see your GPIO configure code so make sure you have a SysCtlPeripheralEnable call for it as well.

  • Hi first of all thanks for taking your time to respond me. I definitely didn't include the global interrupt enable calls because i didn't know i needed to. Are these functions all i need to include from interrupt.c? I am really not that familiar with interrupts sorry. Anyway I included them now.

    I change my DMR in activating clock to SysCtlPeripheral as you suggested. (although i think they are the same).
    In startup_ccs.c file I declared both ISR(I have only included my ISR on TimerB in this thread) with extern under the section "To be added by the User". After that I included their names in their respective section in DATA_SECTION.

    I have configured GPIO through DMR. After all of these my problem still persists: flagB never turns 1. Is there anything left to do that i havent? Thanks again!

    Just in case I edited my code in my thread and included my GPIO configuration  so if you have a bit of time please take a look at it.

  • I'd like to mention something about DRM...

    Your code has this include: #include "tm4c123gh6pm.h"

    Here's a bug that bit us in the not-too-distant past. We had an include like that in our source code and everything was great, except that we have the same codebase for several boards, including several different TM4C parts, such as a TM4C129ENCPDT, a TM4C123AH6PM, etc. Unbeknownst to us (we had forgotten), we had the include "tm4c129encpdt.h" somewhere in our code. When we compiled that codebase for TM4C123AH6PM, some mappings for TM4C129ENCPDT were used, which caused interrupts not to trigger and other quite fascinating and very much unwanted side effects.

    For that reason, either do not include the part-specific header(s), or if you must, then place ifdef guards around that include to make sure that it is included only if the symbol PART_TM4C123GH6PM is defined.
  • Hello Richard,

    If you pause your code in debugger, where does it land? I want to understand if it lands in any of the ISR's used to catch errors.
  • Hi. It gets stucked in the while(!flagB) loop forever.  I would play it and wait for a moment and then stop and it will still be there because my flagB never becomes 1.

    Thanks for the recomendation twelve12pm. I will consider header guard in my future projects if it becomes necessary.

  • " if you must, then place ifdef guards around that include to..."

    TI actually does provide such a file, in distribution that uses CMSIS: github.com/.../CMSIS-framework-for-TM4-devices

  • "#define TIMER1 0x40031000"

    you may not want to use that. Instead, I would rely on the device header files.

    I would check the registers to make sure that 1) the timer is running; 2) the interrupt is enabled; and 3) if necessary, the vector table has the right address for your ISR - under driverlib, you will need to register the isr.

    I would also just flip a pin in the ISR to make it more explicit.
  • Hi everyone. I checked again very specifically everything and want to share what i know:

    Timers are both running fine.  The timerB RIS also activates.   The interrupt NVIC_EN0 register shows both timer1 timers enabled.  (I dont know about NVIC, but checked data sheet to find out those numbers correspond to timer1 timers.)    When I get to TimerEnable(TIMER1, TIMER_B).   The timer indeed runs as RIS flag is toggled.  However it inmediately jumps to while(!flagB) and never goes to Timer1BHandler ISR.  I also see NVIC_Pend0 has a 4 in it which is timerB.   I think this is telling me ISR is not registered correctly.   The interrupt mask bits for each of the timers are correctly set to 1. 

    Could someone please guide me how to setup correctly my ISR? All I have done is what i have said in the startup_ccs.c and using TimerIntRegister().  Thanks for everyone for trying to help me out once again.

  • Ralph please check out my last response! I would really appreciate it.
  • Hello Richard,

    Thanks for clearing up some of the configurations and adding in the extra initialization code.

    Have you tried a setting a breakpoint in the ISR? Does it never hit a breakpoint inside of the ISR?

    If you haven't tried that, then perhaps the issue is because your variable being changed in the ISR isn't declared as a "volatile" variable.

    Try instead of making it 'uint8_t flagB;', to make it 'volatile uint8_t flagB;'
  • Hi Richard,

    I ran a slightly cleaned up version of your code only using Timer 1B and the flagb variable needed to be set as a volatile to correctly update, the initialization when using TivaWare was fine. Please try making your variable volatile and see if the issue resolves.
  • Hi Ralph. Thanks a lot now it does update! I still have some question. Do i need to put volatile every variable in ISR? Is it possible to see ISR step by step? Only by putting play the flagB updates so it looks like I wont be able to debug step by step inside the ISR.
  • Hello Richard,

    Volatile is needed for any global variable which will change it's value within an ISR. If it is not set to volatile, then the value may not get correctly recognized by the compiler optimization system as a variable which will change value when the ISR executes. That is what was occurring in your situation I believe.

    You can go through ISR's step by step. Though CCS occasionally can be picky about where exactly it allows you to place breakpoints, I think that is all based on the compiler optimizations applied to code, but I am not a CCS expert so don't take my word as gospel :)

    You should check out this article about Volatile variables, especially the section concerning updating global variables in an ISR as it is almost exactly what is going on for your situation: https://barrgroup.com/Embedded-Systems/How-To/C-Volatile-Keyword

  • Use volatile whenever a variable is accessed by more than one context (ISR, thread, main loop). These contexts are "asynchronous" to each other meaning that they can interrupt each other at any point in the code. A single line of code in C may be compiled to many processor instructions so in effect this means that code can be interrupted "in the middle of a line" too.

    If you find yourself having to declare too many variables volatile, check whether the code is designed correctly. Having too many contexts operating on the same data can lead to interactions that are difficult to predict.