Jump to content

GINPUT IRQ-based touch driver


woodstock

Recommended Posts

I've (kind of) implemented IRQ-based functionality for a touch driver (ADS7843) on a STM32 running ChibiOS, but I'm not certain if I'm doing it right...

I have done this by setting up an external interrupt with a simple callback function that jabs the mouse timer and sets the GMOUSE_FLG_NEEDREAD flag:

static void extcb(EXTDriver *extp, expchannel_t channel) {
(void)extp;
(void)channel;

GMouse *m;
// Find the instance
if (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, 0)))
return;

chSysLockFromISR();
_gmouseWakeupI(m);
chSysUnlockFromISR();
}

Since GetMouseReading(m) (which is what I believe does the actual work here) is a static function, we are not able to call it externally, hence why I have chosen to use the _gmouseWakeup() function instead.

I assume that the idea is to set GINPUT_MOUSE_POLL_PERIOD to TIME_INFINITE in order to not waste time polling the device, however I encounter some problems when doing so.

When setting the GINPUT_MOUSE_POLL_PERIOD to TIME_INFINITE the standard calibration routine does not recognise any touches (despite the driver's 'get' function being continuously called as expected while the panel is being touched). Additionally, when disabling the calibration routine, the system recognises a touch but (for example) will never release a pushbutton because there are no more interrupts to tell the system to recheck the touch device and determine whether or not the button is still being pressed.

When setting the GINPUT_MOUSE_POLL_PERIOD to something sufficiently small (i.e. 10 ms) the calibration routine works fine (as does normal GFX operation); whilst setting GINPUT_MOUSE_POLL_PERIOD to something much longer (i.e. 1000 ms) results in the calibration routine not 'continuing' to the next point until up to one second (or whatever polling period is chosen) after the touch has been released.

Also, when applying the GMOUSE_VFLG_NOPOLL flag to the touch driver, I get absolutely nothing... This is actually expected when using the approach that I have implemented due to the short-circuiting in line 327 of input_mouse.c (in the MousePoll function), although this is possibly intended to be the case.

My question is, how should I be implementing IRQ handling for a touch driver?

Do I need to implement some sort of routine that checks for a 'mouse up' and calls _gmouseWakeup() in a similar way to what I'm doing with the IRQ handler?

Link to comment
Share on other sites

I should also add that I've just discovered some issues in relation to the PENIRQ signal itself.

The problem is PENIRQ seems to reset when conversions are performed on the touch driver, therefore multiple edge triggers occur during the conversion process without the touch being removed (i.e. finger lifted off panel). Whilst I can't actually confirm this behaviour without an oscilloscope, I'm pretty sure that's what's happening.

One potential solution I thought of is to have a mutex or semaphore or similar associated with the touch driver. Whilst performing the conversions etc. this mutex/semaphore/global should be owned or flagged by the low-level driver. Meanwhile the external interrupt callback should ignore any triggers while this mutex/semaphore/global is locked/flagged.

Or.... we can simply disable the particular external interrupt during the LLD 'get' procedure... I'll try that and see if it improves anything.

[EDIT] adopting the above approach of disabling the interrupt during the 'get' procedure I can reliably (I think) detect the initial touch and then the final release in the interrupt. This introduces a new problem however. Previously the interrupt was continuously triggered whilst the panel was pressed, which allowed the touches to be continuously registered whilst the panel was pressed. Now I only get two triggers: touch down and touch up.

[EDIT^2] I've added in another little snippet of code at the end of my 'get' function that calls _gmouseWakeup() if the PINIRQ is triggered at the end of the routine. i.e. after performing one read of the touch driver check to see if the panel is still being pressed, and if it is jab the timer and set the NEED_READ flag. This overcomes the problem I described at the end of my last paragraph. Using code from the touch_raw_readings demo I am getting output as expected. However, button presses are not working reliably.

[EDIT^3] I have narrowed down the strange behaviour of button presses to something in the GetMouseReading() function, but it's going to take a while to figure out exactly what's wrong. At this stage I'm guessing it has something to do with the update rate being too fast as a result of the IRQ method (rather than slow polling).

Link to comment
Share on other sites

Yes. These are all problems we are well aware of.

The irq for these devices often don't provide a release interrupt. They also sometimes just stop working and only a full chip reset can restart them.

For these reasons we gave up on trying to turn off polling. It just didnt work (reliably).

The only advantage we could get from an interrupt was to use it to increase the responsiveness by triggering gmouseWakeup exactly as you have done.

Other than the obvious hardware bug where interrupts just stop working, it is obvious that the hardware designers have not thought through all the events needed to provide a good touch experience and so good hardware is effectively wasted.

Note that other touch libraries (i looked at many to try and solve these issues) just dont deal with the problems leading to bad readings, jitter and unreliable touch detection. For others that might be ok but for ugfx we wanted to do it right.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...