Opto-coupler Design Notes

This forum is for discussing hardware (electronics) and software design aspects of multiplexers in general.
Post Reply
Luis Sa
Site Admin
Posts: 845
Joined: Thu May 04, 2017 4:12 am

Opto-coupler Design Notes

Post by Luis Sa » Wed Mar 21, 2018 5:42 am

Hello,

In this article I explain the design methodology in the opto-coupler inputs of the NMEA2WIFI multiplexer. This type of input is not strictly necessary but it is very useful when the talker and the listener(the multiplexer) do not share the same ground or when due to noise, a voltage difference could develop between the 2 grounds. Here is the design for input port P2:

opto-coupler.jpg

This is the critical port as it baud rate can go as fast as 38.400 baud. In terms of frequency we may think that we need a circuit that passes a square wave of 19.2KHz through the isolating coupler with minimum modification. The project was built around the 6N139 high speed opto-coupler. As the voltage at the inputs pins of the ESP8266 (pin 6 in the present case) can not go higher than 3V6, the collector of the output transistor is connected to the 3V3 voltage rail (supplied by the internal voltage regulator of the D1 Mini module) through resistor R3. The requirements for the ESP8266 in terms of voltage levels are shown here:

LOW_HIGH.jpg

In order to avoid the destruction of the input pin circuitry, the voltage Vo can not be less than -0.3V or greater than 3.6V. For a voltage to be recognized as a logic LOW, Vo should be less than 0,83V and greater than 2.48V to be recognized as a logic HIGH.

It should be noted that there is a great tolerance margin on the parameters of the 6N139. For example the CTR (current transfer ratio) has a typical value of 1300% but a minimum value of 500%. Let us discuss this value using the 2K2-470R design (R2=2K2 and R3=470R). In the next and following pictures the yellow waveform refers to the voltage Vi (more precisely the voltage measured at the connection between Ri ad R2) and the blue waveform refers to the voltage Vo

2K2-470R.jpg

In this discussion we used a "poor" 6N139 for the sake of the explanation. Normally the waveforms are better than the waveform shown in this picture. The first problem that we note is the difficulty of the output transistor to leave its saturation state. The time tPLH (propagation delay to logic high) is too great. If we look to the 6N139 datasheet it can be as high as 90us (micro seconds) depending mainly on the load resistor (R3 in our case). For a 38400 baud signal (or a 19200 Hz square wave) the width of the pulses have a duration of 26us. Therefore if we had use R3=4K7 as shown in the datasheet for the case of tPLH=90us, the waveform would not leave the LOW stage. We also note that the highest voltage reached by Vo is about 2.1V and so it will not meet the 2.45V requirement to be recognized as a logic HIGH. Normally UARTS read the waveforms not on the middle of the pulse width but further to the right (at least this what happens in the software UART implemented on P1). Even with this "bad" voltage the ESP8266 recognizes it as logic HIGH. Before we discuss this further let us show the same circuit operating with a 2,400Hz (equivalent to 4800 baud). At this speed there is no problem with the circuit as it can be seen in the following picture

2K2-4800-470R.jpg

So let us return to the "38400 speed". Before mounting the IC on the PCB we test each 6N139 one by one and classify them in two classes: "poor" and "rich". The "poor" instances as the one shown in this article are used on P1 whose baud rate is 4800 or 9600. For P2 we choose the "rich instances". In order to alleviate this problem we changed the design aiming at a better 6N139 performance on P2. The way to go was to decrease R3 which also decreases tPLH. First we tried R3=270R

2K2-270R.jpg

It is better but may be not enough. So we tried R3=120R

2K2-120R.jpg

