Help with using Adafruit_FreeTouch library on SAMD21

General project help for Adafruit customers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
juliusbangert
 
Posts: 20
Joined: Thu Oct 20, 2016 6:22 am

Help with using Adafruit_FreeTouch library on SAMD21

Post by juliusbangert »

Hi.

I have a generic SAMD21 breakout board which shows up as an Arduino Zero in the IDE, I would really like to get capacitive touch working on it by tapping into the QTouch capabilities. I asked some questions and was pointed at the Adafruit_FreeTouch library and I've been chatting with the author of the Libre_PTC library which he then merged into a branch of the Adafruit_FreeTouch library ( which is the only one I can get vaguely working ).

When I say I can get it working, I mean it's doing something but the readings seem to be full of noise and unusable.
Here is the code I'm testing :

Code: Select all

//───────────────────────────────

#include "Adafruit_FreeTouch.h"
#define numPads 4

//───────────────────────────────

Adafruit_FreeTouch qt[numPads] = { 
  Adafruit_FreeTouch( A0, OVERSAMPLE_4, RESISTOR_50K, FREQ_MODE_NONE ),
  Adafruit_FreeTouch( A1, OVERSAMPLE_4, RESISTOR_50K, FREQ_MODE_NONE ),
  Adafruit_FreeTouch( A2, OVERSAMPLE_4, RESISTOR_50K, FREQ_MODE_NONE ),
  Adafruit_FreeTouch( A3, OVERSAMPLE_4, RESISTOR_50K, FREQ_MODE_NONE ),
};

//───────────────────────────────

void setup() {
  SerialUSB.begin( 115200 );
  for( byte pad = 0; pad < numPads; pad++ ) {
    qt[pad].begin();
  }
}

//───────────────────────────────

void loop() {
  for( byte pad = 0; pad < numPads; pad++ ) {
    SerialUSB.print( qt[pad].measure() );
    SerialUSB.print("\t");
  }
  SerialUSB.println();
}

//───────────────────────────────
... And here's the output of the Serial plotter when I touch the four inputs sequentially ...
Screen Shot 2017-08-15 at 20.17.51.png
Screen Shot 2017-08-15 at 20.17.51.png (304.8 KiB) Viewed 3062 times
The problem is that I can't find any documentation on the library's functions and I don't know what the arguments of the Adafruit_FreeTouch() function are or what they mean.

Is there any documentation or help out there for this library?
Last edited by juliusbangert on Tue Aug 22, 2017 1:40 pm, edited 1 time in total.

User avatar
adafruit_support_mike
 
Posts: 67454
Joined: Thu Feb 11, 2010 2:51 pm

Re: Help with using Adafruit_FreeTouch library on SAMD21

Post by adafruit_support_mike »

That code is still kind of experimental, so we don't have any tutorials for it yet.

The main document for understanding QTouch is this one:

http://www.atmel.com/Images/Atmel-42195 ... -Guide.pdf

From a quick scan of the code, it looks like it's using the self-capacitance method of touch sensing: Connect a fixed voltage to the pad then swap the connection to high-impedance (basically charging the pad like a capacitor and then disconnecting the voltage source), then wait to see how long it takes for the voltage to drain through a resistor whose value is known. That decay rate is highly predictable, and when everything else is constant, will be inversely proportional to the value of the capacitor.

Water has a high dielectric constant (it makes good capacitors), so anything putting something that contains water (like human skin) near the touch pad increases the pad's capacitance. It will take longer for the pad to discharge through the resistor that way, and the microcontroller can measure the difference.

The first parameter of the library's .begin() function is the input pin connected to the sensor. The second line tells the code how much to oversample the input.

Oversampling is a process of taking several measurements, finding the average, and reporting that instead of the actual readings. It's way of reducing noise, but also improves the accuracy of the measurement. The average value of noise is zero (if it wasn't, it would be a source of free energy), so the more readings you add together, the closer the noise error in the measurements approaches zero.

There's another side-effect of adding noise to measurements though: it dithers the sensor output around the real input value. If I have a window comparator that only measures "below 1v" and "above 2v", and feed it a signal at 1.1v plus a couple of volts of noise, I can expect to see about ten "below 1v" outputs for every one "above 2v" output. The noise pushes the signals above and below the thresholds, but vanishes if I take the average of a large enough sample. Statistically, getting a 10:1 improvement in resolution like that would take about 64 readings to make the noise error small enough to ignore.

Oversampling takes longer though, so there's always a tradeoff between how much you can do and how long the signal will remain stable.

The next parameter to .begin() is the value of the resistor that will discharge the touch pad. The system needs that to calculate timing.

