Wednesday, November 4, 2015

Pixie - Bright Things Come in Small Packages


Exciting! A new product of my design just hit the market last week! World, meet Pixie - a 3W chainable smart LED Pixel. Kind of a long title... what does it mean?

LED Pixel: The Pixie is a color LED module, allowing an external controller to change its color and brightness dynamically.
Chainable: The module is designed so that you can chain many of them and control each one individually. If you know NeoPixels, this concept should be clear, but in case you don't, imagine you want to build a project that requires 50 LEDs to be individually controlled. Naively, you would need to power each on of them individually, then connect each one of them individually to a controller. This would require tons of wiring, many pins on the controller, each one possibly driven by a specialized peripheral, such as UART or PWM. In short, this is not practical. With the Pixie, being chainable, you connect the first LED's input pins to power and a single control pin (serial TX) on the controller. Then you connect the first LED's output pins (power, ground, data) to the input of the second LED, and so on. Each Pixie in the chain consumes its own data, then relays the rest of the data down the chain, so the controller can control each Pixie individually, without being connected to each one.
3W: 3 Watts of power drive the LED, or 1 Watt for each Red, Green, Blue. This is a VERY bright LED. Compare to typical NeoPixels, which are around 0.2W.
Smart: Some really high-end features are available on each Pixie, such as Gamma correction (8-bit to 16-bit) for super-smooth color gradients, over-heating protection (these things do get hot if left on at full blast for too long), communication loss protection.


The idea was born about a year back, when I started designing my Burning Man LED jacket. The jacket required 50 x 3W RGB LED and I couldn't find any off-the-shelf ones that include the required drive circuitry and are chainable. So I decided to make one myself. It was only a couple of month later that I recognized that this might actually be useful for other people, so I decided to try to turn it into a product. It took a couple of iterations to get it right, fixing some issues that I'll describe in detail below.

I chose to collaborate with Adafruit on this project, partly because I've already worked with SparkFun and SeeedStudio in the past, and partly because Adafruit really have a great selection of LED-related products and have a great reputation in this field (and in general). I think I chose well, they were great to work with!

So... before this thing starts sounding too much like a sales pitch, let me share with you some of the design insights I've had while working on this module. As you'll see, sometimes the devil is in the details and what might appear to be a simple product initially may turn out to be quite a challenge. I've shared the same information as a Design Notes page on Adafruit. Keep in mind that as with my previous products, this one is also fully open-source software and hardware for maximum hackability and fun.

Microcontroller

Fairly early down the design path, it became clear that implementing all the features we wanted is a task most suited for a small microcontroller. We chose the 8-bit Microchip PIC12F1571, which had just about everything we could hope for in this application. It is small and cheap, works on 5V, has exactly 5 I/O pins (used for R, G, B, Din, Dout), an internal oscillator, a 16-bit, 3 channel PWM module, on-die temperature sensor and more. Pretty amazing!
Programming the PIC12 is done through exposed pads featured on the circuit for that purpose (labeled rst/pgd/pgc). A cheap PIC programmer can be used, but the programming protocol is so simple that we’ve implemented an Arduino library that can do that for our testbed.
The possibilities with having an on-board microcontroller are endless! The Pixie can be reprogrammed for standalone operation, and the Din/Dout pins can be repurposed to support different protocols or to directly connect to buttons, etc. The Dout pin can even be used for analog input!
The exiting firmware can be found in Pixie's Github repository.

Constant Current Driver

In order to provide a consistent level of illumination each of the R, G, B LEDs needs a constant current supply of about 350mA. We opted for linear regulation for its simplicity and low-cost, despite it being less efficient (and as such, dissipating more heat) than switching regulation.
The constant current circuit is pretty cool. Let’s explain it by first considering the path of the current through the LED. The current comes from the 5V supply, through the LED, then through a nFET (Q1/3/5) then through a 1.74[Ohm] shunt resistor. The more resistive the FET becomes between its drain and source, the smaller the current flowing through this path. Now let’s see how we can use this to our advantage.
The NPN transistors Q2/4/6 have a specified 0.6V drop between base and emitter when on. This means the voltage across their respective shunt resistors R1/3/5 will always be 0.6V. According to Ohm’s law, this means that the current through them will be 0.6[V]/1.74[Ohm], or about 344mA. Close enough. If the current were to decrease, the base voltage would decrease proportionally, resulting in the NPN having more resistance between its collector and emitter, thus causing a higher voltage on the collector (recognize the voltage divider formed between the NPNs and their R2/4/6 pull-ups?). But this would result in a higher voltage on the FET gate, causing it to become less resistive between source and drain and as a result, higher current through the LED. The same logic can be applied in the opposite direction. The conclusion is that this circuit is self-regulating the LED current.

