Page 1 of 1

BJT transistor curve tracer.

Posted: Sun Aug 06, 2023 5:41 pm
by arjen1
Dear forum.

Somehow the images are not shown in the right place, pls scroll down for the attachements....


When I need to measure the characteristics of a BJT transistor I usually try my ALI M-tester, or my simple multi-meter with Hfe socket. However, these measurements will mostly fail with Germanium transistors, and even Silicon transistors are not always measured correctly. How convenient would be a curve tracer. It will give you the Uce-Ic characteristics in a single chart, from which one can determine Leakage current, Hfe, and even output resistance.

There are several 'simple' solutions and schematics to be found on the net. What you need is a staircase Base current input and a sawtooth Uce Voltage. How convenient that the ESP32 has two DAC's readily available. The Collector-Emitter Voltage over the transistor under test is stepped from 0 to max Voltage (3V3) and we need 5 Base currents stepped up from e.g 0 to 10uA.

Image

The Transistor under test is coupled through a current mirror and the current is fed to a 270E resistance. Note the similarity between the NPN and PNP measurement.

The simplest code for this to work is as follows:

Code: Select all

#define DAC1 25       //Define Pin no 25 for DAC1 Output
#define DAC2 26       //Define Pin no 26 for DAC2 Output

void setup(){

}
void loop(){
    // Step DAC2
    for(int Basestep = 0; Basestep < 256; Basestep+=31){
        dacWrite(DAC2, Basestep);
        // Step DAC1 Sawtooth
        for (int CollectorVoltage=0; CollectorVoltage<255; CollectorVoltage++) {
          dacWrite(DAC1, CollectorVoltage);
        }
    }
}
You will need a oscilloscope with XY mode to output the characteristics.
The X probe is connected to the Collector of the NPN, the Y probe to the 270E resistance.
For a standard 2N3904:

Image

Note that Y-axis is now 0.2V/div.
Leakage is pretty high, even for a Germanium BJT: 380mV/270E = 1.4mA (up to 300uA is acceptable, this transistor is not good)


I only tried this with NPN sofar, will setup the experiment for PNP as well later.
I realise that not everyone has an oscilloscope at hand, so I tried to write some code to output it to a webserver (webserver from ESP32 of course), but I lack the knowledge to do that. Assistance would be appreciated. I tried the multiple line Highcharts example as provided on the net, but that only partially works. Further I don't need real time charts, I just collect the data and could then send it to the webserver in an array.
I did manage to output the results via RS232, and then import the data in an excel sheet (I use openoffice). There are many problems to solve, The ADC of the ESP32 has much to be desired......

My experimental code sofar. It outputs some characteristics, however it is not accurate due to the poor ADC.

Code: Select all

//#include "SPIFFS.h"
//#include <WiFi.h>
//#include <AsyncTCP.h>
//#include <ESPAsyncWebServer.h>
//#include <Arduino_JSON.h>

#define DAC_Vc 25       //Define Pin no 25 for DAC1 Output
#define DAC_base 26       //Define Pin no 26 for DAC2 Output
#define ADC_Vb 33    //Define Analog input base voltage
#define ADC_Ic 32    //Define Analog input Ic voltage over 270E
#define ADC_Vc 39    //Define Analog input Vc 
#define Rb 0.27 // Base resistance in MegaOhm
#define Rc  270.0 // Resistance that measures Ic in Ohm
#define Vcc 3.3 // + Voltage
#define Vref0_db 1100.0 // ref Voltage for att=0dB (needs calibration) in mV
#define Vref11_db 3300.0 // ref Voltage for att=11dB (needs calibration) in mV
#define R8200 21 // pin 21 to R8200 (Ohm)

int BaseVoltage, Ic270_1, Ic270_2, IcL;
float Hfe1, Hfe2, Ub, Ib2, Ib1, Ic1, Ic2, IcLeakage, Vref;
int UcIc[300][10], loopnumber=0, valuessent=0;
int ADC_calibration[300], piet;
bool NPNfill = true;

