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.

What is correct initialization for Launchpad TM4C123 button interrupts?

I cannot correctly initialize either of the buttons on the Lauchpad to connect to the GPIO interrupts PF4 or PF0.  I am using Tivaware 2.1 and CCS 5.5.  I have read multiple posts which explain the required code to use these buttons to generate interrupts which seems clear to me, but still my code does not work correctly.

The code shown for button 1 (SW1 in code) produces an immediate and constant SW1 interrupt.

When I comment out the 4 lines in GPIO_Init() which initialize the PF4 interrupt associated with button1 (SW1), the modified code executed as expected, using polling for the 2 Launchpad buttons and an additional button on a proto board, AND uses an interrupt (PC7) for another button (SWP) on the proto board !!!    This interrupt executed as expected.  It is the only one I can get to work.

I apologize for posting so basic an issue, but I have tried in vain over 3 days to identify the issue.

I have multiple clocks with interrupts,  I2c, and QEI modules running correctly but am fairly new to CCS and the Tiva parts.

I have tried removing the prototype board to eliminate any associated hardware/software issues and get similar results.  I could simply use polling to avoid the issue (as I have done for now) but NEED external interrupts for other parts of the project.

Code snippets are posted below.

Any help will be appreciated very much,

Randy

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// called when the processor receives an SW1 button push interrupt, port F4

void SW1_IntHandler (void)
{
    int32_t    swp_button_active;

    printf ("SW1 interrupt\n");
    // test for button active to debounce a little
    swp_button_active = GPIOPinRead (GPIO_PORTF_BASE, GPIO_PIN_4);
    if (swp_button_active != GPIO_PIN_4)
    {
        // post sw+ semaphore
        Semaphore_post (SW1_Sem);
    }
    GPIOIntClear (GPIO_PORTF_BASE, GPIO_INT_PIN_4);

}
/************************************************************************************/

// called when the processor receives an SW2 button push interrupt, port F0

void SW2_IntHandler (void)
{
    int32_t    swp_button_active;

    GPIOIntClear (GPIO_PORTF_BASE, GPIO_INT_PIN_0);
    printf ("SW2 interrupt\n");
    // test for button active to debounce a little
    swp_button_active = GPIOPinRead (GPIO_PORTF_BASE, GPIO_PIN_0);
    if (swp_button_active != GPIO_PIN_0)
    {
        // post sw+ semaphore
        Semaphore_post (SW2_Sem);
    }
}

/************************************************************************************/

// called when the processor receives an SW+ button push interrupt, port C7

void SWP_IntHandler (void)
{
    int32_t    swp_button_active;

    GPIOIntClear (GPIO_PORTC_BASE, GPIO_INT_PIN_7);
    printf ("SWP interrupt\n");
    // test for button active to debounce a little
    swp_button_active = GPIOPinRead (GPIO_PORTC_BASE, GPIO_PIN_7);
    if (swp_button_active != GPIO_PIN_7)
    {
        // post sw+ semaphore
        Semaphore_post (SWP_Sem);
    }
}

/************************************************************************************/
// called when the processor receives an SW- button push interrupt, port C6

void SWM_IntHandler (void)
{
    int32_t    swm_button_active;

    GPIOIntClear (GPIO_PORTC_BASE, GPIO_INT_PIN_6);
    printf ("SWM interrupt\n");
    // test for button active to debounce a little
    swm_button_active = GPIOPinRead (GPIO_PORTC_BASE, GPIO_PIN_6);
    if (swm_button_active != GPIO_PIN_6)
    {
        // post sw- semaphore
        Semaphore_post (SWM_Sem);
    }
}

/***********************************************************************************************************/
void PeripheralEnableInit(Void)
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
}

//************************************************************************************

