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.

How to use the interrupt for SW1 (GPIO pin PF4) on the Tive C Series Launchpad (TM4C123G).

I am using the launchpad in a CAN application and would like to use SW1 to change state. What does the interrupt look like for this button (GPIO pin PF4)?

  • Hi Brian,

         You can see how it is initialized at ButtionsInit(), which can be found at \\drivers\buttons.c

    -kel

  • Hi Brian,

    see this example on how to setup the pin, register and also switch the interrupt handler routine.

    #include <stdint.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include "inc/hw_memmap.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/gpio.h"
    #include "driverlib/sysctl.h"
    
    void onButtonDown(void);
    void onButtonUp(void);
    
    void onButtonDown(void) {
    	if (GPIOIntStatus(GPIO_PORTF_BASE, false) & GPIO_PIN_4) {
    		// PF4 was interrupt cause
    		printf("Button Down\n");
    		GPIOIntRegister(GPIO_PORTF_BASE, onButtonUp);	// Register our handler function for port F
    		GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_4,
    			GPIO_RISING_EDGE);			// Configure PF4 for rising edge trigger
    		GPIOIntClear(GPIO_PORTF_BASE, GPIO_PIN_4);	// Clear interrupt flag
    	}
    }
    
    void onButtonUp(void) {
    	if (GPIOIntStatus(GPIO_PORTF_BASE, false) & GPIO_PIN_4) {
    		// PF4 was interrupt cause
    		printf("Button Up\n");
    		GPIOIntRegister(GPIO_PORTF_BASE, onButtonDown);	// Register our handler function for port F
    		GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_4,
    			GPIO_FALLING_EDGE);			// Configure PF4 for falling edge trigger
    		GPIOIntClear(GPIO_PORTF_BASE, GPIO_PIN_4);	// Clear interrupt flag
    	}
    }
    
    int main(void) {
    	SysCtlClockSet(SYSCTL_SYSDIV_2_5| SYSCTL_USE_PLL | SYSCTL_OSC_INT | SYSCTL_XTAL_16MHZ);
    
    	// Pin F4 setup
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);		// Enable port F
    	GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_4);	// Init PF4 as input
    	GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4,
    		GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);	// Enable weak pullup resistor for PF4
    
    	// Interrupt setuü
    	GPIOIntDisable(GPIO_PORTF_BASE, GPIO_PIN_4);		// Disable interrupt for PF4 (in case it was enabled)
    	GPIOIntClear(GPIO_PORTF_BASE, GPIO_PIN_4);		// Clear pending interrupts for PF4
    	GPIOIntRegister(GPIO_PORTF_BASE, onButtonDown);		// Register our handler function for port F
    	GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_4,
    		GPIO_FALLING_EDGE);				// Configure PF4 for falling edge trigger
    	GPIOIntEnable(GPIO_PORTF_BASE, GPIO_PIN_4);		// Enable interrupt for PF4
    
    	while(1);
    }
    

    Cheers

    Janos

  • Hi ,

    I was trying out the code given above with IAR 6.60 and Tiva C eval board . The compiler works fine with it (0 errors); the linker gives me following errors ..

    Building configuration: Button_Intr - Debug

    Updating build tree...

    Button_2.c  

    Linking

    Error[Li005]: no definition for "SysCtlClockSet" [referenced from D:\WorkSpace\DIY\LED_Button_Interrupt\Debug\Obj\Button_2.o]

    Error[Li005]: no definition for "SysCtlPeripheralEnable" [referenced from D:\WorkSpace\DIY\LED_Button_Interrupt\Debug\Obj\Button_2.o]

    Error[Li005]: no definition for "GPIOPinTypeGPIOInput" [referenced from D:\WorkSpace\DIY\LED_Button_Interrupt\Debug\Obj\Button_2.o]

    Error[Li005]: no definition for "GPIOPadConfigSet" [referenced from D:\WorkSpace\DIY\LED_Button_Interrupt\Debug\Obj\Button_2.o]

    Error[Li005]: no definition for "GPIOIntDisable" [referenced from D:\WorkSpace\DIY\LED_Button_Interrupt\Debug\Obj\Button_2.o]

    Error[Li005]: no definition for "GPIOIntClear" [referenced from D:\WorkSpace\DIY\LED_Button_Interrupt\Debug\Obj\Button_2.o]

    Error[Li005]: no definition for "GPIOIntRegister" [referenced from D:\WorkSpace\DIY\LED_Button_Interrupt\Debug\Obj\Button_2.o]

    Error[Li005]: no definition for "GPIOIntTypeSet" [referenced from D:\WorkSpace\DIY\LED_Button_Interrupt\Debug\Obj\Button_2.o]

    Error[Li005]: no definition for "GPIOIntEnable" [referenced from D:\WorkSpace\DIY\LED_Button_Interrupt\Debug\Obj\Button_2.o]

    Error[Li005]: no definition for "GPIOIntStatus" [referenced from D:\WorkSpace\DIY\LED_Button_Interrupt\Debug\Obj\Button_2.o]

    Error while running Linker

    Total number of errors: 10

    Total number of warnings: 0

    I have added libraries in Project > Options > C/ C++ Compiler > Preprocessor .

    Any thing more I need to do ? I'm bit new to this . 

    Thanks !

  • I know it's a bit old topic, but could someone explain to me what happens when

    if (GPIOIntStatus(GPIO_PORTF_BASE, false) & GPIO_PIN_4)

    block statement is removed from both functions?

    Lets say buttonDown turns off the LED and buttonUP turns on LED. 
    Why are there glitches and sometimes LED is off when it should be actually on?

  • Hello Michal,

    The GPIOIntStatus returns the value of the GPIORIS register and in this case, AND's it with the Pin 4 mask. So if the condition for the interrupt has occurred for the Pin then the if statement is true.

    What is the condition that has been set for the interrupt generation? Is there a LPF on the pin?

    Regards
    Amit
  • Michal Plebanski said:
    Why are there glitches and sometimes LED is off when it should be actually on?

    Might there be a "linkage" between simple, inexpensive, mechanical switches and your report of, "glitches?"

    Such switches, "Open & close" their contacts several times during operation.   As the MCU is SO much faster than those crude switches - it can become confounded by the "multiple" signal arrivals.

    Normal/customary means of reducing (often eliminating) such glitches is to include proper "Switch Debounce" techniques.   As you've "jumped onto" an old thread - and your code base is not available for read/review - your description of "glitch" is usually resolved as mentioned - above...

  • Maybe it helps someone:

    I found out that code reenters the interruption handler because clearing IRQ flag in the last instruction of a handler might result in reentrance to handler due to buffered write to clear the flag.
  • Hello Michal,

    Yes, it may be the case. A small delay loop after the clear operation like SysCtlDely(3) can help avoid the re-entrant ISR.

    Regards
    Amit
  • i just used the code for testing and then found out a very interesting issue.

    When i modified the GPIO_PIN_4 in the code into GPIO_PIN_0, which means i wanna use SW2 instead of SW1. The code doesn't work at  all!!

    I guarantee that my board works well. I am just so confused why?

    cheers,

    alex

  • Did you note that PF0 is burdened w/the always delightful NMI default? Must be unlocked to use as you desire...

    Read/review of the GPIO section - MCU manual - will detail.   (hundreds of posts here detail vendor's "ever helpful" default to NMI decision...)

  • Hello Alex,

    To add to cb1's message, please read the following post for Locked Pins.

    e2e.ti.com/.../374640

    Regards
    Amit
  • hi Amit,

    thanks for your link.

    as followed the instruction in the link,
    i add those two lines,
    HWREG(GPIO_PORTF_BASE+GPIO_O_LOCK) = GPIO_LOCK_KEY;

    HWREG(GPIO_PORTF_BASE+GPIO_O_CR) |= GPIO_PIN_0;

    and also replace the GPIO_PIN_4 in the coding with GPIO_PIN_0,

    but when i pressed the button SW2, still didn't work.

    regards,
    alex
  • Hello Alex,

    You would need to enable the Pull up of the IO. There is no external pull resistor. Hence the IO is always at logic low unless a spurious noise wide enough can cause a toggle.

    Regards
    Amit
  • you mean this code:
    GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_0,GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU); // Enable weak pullup resistor for PF4
    ?

    i added it already in the coding, but still doesn't work :-(.

    i am a beginner so maybe i still made some stupid mistake sorry about that.

    regards,
    alex
  • Hello Alex,

    Yes, that is correct. After adding the code can you check in the GPIO DATA register that the value 0x1 (bit 0 must be set) shows up corresponding to PF0 being high.

    Regards
    Amit
  • Hey Janos, Excellent Post! It worked well!

    I have two questions about your implementation:

    1st) I was wondering how was possible registering a different function name for the interruption in your code? Are we not suppose to use the GPIOFInt_Handler()? How was that possible??

    2nd) how did you get the printf("\n"); function working? I've never made it work. 

    3rd) How did you solve bouncing problems? I ran your code and sometimes the switch bounced. Under the interrupt context, would you have an idea of how to overcome this?


    Thanks!

  • Michal,
    I suggest you don't implement the interrupt as per the posted code above. That solution keeps changing the interrupt service routine registered either for the button being pressed or released. That is confusing, and unnecessary processing, particularly during the brief moments in which you press or release and the mechanics of your switch toggles the signal a few times (read about "debouncing").
    Keep ONE SINGLE routine to service your interrupts for one port. Inside the routine, check the condition of the pin and take the actions you want.
    This will be even more important when you deal with more pins on the same port.
    Regards
    Bruno
  • Hello Thiago

    To register a new function name you could use the function name in the startup file vector table. Another method is to register using GPIOIntRegister API call. However this will eat up SRAM space as the vector table is relocated to SRAM
  • Amit,
    In the Startup_ccs, where I can find the vector table, the function names are not defined, so I always defined them manually. So, this method IntRegister was new for me. Thanks for sharing about the SRAM space!
  • Thiago,

    Look at the image below.

    You just need to place the name of your function on the correct position of the DATA_SECTION shown (replace IntDefaultHandler). The example in blue works for the SysTick handler. And you also need to declare the same function as extern on the piece of code right before the table.

    Bruno