I'm working on an accessibility device for someone with SMA Type II who can only move his thumb, and only slightly at that - he can only apply a small amount of pressure. I ordered and received the Gen 4 Dev Kit and I must say the sensitivity and resolution are fantastic!

In fact, TOO fantastic... Okay, so I've got everything mapped out, coded up, and working fine. For reference, the output is a custom serial string data received by a Windows application that handles injecting the mouse input (as well as processing sip & puff events via separate I2C air pressure sensor data).

I have to use absolute mode since this implementation requires defining zones on the touchpad which perform differently (e.g. middle or right clicks, depending on touchpad contact location). Which means I had to write code to distinguish a tap from a move based on timing and travel distance. Again, got all that sorted out.

The only issue I'm having is how to mitigate jitter on finger lift. When I use my thumb (larger surface area) to move the mouse then lift my thumb, this can result in the cursor jumping as the touchpad is reporting the coordinate changes due to rolling effect of lifting my thumb, resulting in contact area/location changes as my thumb is being lifted.

The problem is, it's difficult to differentiate that event from actually intending to move the mouse the same distance. I tried using several settings like smoothing, jitter, etc. But A) I'm not sure if I'm using them right, B) I don't even know if that's the intent of those settings.

If I could extract the pressure (Z) of the event, I could use that to determine if it looks like a contact is being lifted and build logic around that accordingly. However, I can't seem to find anything in the specs relating to a Z axis - the closest thing that even hints at it is AbsXYZZEnable - but I have no idea what that means or how to read the data if it did include Z axis information. Even contact area data could be helpful, by looking to see if the overall contact area is reducing in size and react accordingly.

Any thoughts or suggestions? Maybe this is a common issue that's been solved in general relating to touchpads and I just am not aware of how to implement it.

Hi Rob,

I'm happy to hear our kit is TOO fantastic. Also, great work diving in and figuring all this out; and what a cool project this is!

It sounds like you're very close to a solution, and we can definitely help you solve this problem. Unfortunately our Gen4 wizards are all gone for the weekend, so expect to hear back early next week.

In the meantime, as a hack, you could try experimenting with adding an overlay top of the touchpad to effectively increase the distance between the finger and the sensor. This should reduce sensitivity and possibly eliminate the hover/jitter issue you've described. The overlay has to be non-conductive. Paper or tape might work temporarily, and if so, the solution could be as simple as turning the sensitivity down, or adjusting a threshold in the registers.

Good luck and have a great weekend!

Thanks Patrick, I will give that a try.

What's interesting is that this does not occur when using relative mode, which means something seems to be handling/mitigating this within maybe the firmware?

Which makes sense, if I'm requesting absolute mode then the Gen 4 says "Okay, I'll give you everything available and you can do what you want with it".

But I actually want the UX enhancements which come with relative mode, it's just that I also need the absolute coordinates 🙂

Thanks again, hopefully someone can give me some guidance next week!

Hello Rob;

I might be able to give you some help. 

To get optimal performance you really do need to have an overlay on the touch surface (as Patrick mentioned). The touchpad firmware is tuned assuming there will be an overlay, This means that when there is no overlay, the finger signals are really high and there is a chance the touchpad could think there is a problem and force a new compensation update. If you you finger is on the surface when this happens, the Compensation Matrix will be bad. This will fix itself when the finger is lifted, but while it is touching, the location data might get pretty erratic.

The "Z" data is not output via the normal packets but you can read the "finger strength" values from some registers. This would require you performing an additional read so I don't know if that will slow you down too much. If you would like to see these values, you can do the following:

Make sure this mode is enabled by setting bit 2 of 0xC2C4. This will turn on XYZZ mode.

When you wish to read the values, you will need to Read 4 bytes starting from 0xC384 (when touching) - These are the "Finger Signal Strength" numbers. There are Two 16 bit values. Combine the first two bytes to get the first value (ZX) and the 2nd two bytes to get the second value (ZY).

