Shifting out to multiple WS2801s using optocouplers

Discussion in 'The Projects Forum' started by espiforenque, Sep 21, 2012.

  1. espiforenque

    Thread Starter New Member

    Sep 21, 2012
    I'm working on a project I call the PixelShifter. Its job is simple: it receives data over ethernet (specifically, it receives Art-Net packets) and shifts that data out to addressable WS2801 chains. This allows me to use a computer to send a video or image over Art-Net and use large quantities of these chains to create what is essentially a giant television. Nifty, huh?

    Here's how it works under the hood: I'm using an mbed microcontroller to shift out to the chains. 16 of the mbed's GPIO pins are used as data lines for 16 different WS2801 chains. I'm shifting out to each of these chains in parallel, which means that, in theory, I should be able to share a single clock line among all the chains.

    It's simple enough in theory, but as is so often the case, the devil is in the details. The mbed runs at 3.3 volts. The WS2801 chips are designed for 5 volt data / clock lines, but will accept 3.3 volts. The problem is that these strips aren't connected directly to the shifter, but are connected via rather long lengths of cable (up to about 20 feet in some cases). This is enough to cause the voltage to drop below what the WS2801 can work with. I've solved the voltage drop issue by using high-speed optocouplers, which have the added benefit of being able to save my $60 mbed from a nasty short (or surge, or whatever).

    The other problem I had been facing was that a single GPIO on the mbed wasn't enough to drive the clock pin on 16 different WS2801 chains. I'm using a MOSFET (post-optocoupler) for this task (although I think I'm using it incorrectly - see below).

    Here's where I am right now: the voltage issue was solved by the optocouplers, but I'm experiencing a terrible slew rate, slow enough to render the outgoing signal unusable for WS2801s. This problem is showing up on both the opto->data lines and the opto->MOSFET->clock lines. Naturally, this is because I've reached a point where I don't quite know what I'm doing. I know that the issue is being caused by too much capacitance, or not enough capacitance, or something; capacitance is a concept on which I have a very loose grasp. Note that these are 6N137 optocouplers, which are supposed to have a throughput of 10mb/s. I've already stumbled across this document (PDF warning), and I'm slowly trying to work my way through it; I just feel like I'm missing some fundamentals that this document assumes I already understand.

    I'm pretty sure I'm using the MOSFET incorrectly as well - I know you're supposed to connect the source to ground, not to your load - but I'm not sure how else to do it.

    Am I so close, and yet so far? Do I just need to toss in a resistor or capacitor in the right place? Or am I doing something fundamentally wrong? Any advice is welcome. Don't be afraid to call me an idiot!

    tl;dr: mbed can't shift out to WS2801s over long distances; using optocouplers results in a lousy slew rate because I'm doing it wrong.
  2. Sensacell


    Jun 19, 2012
    If I can distill the essence from your post, it sounds like the problem you face is moving a bunch of fast digital 3V signals from one place to another, 20 feet or more without corruption.

    One way this can be solved is to use differential signaling, use two wire twisted pair cables with some RS-422/485 driver/receiver chips on both ends.

    This technique is quite tolerant of voltage drops, noise etc., it's used for reliable data transmission in nasty factory environments - at speeds of 10 MBPS, 100's of feet, no problem.

    You could use the SN75HVD08 for example, use one on each end of the signals you want to send, the clock line can have one TX and multiple RX on the same line. You also don't have to fret about level translation.

    Just terminate the end of the twisted pair cable with 120 ohms to avoid signal reflections on the cable. Don't forget to connect the grounds.
  3. espiforenque

    Thread Starter New Member

    Sep 21, 2012
    Hmm. It's interesting you should mention RS485, actually. Art-Net is a successor of sorts to DMX, a protocol designed specifically for lighting applications that uses RS485. In fact, Art-Net packets are little more than DMX packets sent over ethernet.

    In this case, however, the issue isn't so much getting the signal from here to there as it is getting a good signal "out of the gate." I used an Arduino for this application before I upgraded to the mbed, and its more generous / forgiving 5-volt output pins were able to drive four WS2801 chains over ~20-foot cables with no problem. That being said, a differential signal might just be the solution in case I have to make super-extended runs.

    I'm pretty sure that the issue has something to do with the pull-down (pull-up?) resistor after the optocoupler. If I swap it out for a resistor with a lower ohm rating, the slew rate decreases, but I fear that I'll just short something out if I use too small of a resistor. My limited experience tells me that I could also add a resistor somewhere in the circuit to increase load, thus decreasing the slew rate to a workable value. I'm just not sure where. (One will probably note from looking at the schematic that the resistor values I used are somewhat arbitrary, but close enough to work; this could also be what's wrong.)

    I should also probably point out that the slew rate on the scope was tested on the board itself, not after a ~20-foot run.
    Last edited: Sep 21, 2012
  4. Sensacell


    Jun 19, 2012
    Looking at your circuit, the main problem I see is a lack of a pull-down resistor on your FET driver- the drain should be pulled down with 2.2 K.

    What is your target data rate?

    First order of business is keeping the logic levels within spec at the receiving end.

    From the data sheet: Vin (Low) = 0.2 Vdd MAX, which is a mere 100 mv @ 5 volt supply, this small voltage is easily swamped by any ground noise in your system (cable).

    You have some options:

    1) Raise the signal levels and increase the logic thresholds commensurately, basically "make the signals much bigger than the noise" this is how RS-232 works- make the signals gigantic, i.e. +- 9 volt output swings.
    (not recommended in this case however)

    2) Use differential signaling- (as mentioned) This is your high-performance option.

    3) Transmit the signals as a current. For example, put the opto-couplers on the RECEIVING side so you are sending a current to light up the LED in the coupler, not a voltage referenced to ground, this scheme is a typical way to solve this problem.
    Last edited: Sep 23, 2012
  5. Dyslexicbloke

    Well-Known Member

    Sep 4, 2010
    OK I have to admit that some of that is at the limit of my experience but ...

    That FET is N-Channel so you need its source to Gnd and its drain to a pull-up on the clock lines.
    As is, it will never fully turn on because VGS will fall as the voltage on the clock pin rises.
    Granted it will work as a follower with your clock pin reaching (VCC - G threshold) but it will be super slow.

    With the drain connected to the clock pins and pulled up, VGS will be 5v when the OPTO output is high but it may take some time to get there. You want to charge the gate as fast as possible so you need a low impedance to do it.
    The open collector opto is good for 50mA so you could reduce your 680 gate pull-up considerably, speeding up the turn on but your best bet would be a totem pole, which is just two transistors, and will get you the best performance you can achieve with a simple gate drive circuit.

    Moving on ...

    I have played extensively with video over twisted pair and I think you can solve your problems in the same way.

    Firstly video, at least the analogue versions, are voltage based and voltage sensitive to boot. To send any distance, and I am talking 100m+ you would use a BalUn to convert your unbalanced voltage level to a balanced, two wire, signal exactly as described in the earlier post.

    In the case of video, magnitude is still important but digital signals do not suffer from that issue so designing a current based transmission line is somewhat simplified although rise times can be a problem, due to inductance, for very fast signals

    For examples of how to do it look at RS485 and even Ethernet circuits, the two standards are very different but both are current based.

    I suspect that if you use a chip designed to drive either, the Ethernet having isolating magnetics that will replace your opto-couplers, you may find a relatively simple packaged solution. I am fairly sure that Maxim will do both.

    That brings me back to video ... Phase shift on long lines is a problem, RGB or SVGA signals on multiple pairs get out of sync causing colours to blur or even separate on the screen.
    Many commercial products intentionally delay all the signals slightly and then reduce the delay for those that are out of sync at the end of long cables.

    I appreciate that your issue is delay on adjacent receivers as opposed to shifted signals that should be in sync on a single receiver but the problem is essentially the same.

    If you introduce an intentional propagation delay you have the option to shorten it on receivers that experience delay from an external source IE the long line.

    Your other option might be to keep the opto-isolators, well sort of.
    Transmit over fibre, your emitters are all at one end and in sync and the propagation delay is so small over 20 feet as to be insignificant, effectively 0.
    You wont get a voltage drop or slew rate issues that way, or at least if you do it will not be dependant on cable length.
    Commercial products exist to 'tap' fibre without breaking it, I think they are generally called FTTH connectors.

    OK fibre is possibly a flight of fancy, I expect a balanced pair with some attention to controlling prorogation delay is your best bet.
    I am confident that if you research time sensitive signals, video / USB2, over long twisted pair you will find a relatively simple solution to your specific problem.

    Once again I think Maxim do a single chip solution, at least for video, with a programmable delay built in !

    lastly ... CMOS logic chips are FET based internally. CMOS line drivers are designed to accept a wide range of logc 1 levels, much wider than TTL, and capable of output currents capable of supplying many, 10's even 100's of CMOS inputs.
    Have you tried the 'standard' solutions before getting creative?

    DS89C21 is a CMOS differential line driver/receiver. Its slew rate is an order of magnitude faster than your FET and its logic output is good for 25ma which I suspect will drive several LED chip data lines.
    If 25mA isn't enough then standard CMOS buffers, or none differential line drivers, will probably do the job nicely.

    I have never tried this chip it was just the first that goggle listed.

    Hope this helps.
    Last edited: Sep 23, 2012
  6. espiforenque

    Thread Starter New Member

    Sep 21, 2012
    I'm just not sure I need to implement a differential signal, for one simple reason: I shift out rather slowly. At 24 bits per pixel, times 42 pixels per chain, times 30 frames per second, I need a data rate of 30,240 bits per second (the clock would rise and fall during each bit, which I guess doubles the bit rate for the clock?). I would use the SPI bus, except that it would only allow me to shift out to a single WS2801 chain, and I don't need the extra speed. What I have here is more like a bit-banged Parallel Peripheral Interface, as it were.

    Sorry, I don't mean to sound like I'm doubting y'all's knowledge. It's just that I've done this with an Arduino before and it worked perfectly. I didn't use optocouplers because they didn't appear to be necessary. I had 20-foot cables hanging from trees in the middle of winter last year, and the LEDs did their thing through wind and rain and snow. Is that just because of the 5-volt signal on the Arduino, or is there some other property of the output pins on the mbed that might necessitate a differential signal?

    Just so there's a way to objectively compare the quality of the signals pre- and post-long-cable, I'll upload some scope readouts of both my old Arduino shifter and the new mbed hotness, before and after the cable.

    In the meantime, taking the advice of what I've read here so far, I've rearranged the MOSFET into a common drain circuit, where Vout goes to the clock line of all the WS2801s. I also swapped the 680-ohm opto pull-up resistor for a 330-ohm, and now I'm getting what appears to be a totally usable slew rate on the data line (so far I've only gotten one working). Sweet. I've uploaded a new schematic reflecting my changes.

    Now I'm experiencing a new problem: I'm getting some crazy interference on the data line whenever I pulse the clock line (see the attached oscilloscope image). I'm not sure what's causing that. This is what happens when I send a 25µs pulse over just the clock line. In theory, the data line should stay high the whole time. Additionally, the clock line should be hitting 5 volts while high; right now it's only going half-way.

    Oh, and to make matters more complicated, I get a totally different reading on Data when I attempt to get a reading from Data and Clock simultaneously. This is some Heisenberg Uncertainty Principle action here. Just the way I test it affects the outcome.

    Thanks for all your input!
  7. espiforenque

    Thread Starter New Member

    Sep 21, 2012
    Whoops, I forgot to include the resistor in between the MOSFET's Vout and ground. I imagine that sparks would fly (or my power supply would shut off to save itself) if I'd forgotten that.