Gas station without pumps

2016 July 27

Measuring a high-voltage nFET

Filed under: Circuits course — gasstationwithoutpumps @ 21:07
Tags: , , ,

I got the nFETs today that we’re planning to use for the LED theater lights, and decided to characterize them, to make sure that they would work as we expected.  These are IPU50R950CEAKMA1 500V 4.3A nFETs from Infineon.

The gate voltage at which these nFETs turn on is a fairly high one (traditional, rather than low-threshold for logic-level input), so I had to use a voltage divider to measure Vgs.  I tried measuring with the 3.3V power from the Teensy board and with a 9V power supply—I needed to use voltage dividers to measure Vds and Vdd with the 9V power supply.  (Note: the power supply was a Mean Well GS60A09-P1J power supply—it delivered 9.24V without load and 9.14V with a 790mA load.)

The gate voltage at which the nFET turns on drops as the nFET gets warm:

The flat current at higher voltages is an artifact of the load resistor being used—the load resistor acts as a current-limiting resistor.

The flat current at higher voltages is an artifact of the load resistor being used—the load resistor acts as a current-limiting resistor.

The specs give a Vgs for a current of 0.1mA of 2.5V to 3.5V, and so this device seems to be in spec (I have to guesstimate the shift for the higher currents).

The current is limited by the load resistor, but the maximum current here is close to what we expect to use for the LEDs, and the gate voltage is supposed to be at least 7.25V for the driver we are using (HV9910B), so the characteristics here are probably a bit conservative.

I tried using a smaller resistor (1.8Ω) with the 9V power supply to try to characterize at higher currents. The power supply and the 50W resistor had no problems with this, but the nFET got very hot very fast, so I terminated the test before I could damage the nFET. I think that the nFET was trying to dissipate about 8W of power, and at 63°C/W that would exceed the 150°C max junction temperature long before reaching equilibrium.

I also tried running with the 10Ω resistor for a few minutes, to get closer to an equilibrium condition for the nFET, and then recorded for about 87 seconds. I used this recording to plot power dissipated in the nFET versus Vgs, in order to figure out what the steady-state power dissipation would be at the currents we expect to use.

The power peaks at 2.11W when the effective drain-to-source resistance matches the load resistance (around Vgs=4.4V), but even with the transistor fully on, we're dissipating about 1.26W.

The power peaks at 2.11W when the effective drain-to-source resistance matches the load resistance (around Vgs=4.4V), but even with the transistor fully on, we’re dissipating about 1.26W.

The 1.26W at 63°C/W would give a junction temperature around 105°C, which is well below the 150°C limit. Of course, that is assuming an ambient temperature of 25°C, and the interior of the lighting can will be warmer than that. We’ll have to run fans to keep things cool enough.

I would not want to use this nFET for class-D amplifier lab in the circuits course, because it has such a high threshold voltage, though 35¢ price in hundreds is not bad.  It does look like it will work well for the theater lights, though.

2016 July 24

More thoughts on measuring FETs

Filed under: Circuits course — gasstationwithoutpumps @ 21:29
Tags: , , ,

I have spent some time this week thinking about a lab for characterizing nFETs (and pFETs) for the applied electronics course, because I was not very happy with the preliminary work in Possible new FET lab for electronics course and pFET Ron_vs_Vgs. There were a couple of things that bothered me:

  • Should we be looking at equivalent resistance or current? which is more consistent across different test conditions? which is more useful for continued design?
  • Does it matter what circuit we use for making the measurement? What are the advantages or disadvantages of choosing different power supply values, different load resistors, or different transistor configurations?

The most basic choice is between a common-source or common-drain amplifier setup, both of which are special cases of the same circuit:

For a common-source configuration, the output is Vd, the load resistor is Rd, and Rs is set to 0Ω. For a common-drain configuration, Vs is the output, Rs is the load resistor, and Rd is set to 0Ω.

For a common-source configuration, the output is Vd, the load resistor is Rd, and Rs is set to 0Ω. For a common-drain configuration, Vs is the output, Rs is the load resistor, and Rd is set to 0Ω.

