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.cpp Source File

neopixel.cpp

00001 #include <stdint.h>
00002 #include "mbed.h"
00003 #include "neopixel.h"
00004 
00005 namespace neopixel
00006 {
00007 
00008 PixelArray::PixelArray(PinName out, ByteOrder byte_order, Protocol protocol)
00009     : spi_(out, NC, NC), byte_order_(byte_order), protocol_(protocol)
00010 {
00011     if (protocol_ == PROTOCOL_800KHZ) {
00012         // 800kHz bit encodings:
00013         //  '0': ----________
00014         //  '1': --------____
00015         // The period is 1.25us, giving a basic frequency of 800kHz.
00016         // Getting the mark-space ratio right is trickier, though. There are a number
00017         // of different timings, and the correct (documented) values depend on the
00018         // controller chip.
00019         //
00020         // The _real_ timing restrictions are much simpler though, and someone has
00021         // published a lovely analysis here:
00022         //   http://cpldcpu.wordpress.com/2014/01/14/light_ws2812-library-v2-0-part-i-understanding-the-ws2812/
00023         //
00024         // In summary:
00025         // - The period should be at least 1.25us.
00026         // - The '0' high time can be anywhere from 0.0625us to 0.5us.
00027         // - The '1' high time should be longer than 0.625us.
00028         //
00029         // These constraints are easy to meet by splitting each bit into three and packing them into SPI packets.
00030         //  '0': 100             mark: 0.42us, space: 0.83us
00031         //  '1': 110             mark: 0.83us, space: 0.42us
00032         spi_.frequency(2400000);  // 800kHz * 3
00033         spi_.format(12);          // Send four NeoPixel bits in each packet.
00034     } else {
00035         // 400kHz bit encodings:
00036         //  '0': --________
00037         //  '1': -----_____
00038         //
00039         // Timing requirements are derived from this document:
00040         //   http://www.adafruit.com/datasheets/WS2811.pdf
00041         //
00042         // The period is 2.5us, and we use a 10-bit packet for this encoding:
00043         //  '0': 1100000000      mark: 0.5us, space: 2us
00044         //  '1': 1111100000      mark: 1.25us, space: 1.25us    
00045         spi_.frequency(4000000);  // 400kHz * 10
00046         spi_.format(10);          // Send one NeoPixel bit in each packet.
00047     }
00048 }
00049 
00050 static void SendFourBits(BurstSPI& spi, uint32_t bits)
00051 {
00052     // Encode '0' bits as 100 and '1' bits as 110.
00053     // We have this bit pattern: 00000000abcd
00054     // We want this bit pattern: 1a01b01c01d0
00055     uint32_t ac = (bits * 0x088) &        // 0abcdabcd000
00056                   0x410; // 0a00000c0000
00057 
00058     uint32_t bd = (bits * 0x022) &        // 000abcdabcd0
00059                   0x082; // 0000b00000d0
00060 
00061     static uint32_t const base = 04444;   // 100100100100
00062 
00063     spi.fastWrite(base | ac | bd);        // 1a01b01c01d0
00064 }
00065 
00066 static void SendEightBits(BurstSPI& spi, uint8_t bits)
00067 {
00068     int zero = 0x300;  // Encode zero as 0b1100000000
00069     int one = 0x3e0;   // Encode one as 0b1111100000
00070     for (int i = 128; i >= 1; i >>= 1) {
00071         spi.fastWrite((bits & i) ? one : zero);
00072     }
00073 }
00074 
00075 void PixelArray::send_pixel(Pixel& pixel)
00076 {
00077     // Pixels are sent as follows:
00078     // - The first transmitted pixel is the pixel closest to the transmitter.
00079     // - The most significant bit is always sent first.
00080     //
00081     // g7,g6,g5,g4,g3,g2,g1,g0,r7,r6,r5,r4,r3,r2,r1,r0,b7,b6,b5,b4,b3,b2,b1,b0
00082     // \_____________________________________________________________________/
00083     //                           |      _________________...
00084     //                           |     /   __________________...
00085     //                           |    /   /   ___________________...
00086     //                           |   /   /   /
00087     //                          GRB,GRB,GRB,GRB,...
00088     //
00089     // For BYTE_ORDER_RGB, the order of the first two bytes are reversed.
00090 
00091     uint8_t byte0 = (byte_order_ == BYTE_ORDER_RGB) ? pixel.red : pixel.green;
00092     uint8_t byte1 = (byte_order_ == BYTE_ORDER_RGB) ? pixel.green : pixel.red;
00093 
00094     if (protocol_ == PROTOCOL_800KHZ) {
00095         SendFourBits(spi_, (byte0 >> 4) & 0xf);
00096         SendFourBits(spi_, (byte0 >> 0) & 0xf);
00097         SendFourBits(spi_, (byte1 >> 4) & 0xf);
00098         SendFourBits(spi_, (byte1 >> 0) & 0xf);
00099         SendFourBits(spi_, (pixel.blue >> 4) & 0xf);
00100         SendFourBits(spi_, (pixel.blue >> 0) & 0xf);
00101     } else {
00102         SendEightBits(spi_, byte0);
00103         SendEightBits(spi_, byte1);
00104         SendEightBits(spi_, pixel.blue);
00105     }
00106 }
00107 
00108 void PixelArray::update(Pixel buffer[], uint32_t length)
00109 {
00110     for (size_t i = 0; i < length; i++) {
00111         send_pixel(buffer[i]);
00112     }
00113 
00114     wait_us(latch_time_us_);
00115 }
00116 
00117 void PixelArray::update(PixelGenerator generator, uint32_t length, uintptr_t extra)
00118 {
00119     for (size_t i = 0; i < length; i++) {
00120         Pixel out;
00121         generator(&out, i, extra);
00122         send_pixel(out);
00123     }
00124 
00125     wait_us(latch_time_us_);
00126 }
00127 
00128 }