Three Conceptual Approaches To Driving A WS2811 LED Pixel


[Cunning_Fellow] published a post with three proof-of-concept approaches to driving a WS2811 LED pixel. We looked at a project early in December that used an AVR microcontroller to drive the RGB package. [Cunning_Fellow] saw this, and even though he doesn’t have any of these parts on hand he still spent the time hammering out ways to overcome the timing issues involved with address the device. His motto is “put up or shut up” when it comes to criticizing projects featured on Hackaday. We love seeing someone pick up an idea and run with it.

The approach in all three cases aims to conserve clock cycles when timing the communications. This leaves the developer as many cycles as possible to perform other tasks than simply telling the lights what to do. One approach is an assembly routine that is just a shade slower but groups all 14 free cycles into one block. The next looks at using external 7400 series hardware. The final technique is good old-fashioned bit banging.

[Photo Credit]

21 thoughts on “Three Conceptual Approaches To Driving A WS2811 LED Pixel

  1. The NeoPixel library is not quite in the spirit of what Alan or myself where doing. Alan had already tried FastSPI (An SPI library that some people get to work with the WS2811). His hardware did not cope with the inter-byte jitter so he wrote his own. NeoPixel will also have this problem as it shifts a byte then jumps out a subroutine and then then back in.

    Savannah – What trick where you thinking of ?

    1. Since it was in reference to the interrupt, I was thinking one could write code within the interrupt vector area. As long as a person takes care not to have any other interrupt (that would jump into the middle of that code) fire off, it should work. I don’t really know if that would work as described because A) if I’m so clock cycle hungry on that particular AVR, I start looking at a different solution and B) it never really occurred to me and finally C) I don’t have an AVR spec sheet readily available atm to verify such an idea.

      1. Yep – that is the trick.

        The AVR interrupt vectors are not the same as you would expect from from a CPU that can run code from RAM. Instead of having an address that is loaded to the PC from a vector table, the PC just gets loaded with the address of the table element. This address loaded is an RJMP to your ISR.

        If you don’t mind loosing the ability to use the NEXT interrupt in the table you can make the word at the address of your interrupt be OUT IOReg, NewData then have the next word being RJMP to the code you want to run.

        At the end of this code just make sure you leave the next byte in “NewData”.

        Doing that “stupid AVR trick” you can easy get the next data into the IO register in under 9 clocks.

        Downside is you loose the use of the next sequential interrupt in the table.

  2. Nice. I’d previously tried using the TCO approach and failed, but his method looks totally workable. And points for Extreme Cleverness for the SPI slave thing (avoiding the not-double-buffered problem in master mode).

    Adafruit_NeoPixel (thanks for the shout out, @joerautenbach) ended up using bit-banging, the primary motivation being that it’s not tied to a specific peripheral-defined pin or port, and in fact can handle multiple instances on different pins. The latter was especially important for wearable applications…you can run a strand to each extremity and ‘home run’ all the wiring, no need to double back to make a single continuous loop.

    1. Phil, the AVR slave SPI mode is still not double buffered in the transmit direction. When that last bit gets clocked out, you REALLY need to get that next byte loaded ASAP.

  3. Thanks Phillip. I don’t do clever things very often but once and a while something will pop up.

    The SPI as a slave is something I have done for a long time. You can even couple it with a timer interrupt to get higher clock rates and interrupt driven. (without using the stupid trick I alluded too)

    It is something I also use in my high resolution laser photo plotter that I am going to get around to writing an instructable for one day.

  4. I’m actually working on two additional approaches not seen here. One involves using an external 74HC123 monostable to generate appropriate one-shot pulses. The other involves an external SRAM, but I need to test it more before presenting it as a valid solution. My solutions (and eventual products) aren’t trying to avoid external hardware, because I want to come up with a reliable way to drive many WS2811 chains in parallel.

    1. macegr – I have one word to say to you “programmable logic”.

      OK it’s two words.

      But if you don’t mind external hardware then a bit of VHDL and a cheap FPGA/CPLD will get you plenty of parallel WS2811 streams. Will leave you CPU plenty time to read the data over the USB/SD-Card as well.

      1. That was approach three ;) However, I’m saving it for later as it’s not worthwhile unless you really are doing a lot of parallel streams, and I’m trying to make more of a modular system where each channel is mostly a sequential device where programmable logic is not needed. The software and programming methods for CPLDs also leave much to be desired.

        1. VHDL is not so bad. And for $2 or $3 you can get a chip that could offload all the fast/time-critical work.

          That said – you could bit bang 8x WS2811 streams out a single AVR port in software if you didn’t need to shuffle the data order.

          Bit banging 8 parallel streams would take close to 100% of your free time. So you could not serialise AND get new data at the same time. This would mean you would have to

          1, Get the data from UART/USB/SD-Card to RAM
          2, Serialise the data

          SO you are straight away limited to how much RAM you have on board.

          1. For an entirely different project, I was trying to figure out a cute logic trick to rotate an 8-byte bitfield, in order to serialize it for parallel output streams. Never did figure it out…but a CPLD or 8 PISO shift registers would do the trick.

  5. Alastair,

    Always willing to help out fellow Aussies and I have enjoyed reading some of the Make Hack Void stuff.

    HOWEVER – from a very early age all my teachers have said “cunning does not play well with others”

    If you have specific routines you would like looked at then give me a task that I can go off and do in ASM by myself.

  6. OMG. I am using this metod with DMA and timer for a very long time. It was so obvious solution that I didn’t notice it’s even worth posting it here……. I always wondered why everyone was interfacing WS2811s with SPI – this interface has NOTHING TO DO with SPI!

Leave a Reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.