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.

Starterware/EK-TM4C1294XL: Button(SW1) Interrupts on TIVAC- 1294xl launchpad

Part Number: EK-TM4C1294XL

Tool/software: Starterware

Hello, 

I've have been working on my TIVAC-1294xl launchpad. I've used the timer interrupts and want to explore the interrupts for switch. 

I did the following steps. 

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ);
    GPIODirModeSet(GPIO_PORTJ_BASE, GPIO_PIN_0, GPIO_DIR_MODE_IN);
    GPIOPadConfigSet(GPIO_PORTJ_BASE, GPIO_PIN_0, GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU);   /// FOR switch 1 
    IntMasterEnable();
    IntEnable(INT_GPIOJ);

In the startup file  i defined a function buttonpress at place of GPIO PORT J and also defined the extern function as void buttonpress(void);

Now in main.c i have the following code.

void buttonpress(void)
{
    if(GPIOPinRead(GPIO_PORTJ_BASE, GPIO_PIN_0) == 0)
    {
         // blink an LED for for debugging
    }
}
 

Can someone explain me the correct flow for switch interrupts?

  • Nishit said:
    Now in main.c i have the following code. 

    void buttonpress(void)


    Your "subject line" lists, "Switch Interrupts" - yet you list "buttonpress()" as being located in "main."     Should it not be (somewhat) free from main - and located among (other) interrups?    (if any)

    Most importantly - have you placed & declared your, "buttonpress()" function w/in your, "Start-Up file" - and mated it to "Port J's ISR slot?"     Note that there is a "long list" of ISR Sources - each must be named when, "Placed into service.    ("buttonpress" would be placed on the same line as Port J ISR  ...  assumes Port J does not provide "bit-type" interrupts)

    I don't find this (important) function w/in your code listing: "GPIOIntTypeSet()."    

    Suggested parameters for that function (may) include: "GPIO_PORTJ_BASE, GPIO_PIN_0,  GPIO_RISING (or FALLING)_EDGE (or Level)."

    SW-TM4C-DRL "User Guide" greatly details - aiding user comfort, speed, and understanding...   (and provides "reasonable" examples.)     (yet "ducks the hard ones" - apparently so that "unwanted/eased forum downgrades (i.e. excise of (LIKE) may be implemented...)

  • For reasons "unknown" (even after the alleged forum "upgrade") I cannot edit the above.

    Here are detailed illustrations of how, "our Start-Up file" is managed.    (adapted to your purposes - note that I've added "int" to your function's name to reinforce its use as an Interrupt!)

    // External declarations for the interrupt handlers used by the application.
    //
    //*****************************************************************************
    extern void IntDefaultHandler(void);
    extern void intbuttonpress(void); // You must enter this - as shown here
    .
    .
    .
    // The vector table. Note that the proper constructs must be placed on this to
    // ensure that it ends up at physical address 0x0000.0000.
    //
    //*****************************************************************************
    __root const uVectorEntry __vector_table[] @ ".intvec" =
    {
    { .ulPtr = (unsigned long)pulStack + sizeof(pulStack) },
    // The initial stack pointer
    ResetISR, // The reset handler
    NmiSR, // The NMI handler
    FaultISR, // The hard fault handler
    IntDefaultHandler, // The MPU fault handler
    IntDefaultHandler, // The bus fault handler
    IntDefaultHandler, // The usage fault handler
    .
    .
    .
    Intbuttonpress,            // GPIO Port J
    IntDefaultHandler,         // GPIO Port K
    IntDefaultHandler,         // GPIO Port L

    Suspect that the post above - amplified by herein - should get you, "On the Air!"   (at least interrupt wise...)

    I would AVOID the use of IntRegister() as it complicates & provides little benefit in (many) cases...    Simple placement w/in the Start-Up file - as directed - leads to interrupt's eased success!

  • Yes i've done the exact same thing in the startup file as you mentioned above. In int main() i have made the following changes as shown below.

    int main(void)
    {
        g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |SYSCTL_OSC_MAIN |SYSCTL_USE_PLL |SYSCTL_CFG_VCO_480), 120000000);
    
        //*****************************************************************//
        //                      Configure the LED pin                      //
    
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
        GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0);
    
        //*****************************************************************//
    
        //****************************************************************//
        //                       Configure the Switch                     //
    
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ);
        GPIODirModeSet(GPIO_PORTJ_BASE, GPIO_PIN_0, GPIO_DIR_MODE_IN);
        GPIOPadConfigSet(GPIO_PORTJ_BASE, GPIO_PIN_0, GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU);
    
        //*****************************************************************//
    
        //*****************************************************************//
        //                      Enabling the Interrupts                    //
        
        IntMasterEnable();
        IntEnable(INT_GPIOJ);
        GPIOIntTypeSet(GPIO_PORTJ_BASE, GPIO_PIN_0, GPIO_FALLING_EDGE);
    
        //*****************************************************************//
    
        while(1)
        {
    
        }
    
    	return 0;
    }

    And the buttonpress() routine is present in the main.c which includes the following code as shown.

    void buttonpress(void)
    {
        if(GPIOPinRead(GPIO_PORTJ_BASE, GPIO_PIN_0) == 0)
        {
            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, GPIO_PIN_0);
            for(ui32Loop = 0; ui32Loop < 200000; ui32Loop++)
            {
            }
            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, 0x0);
            for(ui32Loop = 0; ui32Loop < 200000; ui32Loop++)
            {
            }
        }
    }


    is the flow correct?
  • If - as you claim - you've placed the "buttonpress()" properly (i.e. aligned to Port-J) w/in the vector table - and "declared it" as well - such was never mentioned in your initial post - such detail IS required.

    Now - have you tested for & confirmed that any such "button press" (i.e. via the hardware) causes your "entry" to the buttonpress ISR?
    If that's so - what is the point of the "if clause" - as it must "have been true" that a negative edge was "felt" upon PJ0.

    More importantly - you never "Clear the Interrupt" w/in your buttonpress() ISR. Such IS required...

    It is noted that you "dwell" upon "flow" - yet the code fundamentals (appear) to be the source of your issue.    And (as always) posters fail to state (any) justification for their choices/beliefs...

  • Yes. The if clause in the in the ISR is not required which i came to know after i posted the above code. Also in my first post i had mentioned that i have defined buttonpress() at the place of PORT J and also defined the function using extern. I'll make a more detailed explanation from next time. Noted. I also checked the second statement that you mentioned about whether the execution ever enters the ISR.

    The execution never enters the ISR. Yes i'll include the clear interrupt inside the buttonpress() ISR. But first it should enter the ISR.
  • Hard to imagine that - if what you (now) say/report proves true - the "buttonpress" ISR is not entered.

    First order would see your, "Testing of the switch signal "reaching" PJ0 (@ the MCU - be careful) and that PJ0 transitions from ~3V3 to Gnd - when the switch is pressed/held. (the 3V3 results from your enabling of the "WPU" (weak pull up) internal to the MCU)

    Note that for clarity - myself/others (often) "prefix" an ISR w/"int" - which well denotes such Interrupt Role. My (sample) code for you followed that practice - if you "mix" intbuttonpress and buttonpress - errors should result and MCU confusion reigns... (along w/hapless helpers...)

    We note your use of, "GPIODirModeSet()." You may set PJ0 to serve as a GPIO Input via another API function. (well noted w/in the DRL User Guide - mentioned earlier) Should your interrupt (still) escape activation - I'd replace "dirmodeset."
  • cb1_mobile said:
    Note that for clarity - myself/others (often) "prefix" an ISR w/"int" - which well denotes such Interrupt Role. My (sample) code for you followed that practice - if you "mix" intbuttonpress and buttonpress - errors should result and MCU confusion reigns... (along w/hapless helpers...)

    I did not understand what you mean to say here? 

    Can you explain it once more in clearer words?

    Thank you!

  • You named your ISR "buttonpress." In the code I supplied - to "better" mark (or denote) the ISR - it was named "intbuttonpress."

    The name of the ISR - w/in the main program - and w/in the "Start-Up file" - must match.

    I wanted to insure that my use of the "more recognizable" intbuttonpress did not "mix" w/your continued use of buttonpress. (which is not easily recognizable as an ISR.

    You are "silent" (i.e. have not responded) to the direction to carefully "probe" PJ0 - both w/the switch actuated & idle - and confirm that PJ0 transitions from ~3V3 to Gnd. (Gnd when the switch is actuated (assuming the switch circuit "closes" to Gnd when actuated.) I do not have your MCU nor your board - the "Falling Edge" interrupt qualifier "depends" upon your switch, "closing to Gnd."
  • Hi Nishit,

    You can see some of cb1 advice at the Tivaware "interrupts" example program.

    There is also a button driver which is used at qs_iot example program.

    - kel
  • cb1_mobile said:
    First order would see your, "Testing of the switch signal "reaching" PJ0 (@ the MCU - be careful) and that PJ0 transitions from ~3V3 to Gnd - when the switch is pressed/held. (the 3V3 results from your enabling of the "WPU" (weak pull up) internal to the MCU)

    I checked the voltage on the PJ0 pin of the microcontroller. It's changing the state from 3V3 to GND whenever the button is pressed. 

    cb1_mobile said:
    We note your use of, "GPIODirModeSet()." You may set PJ0 to serve as a GPIO Input via another API function

    I also changed this and used 

    GPIOPinTypeGPIOInput(GPIO_PORTJ_BASE,GPIO_PIN_0);

    to make GPIO pin as the input. 

    In  the buttonpress() ISR,right now i'm blinking the on board LED for debugging but the execution doesn't enters the ISR. 

  • Nishit said:
    In  the buttonpress() ISR,right now i'm blinking the on board LED for debugging but the execution doesn't enter the ISR. 

    That's strange - thank you for performing the test @ the actual MCU pin PJ0.    And your change to "GPIOPinTypeGPIOInput()" was excellent.   (should occur prior to the other PJ0 configs.)

    It is assumed that you've "Placed a break-point w/in the buttonpress() ISR" is this correct?    Might you add a simple GPIO instruction "w/in and atop" that ISR - and place the break-point on that code line?

    All other code should be (temporarily) removed - we want ONLY to have the MCU "spinning in a simple loop" - and able to exit/escape ONLY upon the occurrence of the sole (only) PJ0 - falling edge interrupt!

    I'm nearing "frustration-exhaustion": follows the directed addition to your ISR:

    void buttonpress(void)

    {

    GPIOPinRead(GPIO_PORTJ_BASE, GPIO_PIN_0);    // Set your breakpoint on this code line (NOT on the function's name) and ELIMINATE the (earlier) IF

    .

    .

    }


    Should this break-point not be reached - can you break on any code line - anywhere?    Really?    When last did you check?   (best would be right now!)

  • Here's what all the things that i tried after your great guidance and following some old school methods ie using the Digital Multimeter. :p

    I soldered 2 berk pins on the breakout that is provided on the edges of the launchpad for both PJ0 and PJ1. Then i checked the connectivity of those pins (let's take only SW1 in to consideration) with the the pads of the switch. Here i was getting a connection whenever i use to press the switch. Here i noticed that the default state of PJ0 is Ground (if nothing is assigned via code to change the default state of the pin). So i made the following changes in the code to change the default state to Weak pull- up. (GPIOPadConfigSet)

    Also another thing i added was the GPIOIntRegister API which was missing in my previous code. 

    void buttonpress(void)
    {
            GPIOIntClear(GPIO_PORTJ_BASE, GPIO_INT_PIN_0);              // Clear the Interrupt flag first.
            ledBlink();
    }
    int main(void)
    {
        g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |SYSCTL_OSC_MAIN |SYSCTL_USE_PLL |SYSCTL_CFG_VCO_480), 120000000);
    
        //*****************************************************************//
        //                      Configure the LED pin                      //
    
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
        GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0);
    
        //*****************************************************************//
    
        //****************************************************************//
        //                       Configure the Switch                     //
    
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ);                                            
        GPIOPinTypeGPIOInput(GPIO_PORTJ_BASE,GPIO_PIN_0);                                           // Set the pin as Input.
        GPIOPadConfigSet(GPIO_PORTJ_BASE, GPIO_PIN_0, GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU);     // Make default state as Pull- up.
    
        //*****************************************************************//
    
        //*****************************************************************//
        //                      Enabling the Interrupts                    //
    
        GPIOIntRegister(GPIO_PORTJ_BASE, buttonpress);                      // Assign the ISR to which it should jump.
        GPIOIntTypeSet(GPIO_PORTJ_BASE, GPIO_PIN_0, GPIO_LOW_LEVEL);        // Assign the state that triggers the jump.
        GPIOIntEnable(GPIO_PORTJ_BASE, GPIO_PIN_0);                         // Enable the Interrupt for the specific pin.
        IntMasterEnable();                                                  // Enable interrupt for the controller.
    
        //*****************************************************************//
    
        while(1)
        {
    
        }
    
    	return 0;
    }
    

    Later tried the same code for both the buttons (SW1 and SW2) and it works smoothly as expected. 

    Thank you for your quick and astute responses whenever any questions are asked. 

    Regards,

    Nishit.

  • Nishit said:
    Thank you for your quick and astute responses whenever any questions are asked. 

    Thank you for your kindness & (earlier) persistence in accepting some/slight tech direction.

    It is noted that you changed the code from, "Falling Edge Detect" to "GPIO Low Level."     Now such "Level Detect" - while sustained - is likely to cause (near) continuous, "Return Entry to your "button-press" ISR!"    Is that (really) what you desire?    The "Edge Detect" method avoids such.

    While your kind remark IS appreciated - the award of, "Verified Answer" has "escaped" any/all of my posts.     (In absence of the "exiled LIKE" button - such "Verify Reward" (applied to the "helper's" post(s)) proves most useful...