The testing I did before was with a common-source circuit. The output voltage range is from very close to 0V up to Vdd, which means that either Vdd has to be limited to the range of the analog-to-digital converter or a voltage divider is needed to divide down Vd. The current we are interested in is I_d = (V_{dd}-V_{d})/R_d. Taking the difference of two measurements increases the noise of the measurement, and if Vdd is large enough that voltage dividers are needed, then the current through the voltage divider also goes through the load resistor, making measuring low drain currents (when Vgs is small) difficult.

The common-drain circuit only requires measuring Vg and Vs, both of which can be within the analog-to-digital converter range even when Vdd is large, assuming that the load resistor (Rs in this case) is chosen sufficiently small. Determining Vgs requires a subtraction, but Id does not. Avoiding voltage dividers (with their current stealing and the extra trouble of measuring the divider ratio) seemed like a good idea.

I tried making measurements with the common-drain configuration today, and found it surprisingly difficult. I kept getting huge amounts of noise on the Vs plot, whenever the FET was on. It appeared to be 120Hz interference, but I have no idea where the interference was coming from—the power supply did not show significant 120Hz ripple and large bypass capacitors on the power supply lines did not help. I finally managed to get rid of the problem by putting a 10µF capacitor between the source and drain, providing a negative feedback path that eliminated the problem. (The capacitor appeared to make no difference to the plots for common-source configurations.)

The common-source circuits, however, provided much cleaner plots than the common-drain circuits. The common-source circuits also allowed me to measure much higher drain currents, because I could go to a higher Vgs value without exceed the ADC range when Vs was constrained to be 0V.

For the range that I could measure, I got essentially the same current whether I measured drain current or source current, and pretty much independent of the voltage and load resistance I used. To first approximation, it looks like Id is a function of Vgs in a way that the equivalent resistance that plotted in Possible new FET lab for electronics course is not.

Using a small load resistor allows measuring up to a fairly high current (Vdd/R), as long as the power supply can deliver the current and the resistor doesn't overheat. Using a large load resistor allows measuring to a fairly low current.

Using a small load resistor allows measuring up to a fairly high current (Vdd/R), as long as the power supply can deliver the current and the resistor doesn’t overheat. Using a large load resistor allows measuring to a fairly low current.

2016 July 16

pFET Ron_vs_Vgs

Filed under: Circuits course,Data acquisition — gasstationwithoutpumps @ 22:25
Tags: , , ,

 

In Possible new FET lab for electronics course, I said

I next need to look at whether a similarly simple pFET circuit will work for them to measure Ron  for pFETs.

That turned out to be even easier than I expected.  All I needed to do was change the source wire from Gnd to 3.3V, the voltage divider for the gate to report the voltage halfway between Vg and Vs, and the flip the function generator leads to drive Vgs negative instead of positive (also flipping the polarity of the electrolytic capacitor at the same time).

I had to adjust the gnuplot scripts somewhat to fix the computations, as Vgs is now -2*($4-$2) rather than 2*$2 and Ron is now (Rload*($4-$3)/$3) rather than (Rload*$3/($4-$3)), with the three channels still connected to Vg, Vd, and 3.3V.

With a drain-source short the wiring resistance came out to 24mΩ this time.

I have 3 pFETs:

  • NTD2955-1G (39.87¢ in 100s) used this year in class
  • IRFU9024NPBF (53.13¢ in 100s)
  • IPP45P03P4L11AKSA1 (66.93¢ in 110s)
The two cheaper pFETs are very similar, but the bigger one (IPP45P03P4L11AKSA1) has a much smaller threshold voltage and a much low on resistance.

The two cheaper pFETs are very similar, but the bigger one (IPP45P03P4L11AKSA1) has a much smaller threshold voltage and a much low on resistance. 

Would it be worth specifying IPP45P03P4L11AKSA1 for the class next year?  The class-D amplifier could run at a lower voltage if the pFET threshold is not so large, which would make testing easier—lots of students were confused by the behavior they got when they used a modest supply voltage that did not allow the pFET to turn on.

