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.

Multiple GPIO interrupt issue



We are having some issues with the GPIO interrupts (on the DSP side) on the OMAP L-138. We are interrupting on both the rising and falling edges of GPIO bank 5 pin 14 and GPIO bank 4 pin 0. When both interrupts are active we are sometimes seeing one of the interrupts (in all cases so far the one for GPIO bank 5 pin 14) not set the INTSTAT when we enter our interrupt routine . We setup our code to have any external source continuously pulse the GPIO5 pin 14 and we tied one of our GPIO outputs (that we toggle in the code) to GPIO 4 pin 0. As we increase how often we toggle the GPIO output that is connected to GPIO4  pin 0, we started to see interrupts appear on GPIO bank 5 that we didn’t recognize - we are checking the INTSTAT bit to determine the cause of the interrupt and added some debug code to capture a GPIO bank 5 interrupts that we don’t recognize.  When we looked at this closer we realized when we hit the breakpoint indicating we didn’t recognize the interrupt, the INTSTAT bit was correct (we are checking the INTSTAT[2] bits while in the ISR). It looks like the INTSTAT bit was not set when we checked it at the start of the ISR but was set by the time we hit the breakpoint later in the ISR. When does the INTSTAT bit corresponding to the interrupt get set? (We assumed it was set as soon as the interrupt occurred.)

We are mapping the GPIO bank 4 and 5 interrupts to hardware interrupt 8 (we tried mapping GPIO bank 4 to hardware interrupt 8 and bank 5 to hardware interrupt 9 but we still saw the same problem), with the Dispatcher enabled. Our pulse width on GPIO5 pin 14 is ~270 mircoseconds spaced 1 second apart. Therefore we will get a two bank 5 interrupts 270 mircoseconds apart, followed by a 1 second delay. We are spending ~ 2 – 4 microseconds in the interrupt routine for bank 5. We toggle the input to GPIO4 pin 0 every 20 msec. We are enabling interrupt events 54 and 59 in the DSP and set the ARM to ignore these interrupts. We are calling Gpio_clearInterruptStatus() to clear the INTSTAT bit once we determine the interrupt(we got this routine from TI example code). We are using CCS3.3 with bios 5.41.03.17.

 

