What I am attempting to do is to detect both the rising and falling edges of a particurlar gpio. To do this I want to configure the interrupt to trigger on ‘anyedge’. When this occurs, in my IST I can then call Imx6Gpio_GetLevel(…) to determine the level of the pin.
I’ve added a modified version of the sample program provided with your API for initialising and detecting interrupts to demonstrate my problem. For the purpose of this query I’ve configured the sample program to detect the rising edge only.
When the IST is released after the interrupt is triggered I am reading the pin state. As I have configured the interrupt to be triggered on the rising edge only, I would expect the pin level returned from the call to Imx6Gpio_GetLevel(…) to always return a value of ioHigh. On occasion however it returns ioLow.
My initial thought was that there was a latency issue, and that the pin state had changed from high back to low before I had read it. To test this I connected a signal generator outputting a square wave, to allow me to vary the length of time the pin remained high for (The duty cycle was always 50%). I set the period to 8 seconds. At this there is 4 second window for the IST to read the pin level, more than enough to cover any latency issues. However, when tracking the total amount of interrupts that are triggered and the pin level when they occur, I am still reading incorrect values when the app is left running, and the signal generator outputting the 8 second square wave.
At this point it did not appear to be a latency issue. I then tried putting the thread to sleep for 5ms after detecting the interrupt, but before reading the pin. This seems to fix the issue.
Is my approach for detecting the pin state correct? I need to be able to detect both rising and falling edges, so reading the pin level is required. Is there some caching taking place at a lower level and I am attempting to read the pin state before it has been updated?
Sample program:
// ToradexIntLibTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include "gpio_imx6.h"
#include "int.h"
HANDLE hEvent;
HANDLE hIrqThread;
HANDLE hMonitorThread;
HANDLE hIntr = NULL;
BOOL threadStatus = 1;
HANDLE hGpio = NULL;
uIo io = COLIBRI_PIN(23);
int risingCount = 0;
int fallingCount = 0;
int interruptCount = 0;
void GpioIrqThread(DWORD *sysirq);
void MonitorThread(DWORD *sysirq);
int wmain(int argc, wchar_t *argv[])
{
printf("Beginning... \r\n");
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;
}
}