When talking MIDI and Arduino, everybody uses the 6N138 opto-isolator, and for good reason. It has a fairly high gain!
Imagine you’re struck by inspiration and you can’t find a 6N138 in your toolbox. Oh no! but you find another opto-isolator and a NPN transistor. You could still make it work!
That high gain is needed because:
- Usually a 470Ω resistor connected to +5V is used to overcome Arduino’s 1kΩ resistors to the USB-to-Serial chip (held at 5V or 0V), so that pin 0 (RX) reads a digital HIGH.
- The MIDI interface needs to sink around 20mA of that resistance to achieve a voltage low enough that Arduino takes as a digital LOW
The problem with “normal” opto-isolators is that their gain, or more datasheet-technical, “Current Transfer Ratio (CTR)” which is usually below 100%. E.g. if an opto has a CTR of 20% it means if you input 15mA you’ll allow around 3mA to pass on the ouput (the case of 6N136 and 4N25). The 6N138, on the other hand, has a CTR of ~2000%, and 15mA would let up to 300mA through! see the difference?
An opto-isolator on the inside is actually a LED that emits infra-red light to a photosensor that turns light into a tiny current that is amplified by a transistor. It’s a strictly current driven device, like BJT transistors.
You control the input current and get an output current that’s a percentage of the input (in a given range).You can later turn that current to voltage with a resistor by Ohm’s law.
One could think “well, we can just increase the input current” but there’s a physical limit the LED can handle before burning (or shortening it’s life span). Usually the cap is 20mA. 20ma at 20% CTR still leaves a lousy 4mA output.
Also there might be a limiting resistor on the other end of the MIDI cable (or the cable itself), and you can’t count on that. You need another transistor to amplify the somewhat weak current delivered by the opto-isolator.
The trick is to copy the way the 6N138 is wired internally, adding the transistor appropriately.
And here’s a diagram on how I’m doing it. The IC is a 6N136 and the NPN transistor is a BC547, but almost any other NPN that can handle or more 20mA and has a 20 or more hFE or more will do, like the 2N2222, 2N3904, etc.
I’ve used a 6N136 (tested) but you can also try with other opto-isolators. The 4N25 might work too (not tested), but take into account those have a different pinout. They both can work in the 250kHz range so we’re good for a fairly slow ~32kHz MIDI protocol rate.
Download Fritzing file midi_in arduino uno – low gain opt.fzz
Some math for a technical explanation
The datasheet on the ATmega328P (which Arduino UNO is based on) specifies that, for a 5V Vcc, a digital LOW is a voltage below 1.5V and a digital HIGH is a voltage over 3V. To be safe we’ll aim for lower than 1.5V and higher than 3V.
The Arduino Pin 0 (RX) is tied by a 1kΩ resistor to the USB-to-serial chip (ATMega8U2 in my case). We don’t know when it will be high or low, so we must “override” this value with ours. The typical 470Ω resistor forms a voltage divider:
Taking into account Vo = Vi * R2 / (R1+R2)
‘Vo = 5V * 1000Ω / (470Ω+1000Ω) = 3.4V
So at any time, the pin 0 will be between 3.4V and 5V. That is a HIGH value.
Now we need to pull that 3.4-to-5V below 1.5V when a MIDI pulse arrives.
If the USB chip is low, we just need to sink 11mA (Ohm’s law, 5V/470Ω ≈ 0.011mA), but if it’s high, both 1kΩ and 470Ω will be in parallel, making lower it’s actual resistance of ~320Ω (R1*R2/(R1+R2)). In which case we need to sink at least 17mA to cover both cases.
With the opto-isolator input current at around 15mA and a CTR of 20% we have 3mA sink, and by multiplying it by the gain (hFE) of our NPN transistor (in the case of a BC547 is around 200), we get a CTR of %4000 and could sink a current of around 600mA.
600mA would burn this small transistor but the 320Ω minimal resistance also limits the maximum current to ~17mA.