void GPIO_Init (void)
{
    // Setup the LED GPIO pins used
    GPIOPinTypeGPIOOutput (GPIO_PORTF_BASE, GPIO_PIN_1); // EK_TM4C123GXL_LED_RED
    GPIOPinTypeGPIOOutput (GPIO_PORTF_BASE, GPIO_PIN_2); // EK_TM4C123GXL_LED_BLUE
    GPIOPinTypeGPIOOutput (GPIO_PORTF_BASE, GPIO_PIN_3); // EK_TM4C123GXL_LED_GREEN

    //////////////////////////////////////////////////////////////////////////////////
    // SW1, PF4

    GPIOPinTypeGPIOInput    (GPIO_PORTF_BASE, GPIO_PIN_4);
    GPIOPadConfigSet        (GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU);
    // interrupt setup, comment out the next 4 lines & polling & SWP interrupt work
    GPIOIntDisable            (GPIO_PORTF_BASE, GPIO_INT_PIN_4);
    GPIOIntClear            (GPIO_PORTF_BASE, GPIO_INT_PIN_4);
    GPIOIntRegister            (GPIO_PORTF_BASE, SW1_IntHandler);    // causes .vtable to exist
    GPIOIntTypeSet            (GPIO_PORTF_BASE, GPIO_INT_PIN_4, GPIO_FALLING_EDGE);

    //////////////////////////////////////////////////////////////////////////////////
    // SW2, PF0 requires unlocking before configuration

    HWREG    (GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG    (GPIO_PORTF_BASE + GPIO_O_CR) |= GPIO_PIN_0;
    //GPIOIntDisable        (GPIO_PORTF_BASE, GPIO_INT_PIN_0);
    //GPIOIntRegister        (GPIO_PORTF_BASE, SW2_IntHandler);
    //GPIOIntTypeSet        (GPIO_PORTF_BASE, GPIO_INT_PIN_0, GPIO_FALLING_EDGE);
    GPIOPinTypeGPIOInput    (GPIO_PORTF_BASE, GPIO_PIN_0);
    GPIOPadConfigSet        (GPIO_PORTF_BASE, GPIO_PIN_0, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU);
    HWREG    (GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_M;


    //////////////////////////////////////////////////////////////////////////////////
    // SWP    PC7    works

    GPIOIntDisable        (GPIO_PORTC_BASE, GPIO_INT_PIN_7);
    GPIOIntRegister        (GPIO_PORTC_BASE, SWP_IntHandler);    // causes .vtable to exist
    GPIOIntTypeSet        (GPIO_PORTC_BASE, GPIO_INT_PIN_7, GPIO_FALLING_EDGE);
    GPIOPinTypeGPIOInput(GPIO_PORTC_BASE, GPIO_PIN_7);
    GPIOPadConfigSet    (GPIO_PORTC_BASE, GPIO_PIN_7, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU);



    //////////////////////////////////////////////////////////////////////////////////
    // SW-    PC6
    GPIOIntDisable        (GPIO_PORTC_BASE, GPIO_INT_PIN_6);
    //GPIOIntRegister    (GPIO_PORTC_BASE, SWM_IntHandler);    // causes .vtable to exist
    //GPIOIntTypeSet    (GPIO_PORTC_BASE, GPIO_INT_PIN_6, GPIO_FALLING_EDGE);
    GPIOPinTypeGPIOInput(GPIO_PORTC_BASE, GPIO_PIN_6);  // FrontPanel Sw-
    GPIOPadConfigSet     (GPIO_PORTC_BASE, GPIO_PIN_6, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU);


}  // FrontPanelInitGPIO()
/**********************************************************************************************************/

Void i2c_task()
{
....

    // sw1, PF4
    GPIOIntClear     (GPIO_PORTF_BASE, GPIO_INT_PIN_4);
    GPIOIntEnable    (GPIO_PORTF_BASE, GPIO_INT_PIN_4);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

  • Hello Randy

    Please change the following

        GPIOIntDisable            (GPIO_PORTF_BASE, GPIO_INT_PIN_4);
        GPIOIntClear            (GPIO_PORTF_BASE, GPIO_INT_PIN_4);
        GPIOIntRegister            (GPIO_PORTF_BASE, SW1_IntHandler);    // causes .vtable to exist
        GPIOIntTypeSet            (GPIO_PORTF_BASE, GPIO_INT_PIN_4, GPIO_FALLING_EDGE);

    to

        GPIOIntDisable            (GPIO_PORTF_BASE, GPIO_INT_PIN_4);
        GPIOIntTypeSet            (GPIO_PORTF_BASE, GPIO_INT_PIN_4, GPIO_FALLING_EDGE);

        GPIOIntClear            (GPIO_PORTF_BASE, GPIO_INT_PIN_4);
        GPIOIntRegister            (GPIO_PORTF_BASE, SW1_IntHandler);    // causes .vtable to exist

    Regards

    Amit

  • Hello Amit,

    Thanks for quick reply.

    I tried your suggestion but unfortunately I still have the same result.  ANytime the button 1, PF4 interrupt is enabled, the system cycles constantly with the printf from the interrupt routine displaying constantly & nothing else running.

    When I disable the PF4 interrupt, I can correctly receive the PC7 interrupt from the prototype board.

    I am going to simplify the program to have virtually nothing except the initialization & interrupt routines and I will report results thinking perhaps other code in application is causing issue.  I have tried this before but simplifying is best idea I have now.

    Thanks again,

    Randy

  • Hi Amit,

    I have only the button1 interrupt enabled.  The interrupt does not occur.  The code does detect the button push.

    Other info is that in the .cfg file for the application I have had the following as the last line for all testing:

    Program.sectMap[".vtable"] = "SRAM";

    I did this in order to get a successful link at build time.  I do not really know if this is correct.

    Map is below.

    MEMORY CONFIGURATION

             name            origin    length      used     unused   attr    fill
    ----------------------  --------  ---------  --------  --------  ----  --------
      FLASH                 00000000   00040000  0000ad2c  000352d4  R  X
      SRAM                  20000000   00008000  00005228  00002dd8  RW X


    SEGMENT ALLOCATION MAP

    run origin  load origin   length   init length attrs members
    ----------  ----------- ---------- ----------- ----- -------
    00000000    00000000    0000ad2e   0000ad2e    r-x
      00000000    00000000    00000360   00000360    r-- .resetVecs
      00000360    00000360    000087fa   000087fa    r-x .text
      00008b5c    00008b5c    000021d2   000021d2    r-- .const
    20000000    20000000    00004540   00000000    rw-
      20000000    20000000    00000360   00000000    rw- .vecs
      20000360    20000360    000031e0   00000000    rw- .bss
      20003540    20003540    00001000   00000000    rw- .stack
    20004540    20004540    00000a7c   00000a7c    rw-
      20004540    20004540    00000a7c   00000a7c    rw- .data
    20005000    20005000    0000026c   00000000    rw-
      20005000    20005000    0000026c   00000000    rw- .vtable

  • Hi Kel,

    Thanks for the post.  I had previously reviewed that post and think I conform to the recommended init code.  So the issue lies elsewhere.   What I think I have learned is that the issue is NOT the short interrupt initialization sequence, but an incorrect setup of the interrupt vectors (also?).

    Some examples have the interrupt vector table defined at compile time.  When this is done, Is the call GPIOIntRegister() still required?

  • Hi,

    The correct initialization and use of switch buttons in any microcontoller must take into account the debouncing process - you have two possible options to learn it:

    a) read this thread and the references highlighted there: http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/p/327836/1142147.aspx#1142147

    b) look to application qs-rgb and see how is done there.

    Any GPIO interrupt is mainly incorrect as long as does not take into account the debugging. Can be done, but not as shown in some code snippets suggested.

    To have the vector interrupts in RAM, no need to modify the linker file - just simply use the ROM_version of IntRegister function. 

    Petrei