ws2812b sample firmware.
Dependencies: BurstSPI
Dependents: mbed_ws2812b mbed_ws2812b
Fork of PixelArray by
Diff: neopixel.cpp
- Revision:
- 2:3c3c41774cdf
- Child:
- 3:6f392fcb1d3b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/neopixel.cpp Fri Aug 01 22:17:23 2014 +0000 @@ -0,0 +1,103 @@ +#include <stdint.h> +#include "mbed.h" +#include "neopixel.h" + +namespace neopixel +{ + +PixelArray::PixelArray(PinName out, ByteOrder byte_order) + : spi_(out, NC, NC), byte_order_(byte_order) +{ + // 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. +} + +static void SendFourBits(BurstSPI& spi, uint32_t bits) +{ + // Encode '0' bits as 100 and '1' bits as 110. + // We have this bit pattern: 00000000abcd + // We want this bit pattern: 1a01b01c01d0 + uint32_t ac = (bits * 0x088) & // 0abcdabcd000 + 0x410; // 0a00000c0000 + + uint32_t bd = (bits * 0x022) & // 000abcdabcd0 + 0x082; // 0000b00000d0 + + static uint32_t const base = 04444; // 100100100100 + + spi.fastWrite(base | ac | bd); // 1a01b01c01d0 +} + +void PixelArray::send_pixel(Pixel& pixel) +{ + // Pixels are sent as follows: + // - The first transmitted pixel is the pixel closest to the transmitter. + // - The most significant bit is always sent first. + // + // g7,g6,g5,g4,g3,g2,g1,g0,r7,r6,r5,r4,r3,r2,r1,r0,b7,b6,b5,b4,b3,b2,b1,b0 + // \_____________________________________________________________________/ + // | _________________... + // | / __________________... + // | / / ___________________... + // | / / / + // GRB,GRB,GRB,GRB,... + + 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); + 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); + } +} + +void PixelArray::update(Pixel buffer[], uint32_t length) +{ + for (size_t i = 0; i < length; i++) { + send_pixel(buffer[i]); + } + + wait_us(latch_time_us_); +} + +void PixelArray::update(PixelGenerator generator, uint32_t length, uintptr_t extra) +{ + for (size_t i = 0; i < length; i++) { + Pixel out; + generator(&out, i, extra); + send_pixel(out); + } + + wait_us(latch_time_us_); +} + +} \ No newline at end of file