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.

RTOS/AM5728: GPIO interrupt response is slow

Part Number: AM5728

Tool/software: TI-RTOS

Hi,

I setup the GPIO2_2 as an input and configured it to interrupt on a rising edge. I used the HWI that is setup by the GPIO driver as well tried this independently using an HWI I statically defined in the cfg file.

The DSP1 IRQ 56 was connected to Crossbar irq 25 (GPIO2). The external interrupt is configured to produce a rising edge every 15us. What I noticed is that it takes almost 500-700us for the control to jump in the ISR. However, if I enable both INT1 and INT2 for GPIO2 (keeping the crossbar config the same as I have mentioned able) I get a very good response.

As you can see the latency is roughly 2us. Blue trace = external interrupt   Maroon trace = GPIO I/O toggled in the ISR to measure response time.

Another observation. If I do not use the GPIO drivers inbuilt HWI and use my own, and clear IRQ status registers in the ISR manually, I noticed that clearing both IRQSTATUS_0 and IRQSTATUS_1 causes the response to become sluggish again.

Please can you let me know what I could be doing wrong or whether this is expected behavior.

Thanks very much.

Regards,

Shaunak

  • The RTOS team have been notified. They will respond here.
  • Hi,

    Can you explain what Processor SDK RTOS version was used for this experiment? Latest 3.2? The GPIO interrupt used is defined in our code pdk_am57xx_1_0_5\packages\ti\drv\gpio\soc\am572x\GPIO_soc.c. The structure only uses one interrupt per GPIO.

    We need some test to benchmark the performance.

    Regards, Eric
  • Hi Eric,

    I am using 'processor_sdk_rtos_am57xx_3_01_00_06' and 'pdk_am57xx_1_0_4'. I traced the GPIO driver code and figured out how the HWI was been created but the question is why I need to enable both the INT0 and the INT1 interrupt for the control to vector into the ISR in a timely fashion. If I just enable INT0 or INT1 the response is sluggish. Do you have any explanation as to why this could be happening?

    Regards,

    Shaunak

  • Hi,

    I investigated this based on the latest 'pdk_am57xx_1_0_5', where we have a GPIO driver example: GPIO_LedBlink_evmAM572x_c66xTestProject running on DSP core. The GPIO is bank #7 (your case is #2, but I don't think this can be much different), and only one interrupt is configured from GPIO_SOC.C:

    #ifdef _TMS320C6X

          CSL_DSP_GPIO7_REGS,

          15,

    #elif defined(__ARM_ARCH_7A__)

          CSL_MPU_GPIO7_REGS,

          67,

    #else

          CSL_IPU_GPIO7_REGS,

          49,

    #endif

          0,

          61,

          0

       },

    Based on the attached modified code (main_led_blink.c),

    main_led_blink_interrupt_count.c
    /**
     *  \file   main.c
     *
     *  \brief  Example application main file. This application will toggle the led.
     *          The led toggling will be done inside an callback function, which
     *          will be called by Interrupt Service Routine. Interrupts are
     *          triggered manually and no external source is used to trigger
     *          interrupts.
     *
     */
    
    /*
     * Copyright (C) 2014 - 2016 Texas Instruments Incorporated - http://www.ti.com/
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * Redistributions of source code must retain the above copyright
     * notice, this list of conditions and the following disclaimer.
     *
     * Redistributions in binary form must reproduce the above copyright
     * notice, this list of conditions and the following disclaimer in the
     * documentation and/or other materials provided with the
     * distribution.
     *
     * Neither the name of Texas Instruments Incorporated nor the names of
     * its contributors may be used to endorse or promote products derived
     * from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    
    
    #ifndef BARE_METAL
    /* XDCtools Header files */
    #include <xdc/std.h>
    #include <xdc/cfg/global.h>
    #include <xdc/runtime/System.h>
    #include <xdc/runtime/Error.h>
    
    
    /* BIOS Header files */
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    #endif
    
    #include <stdio.h>
    
    /* TI-RTOS Header files */
    #include <ti/drv/gpio/GPIO.h>
    #include <ti/drv/gpio/soc/GPIO_soc.h>
    
    #include "GPIO_log.h"
    #include "GPIO_board.h"
    
    #include <ti/board/board.h>
    #include <c6x.h>
    
    /**********************************************************************
     ************************** Macros ************************************
     **********************************************************************/
    #if defined(SOC_AM572x) || defined (SOC_AM571x)
    #if defined (__TI_ARM_V7M4__)
    #define DELAY_VALUE       (0x6FFFFFU) /* Update Delay as it is not sufficent for M4 core */
    #else
    #define DELAY_VALUE       (0x6FFFFFU)
    #endif
    #else
    #define DELAY_VALUE       (0x6FFFFFU)
    #endif
    
    /**********************************************************************
     ************************** Internal functions ************************
     **********************************************************************/
    
    /* Delay function */
    void AppDelay(unsigned int delayVal);
    
    /* Callback function */
    void AppGpioCallbackFxn(void);
    
    #if defined(IDK_AM572X) || defined(IDK_AM571X)
    /* GPIO clock and pinmux configurations */
    extern void AppGPIOInit(void);
    #endif
    
    #if defined(IDK_AM572X)
    extern void GPIOApp_UpdateBoardInfo(void);
    extern void GPIOAppUpdateConfig(uint32_t *gpioBaseAddr, uint32_t *gpioPin);
    #endif
    
    /*
     *  ======== Board_initI2C ========
     */
    static void Board_initGPIO(void)
    {
        Board_initCfg boardCfg;
    
    #if defined(SOC_K2H) || defined(SOC_K2K) || defined(SOC_K2E) || defined(SOC_K2L) || defined(SOC_K2G) || defined(SOC_C6678) || defined(SOC_C6657)
        GPIO_v0_HwAttrs gpio_cfg;
    
        /* Get the default SPI init configurations */
        GPIO_socGetInitCfg(GPIO_LED0_PORT_NUM, &gpio_cfg);
    
        /* Modify the default GPIO configurations if necessary */
    
        /* Set the default GPIO init configurations */
        GPIO_socSetInitCfg(GPIO_LED0_PORT_NUM, &gpio_cfg);
    
    #if defined(SOC_K2G)
        /* Setup GPIO interrupt configurations */
        GPIO_socSetIntMux(GPIO_LED0_PORT_NUM, GPIO_LED0_PIN_NUM, NULL, GPIO_MUX_SEL);
    #endif
    #endif
    
    #if defined(EVM_K2E) || defined(EVM_C6678)
        boardCfg = BOARD_INIT_MODULE_CLOCK |
            BOARD_INIT_UART_STDIO;
    #else
        boardCfg = BOARD_INIT_PINMUX_CONFIG |
            BOARD_INIT_MODULE_CLOCK |
            BOARD_INIT_UART_STDIO;
    #endif
        Board_init(boardCfg);
    
    #if defined(IDK_AM572X)
        GPIOApp_UpdateBoardInfo();
    #endif
    }
    
    /**********************************************************************
     ************************** Global Variables **************************
     **********************************************************************/
    volatile uint32_t gpio_intr_triggered = 0, callback_counter = 0;
    uint32_t buffer1[32], buffer2[32], diff[32];
    uint32_t gpioBaseAddr;
    uint32_t gpioPin;
    
    /*
     *  ======== test function ========
     */
    #ifndef BARE_METAL
    void gpio_test(UArg arg0, UArg arg1)
    {
    #else
    void main()
    {
        Board_initGPIO();
    #endif
        uint32_t testOutput = 1;
        uint32_t loop = 0, index;
    
        /* GPIO initialization */
        GPIO_init();
    
        /* Set the callback function */
        GPIO_setCallback(USER_LED0, AppGpioCallbackFxn);
    
        /* Enable GPIO interrupt on the specific gpio pin */
        GPIO_enableInt(USER_LED0);
    
        /* Write high to gpio pin to control LED1 */
        GPIO_write((USER_LED1), GPIO_PIN_VAL_HIGH);
        AppDelay(DELAY_VALUE);
    
        GPIO_log("\n GPIO Led Blink Application \n");
    
    #if defined(SOC_K2L) || defined(SOC_C6678) || defined(SOC_C6657)
        /* No GPIO pin directly connected to user LED's on K2L/K2G/C6678/C6657 EVM, just trigger interrupt once */
        GPIO_toggle(USER_LED0);
        while (!gpio_intr_triggered);
    
        GPIO_log("\n All tests have passed \n");
    #else
    
        while(loop < 10)
        {
    #if defined(SOC_AM572x) || defined(SOC_AM571x)|| defined(SOC_AM335x) || defined(SOC_AM437x)
    
    #if defined (IDK_AM572X)
            /* Update GPIO info based on the board */
            GPIOAppUpdateConfig(&gpioBaseAddr, &gpioPin);
    #else
            gpioBaseAddr = GPIO_BASE_ADDR;
            gpioPin      = GPIO_LED_PIN;
    #endif
            /* Trigger interrupt */
            buffer1[loop] =  TSCL;
            GPIOTriggerPinInt(gpioBaseAddr, 0, gpioPin);
    
    #endif
    #if defined(SOC_K2H) || defined(SOC_K2K) || defined(SOC_K2E) || defined(SOC_K2G)
            GPIO_toggle(USER_LED0);
    #endif
            AppDelay(1000000);
            loop ++;
        }
        for (index = 0; index < 10; index++) {
            diff[index] = buffer2[index+1] - buffer1[index];
        }
    #endif
        Task_exit();
    }
    
    #ifndef BARE_METAL
    /*
     *  ======== main ========
     */
    int main(void)
    {
        /* Call board init functions */
    	TSCL = 1;
        Board_initGPIO();
    
    #if defined(IDK_AM572X) || defined(IDK_AM571X)
        AppGPIOInit();
    #endif
    
        /* Start BIOS */
        BIOS_start();
        return (0);
    }
    #endif
    
    /*
     *  ======== AppDelay ========
     */
    void AppDelay(unsigned int delayVal)
    {
    	uint32_t start = TSCL;
    
    	while ((TSCL - start) < delayVal);
    }
    
    /*
     *  ======== Callback function ========
     */
    void AppGpioCallbackFxn(void)
    {
        /* Toggle LED1 */
        //GPIO_toggle(USER_LED1);
        //AppDelay(8400);
        //gpio_intr_triggered = 1;
        buffer2[callback_counter] = TSCL;
        callback_counter ++;
    }
    
    
    
    I measured the point when the GPIO interrupt is triggered, to the point callback function is entered. The time is about 1300 cycles based on 600MHz DSP clock, or 2.2us .

    The measure used the DSP cycle counter TSCL. Note the callback function is called at the bottom of GPIO_v1_hwiFxn(). So the time entering into HWI would be shorter than this.

    I don't see the sluggish GPIO interrupt response with only one interrupt line enabled.

    Regards, Eric

  • Hi Eric,
    Thanks for your response. I got around this problem. Since we use rpmsg to fire the DSP1 up and Linux has a bunch of Crossbar switches it has set and may not even need (or these be just defaults), we had to unroute crossbar switches from the other cores before routing it to the DSP1. Do this and the response is real quick.
    Regards,
    Shaunak
  • Hi Eric,

    Turns out this was a false alarm. Please disregard my previous comment.

    What happened was:

    1. Since we use rpmsg to bootstrap the DSP1 core and do not reboot the IDK, the registers hold previous values. So GPIO_IRQSTATUS_SET_1 bit 3 for GPIO2 was set and then setting bit 3 in GPIO_IRQSTATUS_SET_0 meant that we now have both INT channels active. This is the situation in which it works with a good response.

    As far as your example is concerned, I too got a great response when I manually triggered the interrupt using GPIOTriggerPinInt.

    I am still perplexed about why we need to enable both interrupt channel to get minimum latency.

    Regards,

    Shaunak

  • Hi Shaunak ,

    Sorry for the late reply! I wrote/attached an example showing fast GPIO interrupt response Feb 15, that example only uses one interrupt per GPIO bank. It also looks it showed the same at your side "I too got a great response when I manually triggered the interrupt using GPIOTriggerPinInt.".

    It is a bit unclear to me what is the remaining issue? Is that you have to enable both INT0 and INT1 for a fast response? How do you trigger a GPIO interrupt? I am trying to understand if the slowness you saw is caused by the way triggered or by Linux system on A15 (not a standalone DSP test)? Do you have further info?

    Regards, Eric
  • Hi Eric,

    No worries on that!

    The situation is such:

    1. When I manually trigger the GPIO INT0 interrupt:

    a. I configure only the GPIO INT0 interrupt and the crossbar accordingly (again only for INT0)

    b. The GPIO pin has been configured to generate an event on a rising edge

    This results in a great response when the interrupt is manually triggered

    2. When I use an FPGA to generate a pulse @ 15us

    a. I configure only the GPIO INT0 interrupt and the crossbar accordingly (again only for INT0)

    b. The GPIO pin has been configured to generate an event on a rising edge

    This results in sluggish response. But now if I enable INT1 too, leaving the crossbar as is, the response is similar to what I get when I trigger the interrupt manually.

    Please let me know if you need more info.

    Regards,

    Shaunak

  • Hi,

    Thanks for the explanation! In the past we have a customer issue with 1% GPIO interrupt loss https://e2e.ti.com/support/arm/sitara_arm/f/791/t/561674 (not slow response issue), it turned out the customer has both Linux and DSP serving the GPIO interrupt. After the correction on the Linux side (so only DSP serves GPIO interrupt), the problem resolved. So I want to make sure the issue is not caused by Linux on your side as well, assuming that you run A15 Linux and only enable GPIO interrupt 0, and manually trigger the GPIO interrupt, did you see the slow response?

    If the Linux system is ruled out, the difference is the way how interrupt triggered. We don't have a system like your setup to generate a pulse externally (like FPGA), so our test use AM572x EVM, and manually trigger the interrupt by writing to GPIO_IRQSTATUS_RAW_0 register. I tried below:

    • only enable interrupt 0
    • enable both interrupt 0 and 1 (new test case) 

    I didn't see any difference in response time when interrupt is triggered manually.

    So, let me know you if you can rule out the issue by Linux, then we can focus on why interrupt triggering method caused the difference. 

    Regards, Eric

  • Hi Eric,

    The manual trigger I had mentioned in my post was

    a. with Linux running on the A15 side

    b. with only INT0 configured for the GPIO interrupt.

    Also, I make sure, using code in the RTOS, that the INT0 has not been routed to the PMU via the crossbar. I also tried this with GPIO4_4 which was available to route an external interrupt to and the result was the same. Do you have a signal generator that could source a periodic pulse to an available GPIO pin on the IDK? You may need to disable the module using the pin in the dts and then set the pinmux in the RTOS code running on the DSP. Also, if you can generate external interrupts even millisecs apart, it should be fine. You can zoom into a single rising edge and then measure the time it takes from when the edge was presented to when the jump into the ISR takes place.

    Regards,

    Shaunak

  • Hi,

    I don't have a signal generator for periodic pulse input into a GPIO pin, this setup and measuring response will take some time. Before we get the conclusion, can you use both INT0 and INT1 enabled as a workaround?

    Regards, Eric

  • No worries Eric. Take your time. I can proceed for now.
    Regards,
    Shaunak