Color and Brightness Control

Different colors are achieved via Pulse Width Modulation (PWM) on each of the R, G, B LED. The PIC has a built-in 3-channel, 16-bit PWM peripheral. This allows us to be fancy and do Gamma correction, which means we are doing a non-linear mapping of the 8-bit color value we are commanded with to a high resolution 16-bit color, resulting in a much more natural color gradient compared to a straight linear mapping. The PWM peripheral runs at about 500Hz. The generated signals switch the constant-current circuit described above.

Daisy-Chaining

Originally, we have designed the Pixie to support the same serial protocol as the WS28x family (aka NeoPixel). It worked. However, this compatibility, which was originally considered a feature has been eventually deemed a drawback: the WS28x protocol doesn’t easily lend itself to common micro controller peripherals, and in most cases ends up being bit-banged by the controller, requiring a relative high CPU usage, making it hard to do other timing-sensitive operations at the same time, not to mention driving another chain on a different pin… Our solution: stick to the good ol’ 115k.2 asynchronous serial. Almost every microcontroller has a UART peripheral capable of easily generating this protocol without much CPU intervention. Many have more than one. Even a PC with a simple USB-serial dongle can do that fairly easily. Seems like a win! The only drawback we could see what with the data rate being relatively low, we run into frame-rate / chain length limitations (about 60-long chain @ 50 frames/sec). However, at about 1[A] per Pixie, we concluded that typical chains would not be super-long.
The resulting serial protocol is very simple: the controllers sends a byte-string containing a color value for each LED in the chain as follows:
, , , , , , , , , …, , , ,
Each of is a byte representing the brightness of a single color of a single Pixie, where 0 is off, 255 is fully on, and everything is between is, er, everything in between. , , will determine the color of the Pixie that is the first in the chain, counting from the controller end. , , is the next one, etc.
Each Pixie listens on it Din pin for serial data. It will consume the first 3 bytes it sees and store them. It will then echo any subsequent bytes to its Dout pin (with less than a microsecond latency). It will keep doing so until it detects a 1ms-long silence on Din. Then, it will immediately apply (latch) the color values it got and go back to listening for a new color. This yield a very effective mechanism for addressing LEDs individually and making sure they all latch at the same time.

Dealing With Supply Noise

Having a chain with multiple nodes constantly switching 1[A] loads is no small feat! Even an otherwise negligible wire resistance would result in noticeable voltage glitches. Not to mention wire inductance, which likes sudden current changes even less, and reacts with furious voltage surges unless dealt with. To make things worse, being a chain-oriented product, we’re expecting people to use rather long (several meters) wires, which inevitably have more resistance and inductance. And worse still, the on-chip temperature indicator that we really really wanted to use is extremely sensitive to the slightest of noise on the supply. Did we get your attention?
We took several measure to mitigate those issues. First, we made sure the holes for the supply wires are large enough to fit a 16AWG wire. Thicker wires = less resistive = good. The PCB traces connecting the input and output supply are super wide for the same reason.
Then, bulk capacitance! A large 22uF ceramic (hence, low ESR) capacitor across the supply on every node is used to absorb voltage transients, especially those caused by wire inductance. Then, that supply gets further filtered using an R/C circuit comprising R7, R9 and C1, the latter being yet another 22uF ceramic and the relatively high resistor values ensure that the C1 reacts very slowly to any change in the supply voltage. One thing to notice is that we’ve used to resistors and we let the capacitor “float” in the middle. Why? Assuming fairly equal wires for 5V and GND, this setup would result in the supply rails for all microcontrollers in the chain to always have the same Vcc/2 potential, even if their Vcc voltage is different as result of wire resistance x high current. This makes it easier to discern the 0’s from the 1’s between consecutive nodes and thus get a reliable communication channel despite the supply noise. Otherwise, since the detection threshold is relative to the supply rails, we would have smaller error margins.
That simple circuit took a lot of tweaking to get right, but the result is very satisfactory noise-immunity characteristics.

