Control an array or chain of NeoPixel-compatible RGB LEDs. "NeoPixel" is Adafruit's name for WS2812- and WS2811-based addressable RGB LEDs. This library should work with any WS2811- or WS2812-based devices. Both the 400kHz and 800kHz protocols are supported. Most example code uses bit-banging to generate the timed signal precisely. This library uses an SPI peripheral instead. The main advantage of this is that the chip can service interrupts and the like without disrupting the signal (as long as the interrupts don't take _too_ long). The main disadvantage is that it requires the use of an SPI peripheral.

Dependencies:   BurstSPI

Dependents:   mbed_ws2812b easyNeo WS2811_Solidarite blip_rainbow ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers neopixel.h Source File

neopixel.h

00001 #ifndef NEOPIXEL_H
00002 #define NEOPIXEL_H
00003 
00004 #include <stdint.h>
00005 #include "mbed.h"
00006 #include "BurstSPI.h"
00007 
00008 namespace neopixel
00009 {
00010 
00011 /** Represent the value of a single pixel.
00012  *
00013  * Each channel uses the full 8 bits: 0x00 is fully off and 0xff is fully on.
00014  */
00015 struct Pixel {
00016     uint8_t red;
00017     uint8_t green;
00018     uint8_t blue;
00019 };
00020 
00021 /** Control the byte order used by the connected pixels.
00022  *
00023  * The vast majority of NeoPixels use a GRB byte order, so this is the default.
00024  * A few use a RGB byte order.
00025  *
00026  * In principle, the WS281x controllers could be connected with _any_ byte
00027  * ordering, but only GRB and RGB are supported at the moment.
00028  */
00029 enum ByteOrder {
00030     BYTE_ORDER_GRB,
00031     BYTE_ORDER_RGB,
00032 };
00033 
00034 /** Set the protocol mode.
00035  *
00036  * The protocol is named after the clock, as though WS8211 supports only the
00037  * 400kHz clock, WS8212 supports both.
00038  */
00039 enum Protocol {
00040     PROTOCOL_800KHZ,
00041     PROTOCOL_400KHZ,
00042 };
00043 
00044 typedef void (*PixelGenerator)(Pixel* out, uint32_t index, uintptr_t extra);
00045 
00046 /** Control an array or chain of NeoPixel-compatible RGB LEDs.
00047  *
00048  * "NeoPixel" is Adafruit's name for WS2812- and WS2811-based addressable RGB
00049  * LEDs. This library should work with any WS2811- or WS2812-based devices, as
00050  * long as they support the fast-mode (800kHz) interface.
00051  *
00052  * Most example code uses bit-banging to generate the timed signal precisely.
00053  * This library uses an SPI peripheral instead. The main advantage of this is
00054  * that the chip can service interrupts and the like without disrupting the
00055  * signal (as long as the interrupts don't take _too_ long). The main
00056  * disadvantage is that it requires the use of an SPI peripheral.
00057  *
00058  * @note SPI peripherals will tend to leave the output pin ('MOSI') floating
00059  * after a packet is sent. This will confuse the connected pixels, which expect
00060  * the line to be driven low when idle. One way to fix this is to add a 10k
00061  * resistor between 'MOSI' and ground so that it drops to '0' when not driven.
00062  * Another method is to enable the on-chip pull-down resistor on the output pin.
00063  * However, the mbed API only exposes this function through the DigitalIn and
00064  * DigitalInOut classes. If you want to use the on-chip pull-down, you'll have
00065  * to temporarily connect a DigitalIn peripheral _before_ creating instantiating
00066  * the PixelArray.
00067  *
00068  * @code
00069  * // Sample generator: Cycle through each colour combination, increasing the
00070  * // brightness each time. `extra` is used as an iteration counter.
00071  * void generate(neopixel::Pixel * out, uint32_t index, uintptr_t extra) {
00072  *   uint32_t brightness = (index + extra) >> 3;
00073  *   out->red   = ((index + extra) & 0x1) ? brightness : 0;
00074  *   out->green = ((index + extra) & 0x2) ? brightness : 0;
00075  *   out->blue  = ((index + extra) & 0x4) ? brightness : 0;
00076  * }
00077  *
00078  * int main() {
00079  *   // Create a temporary DigitalIn so we can configure the pull-down resistor.
00080  *   // (The mbed API doesn't provide any other way to do this.)
00081  *   // An alternative is to connect an external pull-down resistor.
00082  *   DigitalIn(p5, PullDown);
00083  *
00084  *   // The pixel array control class.
00085  *   neopixel::PixelArray array(p5);
00086  *
00087  *   uint32_t offset = 0;
00088  *   while (1) {
00089  *     array.update(generate, 100, offset++);
00090  *     wait_ms(250);
00091  *   }
00092  * }
00093  * @endcode
00094  */
00095 class PixelArray
00096 {
00097 public:
00098     /** Initialize a PixelArray.
00099      *
00100      * @param out Output (SPI MOSI) pin.
00101      * @param byte_order The order in which to transmit colour channels.
00102      */
00103     PixelArray(PinName out,
00104                ByteOrder byte_order = BYTE_ORDER_GRB,
00105                Protocol protocol = PROTOCOL_800KHZ);
00106 
00107     /** Update the pixel display from a buffer.
00108      *
00109      * This update method is good in the following situations:
00110      * - You want to make incremental changes to a fixed frame pattern.
00111      * - The frame is hard (or impossible) to generate procedurally.
00112      * - The frame requires a lot of time to generate.
00113      *
00114      * @param buffer Pixel data to be written.
00115      * @param length The number of pixels to write.
00116      *
00117      * buffer[0] is written to the pixel nearest the mbed.
00118      * buffer[length-1] is written to the pixel furthest from the mbed.
00119      */
00120     void update(Pixel buffer[], uint32_t length);
00121 
00122     /** Update a pixel chain using the callback to generate the value for each
00123      * pixel.
00124      *
00125      * This update method is good in the following situations:
00126      * - You have a lot of pixels to drive and don't have enough RAM to buffer
00127      *   them all.
00128      * - You want to display a frame pattern that can be generated procedurally
00129      *   generated without intensive processing.
00130      *
00131      * @param generator A callback which is called to generate a value for each
00132      * pixel on demand. This function must be fairly fast: if it takes more
00133      * than about 8-9us, the interface will reset and the display will be
00134      * corrupted. The exact time limits will vary between WS281x variants. As a
00135      * rough guide, an LPC1768 at 96MHz can (conservatively) execute about 750
00136      * instructions in that time.
00137      *
00138      * @param length The number of pixels to write.
00139      *
00140      * @param extra An arbitrary value to pass into the generator function. For
00141      * example, this is a good way to pass an animation time index to the
00142      * generator function.
00143      */
00144     void update(PixelGenerator generator, uint32_t length, uintptr_t extra);
00145 
00146 private:
00147     BurstSPI spi_;
00148     ByteOrder byte_order_;
00149     Protocol protocol_;
00150     
00151     static int const latch_time_us_ = 50;
00152     
00153     void send_pixel(Pixel& pixel);
00154 };
00155 
00156 }
00157 
00158 #endif