touchRead - slow reading when not grounded

Status
Not open for further replies.

harald25

Well-known member
I've just started experimenting with the touchRead()-function on a TeensyLC in order to make touch buttons.
I have a setup with some copper tape that I put on a piece of wood, with a cable soldered to the tape. This cable is connected to a pin on my Teensy.
I print the returned values to the serial monitor, and I can clearly see a difference when I touch the copper tape.

When touching the copper tape I notice the time between measurements increase (because numbers are output more slowly to the serial monitor). If I ground myself and then touch the copper tape, the time between measurements decrease A LOT (numbers are output much faster).
When grounded and touching the tape, measurements are output a lot faster than when I'm not touching the tape at all.
My Teensy is connected with USB to my computer (not a laptop), so it should be grounded through the computer PSU.

Can someone advice me a little bit? What can I do to get fast measurements all the time?
 
Last edited:
The nature of capacitive sensing drives this, since when you are ungrounded and on the plate the charging circuit is charging your entire body up and therefore sense time increases. For reliable touch sensing you need to ensure uniformity in the person touching's gnd state, either by being always free floating or by designing the touch pads so the user is in proximity to a gnd.

If neither of this are an option then you get into the fun world of signal conditioning to find press like events that move the signal in either direction.
 
I'm not sure how to achieve this though.
I tried putting a copper tape, connected to ground, under the copper tape I'm using as sensor. I separated them from each other with a normal piece of tape and double checked that there was no connection.
This, unfortunately, did not help.
 
You want to get a repeatable ground on the USER. So either design things so you float and look for increases in the reading, or do things like the phones where the case is mildly conductive, so having an earthed and condcutive case or at least an earthed surround on touch area. You don't have to have a full connection just a capacitive coupling, though a full connection will make the sensor much more precise. Also not that earths in proximity to the wiring to the touch sensor also acts as part of the sensor area so you need to be careful of your wiring layout and proximity to each other, and to earths/power supplies.
 
if you have electron flow issues with your body, it's not a teensy problem, but you might want to go see a doctor and get checked out... lol joke :)
 
So, You'll have to have a second touchpad attached to ground on your Teensy (e.g. left thumb is grounded to this... then right index finger touches your intended touch sensor attached to a touchPin.

Alternatively, if you're just looking for touched() or not, you can apply a ratio of untouched to touched values returned from TouchPin. e.g. if you find that touched is reliably 1.2 times the untouched value (or 1.5), you can set your "touched" threshold there.

I had to handle this and documented it here:
https://forum.pjrc.com/threads/41714-touchRead()-speed
with a library adapted from Paul's touchRead code.

It automatically handles the capacitance differences of different sensors, and speeds the process of getting a "touched()" indication.
 
Last edited:
So, You'll have to have a second touchpad attached to ground on your Teensy (e.g. left thumb is grounded to this... then right index finger touches your intended touch sensor attached to a touchPin.

Alternatively, if you're just looking for touched() or not, you can apply a ratio of untouched to touched values returned from TouchPin. e.g. if you find that touched is reliably 1.2 times the untouched value (or 1.5), you can set your "touched" threshold there.

I had to handle this and documented it hear:
https://forum.pjrc.com/threads/41714-touchRead()-speed
with a library adapted from Paul's touchRead code.

It automatically handles the capacitance differences of different sensors, and speeds the process of getting a "touched()" indication.

I'm making a lamp, and I wanted to be able to turn the lamp on by simply putting my hand on top of it. I'm starting to think this is not possible with the touchRead-function of the Teensy.
On an arduino I could use the capsense library, and by putting a high value resistor on the sensor make it sensitive enough to notice my hand at several centimeters distance. In this scenario grounding the user is not really an option.
But I also want a smaller touch sensor on the side to adjust brightness and other settings. For this I think your touched()-function is perfect.
 
Touch read will do that sort of thing, but you'll need a lot more signal processing looking for the upwards transition in the read. For a gesture controlled lamp I used an IR distance sensor https://www.pololu.com/product/2489 which was natively reading distance rather than abusing a touch sensing system to get it. Tried ultrasonic first but turns out I can hear those so that was out in a bedside lamp.
 
hello, currently working on touchread with Teensy LC/3.6 also planning to use "touch" as a momentum button for controlling the stuff,
for ultimate coolness.:cool:

I've run though snooze example and can wake through TSI, with fingers touching the pins.
but does anyone knows how to attach interrupt to a touch pin?
or I had to frequently check the touchRead for buttoning?

and do I need hardware settings like https://www.pjrc.com/teensy/td_libs_CapacitiveSensor.html ?
are resistors and big-surface pads needed?
 
After reading through some library and touch.c and some trying,
I found out that we can grab the raw results somewhat later (tried on Teensy LC /T3.6)
Code:
 touchReadDMA(TOUCHPIN); // see code next post

int result =TSI0_DATA & 0xFFFF;

if the program actually did something more length enough, we don't need wait for the results.
my plan is to periodically launch TSI for every 25~50 ms, enough in most touch cases.?
 
Last edited:
I also tried with DMA, but failed , seems DMA are not triggering transfer?
it compiles with Teensy LC and Teensy 3.6 , (teensyduino 1.34 , arduino 1.80)
the TSI worked fine and can detect finger touching,

but data are not going to destination, supposed to be done by DMA.
and if DMAchannel is attached with interrupt, it hangs,

see the full code with 2 pages below, thanks

DMAtouch.ino
Code:
#include "DMAChannel.h"
//DMAMUX_SOURCE_TSI
DMAChannel tsidma;
DMAMEM int touchresult;
volatile int isrcount = 0;
#define TOUCHPIN 15
uint32_t ch;
int32_t y;

void setup() {
  Serial.begin(115200);
  delay(1000);
  dmabegin();
  Serial.println("Started...");
}

unsigned long lastLoopTime = 0,
              mainLoopCount = 0,
              target = 0,
              timeEnd2 = 0;

void loop() {

  // launch and let it go for DMA
  unsigned long timeStart = micros();
  touchReadDMA(TOUCHPIN);
  //touchresult=touchRead(TOUCHPIN);
  unsigned long timeEnd = micros();
  Serial.println("back from launch"); //debug purpose
  // do something(nothing) else
  delay(1000);
  //  while ((TSI0_GENCS & TSI_GENCS_SCNIP)){}
  Serial.print("TSI0_DATA :  "); //debug purpose
  //read result from buffer
  Serial.println(TSI0_DATA & 0xFFFF);//debug purpose
  Serial.print("touchresult : "); //debug purpose
  Serial.println(touchresult); //debug purpose
  
  y = touchresult & 0xFFFF; // I think we need to size it, as only LSB 16 bit of it is result
  
  Serial.println("results"); //debug purpose
  Serial.print("Count : ");
  Serial.print(mainLoopCount);
  Serial.print("\t Touchresult() = ");
  Serial.print(y);
  Serial.print("\t DMA launched in ");
  Serial.print(timeEnd - timeStart);
  Serial.println(" milliseconds.");
  Serial.print("And done in ");
  Serial.print(timeEnd2 - timeStart);
  Serial.print("\t with total isr counts : ");
  Serial.println(isrcount);
  mainLoopCount++;
}

//memset(frameBuffer, 0, bufsize);

void dmabegin() {
  //tsidma.source(TSI0_DATA);
  tsidma.destination(touchresult);
  tsidma.transferSize(2);
  tsidma.transferCount(1);
  tsidma.disableOnCompletion();

  tsidma.triggerAtHardwareEvent(DMAMUX_SOURCE_TSI);
  // tsidma.interruptAtCompletion();
  // tsidma.attachInterrupt(dmaisr);
  // the ISR causes hangs.
}

void dmaisr() {
  timeEnd2 = micros();
  //do something or not
  isrcount++;// a prove of ISR
}

page 2
Code:
//DMAEN
#include "core_pins.h"
#if defined(__MK20DX128__) || defined(__MK20DX256__)
// These settings give approx 0.02 pF sensitivity and 1200 pF range
// Lower current, higher number of scans, and higher prescaler
// increase sensitivity, but the trade-off is longer measurement
// time and decreased range.
#define CURRENT   2 // 0 to 15 - current to use, value is 2*(current+1)
#define NSCAN     9 // number of times to scan, 0 to 31, value is nscan+1
#define PRESCALE  2 // prescaler, 0 to 7 - value is 2^(prescaler+1)
static const uint8_t pin2tsi[] = {
  //0    1    2    3    4    5    6    7    8    9
  9,  10, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255,  13,   0,   6,   8,   7,
  255, 255,  14,  15, 255,  12, 255, 255, 255, 255,
  255, 255,  11,   5
};