void setup(){
  Serial.begin(115200);

  pinMode(R8200, OUTPUT);
  digitalWrite(R8200, LOW);
 
  
  // initial measurements...
  analogSetPinAttenuation(ADC_Vb, ADC_0db); // Base Voltage  can be between 0-700mV 
  analogSetPinAttenuation(ADC_Ic, ADC_0db); // Current sensing over 270E, approx 1V max.
  analogSetPinAttenuation(ADC_Vc, ADC_0db); // Collector Voltage max 3.3V (minus DiodeV)

  
  // Try and calibrate the ADC.
  // step DAC-Vc from 0 to 255 and measure ADC input. 
  // Map it to ADC_calibration[]

/*  for (int Vcal=0; Vcal<256; Vcal++) {
    dacWrite(DAC_Vc, Vcal);
    ADC_calibration[Vcal] = analogRead(ADC_Vc);
    Serial.printf("Vcal: %i --> %f V, ADC: %i --> %f\n", Vcal, (float) Vcal*3.3/255.0, ADC_calibration[Vcal], (float) ADC_calibration[Vcal]/4095*1.1);
    delay(10); 
  }
  */
  // measure leakage current
  Vref = Vref0_db;
  dacWrite(DAC_base, 0); // No basecurrent..
  dacWrite(DAC_Vc, 255); // max Collector Voltage
  delay(100); // not sure this is needed
  IcL = analogRead(ADC_Ic);
  if (IcL>4095) { // Step up attenuation...
    analogSetPinAttenuation(ADC_Ic, ADC_11db); // Current sensing over 270E, approx 1V max.
    Vref = Vref11_db;
    Serial.println("Leakage current too high --> Step up attenuation to 11dB");
  }
  IcLeakage = (float) IcL/4096.0 * Vref*1000.0/Rc; // leakage current @ zero base current.in uA

  // max current @ max base-current
  dacWrite(DAC_base, 255); //max base current
  dacWrite(DAC_Vc, 255); // max Collector voltage
  delay(100); //not sure this is needed
  BaseVoltage = analogRead(ADC_Vb);
  Ub = (float) BaseVoltage*Vref0_db/4096.0; // in mV
  Ib2 = (Vcc-Ub/1000.0)/Rb; // in uA
  Ic270_2 = analogRead(ADC_Ic);
  if (Ic270_2>=4095) { // Step up attenuation...
    analogSetPinAttenuation(ADC_Ic, ADC_11db); // Current sensing over 270E, approx 1V max.
    Vref = Vref11_db;
    Serial.println("Ic too high @ max Uce --> Step up attenuation to 11dB");
    Ic270_2 = analogRead(ADC_Ic); // read again with higher attenuation
  }
  Ic2 = (float) Ic270_2/4096.0 * Vref/Rc; // in mA

  // lower base current for 2nd measurement
  dacWrite(DAC_base, 204); // Lower Basecurrent with 51/255*3V3/270k = 2.444uA
  delay(100); //not sure this is needed
  Ic270_1 = analogRead(ADC_Ic);
  Ib1 = (Vcc*223.0/255.0 - Ub/1000.0) / Rb; // in uA
  Ic1 = (float) Ic270_1/4096.0 * Vref/Rc; // in mA 

  Hfe1 = (Ic1-IcLeakage/1000.0)/Ib1*1000.0;
  Hfe2 = (Ic2-IcLeakage/1000.0)/Ib2*1000.0;

  Serial.printf("BaseVoltage (int):\t%i\t--> %.0f mV\n", BaseVoltage, Ub);
  Serial.printf("Voltage Ic270_2 (int):\t%i\t--> %.0f mV\n", Ic270_2, Ic2*Rc);
  Serial.printf("Voltage Ic270_1 (int):\t%i\t--> %.0f mV\n", Ic270_1, Ic1*Rc);
  Serial.printf("Leakage current (int):\t%i\t--> %.0f uA\n", IcL, IcLeakage);
  Serial.printf("Forward (base) Voltage: \t%.0f mV\n", Ub);
  Serial.printf("Ic1, Ic2:\t%.2f\t%.2f mA\n", Ic1, Ic2);
  Serial.printf("Ib1, Ib2:\t%.2f\t%.2f uA\n", Ib1, Ib2);
  Serial.printf("Hfe1, Hfe2:\t%.0f\t%.0f\n", Hfe1, Hfe2);
}

void loop(){
    // Step DAC2
    for(int Basestep = 0; Basestep < 256; Basestep+=51) {
      dacWrite(DAC_base, Basestep);
      if (NPNfill && loopnumber==4) {
        Serial.printf("%i, ", Basestep);
      }
      // Step DAC1 Sawtooth
      for (int CollectorVoltage=0; CollectorVoltage<255; CollectorVoltage++) {
        dacWrite(DAC_Vc, CollectorVoltage);
        if (NPNfill) {
          if (!loopnumber) {
            UcIc[CollectorVoltage][Basestep] = analogRead(ADC_Ic);
          }
          else {
            UcIc[CollectorVoltage][Basestep] += analogRead(ADC_Ic);
          }
          if (loopnumber==4) {
            Serial.print(UcIc[CollectorVoltage][Basestep]);
            Serial.print(",");
          }
        }
      }
      if (NPNfill) {
        Serial.println();
      }
    }
    if (NPNfill) {
      loopnumber++;
      if (loopnumber > 4) {
        NPNfill = false;
      }
    }


}


Partial output for the 2N3904:


BaseVoltage (int): 2573 --> 691 mV
Voltage Ic270_2 (int): 1483 --> 398 mV
Voltage Ic270_1 (int): 1040 --> 279 mV
Leakage current (int): 0 --> 0 uA
Forward (base) Voltage: 691 mV
Ic1, Ic2: 1.03 1.48 mA
Ib1, Ib2: 8.13 9.66 uA
Hfe1, Hfe2: 127 153

I am open for good suggestions. Does someone have a good example how to transfer a (rather large) array to the (internal) webserver as served by the same ESP32 and plotted in a chart (e.g highcharts,js, but any other chart javascript would do if that is simpler.

Thanks for sticking to the end. :)