The gate-to-source charge plus gate-to-drain charge for the IPP45P03P4L11AKSA1 pFET is 16–24nC (that’s about how much charge is needed on the gate to finish turning on the transistor), while for NTD2955-1G it is only about 11nC, so IPP45P03P4L11AKSA1 will take longer to turn on (and to turn off, though that depends on the total gate charge).  At 10V, the total gate charge is 42–55nC vs 15–30nC for the NTD2955, so the turn off time is probably also about doubled.

The doubling in time will not matter much in the H-bridge circuit we used this year, since we were using 74HC04 inverters to drive the gates, with one inverter dedicated to each gate—the gates were being driven very fast, and a doubling in time would not affect performance.  It would have been a huge problem when we were trying to drive the gates directly from the output of the comparators.

Although I like the IPP45P03P4L11AKSA1 better for computer-controlled circuits, for the class-D amplifier it probably doesn’t offer enough of an advantage to justify the extra 54¢ per student. It might be worth having a difference in packaging between the nFET and the pFET, though, as several students swapped pFETs and nFETS in their breadboards this year. Because the IPP45P03P4L11AKSA1 comes in a larger TO220 package, the visual difference may be enough to justify the increased price.

 

Possible new FET lab for electronics course

Filed under: Circuits course,Data acquisition — gasstationwithoutpumps @ 20:59
Tags: , , ,

I’ve been considering adding a warmup exercise to the class-D amplifier lab, having the students plot Ron for the FETs vs. Vgs.  The problem is not completely trivial, since we want to measure small resistances around 100mΩ.  To get sufficient resolution with the ADC on the Teensy boards, we want a fairly high current at those low resistances, which means using a small load resistance.  If I use 0.25W resistors and a 3.3V supply, I can’t go less than 43.6Ω without exceeding the rating for the resistor.

My first attempt is to measure just my nFETs. I generated Vgs with my FG085 function generator doing a slow triangular wave (24s period) set to 4Vpp and a 3.1V offset (so Vgs is swept from about 1.1V to about 5.1V).  I also put a 470µF capacitor across the function generator outputs, to smooth out the steps of the low-quality DAC a bit (which wouldn’t be needed on a better function generator with a higher-resolution DAC). To measure the gate voltage, I used a pair of 6.8kΩ resistors to cut the voltage in half, to keep it in the range of the Teensy ADC (0–3.3V).

To provide large currents, I used the 5V USB supply (instead of the 3.3V regulated supply, which cannot supply much current on the Teensy 3.1 board and even less on the Teensy LC).  To measure the supply voltage (Vdd) and the drain voltage (Vdd), I used two voltage dividers, each with a pair of 8.2kΩ resistors.  It turned out I had two different batches of 8.2kΩ resistors, which were slightly different, so I had to redo the measurements after rearranging the resistors to make sure that each voltage divider used resistors from the same batch.

I used a nominally 16Ω (measured at 15.3Ω) 10W resistor as a load. At 5V this would dissipate 1.6W with a current of 327mA (within the USB limits).

I first made measurements with no FET—both with and open circuit between drain and source test points and with a short circuit between the drain and source test points.  The open-circuit test gave me an estimate of the maximum on-resistance I could measure (and is how I detected the mismatches of the 8.2kΩ resistors).  The short-circuit test gave me an estimate of the test fixture wiring resistance, which needed to be subtracted from the measurements.  I got about 134mΩ of wiring resistance, which is large compared to some of the power-transistor on-resistances, but fairly small for long breadboard wiring.

I tested all 6 nFET transistors that I have: 4 power nFETs and 2 low-power ones in TO92 cases:

The resistance reported here has the wiring resistance already subtracted off.

The resistance reported here has the wiring resistance already subtracted off.

I was not very impressed with these measurements and decided to do them over using the more obvious technique of using a 47Ω resistor to the 3.3V supply as the load and recording Vds and Vdd directly, without voltage dividers (still using a voltage divider for Vgs, though). The wiring resistance came out smaller this time (77mΩ), but it varied a bit when I reran the same measuring process, so I’m a bit dubious about the Ron measurements for the power transistors—changes in the wiring resistance estimate were larger than the final estimated Ron for AOI514.

The results were somewhat better with the larger load resistor and smaller drain currents.

A 47Ω load resistor to 3.3V makes for cleaner plots, and is easier for students to design and set up, since only the gate voltage needs to be passed through a voltage divider.

A 47Ω load resistor to 3.3V makes for cleaner plots, and is easier for students to design and set up, since only the gate voltage needs to be passed through a voltage divider.

The gate voltages at which the resistance dropped abruptly seems to have shifted lower when using the 15.3Ω load to 5V.  I’m not sure why this is, as the same voltage divider was used for the gate voltage in both cases. For the smallest transistors, the problem may have been overheating, as they were only rated for 200mA or 300mA of current and I was delivering about 325mA.  But the bigger transistors should not have been heating much, and even on the small transistors I’m not seeing the hysteresis you would expect from slowly heating and cooling the parts.

I next need to look at whether a similarly simple pFET circuit will work for them to measure Ron for pFETs.

Testing all the nFETs I have on hand should also have been useful for deciding which ones to use next year, but the AOI514, AOI518, and NTD5867NL-1G are no longer available.  In any event, the AOI thresholds are a bit high for using with 3.3V logic, but the PSMN022-30PL,127  (39.06¢ in 100s) looks perfectly reasonable with an on-resistance of about 47mΩ at 5V and a threshold voltage around 2.08V (where Ron=1Ω). I should probably get and test the NTD4858N-35G nFETs (38.56¢ each in 100s) that the students used this year, as well as the IPU50R950CEAKMA1-ND 500V nFETs (47.2¢ in 10s) that my son and I are thinking of using for the theater-light LED drivers.

I think that doing nFET measurements for a single nFET should be fairly quick for students, though convincing them of the need for “drain-source short” test to subtract off wiring resistance may be difficult. I next need to look at whether a similarly simple pFET circuit will work for them to measure Ron vs. Vgs for pFETs.

2016 July 13

Autoranging capacitance meter using TeensyLC

Filed under: Circuits course — gasstationwithoutpumps @ 09:59
Tags: , , , ,

 

My earlier post, Capacitance meter using touchRead(), showed the beginnings of a capacitance meter, using the touchRead() routine in the Teensyduino environment.

Today I’ll share a slightly more complicated program that uses the TSI (touch sensing input) peripheral more directly to make an autoranging capacitance meter that can measure capacitors down to 1pF and up to 3µF.  The repeatability of the measurements is not great (about ±3%), but the linearity seems pretty good.

The program includes the ability to zero out the test fixture (important for measuring small capacitances) and to calibrate the meter to a known capacitor.  I don’t have a capacitor with a tight tolerance, so I had to do my calibration against a DT-9205A multimeter, which is not a very reliable standard.  Still, it seemed more consistent than the labeling on the cheap ceramic capacitors I have, some of which seem to be off by a factor of two!

The multimeter could not measure capacitances at the low end of the range, so only nominal values are used there.

The multimeter could not measure capacitances at the low end of the range, so only nominal values are used there.

A number of the capacitors in the 100pF–10nF range seemed to drift consistently upward for quite a while, both with the multimeter and my homebrew capacitance meter. Touching them with my finger brought them sharply back down again, but touching them with stainless steel tweezers did not. I suspect that the effect is a thermal one, with the capacitance dropping when my fingers warmed the capacitors and going up again as the capacitors cooled to room temperature. The change was several percent, which is consistent with a low-quality “Y” dielectric.

// Preliminary program for a capacitance meter
// Kevin Karplus
// 2016 Jul 13


// To use:
//	* Connect a serial monitor (like the Arduino IDE) to the USB port
//	* Connect capacitor to measure between pin 0 and ground
//	* Press "a" and <return> to make an autorange measurement.

// Capacitances in the range 1pF to 3uF can be measured, but large
// capacitors take a long time to measure, up to 9s for 3uF.
// The measurement time can be reduced by reducing NUM_READS, perhaps
//	replacing the constant by an array dependent on range.
//	A factor of about 10 reduction in measurement time is available, as
//	NUM_READS is currrently set to 20.

// Note: readings may drift by +- 5%.  I've not yet determined the
// cause of this drift.  It may be thermal (cooling from finger
// temperature to room temperature may raise the capacitance by 2%,
// depending on the additives to the ceramic used as the dielectric).

// To calibrate:
//	* Remove capacitors from pin 0
//	* Type 'z' to measure the counts for the empty test fixture
//	* Pick a known capacitor (around 1nF) and connect it between
//		pin 0 and ground.  The capacitor must be small enough
//		to be measurable on the highest-resolution range (<=3nF).
//		To calibrate with a larger capacitor, first calibrate with
//		a small one to get the highest-resolution range set, then
//		repeat the calibration with the larger capacitor, which
//		will only reset the larger ranges.
//	* Type 'k', followed by an integer known capacitance in pF,
//		followed by a separator (like ';')
//	* Type 'c', to measure the pF per count

// Note: the calibrations are reported to the USB serial port, so they
// can be saved and used to edit the source code, changing count_for_0pF
// and pf_per_count arrays.

// The measurement process can be followed in more detail by turning
// on debugging with the 'D' command.
// Debugging can be turned off with the 'd' command.

// Capacitance is measured on pin 0 (one of several pins with TSI),
// because pin 0 is immediately next to ground, making it easy to connect
// small capacitors between pin 0 and ground.
#define TOUCH_PIN (0)

// forward references to later routines
int32_t capRead(uint8_t pin, 
		uint8_t I_ext=3, uint8_t I_ref=4, 
		uint8_t Prescale=2, uint8_t N_scan=9);
float autoCapRead(uint8_t pin);
int readInt(void);
void print_calib(int count, int n_cycles=1);
float read_counts_per_cycle(uint8_t i_ext, uint8_t i_ref,float count_for_zero);

volatile uint8_t debug;

// The current for the external oscillator and the reference
// oscillator of the TSI interface determine the capacitance range, resolution,
// and speed of the measurement.
// The program uses the highest-resolution range that does not cause
// the 16-bit counter to overflow.

// Settings of the current paramters for the different ranges
// The highest-resolution range is first, the widest range is last.
#define NUM_RANGES (6)
const int8_t i_ext_choices[NUM_RANGES] = {2,3,4,5,6,7};
const int8_t i_ref_choices[NUM_RANGES] = {5,4,3,2,1,0};

float pF_per_count[NUM_RANGES]=
	{0.2126, 0.772, 2.897, 11.08, 47., 195.3};
float count_for_0pF[NUM_RANGES] =
	{48.7612, 13.82, 3.813, 1.0605, 0.273, 0.0517};

// parameters for calibration
int C_known=0;	// known capacitance value 

void setup() 
{
    pinMode(TOUCH_PIN, INPUT);
    Serial.begin(115200);
    debug=0;
}

void loop()
{
     if (Serial.available())
     {   char c=Serial.read();
         if (c=='D') {debug=1;}
	 else if (c=='d') {debug=0;}
	 else if (c=='a')
         {   // do one reading and print it
             Serial.print(autoCapRead(TOUCH_PIN));
             Serial.println(" pF");
        }
        else if (c=='k')
        {   // set known capacitance for calibration checks
	   C_known=readInt();
        }
	else if (c=='z')
	{   // Set the count_for_0pF array for each range.
	    // Print the current parameters and zero count for each range.
	    // Only issue this command if there is no capacitor connected
	    // to TOUCH_PIN
	    for (int range=0; range<NUM_RANGES; range++)
	    {   uint8_t i_ext=i_ext_choices[range];
	        uint8_t i_ref=i_ref_choices[range];
		count_for_0pF[range] =read_counts_per_cycle(i_ext,i_ref,0.0);
		Serial.print("# zero for ");
		Serial.print(i_ext); Serial.print("\t");
		Serial.print(i_ref); Serial.print("\t");
		Serial.println(count_for_0pF[range],4);
	    }	
	}
	else if (c=='c')
	{   // do autocalibration, setting pF_per_count
	    // printing known capacitance, 
	    //		external current setting,
	    //		reference current setting,
	    //		average pF_per_count for a single cycle
	    
	    if (C_known==0)
	    {   Serial.println("# use 'k<known C in pF>;' first");
	    	return;
	    }
	    for (int range=0; range<NUM_RANGES; range++) { uint8_t i_ext=i_ext_choices[range]; uint8_t i_ref=i_ref_choices[range]; float calib=read_counts_per_cycle(i_ext,i_ref,count_for_0pF[range]); if (!isnan(calib)) { calib = C_known/calib; pF_per_count[range]= calib; } else { Serial.print("# "); // comment out overflows } Serial.print(C_known); Serial.print("\t"); Serial.print(i_ext); Serial.print("\t"); Serial.print(i_ref); Serial.print("\t"); Serial.println(calib,4); } } } } // print a calibration line void print_calib(int count, uint8_t i_ext, uint8_t i_ref, int n_cycles) { float avg_count = (count+0.0)/n_cycles; Serial.print(C_known); Serial.print("\t"); Serial.print(i_ext); Serial.print("\t"); Serial.print(i_ref); Serial.print("\t"); Serial.print(count); Serial.print("\t"); Serial.print(n_cycles); Serial.print("\t"); Serial.println(C_known/avg_count,4); } float read_counts_per_cycle(uint8_t i_ext, uint8_t i_ref, float count_for_zero) { // Do one measurement and return average counts/cycle - count_for_zero. // If debug set, print C_known, count, i_ext, i_ref, n_cycles, cap/count // // Actually does NUM_READS+1 measurements: one with a single cycle, // then again NUM_READS times with as many cycles as can be fit without // overflowing counter. if (debug) { Serial.println("# C\ti_ext\ti_ref\tcount\tn_cycle\tC/avg_count"); } int count=capRead(TOUCH_PIN, i_ext, i_ref, 0, 0); if (count>=0xFFFF)
    {   if (debug)
    	{   Serial.print("# "); // comment out overflows
	    print_calib(count,i_ext,i_ref,1);
	}
	return NAN;	// abort rest of calibration check
    }

    // Determine max number of cycles that can fit
    int cycles= 0xFFFE/count; // how many cycles to use
    int prescale,n_scan;
    for (prescale=0; cycles>32 && prescale<7; prescale++) {cycles/=2;} if (cycles==0) {n_scan=0;} else if (cycles>32) {n_scan=31;}
    else {n_scan=cycles-1;}
    cycles = (n_scan+1)<<prescale;

#define NUM_READS	(20)
    // To do: replace NUM_READS with a const uint8_t num_reads[NUM_RANGES]
    // array, to speed up measurement at high ranges.

    int sum_count=0;
    for (int i=0; i<NUM_READS; i++) { count=capRead(TOUCH_PIN, i_ext, i_ref, prescale, n_scan); if (debug) { print_calib(count, i_ext, i_ref, cycles); } sum_count+=count; } return (sum_count+0.0)/ (NUM_READS*cycles) -count_for_zero; } // Read a non-negative integer from Serial as a series of digits, terminated // by any non-digit (recommend using something obvious like ';'). // The terminating character is discarded. int readInt(void) { int value=0; while (!Serial.available()) {} // wait for next char char c=Serial.read(); while (c>='0' && c<='9')
    {   value= 10*value + (c-'0');
	while (!Serial.available()) {}	// wait for next char
       	c=Serial.read();
    }
    return value;
}
   


float autoCapRead(uint8_t pin)
{
    // Return the capcitance in pF at the pin, using the highest-resolution
    // range that doesn't overflow the counter.
    
    // pick the lowest (highest resolution) range that doesn't overflow
    int32_t count;	// number of counts of ref oscillator
    int range;
    for (range=0, count=0xFFFF;  range<NUM_RANGES && count>=0xFFFF; range++)
    {	count=capRead(pin, i_ext_choices[range],i_ref_choices[range],0,0);
    }
    range--;
    
    if (count>=0xFFFF)
    {    return NAN;	// capacitance too big to measure with TSI
    }
    
    float count_per_cycle=read_counts_per_cycle(i_ext_choices[range],
		i_ref_choices[range],
		count_for_0pF[range]);
    return pF_per_count[range]*count_per_cycle;
}


/* Raw reading is based on the
 * Teensyduino Core Library touch.c (which implements touchRead)
 * http://www.pjrc.com/teensy/
 * Copyright (c) 2013 PJRC.COM, LLC.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * 1. The above copyright notice and this permission notice shall be 
 * included in all copies or substantial portions of the Software.
 *
 * 2. If the Software is incorporated into a build system that allows 
 * selection among a list of target devices, then similar target
 * devices manufactured by PJRC.COM must be included in the list of
 * target devices and selectable in the same manner.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

// #include "core_pins.h"

// capacitance is supposed to be
//	Cref * (1<<I_ext) / ( (1<<I_ref) * (1<<Prescale) * (N_scan+1) ) * COUNT
// but use 
// Cref * ext_current[I_ext] / ( ref_current[I_ref] * (1<<Prescale) * (N_scan+1) ) * COUNT // because the current ratios are not a constant factor of 2 // with DVOLT==0 (slowest, but least noise sensitive), // I_ext = I_ref-1, // Prescale=2, // N_scan=9, // Capacitance is approx 0.01846 pF * COUNT, // so Cref approx 1.47694pF #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. 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__) 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__) 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 // for I_ref=I_ext+1, N_scan=9, Prescale=2, output is approx pF * 50 // time to measure 33 pF is approx 0.25 ms // time to measure 1000 pF is approx 4.5 ms int32_t capRead(uint8_t pin, uint8_t I_ext, uint8_t I_ref, uint8_t Prescale, uint8_t N_scan) { uint32_t ch; int32_t count; 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;
#if defined(KINETISK)
    TSI0_GENCS = 0;
    TSI0_PEN = (1 << ch);
    TSI0_SCANC = TSI_SCANC_REFCHRG(I_ref) | TSI_SCANC_EXTCHRG(I_ext);
    TSI0_GENCS = TSI_GENCS_NSCN(N_scan) | TSI_GENCS_PS(Prescale) | TSI_GENCS_TSIEN | TSI_GENCS_SWTS;
    delayMicroseconds(10);
    while (TSI0_GENCS & TSI_GENCS_SCNIP) ; // wait
    delayMicroseconds(1);
    count= *((volatile uint16_t *)(&TSI0_CNTR1) + ch);
#elif defined(KINETISL)
    TSI0_GENCS = TSI_GENCS_REFCHRG(I_ref) | TSI_GENCS_EXTCHRG(I_ext) | TSI_GENCS_PS(Prescale)
	    | TSI_GENCS_NSCN(N_scan) | TSI_GENCS_TSIEN | TSI_GENCS_EOSF;
    TSI0_DATA = TSI_DATA_TSICH(ch) | TSI_DATA_SWTS;
    delayMicroseconds(10);
    while (TSI0_GENCS & TSI_GENCS_SCNIP) ; // wait
    delayMicroseconds(1);
    count= TSI0_DATA & 0xFFFF;
#endif
    if (debug)
    {
	Serial.print("  I_ext= ");  Serial.print(I_ext);
	Serial.print("  I_ref= ");  Serial.print(I_ref);
	Serial.print("  Prescale= ");  Serial.print(Prescale);
	Serial.print("  N_scan= ");  Serial.print(N_scan);
	Serial.print("  count= ");  Serial.print(count);
	Serial.println();
    }
    return count;
}
Next Page »

The Rubric Theme. Create a free website or blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 349 other followers

%d bloggers like this: