Interrupt handling from GPIO pins of the same port group for CY8CKIT-145-40XX

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
YoIs_1298666
Level 5
Level 5
250 sign-ins 100 replies posted 100 sign-ins

Hello,

I have prepared a sample project for interrupt processing from GPIO pins of the same port group.

This is based on "7.8 Pin Interrupt" in AN86439.

GPIO interrupts are possible from P0.2 and P0.3. This method will result in an error when building if the port numbers are not consecutive. For example, it cannot be set to P0.2 and P0.4. Since the IRQ is the same in the same port group, the same interrupt handler is used. Therefore, for example, the handler contains a judgment as to whether or not a P0.3 interrupt occurred during interrupt processing by P0.2.

Unfortunately, Pin_P0_ClearInterrupt () clears the pending interrupt bit of all bits, so any interrupts from other pins between the following will be ignored. It is necessary to devise such as adding the pin input to the judgment.

     while((uint8)Pin_P0_INTSTAT != intstatus_flag)
    { ...}

        **If an interrupt on another pin occurs during this time, it will be ignored.**

    Pin_P0_ClearInterrupt();

[Method of operation]

- Connect two tact switches as shown below.

YoIs_1298666_1-1617152664059.png

 

- When you press SW3, LED4 lights up for 1 second. And when you press SW4, LED5 lights up for 1 second.

  If you press one of the SWs and press the other SW while it is lit for 1 second, two SWs will be processed in one interrupt handler, and LED6 will be lit.

 

Best regards,

Yocchi

0 Likes
1 Solution

Hello Len-san,

Thank you very much for your reply.

CyDelay () is just for debugging to see the behavior of the handler, and you can freely modify it.

This is just a hint.

 

The following explains how to avoid the dead zone.

Change Pin_P0_ClearInterrupt () to Custom.

Pin_P0_CustomClearInterrupt(intstatus_flag);

----------------------------------------------------------------------------------------------------------------

     while((uint8)Pin_P0_INTSTAT != intstatus_flag)
    { ...}

        **If an interrupt on another pin occurs during this time, it will be ignored.**

    // Pin_P0_ClearInterrupt();

    Pin_P0_CustomClearInterrupt(intstatus_flag);

----------------------------------------------------------------------------------------------------------------

uint8 Pin_P0_CustomClearInterrupt(uint8 Pin_MASK);    //prototype declaration 

uint8 Pin_P0_CustomClearInterrupt(uint8 Pin_MASK)
{
    uint8 maskedStatus = (uint8)(Pin_P0_INTSTAT & (uint32)Pin_MASK);
    Pin_P0_INTSTAT = maskedStatus;
    return (maskedStatus >> Pin_P0_SHIFT);
}

Best regards,

Yocchi

View solution in original post

0 Likes
3 Replies
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

Yocchi,

Thank you for contributing code to this forum.

You are correct in that there is one interrupt per port.  Therefore if you need to process more than one pin as an interrupt event on the same port, you need to do something 'special' with the one ISR you have available.

I've tried your contributed code.   It does process each pin separately (turning on the respective LED).  However it does process pins pressed at the same time.

I hope you don't mind some improvements. 

Your code uses the CyDelay() calls inside the ISR.  CyDelay() are blocking calls.  In other words, once inside the function, it will not return until completed.   Therefore CyDelay(1000) will require the code be stuck in the interrupt for more than 1 second before exiting the ISR.   Since you have not allowed for interrupt nesting, the code cannot process other interrupts until exiting from the isr_P0_handler.   This can be a problem if you were planning on using other PSoC and services like BLE, UARTs and other time critical resources.

The general rule-of-thumb of interrupt service routines is to "get in and get out" as quickly as possible.  This allows for very time-efficient use of the CPU as well as providing optimum resource processing.  If you ever use an RTOS, this will become hyper-critical.

Commonly when entering an interrupt, you perform the following steps:

  • clear the interrupt first (if needed)
  • Determine what caused the interrupt.  In the case of your project, it is one or more pins on the port.
  • If there is data to be processed, it is preferred to store it in a buffer for later processing.  For example, received data from a UART should NOT be acted on in the ISR but stored for the main() task to process after exiting the ISR.
  • Set an ISR event flag.  This is to signal the main() that the ISR triggered and in some cases that data is waiting.  Once in main() you can process the data or service the event.
  • Lastly, if ABSOLUTELY needed because of time criticality, you can perform an action.  Be very careful that the action which might be in a function doesn't take very long or is a blocking function.  For example, you could set (or clear) and port pin attached to an LED.  

The steps above become more critical as your application becomes more complex and require higher speed resources that need to be serviced in a timely fashion.

I've attached a modified version of your code.   It has the following changes/advantages:

  • The isr_P0_handler() is simplified to only process which pin(s) caused the interrupt and set an event flag.
  • I added the SysTick (@ 1ms per Tick).  This eliminates the need for a blocking CyDelay() function call.
  • The main() has three virtual threads.  One for P0_0 pressed,  P0_0 pressed and P0_0 and P0_1 pressed.   Each LED is individually controlled by the press.   This allows for LEDs to be turned on with overlapped timing.  This is more RTOS-friendly.
  • To activate the P0_0 and P0_1 pressed to turn on LED6, tie P0_0 and P0_1 together then active one of the switches.   It will see that both switches were active at the same time.

 

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Hello Len-san,

Thank you very much for your reply.

CyDelay () is just for debugging to see the behavior of the handler, and you can freely modify it.

This is just a hint.

 

The following explains how to avoid the dead zone.

Change Pin_P0_ClearInterrupt () to Custom.

Pin_P0_CustomClearInterrupt(intstatus_flag);

----------------------------------------------------------------------------------------------------------------

     while((uint8)Pin_P0_INTSTAT != intstatus_flag)
    { ...}

        **If an interrupt on another pin occurs during this time, it will be ignored.**

    // Pin_P0_ClearInterrupt();

    Pin_P0_CustomClearInterrupt(intstatus_flag);

----------------------------------------------------------------------------------------------------------------

uint8 Pin_P0_CustomClearInterrupt(uint8 Pin_MASK);    //prototype declaration 

uint8 Pin_P0_CustomClearInterrupt(uint8 Pin_MASK)
{
    uint8 maskedStatus = (uint8)(Pin_P0_INTSTAT & (uint32)Pin_MASK);
    Pin_P0_INTSTAT = maskedStatus;
    return (maskedStatus >> Pin_P0_SHIFT);
}

Best regards,

Yocchi

0 Likes

Yocchi-san,

Good to know.  Thanks.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes