how do I adjust touchRead current on Teensy 3.6?

JeppeRas

Member
Hi everyone. Hope someone can help me with this.

I'm working on a Teensy-based MIDI-controller. Over the course of the last couple of years I've gone through many prototypes using Teensy 3.1 and 3.2, but with my recent switch to the Teensy 3.6 I've run into some problems.
Part of my controller interface is capacitive. The Teensy touchRead() function is awesome, and I have been able to get good sensitivity and speed, with all kinds of sensor types, materials and sizes, by adjusting the "CURRENT", "NSCAN" and "PRESCALE" in touch.c. I have settings for each of these for each of my prototypes, which produce similar output range, while (and this is very important) not introducing much latency.
However, there doesn't seem to be a "CURRENT" setting in touch.c for the chip used in the Teensy 3.6 (MK66FX1M0), and now I'm having a hard time getting sufficient resolution and sensitivity without making things too slow. My own rough bench-marking (specific to my setup) shows: best case 10 times slower for equivalent resolution/sensitivity, now that I can't adjust the current.

Is there a fix for this? Maybe it's some not yet implemented feature of the chip? Maybe just the harsh and painful reality of electronics development trade-offs?
I would appreciate any input on this. I'm really hoping to stay with the Teensy 3.6 because of it's raw speed and floating point unit, but if this isn't possible I'll go back to the Teensy 3.2 and not look back (or forward, or whatever...)
Thanks!

Edit. Here's the section of touch.c where I adjust the settings:
Code:
#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   15 // 0 to 15 - current to use, value is 2*(current+1)
#define NSCAN     1 // number of times to scan, 0 to 31, value is nscan+1
#define PRESCALE  1 // 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
};
// Teensy 3.6:
#elif defined(__MK66FX1M0__) 
#define NSCAN     5
#define PRESCALE  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, 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
 
Last edited:
After having another look at both datasheets I'm getting closer to a conclusion, but I'm still not exactly sure that I understand what's going on.

In the datasheet for the MK20DX256 https://www.pjrc.com/teensy/K20P64M72SF1.pdf (Teensy 3.2) there is a full page on the touch interface electrical properties (section 6.9.1) which mentions a "Reference oscillator current source" and also states that: "The programmable current source value is generated by multiplying the SCANC[REFCHRG] value and the base current", plus some more of that kind of stuff.
Ok, so it looks like there is some programmable current functionality going on, which must be what I've been fiddling with on the Teensy 3.2.

However, in the datasheet for the MK66FX1M0 https://www.pjrc.com/teensy/K66P144M180SF5V2.pdf (Teensy 3.6) the section on the touch interface is much shorter (Section 3.9.1), and makes no mention of programmable anything. There is a mention of a "Variable power consumption in run mode", but I'm pretty sure that's something else.

I'm leaning towards the conclusion that the touch interface on the Teensy 3.6 is simply less configurable than it's counterpart on the Teensy 3.2.
In practical terms this means that I'll have much less freedom to design my sensors as far as size, overlay etc, if I want to stay within my all-important latency limits.

Someone please tell me that I don't know how to read a datasheet (which is arguably true), and that there is a way to adjust touch-sensor current on the Teensy 3.6 as well.
 
I'm leaning towards the conclusion that the touch interface on the Teensy 3.6 is simply less configurable than it's counterpart on the Teensy 3.2.
In practical terms this means that I'll have much less freedom to design my sensors as far as size, overlay etc, if I want to stay within my all-important latency limits.

Yes, that's correct. Freescale put the simpler, less configurable TSI into K66.
 
Thanks Paul.
Although that's not exactly good news for me, at least now I can stop banging my head against this.
I have found the Teensy 3.6 to be awesome in every way (except for this one thing), but given that my current project depends specifically on the flexibility of the TSI, I think I'll move it back to the Teensy 3.2, whose touch interface is indeed incredibly powerful.

Thanks again, and all the best.
 
It is possible to adjust. You can chose between 8 options for the reference oscilator and also for the touch sensor (have a look at http://www.nxp.com/assets/documents/data/en/reference-manuals/K66P144M180SF5RMV2.pdf) :

000 500 nA.
001 1 μA.
010 2 μA.
011 4 μA.
100 8 μA.
101 16 μA.
110 32 μA.
111 64 μA.

I have adjusted the touchread function for my purpose.


Code:
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
};






int touchReadto(uint8_t pin, uint8_t NSCAN, uint8_t  PRESCALE,uint8_t  EXTCHRG,uint8_t REFCHRG ,uint8_t DVLOT )
{
  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;

  TSI0_GENCS = TSI_GENCS_REFCHRG(REFCHRG) | TSI_GENCS_EXTCHRG(EXTCHRG) | TSI_GENCS_PS(PRESCALE) | TSI_GENCS_DVOLT(DVLOT)
    | TSI_GENCS_NSCN(NSCAN) | TSI_GENCS_TSIEN | TSI_GENCS_EOSF;
  TSI0_DATA = TSI_DATA_TSICH(ch) | TSI_DATA_SWTS;

  while (TSI0_GENCS & TSI_GENCS_SCNIP) ; // wait

  return TSI0_DATA  & 0xFFFF;

}
 
Last edited:
Wow, nice!
So your new touchread() function has more arguments to it.
The use of NSCAN and PRESCALE are familiar to me, and I guess REFCHRG and EXTCHRG then play together to produce something like the "CURRENT" setting from the Teensy 3.2.
I couldn't find a reference for "DVLOT" in the datasheet, guess it's just a typo for "DVOLT"..? Will have to experiment to see how this influences everything...

What I understand is that this will allow me to set the pertinent currents as well as NSCAN and PRESCALE for each read of each sensor. If I get this running on my Teensy 3.6 setup, that'll be very exciting!
Thanks a lot!

@PaulStoffregen
Is it really that straightforward? If yes, would it not be worth it to include this functionality in the official touchread function?
 
Last edited:
Thank you for starting this thread. I just ran into a similar problem when migrating from a 3.2 to a 3.6 and this thread helped me figure out a work-around to get everything working.

I found out that by enabling the TSI_GENCS_TSIIEN and TSI_GENCS_ESOR flags, you can set up the ISR tsi0_isr to automatically cycle through sensors, setting the NSCAN, PRESCALE, EXTCHRG, REFCHRG and DVOLT options individually for each TSI pin.

If anything, the new, simpler TSI module in the 3.6 is better for my project than the 3.2, though it required some refactoring and redesigning of my existing code.
 
Ugh. Yes. Looks like page 2197 gets into the meat of all the gazillion settings you can theoretically use to adjust capacitance sensitivity: http://www.nxp.com/assets/documents/data/en/reference-manuals/K66P144M180SF5RMV2.pdf

But it's not much that I can actually use in short order. I was sort of hoping for a more managable way to get a capacitance value without having to get a PhD in how touch sensors work (similar to teensy3.2). Is there going to some kind of function that allows for adjustment of sensitivity in the near future?? I am finding the touchRead function to be much less predictable an easy to use in 3.6 and I'll probably have to roll back my whole project to 3.2 because of it.
 
For me, It took around 6 hours of reading and research to get a good understanding of the TSI module and how to tweak the sensitivity. If you have a decent understanding of intermediate maths and physics, you should have no problem developing a system for adjusting sensitivity. There are really only like 6 parameters to adjust, but they're all very specific to what you need for your project.

I don't think it's feasible to create a perfect, universal method of simplifying the capacitive sensing options. Sadly, you might just have to put in the time to research the module.
 
Sure. I get that. But it makes sense to me to have a little more documentation at hand and maybe even a little function that simplifies the understanding of context for the various parameters. An example fragment of code even with some words that explains what is being achieved?
 
Ugh. Yes. Looks like page 2197 gets into the meat of all the gazillion settings you can theoretically use to adjust capacitance sensitivity: http://www.nxp.com/assets/documents/data/en/reference-manuals/K66P144M180SF5RMV2.pdf

But it's not much that I can actually use in short order. I was sort of hoping for a more managable way to get a capacitance value without having to get a PhD in how touch sensors work (similar to teensy3.2). Is there going to some kind of function that allows for adjustment of sensitivity in the near future?? I am finding the touchRead function to be much less predictable an easy to use in 3.6 and I'll probably have to roll back my whole project to 3.2 because of it.

Hi

I've found that reference manual gave a 404, I found a copy on mouser https://www.mouser.com/datasheet/2/813/K66P144M180SF5RMV2-1074869.pdf.

I did some tests and found on a LC using TSI_GENCS_REFCHRG(6) | TSI_GENCS_EXTCHRG(6)
and NSCAN 3 (aka reading 4 samples and averaging )

Gives me readings of about 45-50 µsec and quite stable for touch button applications.
The NSCAN 3 is maybe a little low, but I plan to do an extra touchread on state change.

I also pull the touchpads down to ground when not reading them, instead of keeping them floating.

aka adding
pinMode(pin, OUTPUT_OPENDRAIN);
digitalWrite(pin, LOW);

after touchread().
 
Hi

...
I also pull the touchpads down to ground when not reading them, instead of keeping them floating.

aka adding
pinMode(pin, OUTPUT_OPENDRAIN);
digitalWrite(pin, LOW);

after touchread().

I'm thinking if it's not better to use :

pinMode(pin, INPUT_PULLDOWN);

That will pull the not sensings pad's down also, but has a far lower starting current. First caclulation show that it would be just a few microseconds to pull them low...
Not sure what would be best, any suggestions?
 
Back
Top