EW

  • Eric,

    Can you please attach a code snippet of your ISR relevant to the checking of INSTAT bit and clearing of the interrupt status?

    Thx,

    Mark

  • Mark,

    The code snippet of the ISR is below. Also, I checked some of the timings on a scope and it appears that if the GPIO interrupts occur within 500 - 600 nsec of each other(I added code to toggle  test points when I entered the interrupt routines) I will see the problem. In our current setup only GPIO5 bank 5 pin 14 and GPIO bank 4 pin 0 are active.

    static CSL_GpioRegsOvly  _gpioRegs = (CSL_GpioRegsOvly)(CSL_GPIO_0_REGS);

    void Bank5Isr(void)
    {
        Uint32 gpioIntStatus;
        Gpio_PinCmdArg pinCmdArg;
               

        gpioIntStatus = _gpioRegs->BANK[2].INTSTAT;

        if (gpioIntStatus & CSL_GPIO_INTSTAT_STAT30_MASK)
        {
            pinCmdArg.pin = GPIO5_14_PIN;
            Gpio_clearInterruptStatus(_gpioHandle, &pinCmdArg);
         }

       else if (gpioIntStatus & CSL_GPIO_INTSTAT_STAT19_MASK)
        {
           pinCmdArg.pin = GPIO5_3_PIN;
           Gpio_clearInterruptStatus(_gpioHandle,&pinCmdArg);
        }
         else if (gpioIntStatus & CSL_GPIO_INTSTAT_STAT20_MASK)
        {
            pinCmdArg.pin = GPIO5_4_PIN;
            Gpio_clearInterruptStatus(_gpioHandle,&pinCmdArg);
        }
        
        else if (gpioIntStatus & CSL_GPIO_INTSTAT_STAT21_MASK)
        {
            pinCmdArg.pin = GPIO5_5_PIN;
            Gpio_clearInterruptStatus(_gpioHandle,&pinCmdArg);
        }
        
        else if (gpioIntStatus & CSL_GPIO_INTSTAT_STAT22_MASK)
        {
             pinCmdArg.pin = GPIO5_6_PIN;
            Gpio_clearInterruptStatus(_gpioHandle,&pinCmdArg);
        }
        else
        {
            LOG_printf(&trace,"Received unknown interrupt on bank 5 \n");
        }
    }

    void Bank4Isr(void)
    {
        Gpio_PinCmdArg  pinCmdArg;

        if (_gpioRegs->BANK[2].INTSTAT & CSL_GPIO_INTSTAT_STAT0_MASK)
        {           

             pinCmdArg.pin = GPIO4_0_PIN;
             Gpio_clearInterruptStatus(_gpioHandle,&pinCmdArg);

        }
    }

  • Eric,

    The code snippet looks fine (for the purpose it is intended). Can you please provide more information on what are you trying to achieve with these multiple GPIO interrupts?

    Bank 4 and Bank 5 shares the same registers (INTSTAT, CLR etc). Can you please try the same test with GPIOs which are not in the same bank?

    Also can you post the Gpio_clearInterruptStatus routine code (is there a chance that more than one ISR is getting cleared)?

    Thanks,
    Gaurav

  • Gaurav,

    We are using the interrupt on bank 5 to start another process. The interrupt on bank 5 is periodic. The interrupt on bank 4 is non periodic - it can occur at anytime . We need to record the time from the bank 5 interrupt to the bank 4 interrupt..

    I will modify the code to use GPIOs on different banks and see if this helps.

     

    The Gpio_clearInterruptStatus() routine is below. I don't believe more than one ISR status bit is being cleared. We got this routine from TI sample code.

    Int32 Gpio_clearInterruptStatus(Gpio_Object* instHandle,
                                    Gpio_PinCmdArg *cmdArg)
    {
        Uint32               index;
        CSL_GpioRegsOvly     gpioBaseAddress;
        Uint32               gpioPin;
        Gpio_Bank           *bankInfo = NULL;
        Gpio_Pin            *pinInfo  = NULL;
        Int32                status = IOM_COMPLETED;

    #ifndef PSP_DISABLE_INPUT_PARAMETER_CHECK

        if((NULL == instHandle) || (NULL == cmdArg))
        {
            status = IOM_EBADARGS;
        }
        /* The pin number given should not exceed nummber of pins for this inst*/
        else if(instHandle->deviceInfo.numPins <= cmdArg->pin)
        {
            status = IOM_EBADARGS;
        }
        else if(NULL == instHandle->deviceInfo.baseAddress)
        {
            status = IOM_EBADARGS;
        }
        else
        {
            status = IOM_COMPLETED;
        }   

    #endif 

        if(IOM_COMPLETED == status)
        {
            gpioBaseAddress = instHandle->deviceInfo.baseAddress;
           
            if(NULL != gpioBaseAddress)
            {
                /* The gpioPin number in the driver starts from zero. While in User's
                   guide it starts from 1. Hence this operation                   */
                gpioPin = (cmdArg->pin - 1u);
               
                /*
                 * Get the bank info for the bank of this pin
                 * The index is gpioPin divided by 16
                 */
                bankInfo = &instHandle->BankInfo[(gpioPin >> 4u)];
               
                /*
                 * Get the pin info for the pin in this bank
                 * The index is 4 lsb's of the gpioPin in the bank info
                 */
                pinInfo = &bankInfo->PinInfo[(gpioPin & 0xfu)];
               
                /* The index of the bank register to which the pin belongs to is
                 * the pin number divided by 32, since, each register (32-bit) has
                 * control/data bit fields for 32 pins
                 */
                index = (gpioPin >> 5u);
               
                /* In a bank register pin bit field can't exceed 31 since there are
                 * only 32 bits. Hence we mask of the higher bits
                 */
                gpioPin = (gpioPin & 0x1fu);
               
                if((Gpio_InUse_Yes != bankInfo->inUse) &&
                   (Gpio_InUse_Yes != pinInfo->inUse))
                {
                        gpioBaseAddress->BANK[index].INTSTAT |= (1u<<gpioPin);
                }
            }
            else
            {
                status = IOM_EBADARGS;   
            }
       
        }
        return (status);
    }

  • Hi Gaurav,

    Once I changed the code to use a GPIO on bank 5 and a GPIO on bank 2 instead of GPIOs on bank 5 and bank 4 the issue with the INTSTAT bit went away. So I guess there was an issue when both GPIOs use the same interrupt status (INTSTAT, CLR, SET, etc) register. Will someone in TI look into this issue to confirm whether there is a problem? And if there is a problem, will someone at TI  determine the minimum time between GPIO interrupts that allow the INTSTAT register to be read properly when the interrupts share the same status registers?

    Thanks,

    Eric

  • Gaurav,

    I think there is maybe an issue with the below statement in the Gpio_clearInterruptStatus() routine.

    gpioBaseAddress->BANK[index].INTSTAT |= (1u<<gpioPin);

    Shouldn't use a read-modify-write operation to clear the INTSTAT bit.

    If another GPIO INTSTAT bit gets set just before the read, then the write back to it will erroneously clear the bit.

    I think the statement should be as follows:

    gpioBaseAddress->BANK[index].INTSTAT = (1u<<gpioPin);

    Do you agree?

    -Mark

  • Mark,

    Good point. I agree. Can you please give this a try?

    Thanks,
    Gaurav

  • Gaurav,

    Eric modifed the code per the suggestion and the problem was eliminated.

    Can we get the code modified in the next release?

    Thx,
    Mark

  • Mark,

    Can you please provide the link from where the code was downloaded? Is it part of BIOS package?

    Thanks,
    Gaurav

  • We are using version 01.30.01 of the BIOS PSP. The link is:

    http://software-dl.ti.com/dsps/dsps_public_sw/psp/BIOSPSP/index.html

     

     

    Thanks,

    Eric

  • Eric, Mike,

    I have requested the BIOS PSP team to take a look at the issue. Once the problem is confirmed, I believe that the fix will be introduced in subsequent releases.

    Thanks,
    Gaurav