These two values are a representations of the finger signal strength on each axis. They might help you make some decisions on if it is a lift-off or movement.

One other approach might be to lower the gain of the touchpad. This will help in the case of no overlay or a an overlay that is really thin. You can do this by changing the ADC Gain. This is at 0xC2E8. The default should be 0x94. If you up that to 0x95, this will lower the gain a little. If you change this value, you need to make sure you force a fresh "comp" (refreshes he stored compensation matrix). Be careful with this value, I would not go any higher that 0x96. 
This value will go back to the default on power cycle unless you persist the changes.

The gain/sensitivity of the touchpad can be changed more finely and permanently by changing a resister on the touchpad. This resister, we call RExt, is preferred method of changing the sensitivity. If you wish to head down this path, let me know and I can walk you through it.

Give some of these a try and feel free to ask more questions.

Good Luck



Thank you very much!

I have tried adding Post-It notes on the touchpad surface, increasing to 4 notes total. This doesn't resolve the issue, only exacerbates it when I get to 4 notes as the readings become erratic as you'd expect. The issue seems to be the overall contact surface area. An able bodied person generally uses a smaller point of contact (finger tip), but having a wider part (side of thumb) introduces a rolling effect when lifted. So the contact drifts as the front part of the thumb is lifted while the middle part remains in contact prior to complete lifting off the surface. I'm aware this is outside of the standard scope/expected use case of the hardware/firmware design - I'm just trying to find some way to accomplish this if at all possible. 

If you change this value, you need to make sure you force a fresh "comp" 

I looked through the datasheet and nothing stood out as a definitive method for achieving this.

Would you mind pointing me in the right direction?

This will turn on XYZZ mode

This looks very promising! I enabled XYZZ and dumped the data via serial, the numbers look like exactly the kind of data I'm seeking.

However, once I enable that mode, the reportID is no longer CRQ_ABSOLUTE_REPORT_ID (it becomes zero) so the example code doesn't work and I no longer have finger X,Y - I just get "Error: Unknown Report ID".

Does XYZZ mode mean it's no longer in absolute mode?
If so, how would I obtain the contact X,Y?
I only need X,Y and Z (finger strength) to function - this person will never have more than one contact on the surface.
I see API_C2_forceComp is there to force comp refresh, so ignore that question and I'll give it a try.

Also, looking in API_C2 I see that API_C2_decodeReport clears the result before return, so the XYZZ reportID is actually FF. 
Hi Rob;

You are probably aware of this but just be be sure....

When I said "Set bit 2 of 0xC2C4" you should leave the other bits as they were. So I think you should read 0x03 at first, then setting the bit means you should be writing a 0x07.

If that is not the issue, let me know and I will dig a bit deeper.

The Compensation is shown in our sample code on GitHub. The forceComp function in in the API_C2.c and looks like this:

/** Forces a reset of the compensation.
Wait 50ms for it to take effect. */
void API_C2_forceComp()
uint8_t feedConfig1 = API_C2_readRegister(0xC2C4); // read
feedConfig1 |= 0x80; // modify
API_C2_writeRegister(0xC2C4, feedConfig1); // write

I added this to API_C2, modelling after the existing functions:

