You are here

More PDL Examples - Port Interrupts | Cypress Semiconductor

More PDL Examples - Port Interrupts

In my last post I covered input pins and compared the component and firmware-only approaches. Now I shall do the same with interrupts. If you remember, I have a very simple design with just a couple of pins - SW2 (input) and LED9 (output). 

Input and output pins in PSoC Creator schematic

To start the interrupt discussion I open the customizer for the SW2 GPIO component,  enable interrupts and select a falling edge condition. The falling edge means I will get an interrupt when I press, rather than release, the button.

Selecting Falling Edge Interrupts in the PSoC GPIO_PDL Component

Notice that, unlike with PSoC 4 projects, the component instance does not expose an interrupt terminal. This is because pins generate interrupts on a port and so multiple pins may need to share an interrupt. For example, in last week's project I put two switches on port 0 and so, if I configured both to generate interrupts, they would share just one actual IRQ with the wonderful name "ioss_interrupts_gpio_0_IRQn". PSoC Creator does not support wiring multiple interrupt terminals to one interrupt component and so we created a Global Signal Reference component that lets you pick an IRQ and attach an interrupt component.
IMG Configuring IRQ0 in PSoC Creator - two images

Configuring IRQ0 in PSoC Creator

Configuring IRQ0 in PSoC Creator

One thing to remember here is that if you re-map the pin to another port via the resources file then make sure you re-select the port IRQ to match the new one or your interrupts will stop firing.

In firmware I need to install and enable the interrupt handler and remove all the code from the main loop. Notice how I use the generated SW2_Int_cfg struct in the function arguments. That is the initialization struct generated by the SW2_Int component. I'll talk about this a little more in a moment!

    Cy_SysInt_Init( &SW2_Int_cfg, button_handler );
    NVIC_EnableIRQ( SW2_Int_cfg.intrSrc );

In my handler I just toggle the pin so that it turns on and off when I press the switch. Here is all the code.

void button_handler( void )
{
    Cy_GPIO_ClearInterrupt( SW2_PORT, SW2_NUM );
    Cy_GPIO_Write( LED9_PORT, LED9_NUM, ! Cy_GPIO_ReadOut( LED9_PORT, LED9_NUM ) );
}

int main(void)
{    
    Cy_SysInt_Init( &SW2_Int_cfg, button_handler );
    NVIC_EnableIRQ( SW2_Int_cfg.intrSrc );
    
    __enable_irq();
    
    for(;;)
    {   
    }
}

Now let's re-write that for the firmware-only solution. It is mostly the same except I need to set the interrupt condition to falling edge in firmware and tell the port that I want to interrupt on this pin (bit). Here is the code to replicate the program above for the manual (jumper wire) SW2 switch and LED8.

#define LED8_PORT   GPIO_PRT1  
#define LED8_NUM    5
#define SW_PORT     GPIO_PRT0
#define SW_NUM      2

void button_handler( void )
{
    Cy_GPIO_ClearInterrupt( SW_PORT, SW_NUM );
    Cy_GPIO_Write( LED8_PORT, LED8_NUM, !Cy_GPIO_ReadOut( LED8_PORT, LED8_NUM ) );
}
int main(void)
{    
    Cy_GPIO_Pin_FastInit( LED8_PORT, LED8_NUM, CY_GPIO_DM_STRONG, 1, HSIOM_SEL_GPIO );
    Cy_GPIO_Pin_FastInit( SW_PORT, SW_NUM, CY_GPIO_DM_PULLUP, 1, HSIOM_SEL_GPIO );
    Cy_GPIO_SetInterruptEdge( SW_PORT, SW_NUM, CY_GPIO_INTR_FALLING );
    Cy_GPIO_SetInterruptMask( SW_PORT, SW_NUM, 1 );
    
    cy_stc_sysint_t SW_Int_cfg = { ioss_interrupts_gpio_0_IRQn, 3 };
    Cy_SysInt_Init( &SW_Int_cfg, button_handler );
    NVIC_EnableIRQ( SW_Int_cfg.intrSrc );
    
    __enable_irq();
    
    for(;;)
    {       
    }
}

Notice that I have to create my own cy_stc_sysint_t struct for the call to Cy_SysInt_Init(). It's not a hardship - just two members - the port number and interrupt priority. I'll finish the article by merging the two solutions - using one port IRQ to toggle two LEDs with two switches (I deliberately put my jumper wire switch on port 0 to make this point). All I have to do is add some code to the handler to recognize the generating pin. PDL gives us the Cy_GPIO_GetInterruptStatus() function to do just that.

void button_handler( void )

    if( Cy_GPIO_GetInterruptStatus( SW_PORT, SW_NUM ) == CY_GPIO_INTR_STATUS_MASK )
    {
        Cy_GPIO_ClearInterrupt( SW_PORT, SW_NUM );
        Cy_GPIO_Write( LED8_PORT, LED8_NUM, !Cy_GPIO_ReadOut( LED8_PORT, LED8_NUM ) );
    }
    else if( Cy_GPIO_GetInterruptStatus( SW2_PORT, SW2_NUM ) == CY_GPIO_INTR_STATUS_MASK )
    {
        Cy_GPIO_ClearInterrupt( SW2_PORT, SW2_NUM );
        Cy_GPIO_Write( LED9_PORT, LED9_NUM, !Cy_GPIO_ReadOut( LED9_PORT, LED9_NUM ) );
    }
}

I made no changes to the body of the main() program because it already sets up the SW switch and installs the ISR into the vector table. My program reliably toggles the LEDs (although I have to admit that my jumper wire switch is far from clean and tends to generate many interrupts whenever I poke the wire into the J4 header).

As you can see, it is perfectly simple to use interrupts with the schematic file or firmware-only, or even with a mixture of the two. There is no performance advantage in either approach and so which one to use is entirely up to you. I tend to like the firmware approach because I can read the pin drive mode, physical address (e.g.P0.2), interrupt condition, priority level and enablement, all in my C code. Some of my colleagues, the other hand, are very thorough at documenting their hardware setup in the schematic file, with multiple pages and plenty of text boxes, so they prefer the schematic approach. Who is right? Well, its me, obviously, but that may depend on who you ask!

 

Blog: 

ALL CONTENT AND MATERIALS ON THIS SITE ARE PROVIDED "AS IS". CYPRESS SEMICONDUCTOR AND ITS RESPECTIVE SUPPLIERS MAKE NO REPRESENTATIONS ABOUT THE SUITABILITY OF THESE MATERIALS FOR ANY PURPOSE AND DISCLAIM ALL WARRANTIES AND CONDITIONS WITH REGARD TO THESE MATERIALS, INCLUDING BUT NOT LIMITED TO, ALL IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT OF ANY THIRD PARTY INTELLECTUAL PROPERTY RIGHT. NO LICENSE, EITHER EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, IS GRANTED BY CYPRESS SEMICONDUCTOR. USE OF THE INFORMATION ON THIS SITE MAY REQUIRE A LICENSE FROM A THIRD PARTY, OR A LICENSE FROM CYPRESS SEMICONDUCTOR.

Content on this site may contain or be subject to specific guidelines or limitations on use. All postings and use of the content on this site are subject to the Terms and Conditions of the site; third parties using this content agree to abide by any limitations or guidelines and to comply with the Terms and Conditions of this site. Cypress Semiconductor and its suppliers reserve the right to make corrections, deletions, modifications, enhancements, improvements and other changes to the content and materials, its products, programs and services at any time or to move or discontinue any content, products, programs, or services without notice.