ws2812b sample firmware.
Dependencies: BurstSPI
Dependents: mbed_ws2812b mbed_ws2812b
Fork of PixelArray by
Diff: neopixel.cpp
- Revision:
- 3:6f392fcb1d3b
- Parent:
- 2:3c3c41774cdf
- Child:
- 4:c3b314df3dfe
--- a/neopixel.cpp Fri Aug 01 22:17:23 2014 +0000 +++ b/neopixel.cpp Mon Aug 18 21:38:40 2014 +0000 @@ -5,32 +5,46 @@ namespace neopixel { -PixelArray::PixelArray(PinName out, ByteOrder byte_order) - : spi_(out, NC, NC), byte_order_(byte_order) +PixelArray::PixelArray(PinName out, ByteOrder byte_order, Protocol protocol) + : spi_(out, NC, NC), byte_order_(byte_order), protocol_(protocol) { - // WS281x bit encodings: - // '0': ----________ - // '1': --------____ - // The period is 1.25us, giving a basic frequency of 800kHz. - // Getting the mark-space ratio right is trickier, though. There are a number - // of different timings, and the correct (documented) values depend on the - // controller chip. - // - // The _real_ timing restrictions are much simpler though, and someone has - // published a lovely analysis here: - // http://cpldcpu.wordpress.com/2014/01/14/light_ws2812-library-v2-0-part-i-understanding-the-ws2812/ - // - // In summary: - // - The period should be at least 1.25us. - // - The '0' high time can be anywhere from 0.0625us to 0.5us. - // - The '1' high time should be longer than 0.625us. - // - // These constraints are easy to meet by splitting each bit into three and packing them into SPI packets. - // '0': 100 mark: 0.42us, space: 0.83us - // '1': 110 mark: 0.83us, space: 0.42us - - spi_.frequency(2400000); // 800kHz * 3 - spi_.format(12); // Send four NeoPixel bits in each packet. + if (protocol_ == PROTOCOL_800KHZ) { + // 800kHz bit encodings: + // '0': ----________ + // '1': --------____ + // The period is 1.25us, giving a basic frequency of 800kHz. + // Getting the mark-space ratio right is trickier, though. There are a number + // of different timings, and the correct (documented) values depend on the + // controller chip. + // + // The _real_ timing restrictions are much simpler though, and someone has + // published a lovely analysis here: + // http://cpldcpu.wordpress.com/2014/01/14/light_ws2812-library-v2-0-part-i-understanding-the-ws2812/ + // + // In summary: + // - The period should be at least 1.25us. + // - The '0' high time can be anywhere from 0.0625us to 0.5us. + // - The '1' high time should be longer than 0.625us. + // + // These constraints are easy to meet by splitting each bit into three and packing them into SPI packets. + // '0': 100 mark: 0.42us, space: 0.83us + // '1': 110 mark: 0.83us, space: 0.42us + spi_.frequency(2400000); // 800kHz * 3 + spi_.format(12); // Send four NeoPixel bits in each packet. + } else { + // 400kHz bit encodings: + // '0': --________ + // '1': -----_____ + // + // Timing requirements are derived from this document: + // http://www.adafruit.com/datasheets/WS2811.pdf + // + // The period is 2.5us, and we use a 10-bit packet for this encoding: + // '0': 1100000000 mark: 0.5us, space: 2us + // '1': 1111100000 mark: 1.25us, space: 1.25us + spi_.frequency(4000000); // 400kHz * 10 + spi_.format(10); // Send one NeoPixel bit in each packet. + } } static void SendFourBits(BurstSPI& spi, uint32_t bits) @@ -49,6 +63,15 @@ spi.fastWrite(base | ac | bd); // 1a01b01c01d0 } +static void SendEightBits(BurstSPI& spi, uint8_t bits) +{ + int zero = 0x300; // Encode zero as 0b1100000000 + int one = 0x3e0; // Encode one as 0b1111100000 + for (int i = 1; i < 256; i *= 2) { + spi.fastWrite((bits & i) ? one : zero); + } +} + void PixelArray::send_pixel(Pixel& pixel) { // Pixels are sent as follows: @@ -62,21 +85,23 @@ // | / / ___________________... // | / / / // GRB,GRB,GRB,GRB,... + // + // For BYTE_ORDER_RGB, the order of the first two bytes are reversed. - if (byte_order_ == BYTE_ORDER_RGB) { - SendFourBits(spi_, (pixel.red >> 4) & 0xf); - SendFourBits(spi_, (pixel.red >> 0) & 0xf); - SendFourBits(spi_, (pixel.green >> 4) & 0xf); - SendFourBits(spi_, (pixel.green >> 0) & 0xf); + uint8_t byte0 = (byte_order_ == BYTE_ORDER_RGB) ? pixel.red : pixel.green; + uint8_t byte1 = (byte_order_ == BYTE_ORDER_RGB) ? pixel.green : pixel.red; + + if (protocol_ == PROTOCOL_800KHZ) { + SendFourBits(spi_, (byte0 >> 4) & 0xf); + SendFourBits(spi_, (byte0 >> 0) & 0xf); + SendFourBits(spi_, (byte1 >> 4) & 0xf); + SendFourBits(spi_, (byte1 >> 0) & 0xf); SendFourBits(spi_, (pixel.blue >> 4) & 0xf); SendFourBits(spi_, (pixel.blue >> 0) & 0xf); } else { - SendFourBits(spi_, (pixel.green >> 4) & 0xf); - SendFourBits(spi_, (pixel.green >> 0) & 0xf); - SendFourBits(spi_, (pixel.red >> 4) & 0xf); - SendFourBits(spi_, (pixel.red >> 0) & 0xf); - SendFourBits(spi_, (pixel.blue >> 4) & 0xf); - SendFourBits(spi_, (pixel.blue >> 0) & 0xf); + SendEightBits(spi_, byte0); + SendEightBits(spi_, byte1); + SendEightBits(spi_, pixel.blue); } }