The last parameter is the frequency mode, which also takes a bit of explaining.

For systems that take repeated measurements, there's one kind of noise that doesn't average to zero: noise that occurs at the same frequency as the sampling rate. There are all sorts of videos that show the effect of a camera being in sync with the thing it's recording.. this one is especially nice:

https://www.youtube.com/watch?v=uENITui5_jU

For capacitive sensors, things like induced signal from flourescent lighs can create noise, and if the lamp frequency is just slightly off of your sampling frequency, the touch system will think it looks like a series of touches.

(if you have an oscilloscope, hold the tip of a probe between your fingers and put your hand within a foot or so of a flourescent light)

One way to prevent that is to change the sampling frequency. You can shift it up and down in a predictable pattern, hop from one frequency to another, or add some random jitter. Atmel's QTouch library supports all those options, but 'NONE' (fixed frequency readings) is the simplest.

To use the output from the sensors, keep a running average of the readings like so:

Code: Select all

    level = (( N * level ) + latest_reading  ) / ( N + 1 );
and find the value for N that gives you the best tradeoff between quick touch detection and limited noise.

User avatar
juliusbangert
 
Posts: 20
Joined: Thu Oct 20, 2016 6:22 am

Re: Help with using Adafruit_FreeTouch library on SAMD21

Post by juliusbangert »

Wow. Thank you Mike, this is truely top notch forum support and your answers are always really in depth. I'm going to play around with the oversampling and frequency mode settings to see how clean I can get my input signals without too much latency.

So, in terms of the problem I described above with implementing the FreeTouch library on a generic SAMD21 development board...
I literally didn't know what I was doing but I just had a poke around in the Adafruit_FreeTouch.cpp file of the jgilbert20 branch of the Adafruit_FreeTouch library, and I found that if I removed the block of code between :

Code: Select all

#ifdef __SAMD21G18A__
// I removed everything in here
#endif
… and then commented out the ifdef clause around the next block for SAMD11 so it would just get called regardless

Code: Select all

//#ifdef __SAMD21G18A__
// Exposing this code
//#endif
This suddenly improved my results tremendously. I guess there must be errors in whatever is happening in the code that sets up the clocks needed for the PTC module for the SAMD21. Compare these serial plotter outputs before and after this hack.
SAMD21_touch_plotter_before.jpg
SAMD21_touch_plotter_before.jpg (258.42 KiB) Viewed 3010 times
SAMD21_touch_plotter_after.jpg
SAMD21_touch_plotter_after.jpg (142.4 KiB) Viewed 3010 times
The reason I used this branch over the original Adafruit on was because the original didn't seem to work for lack of some library dependencies.

Anyway, it's looking a lot better.

User avatar
juliusbangert
 
Posts: 20
Joined: Thu Oct 20, 2016 6:22 am

Re: Help with using Adafruit_FreeTouch library on SAMD21

Post by juliusbangert »

I'd really love some documentation of this library's functions.
I'm just summing up all the possible arguments you can feed the Adafruit_FreeTouch initialiser function and I've come up with this list...

For oversample :
  • OVERSAMPLE_1
    OVERSAMPLE_2
    OVERSAMPLE_4
    OVERSAMPLE_8
    OVERSAMPLE_16
    OVERSAMPLE_32
    OVERSAMPLE_64
For series resistor :
  • RESISTOR_0
    RESISTOR_20K
    RESISTOR_50K
    RESISTOR_100K
For freq mode :
  • FREQ_MODE_NONE
    FREQ_MODE_HOP
    FREQ_MODE_SPREAD
    FREQ_MODE_SPREAD_MEDIAN
Is this correct? Are these limited by the QTouch hardware or are they just values picked out by Lady Ada in her reverse-engineering?

For example in the QTouch documentation it recommends a series resistor and sample capacitor of 1k and 22nF, but I notice 1k is not an option in your library?
Screen Shot 2017-08-20 at 14.07.40.png
Screen Shot 2017-08-20 at 14.07.40.png (56.51 KiB) Viewed 2995 times
Also how would I change the value for the sample capacitor? I notice there are Adafruit_FreeTouch::setCompCap(uint16_t cc) and Adafruit_FreeTouch::setIntCap(uint8_t ic).. How would I use these?

__________________

So my main question is How can I get the most amount of touch inputs?

Basically I want to have as many touch sensors as possible in my project and I've read in the SAMD21 datasheet that the chip can support up to "256-Channel capacitive touch and proximity sensing" with QMatrix mode. Please could you advise me how I might get this kind of implementation using the Adafruit_FreeTouch library??

