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.

Questions about GPIO functionality (edge detection)

Hello,

I've just tried on a C6678-EVM this simple GPIO example for interrupts (http://e2e.ti.com/support/dsp/c6000_multi-core_dsps/f/639/t/160712.aspx).

Everything works fine, but having a closer look on the GPIO with an oscilloscope, two strange behaviours appeared:

-"Edge detection": it's only possible to generate an interrupt (e.g. rising edge detection) if the GPIO is toggeled from 0 - 1 - 0. Only switch the GPIO from 0 - 1 will not lead to an edge detection. Same proceedure for falling edge. Do I have a wrong understanding of the edge detection?

-Furthermore using the CSL API instead of writing to the registers directly (see below) will result in a faster toggeling of the GPIO. With CSL the whole toggle (0 - 1 - 0) lasts 360 ns, with writing into registers 5.2 us. Also the fast toggeling with CSL is not recognized as an interrupt. But I think 360 ns are long enough, aren't they?

Thanks for clarifying!

Best Regards,
Bernd

#define GPIO_INTERRUPT_TRIGGER   (0)
CSL_GPIO_clearOutputData(GPIOHandle, GPIO_INTERRUPT_TRIGGER);
CSL_GPIO_setOutputData(GPIOHandle, GPIO_INTERRUPT_TRIGGER);
CSL_GPIO_clearOutputData(GPIOHandle, GPIO_INTERRUPT_TRIGGER);

#define GPIO_CFG_BASE                  (0x02320000)
#define GPIO_REG_OUT_DATA        (0x14)
*(unsigned int*)(GPIO_CFG_BASE+GPIO_REG_OUT_DATA) &= 0xFFFFFFFE;
*(unsigned int*)(GPIO_CFG_BASE+GPIO_REG_OUT_DATA) |= 0x1;
*(unsigned int*)(GPIO_CFG_BASE+GPIO_REG_OUT_DATA) &= 0xFFFFFFFE;

  • Hello,

    for the second question, after further timing measurements it is obvious that the toggeling of the GPIO with the CSL Api doesn't lead to recognize the interrupt. I've checked the GPIO with the oscilloscope and the GPIO registers, behaviour is for both methods the same. But the ISR is only reached by writing directly into the registers.

    What's going on here? If somebody wants to try, I attached my simple project. Just import it into CCS.

    Thanks for help.

    Best Regards,
    Bernd

    TestGPIOIRQ.zip
  • Hi Bernd,

    I'm not sure really why you have observed this behavior. I downloaded your project and got the same results. However, I changed the code up a bit and now I can succesfully get interrupts using the CSL calls, without going 0->1->0 or 1->0->1.

    Please take a look at the attached main.c file. Use the define statements on lines 19 and 20 to choose to test either the falling edge or rising edge.

    Thanks,

    Ian

    #include <xdc/std.h>
    #include <xdc/runtime/System.h>
    #include <ti/sysbios/BIOS.h>
    #include <ti/csl/csl_gpioAux.h>
    
    #define GPIO_CFG_BASE            (0x02320000)
    #define GPIO_REG_BINTEN          (0x8)
    #define GPIO_REG_DIR             (0x10)
    #define GPIO_REG_OUT_DATA        (0x14)
    #define GPIO_REG_SET_DATA        (0x18)
    #define GPIO_REG_CLR_DATA        (0x1C)
    #define GPIO_REG_IN_DATA         (0x20)
    #define GPIO_REG_SET_RIS_TRIG    (0x24)
    #define GPIO_REG_CLR_RIS_TRIG    (0x28)
    #define GPIO_REG_SET_FAL_TRIG    (0x2C)
    #define GPIO_REG_CLR_FAL_TRIG    (0x30)
    #define GPIO_INTERRUPT_TRIGGER   (0)
    
    //#define FALL_EDGE				//Falling edge test
    #define RIS_EDGE				//Rising edge test
    
    CSL_GpioHandle                  GPIOHandle;
    unsigned int                    GPIO_INT_DONE = 0;
    
    Void hwiGPIOnFunc(UArg arg)
    {
        System_printf("GPIO_0 interrupt occurred!\n");			// Write to console to indicate interrupt
        System_exit(0);											// Exit
    }
    
    Void myIdleFunc()
    {
    #ifdef RIS_EDGE
    	CSL_GPIO_clearOutputData(GPIOHandle, GPIO_INTERRUPT_TRIGGER);		// Set GPIO low
        CSL_GPIO_setOutputData(GPIOHandle, GPIO_INTERRUPT_TRIGGER);			// Set GPIO high
    #endif
    #ifdef FALL_EDGE
        CSL_GPIO_setOutputData(GPIOHandle, GPIO_INTERRUPT_TRIGGER);			// Set GPIO high
    	CSL_GPIO_clearOutputData(GPIOHandle, GPIO_INTERRUPT_TRIGGER);		// Set GPIO low
    #endif
    
        while(1);				// Wait for an interrupt
    }
    
    Void main()
    {
        GPIOHandle = CSL_GPIO_open(0);										// Assign handle to GPIO
        CSL_GPIO_setPinDirOutput(GPIOHandle, GPIO_INTERRUPT_TRIGGER);		// Set GPIO direction
    
    #ifdef RIS_EDGE
        CSL_GPIO_setRisingEdgeDetect(GPIOHandle, GPIO_INTERRUPT_TRIGGER);	// Interrupts on Rising Edge
        CSL_GPIO_clearFallingEdgeDetect(GPIOHandle, GPIO_INTERRUPT_TRIGGER);// No interrupts on Falling Edge
    #endif
    #ifdef FALL_EDGE
        CSL_GPIO_setFallingEdgeDetect(GPIOHandle, GPIO_INTERRUPT_TRIGGER);  // Interrupts on Falling Edge
        CSL_GPIO_clearRisingEdgeDetect(GPIOHandle, GPIO_INTERRUPT_TRIGGER); // No interrupts on Rising Edge
    #endif
    
        CSL_GPIO_bankInterruptEnable(GPIOHandle, 0);						// Enable GPIO interrupt
    
        BIOS_start();
    }
    

  • Hello,

    problem seems to be the style of the while-loop. The below statement works, this not:
    while (GPIO_INT_DONE != 1) {}

    Maybe this while-loop can't be interrupted as the variable is checked always in the condition an not in the body.

    Thanks for clarifying this behaviour!

    Best Regards,
    Bernd

    while (1)
    {
        if(GPIO_INT_DONE == 1) break;
    }

  • You need to declare the variable as volatile:

    volatile unsigned int                    GPIO_INT_DONE = 0;

    Otherwise the compiler feels it can move the test outside the loop, because the variable is not apparently being modified within it.  You're just getting lucky that if you put it in the loop head, the compiler if choosing not to do that.

    Generally anything modified in an ISR needs to be declared volatile.  Easy to miss!

  • Thanks for that hint, that's what I missed!