#elif defined(__MK66FX1M0__)
#define NSCAN     9
#define PRESCALE  2
static const uint8_t pin2tsi[] = {
  //0    1    2    3    4    5    6    7    8    9
  9,  10, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255,  13,   0,   6,   8,   7,
  255, 255,  14,  15, 255, 255, 255, 255, 255,  11,
  12, 255, 255, 255, 255, 255, 255, 255, 255, 255
};

#elif defined(__MKL26Z64__)
#define NSCAN     9
#define PRESCALE  2
static const uint8_t pin2tsi[] = {
  //0    1    2    3    4    5    6    7    8    9
  9,  10, 255,   2,   3, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255,  13,   0,   6,   8,   7,
  255, 255,  14,  15, 255, 255, 255
};

#endif

int touchReadDMA(uint8_t pin)
{
  uint32_t ch;

  if (pin >= NUM_DIGITAL_PINS) return 0;
  ch = pin2tsi[pin];
  if (ch == 255) return 0;

  *portConfigRegister(pin) = PORT_PCR_MUX(0);
  SIM_SCGC5 |= SIM_SCGC5_TSI;
  touchresult = -1; // clean results to make sure it did work each time
#if defined(HAS_KINETIS_TSI)
  // this path seems to be ignore, may cause error on T3.2 or whatever has  // tsidma.interruptAtCompletion();
  Serial.println("LET'S GO TSI");
  tsidma.source((volatile uint16_t *)(&TSI0_CNTR1) + ch);
  tsidma.enable();
  delayMicroseconds(1);
  TSI0_GENCS = 0;
  TSI0_PEN = (1 << ch);
  TSI0_SCANC = TSI_SCANC_REFCHRG(3) | TSI_SCANC_EXTCHRG(CURRENT);
  //TSI0_GENCS = TSI_GENCS_NSCN(NSCAN) | TSI_GENCS_PS(PRESCALE) | TSI_GENCS_TSIEN | TSI_GENCS_SWTS | TSI_GENCS_TSIIEN; // TSI_GENCS_ESOR |; // DMAEN
  //TSI0_DATA = TSI_DATA_TSICH(ch) | TSI_DATA_SWTS | TSI_DATA_DMAEN;


  // while ((TSI0_GENCS & TSI_GENCS_SCNIP) && (timeNow < targetTime)) {   //   wait
  //     if (useMax) {
  //         timeNow = micros();
  //     }
  // }
  //if (useMax && (timeNow >= targetTime)) {
  //    return (-1);
  //}
  // we have DMA so we don't w8t.

  // return *((volatile uint16_t *)(&TSI0_CNTR1) + ch); // we dont return, but get from DMA / ISR
  //

#elif defined(HAS_KINETIS_TSI_LITE)
  Serial.println("LET'S GO TSI_LITE"); //debug purpose
  tsidma.enable();
  Serial.println("TSIDMA_enabled..."); //debug purpose
  //delayMicroseconds(1);
  TSI0_GENCS = TSI_GENCS_REFCHRG(4) | TSI_GENCS_EXTCHRG(3) | TSI_GENCS_PS(PRESCALE)
               | TSI_GENCS_NSCN(NSCAN) | TSI_GENCS_TSIEN | TSI_GENCS_EOSF |  TSI_GENCS_TSIIEN | TSI_GENCS_ESOR ;
               //added  TSI_GENCS_TSIIEN | TSI_GENCS_ESOR ; 
  TSI0_DATA = TSI_DATA_TSICH(ch) | TSI_DATA_SWTS | TSI_DATA_DMAEN;
              //added  DMAEN
    Serial.println("...launch_TSI"); //debug purpose
// nope, we don't wait with DMA

  delayMicroseconds(1);
  // return TSI0_DATA & 0xFFFF;
  //we dont return either.
#endif

}
 
Status
Not open for further replies.
Back
Top