Sorry for asking so many questions at once.
Cheers.
Last edited by juliusbangert on Tue Aug 22, 2017 1:39 pm, edited 1 time in total.

User avatar
juliusbangert
 
Posts: 20
Joined: Thu Oct 20, 2016 6:22 am

Re: Help with using Adafruit_FreeTouch library on SAMD21

Post by juliusbangert »

I suspect that attempting the mutual capacitive touch sensing is too involved for my skillset and way over my head.

My guessing is that Lady Ada wanted to trim things right down and selected only the parts of her reverse engineered library that were useful for the circuit playground development.

I noticed her hint at this at this point in one of her live videos as she was working on it. However, one of the viewers ( Karl Koscher ) commented and uploaded this decompilation of the entire QTouch library ....
libsamd21_qtouch_gcc_decompiled (1).zip
(44.53 KiB) Downloaded 74 times
Is there anyone out there with ninja reverse-engineering skills who can help me add this into a branch of the Lady Ada's FreeTouch library so it can support the mutual capacitance as well as the self capacitance?

@adafruit_support_mike, do you know if there are any plans at Adafruit to continue and expand the work on this?

User avatar
adafruit_support_mike
 
Posts: 67454
Joined: Thu Feb 11, 2010 2:51 pm

Re: Help with using Adafruit_FreeTouch library on SAMD21

Post by adafruit_support_mike »

I don't know of any plans to expand it, but anyone else is free to build on it if they want to.

WRT getting the maximum number of inputs, mutual capacitance would be the easiest way to do it.

The principle of mutual capacitance is similar to self-capacitance, but with one more pad in the mix. As I explained above, putting a finger on a touchpad increases the pad's capacitance. Another way to say the same thing is that the fingertip gets 'capacitively coupled' to the pad. If you touch two pads at the same time, the fingertip gets capacitively coupled to both of them.. like a capacitor with one large plate (the fingertip) and two smaller parallel plates (the pads).

When two pads are capacitively coupled to the same fingertip, they're also coupled to each other through the finger. A signal on either pad will have an effect on the finger, and a signal on the finger will have an effect on both pads.

The idea of mutual capacitance is to connect a signal to pad A, then watch for a signal on pad B. Without a finger, there won't be much capacitive coupling between the pads, so pad B will only respond weakly to the signal on pad A. When you put a finger over both pads, it basically links the pads together and pad B shows a much stronger response to the signal on pad A.

Based on that principle, you can built a matrix of dual pads.. all the left-side pads of column 'm' being connected to pin Xm, and all the right-side pads in row 'n' being connected to pin Yn. From there, you can scan the pairs by putting a signal on pin Y1 (all the right-side pins in row 1), then checking the response in pins X1, X2, X3, and so on (the left-hand pad in each column).

User avatar
juliusbangert
 
Posts: 20
Joined: Thu Oct 20, 2016 6:22 am

Re: Help with using Adafruit_FreeTouch library on SAMD21

Post by juliusbangert »

I didn't realise that the mutual capacitance talked about in the QTouch Library Peripheral Touch Controller document was describing a setup in which the X and Y parts are actually two separated pads.

For some reason I assumed that once QTouch was configured for mutual capacitance, the X-line (drive line) is just linked to the Y-line (sense line) directly via a pad and somehow senses the the capacitance change due to the coupled fingertip on that pad. I guess this block diagram in the document led me to think that...
Screen Shot 2017-08-23 at 19.45.30.png
Screen Shot 2017-08-23 at 19.45.30.png (51.34 KiB) Viewed 2933 times
It seems what you're talking about is more like this ( where the blue and red pads and traces are not touching ) ...
ito.png
ito.png (27.1 KiB) Viewed 2933 times
This is a shame because I already planned on utilising this pad layout, as it works well where the X and Y lines are setup to do self capacitance sensing and I thought I'd be able to increase my touch inputs by an order of magnitude.

Anyway, so far with the FreeTouch library as is; using just self capacitance on the Y line inputs, I can only get get 8 inputs working on the Arduino Zero (SAMD21G).
The document says with mutual capacitance I should be able to get up to 120 with this chip variant..
Screen Shot 2017-08-23 at 20.00.26.png
Screen Shot 2017-08-23 at 20.00.26.png (56.4 KiB) Viewed 2933 times
Now I appreciate that not all the pins are broken out on the Arduino Zero, but do you know if it is even theoretically possible to attempt this on a development board without having to design new hardware?

So, where do I start with trying to do this? I'm determined but not super competent in C so I would love some guidance.

Locked
Please be positive and constructive with your questions and comments.

Return to “General Project help”