Now the waveform is clearly better but a new problem appears. The transistor current Io is approximately 25mA (3V / 120R). The maximum allowed current for Io is 60 mA so we need to be careful. On the other hand for a transistor to be in saturation its base current Ib should be greater than Ic/hFE. With opto couplers is almost the same using If instead of Ib. We already referred to that the CTR (current transfer ratio) has a minimum value of 500%. This means that for Io=25mA the diode current has a maximum value of 5mA (500% gain is an absolute gain of 5). Actually we can evaluate the If current. The yellow waveform was taken at the junction of Ri and R2. Also, in order to use both oscilloscope channels we had to connect pin 3 on the 6N139 to ground. So we have a voltage across R2 and Vf of 4.2V as measured from the picture. Taking into account that for If=5mA Vf is about 1,4V (see Fig.4 on the datasheet) the voltage across R2 is 2.8V. So If is not 5mA but 2.8V/2K2 or 1,27mA. Therefore the CTR is 25mA/1,27mA x 100% or CTR = 1900% which is even better than the typical value of 1300% shown in the datasheet. But had CTR be 400 we would need If to be 5mA to take the transistor into its saturation state. With R2=2K2 a voltage of about 12,5V would be necessary. We hardly believe that Nmea 0183 talkers are able to supply such high voltage not to speak on the internal resistor Ri. Also, if we look carefully, the blue logic LOW is now about 0.2V. That is OK but in our experiments with different 6N139 instances we got this voltage to be as high as 1V and so not respecting its "logic electric" requirement.

So we return to 270R as a compromise (also less power dissipation) and decreased R2 from 2K2 to 1K. Those are the values that we are now using in the multiplexer. By lowering R2 from 2K2 to 1K we are asking more current from the talkers. However, if an user has a talker that is not capable of supplying 3.5mA at 5V (using Vf as 1.5V) an external series resistance can be used. Since the CTR of the 6N139 is typically much greater than 314% (3V/270R results in Io=11 mA which divided by 3.5mA gives CTR=314%) a greater than 1K value for R2 is admissible. In the following picture it is shown the result with R2=1K and R3=470R

1K-270R.jpg

Before I terminate, I refer the possibility of forgetting opto isolation and using a simple transistor to invert the yellow signal. Note that in a idle state (no data coming) the yellow voltage (RS232) is low and the LED diode does not conduct. Pin 6 on the ESP8266 is high (idle state on TTL serial). While taking the picture to write this article I removed the 6N139 IC and inserted a BC547 NPN transistor in the DIL-8 socket as shown here:

NO-OPTO_NPN.jpg

The base went to pin 2 of the DIL-8 The emitter went to pin 3 which we short to pin 5 and collector went to pin 6. With R2=2K2 and R3=470R the waveform is as here:

2K2-NPN-470R.jpg

Not surprisingly BAD! If the hfe of the transistor is, say 200 it corresponds to a "CTR" of 20000%!!! So the transistor is almost permanently in saturation. But putting a series resistor of 27K in series with R2 we ge this:

29K-NPN-470R.jpg

Good but no isolation!

Best Regards, Luis

Luis Sa
Site Admin
Posts: 845
Joined: Thu May 04, 2017 4:12 am

Re: Opto-coupler Design Notes

Post by Luis Sa » Wed Dec 25, 2019 9:43 pm

Hello,

I recently looked at optocoupler switching characteristics and in particular to the 2731 IC used in the Nmea4Wifi multiplexer. The 2731 optocoupler is a 2 channel optocoupler with a darlington output transistor. It contains 2x 6N139 in a single DIP-8 package. I compared the 2731 with the 2531. The 2531 is also a 2 channel optocoupler but has a single output transistor. It is pin to pin compatible with the 2731 and we can think of it as being a double 6N136 in a single DIP-8 package.