Power Dissipation and Over-Temperature Protection

Despite LEDs being relatively efficient light sources, they still convert the vast majority of their consumed power into heat. Furthermore, our linear constant current circuit uses resistance (across the FET) to limit the current, resulting in the extra power being converted to heat. In total, at full steam (driving all 3 LEDs at 100% duty cycle) our little circuit dissipates around 5W! Keeping it from over-heating in this condition is unfeasible. We’ve allocated largish thermal places on the PCB to improve cooling efficiency, but really, the intention is to not leave the LED full-on for more than a couple of seconds. Rather, working continuously at lower brightness is perfectly fine as well as generating fast, bright pulses periodically.
But we wanted to make sure that the LEDs would not get dangerously hot even by accident. For that reason, the Pixie firmware uses the PIC’s on-chip temperature indicator to estimate the board’s temperature and would shut-down the LED when it gets too hot (above about 70 degrees celsius). It will automatically resume operation when it cools down. Getting this temperature indicator to work with reasonable precision was a challenge. First, the PIC’s supply voltage needed to be extra-clean (as described above) and second, to account for variability between different instances of the PIC, each and every unit goes through an automated calibration process during manufacturing and the temperature calibration data gets written to the PIC’s flash memory.

Loss of Communication

Have you ever noticed how NeoPixels retain their color if their controller goes away? While this can be considered a convenient feature in some cases, it is an absolute no-go in a 3W LED case. Losing communications with the controller for any reason during a high-brightness pulse, that was otherwise intended to be very short, could potentially result in LEDs being left on for extended periods, consuming a lot of power and dissipating a lot of heat (limited by the over-temperature feature described above). Even more, what if we have a firmware bug (not that we ever have bugs, but just for the sake of the discussion ;D) causing the PIC to hang while its LED is on? That would be unacceptable.
Watchdog to the rescue! Remember we told you how awesome the PIC12 is? Another feature that is useful for us is the watchdog. It will reset the PIC if it doesn’t hear from our firmware that everything is fine for about 2 seconds. In turn, our firmware will only pet the watchdog every time it gets a valid color and successfully latches it. So unless we hear from our controller at least every 2 seconds (and in practice, better leave a little margin), the Pixie resets, causing the LED to turn off until told otherwise.
So unlike NeoPixels, if you want your Pixies to stay on for extended periods, even with no color change, you need to constantly remind them that you’re alive by sending them their favorite string.

Conclusion

Who would have guessed that designing a circuit having only about 20 simple parts could get so complicated? Certainly not us! We have done our best to provide a high quality, useful product and learned a lot along the way. We’re hoping you’ll like the result and enjoyed reading about some of the reasoning behind it.

I have some cool ideas for projects now that this is done. Stay tuned :)