void API_C2_enableAbsXYZZ(){
    uint8_t feedConfig1 = API_C2_readRegister(0xC2C4); // read
    feedConfig1 |= 0x04; // modify
    API_C2_writeRegister(0xC2C4, feedConfig1); // write

In my setup method, I'm calling:

Using the programmer mode calculator, it seems this should result in 0x7. 

I tried reversing the order of the calls, but that has the same result. I also made a test function to specifically write that ( API_C2_writeRegister(0xC2C4, 0x07); ), but the result is the same.

Also, I'm extremely new to MCU development, though I have a fair amount of overall development experience - so I generally grasp the bit stuff and concepts - but it's safe to assume I could be missing something!
FYI, I dumped C2C4 in my loop and it does return 0x03 when only API_C2_setCRQ_AbsoluteMode() is called, and returns 0x07 when API_C2_setCRQ_AbsoluteMode() and API_C2_enableAbsXYZZ() are both called. But reportID becomes FF once AbsXYZZEnable is set.

I also tried to call decodeCirqueAbsoluteReport in API_C2_decodeReport when reportID == FF, but the finger data is not present/populated/extracted properly.

It turns out I gave you the wrong information. The XYZZ mode is a completely different output packet format that was only used in testing.

So, forget that mode and make sure that C2C4 is set to 0x03.

What I did find out is that you might have what you need in our "advanced absolute" mode. This is enabled by setting 0xC2DA to 1. was told that this should leave the normal XY parts of the packet the same but adds additional data to the end of the 53 bytes.

I am trying to locate more info on this packet format and will follow up once I find out. In the mean time you can try this and I think that there are bytes that represent the finger strength (Z) in this mode. In my tool, it looks like byte 35 might be finger 1 Z. 

Sorry for sending you down a wrong path.

I will try and find a description of the bytes in this packet format and let you know.


I think you're right about byte 35!

Obviously I'll still wait to see what you find, but it seems to be exactly what I needed. I added a .z property to fingerData_t and set it in decodeCirqueAbsoluteReport (if i == 0). I also set FeedConfig4.LockDownToOneFinger in 0xC2DA since that is the use case here and to eliminate any noise.

Running my test case, I can see the cursor jump happens right during the lift event and the z drops during that time as the coordinates are drifting. This is exactly what I can use to set a current z once contact is established and define a threshold to discard the events when z drops by a certain amount.

Thank you so much for your help! This endeavor is the first time I'd even heard of Cirque (not surprising given my web development background), but I will absolutely praise you folks when/if the situation presents itself. You've been very responsive, helpful, and knowledgeable. 

I'd still like to see the full packet format data if you find it, of course :-)
For reference (format: X,Y,Z with pipe terminator)

14:24:43.002 -> 2693,1343,64|
14:24:43.002 -> 2695,1343,63|
14:24:43.137 -> 2698,1343,56|
14:24:43.137 -> 2698,1344,50|
14:24:43.171 -> 2698,1353,44|
14:24:43.171 -> 2696,1357,42|
14:24:43.171 -> 2694,1364,40|
14:24:43.205 -> 2694,1364,0|

I was finally able to find the information.

This is all the bytes. 

Cirque Advanced Absolute Packet Mode
3Contact bitfield
5F0 Xlow
6F0 Xhigh
7F0 Ylow
8F0 Yhigh
10F1 Xlow
11F1 Xhigh
12F1 Ylow
13F1 Yhigh
15F2 Xlow
16F2 Xhigh
17F2 Ylow
18F2 Yhigh
20F3 Xlow
21F3 Xhigh
22F3 Ylow
23F3 Yhigh
25F4 Xlow
26F4 Xhigh
27F4 Ylow
28F4 Yhigh
35FZX[0] (scaled)
36FZX[1] (scaled)
37FZX[2] (scaled)
38FZX[3] (scaled)
39FZX[4] (scaled)
40FZY[0] (scaled)
41FZY[1] (scaled)
42FZY[2] (scaled)
43FZY[3] (scaled)
44FZY[4] (scaled)
51timestamp low
52timestamp high
I do see that there is a "Z" number for both X and Y axis. If the thumb is predominately going North/South or East/West then one Z might be better than the other. You will have to play around and see.

I am glad things seem to be working better. Once you have everything up and running it would be great to hear back from you. It would be awesome to know if we helped play a part in improving someone's life. 

Good Luck.

Yeah I pulled in and dumped zx and zy, but seem to be the same no matter how I orient or move my thumb around - which doesn't at all matter for our purpose.

That's the story from the beginning if you're at all interested. That thread is updated as things go back and forth between he and I, but I will absolutely provide a separate update here once I get this all done, shipped off, and he's using it.

Thanks again!