I’ve been playing with the FEZTouch driver and got to wondering why the touch IRQ pin was being polled instead of taking advantage of the fact that it is wired to an interrupt capable pin. My guess was that polling was faster but I thought I would try it using an interrupt as well.
First step, comment out the TouchThread configuration, and create the interrupt handler:
/// <summary>
/// Initialize the touch screen
/// </summary>
/// <param name="touchConfig">Touch screen configuration settings</param>
private void InitTouch(TouchConfiguration touchConfig)
{
this.SPIBus = new SPI(new SPI.Configuration(touchConfig.ChipSelect, false, 1, 1, false, true, 2000, touchConfig.Channel));
// Use this for polling IRQ
//this.TouchIRQ = new InputPort(touchConfig.TouchIRQ, false, Port.ResistorMode.Disabled);
//this.TerminateTouchThread = false;
//this.TouchThread = new Thread(this.TouchThreadMethod);
//this.TouchThread.Priority = ThreadPriority.Highest;
//this.TouchThread.Start();
// Use this for using inturrpt on IRQ
TouchIRQ = new InterruptPort(touchConfig.TouchIRQ, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);
TouchIRQ.OnInterrupt += new NativeEventHandler(TouchInt);
}
Here is the original polling based code. Ignore the ‘Point’ object, it is just a simple struct to hold (x, y). The commented out variables were moved out and made globals so I could easily switch between the polling and interrupt versions.
/// <summary>
/// Thread to poll for touch events
/// </summary>
/// todo: call touch events on seperate thread
private void TouchThreadMethod()
{
//Point CurrentPoint = new Point(0, 0);
//Point LastPoint = new Point(0, 0);
//bool TouchStatus;
//bool LastTouchStatus = false; // true means there are touches
//byte[] WriteBuffer = new byte[] { 0, 0, 0, 0 };
//byte[] ReadBuffer = new byte[2];
while (TerminateTouchThread == false)
{
Thread.Sleep(TOUCH_SAMPLING_TIME);
TouchStatus = !TouchIRQ.Read();
if (TouchStatus == true)
{
TouchWriteBuffer[0] = 0x90;
SPIBus.WriteRead(TouchWriteBuffer, TouchReadBuffer, 1);
CurrentPoint.Y = TouchReadBuffer[0]; CurrentPoint.Y <<= 8;
CurrentPoint.Y |= TouchReadBuffer[1]; CurrentPoint.Y >>= 3;
TouchWriteBuffer[0] = 0xD0;
SPIBus.WriteRead(TouchWriteBuffer, TouchReadBuffer, 1);
CurrentPoint.X = TouchReadBuffer[0]; CurrentPoint.X <<= 8;
CurrentPoint.X |= TouchReadBuffer[1]; CurrentPoint.X >>= 3;
CalibratePoint(ref CurrentPoint);
// First touch
if (LastTouchStatus == false)
{
FireTouchDownEvent(CurrentPoint);
LastTouchStatus = true;
LastPoint = CurrentPoint;
}
else // drag across screen
{
// filter small changes
if (global::System.Math.Abs(CurrentPoint.X - LastPoint.X) > 5
|| global::System.Math.Abs(CurrentPoint.Y - LastPoint.Y) > 5)
{
FireTouchMoveEvent(CurrentPoint);
LastPoint = CurrentPoint;
}
}
}
else if (LastTouchStatus == true) // finger pulled up
{
FireTouchUpEvent(LastPoint);
LastTouchStatus = false;
}
}
}
No here is the interrupt based method.
private void TouchInt(uint port, uint state, DateTime time)
{
//Point CurrentPoint = new Point(0, 0);
//Point LastPoint = new Point(0, 0);
//bool TouchStatus;
//bool LastTouchStatus = false; // true means there are touches
//byte[] TouchWriteBuffer = new byte[] { 0, 0, 0, 0 };
//byte[] TouchReadBuffer = new byte[2];
TouchStatus = (state == 0);
if (TouchStatus == true)
{
TouchWriteBuffer[0] = 0x90;
SPIBus.WriteRead(TouchWriteBuffer, TouchReadBuffer, 1);
CurrentPoint.Y = TouchReadBuffer[0]; CurrentPoint.Y <<= 8;
CurrentPoint.Y |= TouchReadBuffer[1]; CurrentPoint.Y >>= 3;
TouchWriteBuffer[0] = 0xD0;
SPIBus.WriteRead(TouchWriteBuffer, TouchReadBuffer, 1);
CurrentPoint.X = TouchReadBuffer[0]; CurrentPoint.X <<= 8;
CurrentPoint.X |= TouchReadBuffer[1]; CurrentPoint.X >>= 3;
CalibratePoint(ref this.CurrentPoint);
// First touch
if (LastTouchStatus == false)
{
FireTouchDownEvent(CurrentPoint);
LastTouchStatus = true;
LastPoint = CurrentPoint;
}
else // drag across screen
{
// filter small changes
if (global::System.Math.Abs(CurrentPoint.X - LastPoint.X) > 5
|| global::System.Math.Abs(CurrentPoint.Y - LastPoint.Y) > 5)
{
FireTouchMoveEvent(CurrentPoint);
LastPoint = CurrentPoint;
}
}
}
else if (LastTouchStatus == true) // finger pulled up
{
FireTouchUpEvent(LastPoint);
LastTouchStatus = false;
}
}
The interesting thing is that when the screen is touched the TouchInt handler is called (TouchDown), the point read back is something goofy like (0, 4095). Then it is called on the other edge (TouchUp), the point read is the same goody point. And, just like the Engergizer bunny it just keeps going and going, the TouchInt handler is called over and over again even though the screen is not being touched. I’m too lazey to grab the O’scope to see if the pin is actually toggling repeatedly (I doubt it) but I’m at a loss to explain the why the handler keeps getting called and why it is always reading in the same (and wrong) point.
Any thoughts?