Several laptop touchpads to Arduino - ps2 library latency

Hi,

I’m working on a project that involves several Synaptics laptop touchpads wired up to an Arduino Mega (ATMega 1280). My original code in the loop function conceptually looked something like this:

int trackpadCount = 4;

// PS2 trackpad objects
PS2 trackpad[trackpadCount]

// Array of variables to hold X and Y data
char mstat[trackpadCount];
char mx[trackpadCount];
char my[trackpadCount];

void loop()
{  
  for (int i = 0; i < trackpadCount; i++)
  {
    /* get a reading from the mouse */
    trackpad[i].write(0xeb);
    trackpad[i].read();
    mstat[i] = trackpad[i].read();
    mx[i] = trackpad[i].read();
    my[i] = trackpad[i].read();
  }
  
  // Do stuff with the data
}

I just took the code from of the PS2 library example and created arrays for the PS2 objects and X/Y data instead of single variables.

This worked, but I noticed that performance degraded the more touchpads I added to the project. At more than 6 touchpads it took >300ms to grab all the touchpad data which is unsuitable for the project.

I spent some time investigating the PS2 library (and learned quite a bit in the process) and discovered that the PS2 read and write functions have delays and blocking while statements that hold things up to sync with the attached PS2 device clock. To get a full ‘packet’ of X/Y and Z data from a touchpad takes about 50ms, and as I piled them on the latency increased proportionately.

My next ‘bright’ idea was to hack up the PS2 library to try and perform all the byte reads and writes for an array of touchpads simultaneously. The code was pretty ugly but I did get it to work, however after adding 3 or 4 touchpads to the project I started to see erratic behavior and crashes - I think this was due to latency from the Arduino digitalRead and digitalWrite functions. Reading up shows that those functions can take up to 5 microseconds to execute, and I think the cumulative latency within the read and write functions I wrote was throwing things off.

At this point I’m looking for advice on the project, and if it is even possible to achieve what I’m trying to do with an Arduino - that is, read data from 8 or more Synaptics touchpads with low latency (<50ms). I’m looking at direct port manipulation but it is a little beyond my expertise - however I’ll learn if this is a potential solution.

Thanks in advance, I really appreciate the help!

I don't know what PS2 library you're using, but it sounds as if what you need is to redesign the library to work asynchronously. Perhaps the library uses some sort of serial protocol, in which case the interrupt-based approaches used by SoftwareSerial and AltSoftSerial might be applicable. Since I don't have any idea what happens inside that library, I can't advise how difficult that sort of change would be to implement.

Hi,

Thanks for taking a look! To give you an idea, here is the code from the read function within the PS2 library I am using:

unsigned char
PS2::read(void)
{
	unsigned char data = 0x00;
	unsigned char i;
	unsigned char bit = 0x01;

	// start clock
	gohi(_ps2clk);
	gohi(_ps2data);
	delayMicroseconds(50);
	while (digitalRead(_ps2clk) == HIGH)
		;
	delayMicroseconds(5);	// not sure why.
	while (digitalRead(_ps2clk) == LOW)
		;	// eat start bit
	for (i=0; i < 8; i++)
	{
		while (digitalRead(_ps2clk) == HIGH)
			;
		if (digitalRead(_ps2data) == HIGH)
		{
			data = data | bit;
		}
		while (digitalRead(_ps2clk) == LOW)
			;
		bit = bit << 1;
	}
	// eat parity bit, ignore it.
	while (digitalRead(_ps2clk) == HIGH)
		;
	while (digitalRead(_ps2clk) == LOW)
		;
	// eat stop bit
	while (digitalRead(_ps2clk) == HIGH)
		;
	while (digitalRead(_ps2clk) == LOW)
		;
	golo(_ps2clk);	// hold incoming data

	return data;
}

All those empty while statements and delays seem to be the problem - the function is blocking while it waits for the clock signal from the touchpad. This function reads one byte from the pad - it’s called 6 times to read the whole packet, times however many touchpads I have attached. All that latency is adding up!

Is rewriting this to be asynchronous something that can be realistically achieved?

Again, I really appreciate the help.

smetoyer:
Is rewriting this to be asynchronous something that can be realistically achieved?

Absolutely. This is one place where you (almost certainly) need to use interrupts.

I am not at this moment sufficiently conversant with the PS/2 protocol (and haven't studied the code) to recall whether it would be appropriate to use interrupts on the data lines (and read times from the main clock), or to set up another timer interrupt according to the appropriate interval and poll through the data lines in turn, which is probably going to be easier.

This (simply) involves "state machine" systems - one or more variables (flags) keeps track of where you are in the protocol - for each given instance of the protocol - and when an event happens, according to the state and the nature of the inputs (and/ or times) for that event, a decision is made, data is updated, and the state (flags) set awaiting the next event. This could either happen in the main loop, or in a regular interrupt routine - or actually, in both. An interrupt routine must finish without calling any other routine such as display or serial output, which latter are always the task of the main loop (and even then should have no "wait" states).

You cannot use "delay" - or even arguably, "delayMicroseconds" in any serious program.

Corollary - most of the "libraries" are really "demo" code, :smiley:

This might be an appropriate time to provide a link to the library you're using.

It looks as if the code you posted is doing a synchronous (blocking) read on a synchronous serial interface which is clocked at the byte level - or perhaps that is just a misleadng description of some variant of CTS/DTR signalling. It would require quite drastic changes to the implementation to work asynchronously but seems conceptually quite practical to do. I think the AltSoftSerial library would probably be a good starting point.

Here's a link to the PS2 library I am using:

http://playground.arduino.cc/componentLib/Ps2mouse

I'll take a look at the suggested libraries and see what I can come up with.

You guys have been a huge help so far, I really appreciate it!