15 comments:

  1. Compare this with my amateurish rambles around Arduino timers... :)
    Great work !

    ReplyDelete
  2. Ytsi;

    Do you have any additional Arduino code examples that you might be willing to post?
    The Adafruit "Strandtest" example works, but I'm a novice at moving bytes with the Arduino, so a few more commented code examples may help a lot of beginners like myself.

    Thanks!

    ReplyDelete
    Replies
    1. The interface of Adafruit's Arduino Pixie library is almost identical to their NeoPixel library, so any example you find for NeoPixel (I bet you can easily find thousands) should be trivial to port to Pixie (i.e. just change the library you're importing and the couple of lines that initialize the object).

      Delete
  3. What about a version that has a heat sink mountable surface for continuous operation?

    These would be great for ambient or event lighting.

    ReplyDelete
    Replies
    1. I'm not planning one. However, a user reported that he's been able to turn the Pixies on at 100% duty cycle by coupling a metal heat sink using thermal epoxy to the back of the board (I imaging he completely buried the back with the epoxy). Another option, since the design is fully open source, is to customize it yourself.

      Delete
    2. As a professional designer of programmable LED lights, I cringe at the thought of trying to dissipate that much heat through a (relatively thick) blob of thermal epoxy, or honestly ANY non-conductive thermal interface that's at least the thickness of the backside components.
      The thermal resistance of even the best of these materials is terrible compared to metals (even "poor" heat conductors such as steel), and the total resistance to heat flow is multiplied by its thickness. For this kind of application, i.e. passing bulk heat from one layer to another, the key is to make the adhesive as thin as possible.
      Spreading heat from a surface mount component using large copper pours is a good trick. However, when it must be transferred to the opposite side of the PCB, its effectiveness is much reduced and requires as many vias as possible to be of much help at all.
      Coupling that limited thermal path to a thick layer of thermal epoxy only compounds an already dicey situation. The overtemperature limit feature in this design is critical to protecting the LEDs in particular since it's only estimating the actual die temperature of the LEDs.
      For short term use, and brief full-power pulses, as long as the maximum junction temperature of the LED is not exceeded it will probably work fine at room temperature, and the user will not notice any problems.
      However, to take the same design, push it to its limits using a combination of marginal heat sink interfaces, and install it in an environment where it would be used long term (and where the ambient temperature could be somewhat higher than 25C) would cause it to shut down often if the overtemperature feature is doing its job correctly. If it's just barely avoiding shutdown, the lifetime of the LEDs and other semiconductors on board will just be reduced.
      Generally the safe approach would be to have at minimum a redesigned board with no backside components, copious thermal vias surrounding the LED and large copper areas on back, coupled to a very thin insulating thermal pad bonded to a heat sink larger than this board. Or alternatively, a frontside heatsink with a hole in the center for the LED to shine through.

      Delete
    3. You seem to know about thermals more than I do. If you want to use the existing schematic and code and design an alternative layout which has better thermal properties, I would be happy to help you promote it!

      Delete
    4. Thanks, I had to learn a lot about thermal management in order to make reliable designs for commercial use!
      You've honestly done a much better job of engineering the various power and heat management issues than the vast majority of LED projects I see online these days. I think the Pixie is a fine design for projects where the user clearly understands the limitations on longer-term power dissipation - and if they don't, at least it won't be destroyed.
      In a way, it's unfortunate that LEDs are as robust as they are - so, so many experimenters have convinced themselves that because their heatsink "feels hot" (or "feels cool"!) when they touch it and the LED appears to be working just fine after some hours that it *must* be operating at a safe, sustainable temperature when quite often that is not the case at all...unless you don't mind if it dims prematurely or only lasts for a few hundred hours before mysteriously dying.
      Someday I plan to write up a nice tutorial for Makers on proper heat and power management for high power LEDs.

      Delete
  4. Can the Pixie's D1 and D0 be connected to 5050s with a WS2812B and controlled with a single data signal?

    ReplyDelete
  5. As you can see in the post, the decision was to use a standard serial interface as opposed to the proprietary WS28' protocol. However, if you care enough and willing to put in the work, with custom firmware you can implement the WS28' interface at 400kHz without needing to make any hardware changes.

    ReplyDelete
  6. This project is absolutely awesome! I was trying to adapt your design to my storage of components. It is possible to swap the n-FET in your project with an IRFZ44N? I know probably is overdesign but I have plenty of them.
    Another question, could you share the Arduino-PIC programming library? I would try to modify the original firmware. Thanks!

    ReplyDelete
    Replies
    1. Sorry for the late response. The FET you're mentioning is probably not a great choice, since it is not rated for gate voltages lower than 4.5V. In practice, it may work, but it might be inconsistent between different transistors of the same model.
      The Arduino library is here: https://bitbucket.org/ytaibt/ic1257x_prog, but I would recommend getting a PICKit3, which would allow you to much more easily go through code-compile-program cycles as well as live debugging.

      Delete