In the case of the 2731, the minimum CTR is 500% at IF=1.6mA. In the multiplexer the colector is connected to 3.3V with a 330R resistor. The saturation current is therefore 10mA. Using the minimum CTR of 500% the input Led current IF should be at least 2mA. We are using a 1K5 input resistance in series with the Led. If the input is driven with 5V signal, the voltage across this resistor is 3.3V (1.7V is the voltage drop at the diode) so that the IF is greater than 2mA. If we increase the input resistor, the input IF current becomes smaller and it can be the case that the transistor does not enter the saturation (does not go to zero in the blue waveforms below). On the contrary if the input resistance is smaller, too much IF current can put the transistor deeply in saturation (even with 1K5 and noting that the typical CTR for the 2731 is 1300%, the transistor can be highly saturated with IF=2mA). When the transistor is deeply saturated it will take time to leave the saturation. We can observe that with the rounded rising edge in the blue waveforms below. In the picture, the blue waveform is the colector voltage with a pull-up 470R resistor to 5V (more or less equivalent to 330R to 3.3V) when the Led diode is driven with the yellow signal through a 1K5 resistor. Frequency is 38400Hz which is equivalent to a baud rate of 76800.

opto-2731.jpg

For the 2531 the minimum CTR is 20% at IF=16mA. We used a 7K5 pull-up resistor to 5V (more or less as 4K7 to 3.3V) so that the colector current is 5V/7K5 = 0.67mA. With a CTR of 20% the IF current should be at least 3.3mA (5x greater). With a 5V input signal, an input series resistor of 1K could be used to give the 3.3mA current. However, the CTR of 20% is specified at IF=16mA. At IF=3.3mA it is lower. Also I found that with low values of IF the Led will not drive the transistor properly. A compromise is an input resistor of 330R which corresponds to an IF of 10mA. The following picture corresponds to that case.

opto-2531.jpg

Summarizing: the 2531 is faster (the rising edge is better) but it needs to be driven with a stronger curent. On the contrary the 2731 can be driven with lower currents (about 2mA). Using the 2731 we can have several listeners receiving data from the same talker. With the 2531, one listener requires about 10mA of driven current and 2 listeners require 20mA. The talker should have a capacity of 20mA to drive 2 listeners simultaneously. That was the reason we chose the 2731 in designing the multiplexer.

Regards, Luis

Luis Sa
Site Admin
Posts: 845
Joined: Thu May 04, 2017 4:12 am

Re: Opto-coupler Design Notes

Post by Luis Sa » Thu Dec 26, 2019 11:54 am

Hello,

In the previous posts I was using a square wave to test the optocouplers. That is not sufficient. I just noticed that about one year ago when I received a lot of 2731 from a well known european supplier. Here is the waveform at 76800b that I was getting:

2731-pol-sq.jpg

Still I was getting errors at the lower speed of 38400b. To my surprise I found that the time to logic low can be very high. Testing the same IC of the previous figure with a 100Hz signal I got this:

2731-pol-one.jpg

When receiving serial data, we have a low voltage idle state and the voltage goes high when the start bit is received. This is like the yellow signal above. At the output of the optocoupler (blue signal) we have a high to low transition. In my software implementation of UARTs that falling edge determines the instants that the signal must be sampled. The "12uS error" is very large when compared to the bit duration of 26uS at 38400b. With a square wave we do not see this propagation delay as the signal was not stable (it was still raising) before going low. That is the reason why I use the string "UUUUUUUUUUUUUUUUUUUU~~~~~~~~~~@@@@@@@@@@" in the testing as "U" in binary is 1010101, "~" in binary is 1111110 and "@" in binary is 1000000. I left here the programme that I use to test the 2x channel optocouplers as well as an extract of the switching characteristics of the 6N139/HCPL2731.

time-to-low.gif

Code: Select all

/* OPTO COUPLER TESTER
 *  
 *  Runs on an ESP32 module. It tests 2 channel optocouplers type HCPL2731
 *  It sends a string of 40 characters on the TX pin and reads back the
 *  string on the output of the optocoupler using 9600b and 57600b. If no
 *  error is detected a LED lights on. The string is
 *  
 *  "UUUUUUUUUUUUUUUUUUUU~~~~~~~~~~@@@@@@@@@@"
 *  
 *  "U" in binary is 1010101
 *  "~" in binary is 1111110
 *  "@" in binary is 1000000
 *  
 */

// GPIO pins for Leds L1 L2 L3 L4

#define LED_PIN_1    12       // diode L1 for input port #1 and 9600
#define LED_PIN_2    14       // diode L2 for input port #1 and 57600
#define LED_PIN_3    15       // diode L3 for input port #2 and 9600
#define LED_PIN_4     0       // diode L4 for input port #2 and 57600

// GPIO pins for UARTs
#define RX_PIN_1     16       // HardwareSerial (1) 
#define TX_PIN_1     17       // HardwareSerial (1)  not used


#define RX_PIN_2     23       // HardwareSerial (2) 
#define TX_PIN_2     17       // HardwareSerial (2)  not used


void setup() {

  pinMode(RX_PIN_1, INPUT_PULLUP);
  
  pinMode(TX_PIN_1, OUTPUT);
  
  pinMode(LED_PIN_1, OUTPUT);
  pinMode(LED_PIN_2, OUTPUT);
  pinMode(LED_PIN_3, OUTPUT);
  pinMode(LED_PIN_4, OUTPUT);

  LedsOff();
  
}

void loop() {

    Serial.begin(9600);
    Serial1.begin(9600, SERIAL_8N1, RX_PIN_1, TX_PIN_1);    
    delay(10);
    if ( Test_1() ) { digitalWrite(LED_PIN_1, HIGH); }
    else { digitalWrite(LED_PIN_1, LOW); }
    delay(10);

    Serial.begin(57600);
    Serial1.begin(57600, SERIAL_8N1, RX_PIN_1, TX_PIN_1);    
    delay(10);
    if ( Test_1() ) { digitalWrite(LED_PIN_2, HIGH); }
    else { digitalWrite(LED_PIN_2, LOW); }
    delay(10);

    Serial.begin(9600);
    Serial2.begin(9600, SERIAL_8N1, RX_PIN_2, TX_PIN_2);
    delay(10);
    if ( Test_2() ) { digitalWrite(LED_PIN_3, HIGH); }
    else { digitalWrite(LED_PIN_3, LOW); }
    delay(10);

    Serial.begin(57600);
    Serial2.begin(57600, SERIAL_8N1, RX_PIN_2, TX_PIN_2);
    delay(10);
    if ( Test_2() ) { digitalWrite(LED_PIN_4, HIGH); }
    else { digitalWrite(LED_PIN_4, LOW); }
    delay(10);
    
}

boolean Test_1() {
  int j, n;
  byte b;
  boolean IsOK = true;
  while (Serial1.available() > 0) {    // get all characters that may exist
    b = Serial1.read();
    delay(1);
  }
  for ( j = 0; j < 5; ++j ) {
    n = 0;
    Serial.print( "UUUUUUUUUUUUUUUUUUUU~~~~~~~~~~@@@@@@@@@@" );
    delay(100);
    while (Serial1.available() > 0) {    // get the characters
      b = Serial1.read();
      n = n + 1;
      if ( (b != 85) && (b != 0x7E) && (b != 0x40) ) { return false; }
    }
    if (n != 40) { return false; }
  }
  return IsOK;
}

boolean Test_2() {
  int j, n;
  byte b;
  boolean IsOK = true;
  while (Serial2.available() > 0) {    // get all characters that may exist
    b = Serial2.read();
    delay(1);
  }
  for ( j = 0; j < 5; ++j ) {
    
    n = 0;
    Serial.print( "UUUUUUUUUUUUUUUUUUUU~~~~~~~~~~@@@@@@@@@@" );
    delay(100);
    while (Serial2.available() > 0) {    // get the characters
      b = Serial2.read();
      n = n + 1;
      if ( (b != 85) && (b != 0x7E) && (b != 0x40) ) { return false; }
    }
    if (n != 40) { return false; }
  }
  return IsOK;
}

void LedsOff() {
  digitalWrite(LED_PIN_1, LOW);       // light goes OFF
  digitalWrite(LED_PIN_2, LOW);       // light goes OFF
  digitalWrite(LED_PIN_3, LOW);       // light goes OFF
  digitalWrite(LED_PIN_4, LOW);       // light goes OFF  
}


Regards, Luis

Post Reply