Understanding gpio pin configuration for use as an interrupt

I am having trouble understanding how gpio configuration works for interrupts.

My issue is that I have applied the same configuration to two different pins, run the same tests on both of them, but I am seeing different results between the tests.

The pins that I am testing are colibripin 81 and colibripin 102.

Reading the configuration back using Gpio_GetConfigString() I get the following:

81 – dir=in, lvl=1, altfn=5, pull=up, strength=6, outmode=std, inmode=schmitt, slew=slow, speed=rsvd, irqtrig=low, sion=normal

102 – dir=in, lvl=1, altfn=5, pull=up, strength=6, outmode=std, inmode=schmitt, slew=slow, speed=rsvd, irqtrig=none, sion=normal

Both pins appear to have identical configuration.

When the test application initialises it configures one of these pins to detect an interrupt. After the test application initialises it waits for an interrupt to be triggered. Once one has been detected the pin state is read and a counter is incremented.

Variation 1:
The interrupt source is generated by switching colibri pin 104 from a separate application. It is switched with a period of 200mS and connected to the pin under test via the gpio breakout headers on the evaluation board.

Variation 2:
The interrupt source is generated by connecting a signal generator outputting a square wave with a period of 200mS to the pin under test via the gpio breakout headers on the evaluation board.

Results:
When testing pin 81 with variation 1: Roughly 5 interrupts per second are recorded in the application.

When testing pin 81 with variation 2: Roughly 5 interrupts per second are recorded in the application.

When testing pin 102 with variation 1: Roughly 5 interrupts per second are recorded in the application.

When testing pin 102 with variation 2: Thousands of interrupts per second are recorded in the application.

I have two questions:
1 - Is there some configuration for the gpio that affects the ‘sensitivity’ for detecting an interrupt?

2 – Given that the configuration is the same for pins 81 and 102, why am I not seeing the same behaviour when testing them both while using the signal generator as the source?

How do you trigger those interrupt? On level or edge?
Can you use the GPIO tool (http://developer.toradex.com/knowledge-base/imx6-gpio-tool) to check configuration and state of those pins?
You can also use the auto-refresh option to see if the pin state read from the tool changes when connected to the generator (you may set a low refresh rate like 200ms and increase signal freq to 1 Hz).
On the HW side both pins are directly connected to the SOC. Pin 81 has a 22ohm resistor between the connector on the EVB and the SO-DIMM connector, but this should not make a difference for interrupt generation.

I’m triggering on ‘rising’ but I have also tried it set to ‘high’, which also results in my test application detecting a burst of interrupts.

When using the GPIO tool I can see the level of the pin change when the function generator is connected.

I’ve attached the code for my test application.

#include "stdafx.h"
#include <windows.h> 
#include "gpio_imx6.h"
//#include "gpio.h"
#include "int.h"

HANDLE hEvent;
HANDLE hIrqThread;
HANDLE hMonitorThread;
HANDLE hIntr = NULL;
BOOL threadStatus = 1;

HANDLE hGpio = NULL;

uIo io;// = COLIBRI_PIN(104); // 23 // 81 // 102

int risingCount = 0;
int fallingCount = 0;
int interruptCount = 0;

void GpioIrqThread(DWORD *sysirq);


void MonitorThread(DWORD *sysirq);

DWORD WToUIo(TCHAR *buffer, uIo *io);

int wmain(int argc, wchar_t *argv[])
{
	printf("Beginning... \r\n");

	wprintf(L"Enter colibri pin to configure as interrupt. E.g. 'ccolibripin_102'");
	wprintf(L"\r\n");

	int count = 0;
	int c = getchar();

	TCHAR inputBuffer[255];
	memset(inputBuffer, 0, sizeof(inputBuffer));

	while (c != '\n' && count < 255)
	{
		inputBuffer[count++] = c;
		c = getchar();
	}

	wprintf(L"\r\n");

	WToUIo(inputBuffer, &io);

	if ((io.Type == 0) || (io.Number == 0))
	{
		wprintf(L"Error: unable to configure pin. Exiting...\r\n");
		getchar();
		return(true);
	}

	DWORD irqNum = 0;
	DWORD sysIrq;

	// Set the IO used for interrupt pin as GPIO input
	hGpio = Gpio_Init(NULL);
	Gpio_Open(hGpio);
	Gpio_ConfigureAsGpio(hGpio, io);  // Configure io as GPIO
	Gpio_SetDir(hGpio, io, ioInput);  // Set GPIO Configured io as input
	io = Gpio_NormalizeIo(hGpio, io); // Convert IO (ioColibriPin, ioApalis or ioGpio) to ioGpio

    // Initialize interrupt Library
	hIntr = Int_Init();
	if (hIntr == NULL)
		printf("ERROR:: interrupt init function");

	// Set Edge to trigger
	Gpio_SetConfigString(hGpio, io, NULL, L"irqtrig=rising", StoreVolatile);
	// Get Irq number from GPIO number
	Gpio_GetConfigInt(hGpio, io, L"irq", &irqNum);

	// Create an Event
	hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (hEvent == NULL)
	{
		printf("ERROR:: Create Event failed number %d\r\n", GetLastError());
		return -1;
	}
	// Get the system interrupt for the corresponding Irq number
	sysIrq = Int_RequestSysInterrupt(hIntr, irqNum);
	// Initialize interrupt
	Int_InterruptInitialize(hIntr, sysIrq, hEvent, NULL, 0);

	// Create thread to handle Interrupt event
	hIrqThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)GpioIrqThread, &sysIrq, 0, NULL);

	hMonitorThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MonitorThread, NULL, 0, NULL);

	printf("Enter key to Exit Irq test\r\n");
	getchar();

	threadStatus = 0;
	SetEvent(hEvent);
	Sleep(100);

	// It is very important to deinitalise the interrupt, otherwise it will not work the next time you start the program
	Int_InterruptDisable(hIntr, sysIrq);
	Int_ReleaseSysIntr(hIntr, sysIrq);
	Int_Deinit(hIntr);

	// Close and DeInitialize GPIO handle
	Gpio_Close(hGpio);
	Gpio_Deinit(hGpio);

	return 0;
}

void MonitorThread(DWORD *sysirq)
{
	while (threadStatus != false)
	{
		printf("Rising count: %d    Falling count: %d   Interrupt count:   %d\r\n", risingCount, fallingCount, interruptCount);

		Sleep(5000);
	}
}

void GpioIrqThread(DWORD *sysirq)
{
	CeSetThreadPriority(GetCurrentThread(), CE_THREAD_PRIO_256_TIME_CRITICAL);

	tIoLevel pinLevel;

	int count = 1;
	DWORD lpdwExitCode;
	while (threadStatus)
	{
		if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, INFINITE) && threadStatus)
		{
			//Sleep(5);

			interruptCount++;

			pinLevel = Imx6Gpio_GetLevel(hGpio, io);

			if (pinLevel == ioLow)
			{
				fallingCount++;
			}
			else if (pinLevel == ioHigh)
			{
				risingCount++;
			}

			Int_InterruptDone(hIntr, *sysirq);
		}
		else
		{
			printf("Close Thread \r\n");
			break;
		}
	}
	if (hIrqThread != NULL)
	{
		GetExitCodeThread(hIrqThread, &lpdwExitCode);
		// Exit Thread
		ExitThread(lpdwExitCode);
		hIrqThread = NULL;
	}
}

/// Convert string to uIo 32bit value.
/// @param[in]  buffer      pointer to string 
/// @param[out] io          GPIO/Colibripin number 
/// return      Length of converted string
DWORD WToUIo(TCHAR *buffer, uIo *io)
{
	DWORD i;
	TCHAR sIoType[20] = { 0 };

	// Get io Type
	for (i = 0; i < 20; i++)
	{
		if (buffer[i] != '_')
			sIoType[i] = buffer[i];
		else
			break;
	}
	if (_wcsicmp(sIoType, L"colibripin") == 0)
		io->Type = ioColibriPin;
	else if (_wcsicmp(sIoType, L"gpio") == 0)
		io->Type = ioGpio;
	else
		io->Type = ioNone;

	// Get io number
	io->Number = _wtoi(&buffer[i + 1]);

	return (wcslen(buffer));
}

I did some tests here, but I was not able to reproduce the issue.
I am using image 1.1 beta 4 and the latest release of our libraries.
This is the input signal (using a generator) on pin 102:
alt text
I changed the code of the app to measure also frequency:

void MonitorThread(DWORD *sysirq)
{
	while (threadStatus != false)
	{
		DWORD startcount=interruptCount;
		DWORD start=GetTickCount();
		Sleep(5000);
		DWORD curr=GetTickCount();
		DWORD endcount=interruptCount;

		double freq=((double)endcount-startcount)/(((double)curr-start)/1000.0);

		printf("Rising count: %d    Falling count: %d   Interrupt count:   %d - freq: %0.3g\r\n", risingCount, fallingCount, interruptCount,freq);
	}
}

Printed out frequency matches what I see from my scope and interrupt count matches rising count or at most differs by 1 with rising count set to 1 on first iteration (this may be due to thread startup).
Those are pictures of my test setup, just to check that matches what you did.
alt text
alt text

Another update. When turning off the generation I see the weird behaviour,but just for a very short time (one loop). Here I see frequency rising above 200Hz and falling count increasing. But for sure on power off the signals coming out of the generator are generating spikes etc.
Did you try to connect a scope to the pin to check signal quality? On the other pin there is a 22k resistor. This should not change the signal, but it’s the only difference I can see.

I double checked the schematics and found a difference.
Both pins have 22R in series, but pin 81 also has a 100k pull-down.
On both pins internal pull up resistors are enabled and, depending on the kind of input signal you have (on the offset of it) you may have actual voltage on the pin floating around the threshold between state 0 and 1.
Can you try to disable the internal pull ups and check that the input signal is 0-3.3V?

After looking at my setup it turns out I didn’t have my function generator configured correctly. After adding a DC offset to the signal being generated this changed the voltage that was being sent to the pin from +/- 1.65V to 0-3.3V. I’m assuming the reason I saw pin 81 behave differently was due to the pull-down resistor. All appears to be working now. Thanks for your support.