ws2812b sample firmware.
Dependencies: BurstSPI
Dependents: mbed_ws2812b mbed_ws2812b
Fork of PixelArray by
neopixel.h@6:f9190f4a19cc, 2016-11-01 (annotated)
- Committer:
- AamirNiaz
- Date:
- Tue Nov 01 04:34:00 2016 +0000
- Revision:
- 6:f9190f4a19cc
- Parent:
- 3:6f392fcb1d3b
ws2812b Sample code
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
JacobBramley | 2:3c3c41774cdf | 1 | #ifndef NEOPIXEL_H |
JacobBramley | 2:3c3c41774cdf | 2 | #define NEOPIXEL_H |
JacobBramley | 2:3c3c41774cdf | 3 | |
JacobBramley | 2:3c3c41774cdf | 4 | #include <stdint.h> |
JacobBramley | 2:3c3c41774cdf | 5 | #include "mbed.h" |
JacobBramley | 2:3c3c41774cdf | 6 | #include "BurstSPI.h" |
JacobBramley | 2:3c3c41774cdf | 7 | |
JacobBramley | 2:3c3c41774cdf | 8 | namespace neopixel |
JacobBramley | 2:3c3c41774cdf | 9 | { |
JacobBramley | 2:3c3c41774cdf | 10 | |
JacobBramley | 2:3c3c41774cdf | 11 | /** Represent the value of a single pixel. |
JacobBramley | 2:3c3c41774cdf | 12 | * |
JacobBramley | 2:3c3c41774cdf | 13 | * Each channel uses the full 8 bits: 0x00 is fully off and 0xff is fully on. |
JacobBramley | 2:3c3c41774cdf | 14 | */ |
JacobBramley | 2:3c3c41774cdf | 15 | struct Pixel { |
JacobBramley | 2:3c3c41774cdf | 16 | uint8_t red; |
JacobBramley | 2:3c3c41774cdf | 17 | uint8_t green; |
JacobBramley | 2:3c3c41774cdf | 18 | uint8_t blue; |
JacobBramley | 2:3c3c41774cdf | 19 | }; |
JacobBramley | 2:3c3c41774cdf | 20 | |
JacobBramley | 2:3c3c41774cdf | 21 | /** Control the byte order used by the connected pixels. |
JacobBramley | 2:3c3c41774cdf | 22 | * |
JacobBramley | 2:3c3c41774cdf | 23 | * The vast majority of NeoPixels use a GRB byte order, so this is the default. |
JacobBramley | 2:3c3c41774cdf | 24 | * A few use a RGB byte order. |
JacobBramley | 2:3c3c41774cdf | 25 | * |
JacobBramley | 2:3c3c41774cdf | 26 | * In principle, the WS281x controllers could be connected with _any_ byte |
JacobBramley | 2:3c3c41774cdf | 27 | * ordering, but only GRB and RGB are supported at the moment. |
JacobBramley | 2:3c3c41774cdf | 28 | */ |
JacobBramley | 2:3c3c41774cdf | 29 | enum ByteOrder { |
JacobBramley | 2:3c3c41774cdf | 30 | BYTE_ORDER_GRB, |
JacobBramley | 2:3c3c41774cdf | 31 | BYTE_ORDER_RGB, |
JacobBramley | 2:3c3c41774cdf | 32 | }; |
JacobBramley | 2:3c3c41774cdf | 33 | |
mcapewel | 3:6f392fcb1d3b | 34 | /** Set the protocol mode. |
mcapewel | 3:6f392fcb1d3b | 35 | * |
mcapewel | 3:6f392fcb1d3b | 36 | * The protocol is named after the clock, as though WS8211 supports only the |
mcapewel | 3:6f392fcb1d3b | 37 | * 400kHz clock, WS8212 supports both. |
mcapewel | 3:6f392fcb1d3b | 38 | */ |
mcapewel | 3:6f392fcb1d3b | 39 | enum Protocol { |
mcapewel | 3:6f392fcb1d3b | 40 | PROTOCOL_800KHZ, |
mcapewel | 3:6f392fcb1d3b | 41 | PROTOCOL_400KHZ, |
mcapewel | 3:6f392fcb1d3b | 42 | }; |
mcapewel | 3:6f392fcb1d3b | 43 | |
JacobBramley | 2:3c3c41774cdf | 44 | typedef void (*PixelGenerator)(Pixel* out, uint32_t index, uintptr_t extra); |
JacobBramley | 2:3c3c41774cdf | 45 | |
JacobBramley | 2:3c3c41774cdf | 46 | /** Control an array or chain of NeoPixel-compatible RGB LEDs. |
JacobBramley | 2:3c3c41774cdf | 47 | * |
JacobBramley | 2:3c3c41774cdf | 48 | * "NeoPixel" is Adafruit's name for WS2812- and WS2811-based addressable RGB |
JacobBramley | 2:3c3c41774cdf | 49 | * LEDs. This library should work with any WS2811- or WS2812-based devices, as |
JacobBramley | 2:3c3c41774cdf | 50 | * long as they support the fast-mode (800kHz) interface. |
JacobBramley | 2:3c3c41774cdf | 51 | * |
JacobBramley | 2:3c3c41774cdf | 52 | * Most example code uses bit-banging to generate the timed signal precisely. |
JacobBramley | 2:3c3c41774cdf | 53 | * This library uses an SPI peripheral instead. The main advantage of this is |
JacobBramley | 2:3c3c41774cdf | 54 | * that the chip can service interrupts and the like without disrupting the |
JacobBramley | 2:3c3c41774cdf | 55 | * signal (as long as the interrupts don't take _too_ long). The main |
JacobBramley | 2:3c3c41774cdf | 56 | * disadvantage is that it requires the use of an SPI peripheral. |
JacobBramley | 2:3c3c41774cdf | 57 | * |
JacobBramley | 2:3c3c41774cdf | 58 | * @note SPI peripherals will tend to leave the output pin ('MOSI') floating |
JacobBramley | 2:3c3c41774cdf | 59 | * after a packet is sent. This will confuse the connected pixels, which expect |
JacobBramley | 2:3c3c41774cdf | 60 | * the line to be driven low when idle. One way to fix this is to add a 10k |
JacobBramley | 2:3c3c41774cdf | 61 | * resistor between 'MOSI' and ground so that it drops to '0' when not driven. |
JacobBramley | 2:3c3c41774cdf | 62 | * Another method is to enable the on-chip pull-down resistor on the output pin. |
JacobBramley | 2:3c3c41774cdf | 63 | * However, the mbed API only exposes this function through the DigitalIn and |
JacobBramley | 2:3c3c41774cdf | 64 | * DigitalInOut classes. If you want to use the on-chip pull-down, you'll have |
JacobBramley | 2:3c3c41774cdf | 65 | * to temporarily connect a DigitalIn peripheral _before_ creating instantiating |
JacobBramley | 2:3c3c41774cdf | 66 | * the PixelArray. |
JacobBramley | 2:3c3c41774cdf | 67 | * |
JacobBramley | 2:3c3c41774cdf | 68 | * @code |
JacobBramley | 2:3c3c41774cdf | 69 | * // Sample generator: Cycle through each colour combination, increasing the |
JacobBramley | 2:3c3c41774cdf | 70 | * // brightness each time. `extra` is used as an iteration counter. |
JacobBramley | 2:3c3c41774cdf | 71 | * void generate(neopixel::Pixel * out, uint32_t index, uintptr_t extra) { |
JacobBramley | 2:3c3c41774cdf | 72 | * uint32_t brightness = (index + extra) >> 3; |
JacobBramley | 2:3c3c41774cdf | 73 | * out->red = ((index + extra) & 0x1) ? brightness : 0; |
JacobBramley | 2:3c3c41774cdf | 74 | * out->green = ((index + extra) & 0x2) ? brightness : 0; |
JacobBramley | 2:3c3c41774cdf | 75 | * out->blue = ((index + extra) & 0x4) ? brightness : 0; |
JacobBramley | 2:3c3c41774cdf | 76 | * } |
JacobBramley | 2:3c3c41774cdf | 77 | * |
JacobBramley | 2:3c3c41774cdf | 78 | * int main() { |
JacobBramley | 2:3c3c41774cdf | 79 | * // Create a temporary DigitalIn so we can configure the pull-down resistor. |
JacobBramley | 2:3c3c41774cdf | 80 | * // (The mbed API doesn't provide any other way to do this.) |
JacobBramley | 2:3c3c41774cdf | 81 | * // An alternative is to connect an external pull-down resistor. |
JacobBramley | 2:3c3c41774cdf | 82 | * DigitalIn(p5, PullDown); |
JacobBramley | 2:3c3c41774cdf | 83 | * |
JacobBramley | 2:3c3c41774cdf | 84 | * // The pixel array control class. |
JacobBramley | 2:3c3c41774cdf | 85 | * neopixel::PixelArray array(p5); |
JacobBramley | 2:3c3c41774cdf | 86 | * |
JacobBramley | 2:3c3c41774cdf | 87 | * uint32_t offset = 0; |
JacobBramley | 2:3c3c41774cdf | 88 | * while (1) { |
JacobBramley | 2:3c3c41774cdf | 89 | * array.update(generate, 100, offset++); |
JacobBramley | 2:3c3c41774cdf | 90 | * wait_ms(250); |
JacobBramley | 2:3c3c41774cdf | 91 | * } |
JacobBramley | 2:3c3c41774cdf | 92 | * } |
JacobBramley | 2:3c3c41774cdf | 93 | * @endcode |
JacobBramley | 2:3c3c41774cdf | 94 | */ |
JacobBramley | 2:3c3c41774cdf | 95 | class PixelArray |
JacobBramley | 2:3c3c41774cdf | 96 | { |
JacobBramley | 2:3c3c41774cdf | 97 | public: |
JacobBramley | 2:3c3c41774cdf | 98 | /** Initialize a PixelArray. |
JacobBramley | 2:3c3c41774cdf | 99 | * |
JacobBramley | 2:3c3c41774cdf | 100 | * @param out Output (SPI MOSI) pin. |
JacobBramley | 2:3c3c41774cdf | 101 | * @param byte_order The order in which to transmit colour channels. |
JacobBramley | 2:3c3c41774cdf | 102 | */ |
JacobBramley | 2:3c3c41774cdf | 103 | PixelArray(PinName out, |
mcapewel | 3:6f392fcb1d3b | 104 | ByteOrder byte_order = BYTE_ORDER_GRB, |
mcapewel | 3:6f392fcb1d3b | 105 | Protocol protocol = PROTOCOL_800KHZ); |
JacobBramley | 2:3c3c41774cdf | 106 | |
JacobBramley | 2:3c3c41774cdf | 107 | /** Update the pixel display from a buffer. |
JacobBramley | 2:3c3c41774cdf | 108 | * |
JacobBramley | 2:3c3c41774cdf | 109 | * This update method is good in the following situations: |
JacobBramley | 2:3c3c41774cdf | 110 | * - You want to make incremental changes to a fixed frame pattern. |
JacobBramley | 2:3c3c41774cdf | 111 | * - The frame is hard (or impossible) to generate procedurally. |
JacobBramley | 2:3c3c41774cdf | 112 | * - The frame requires a lot of time to generate. |
JacobBramley | 2:3c3c41774cdf | 113 | * |
JacobBramley | 2:3c3c41774cdf | 114 | * @param buffer Pixel data to be written. |
JacobBramley | 2:3c3c41774cdf | 115 | * @param length The number of pixels to write. |
JacobBramley | 2:3c3c41774cdf | 116 | * |
JacobBramley | 2:3c3c41774cdf | 117 | * buffer[0] is written to the pixel nearest the mbed. |
JacobBramley | 2:3c3c41774cdf | 118 | * buffer[length-1] is written to the pixel furthest from the mbed. |
JacobBramley | 2:3c3c41774cdf | 119 | */ |
JacobBramley | 2:3c3c41774cdf | 120 | void update(Pixel buffer[], uint32_t length); |
JacobBramley | 2:3c3c41774cdf | 121 | |
JacobBramley | 2:3c3c41774cdf | 122 | /** Update a pixel chain using the callback to generate the value for each |
JacobBramley | 2:3c3c41774cdf | 123 | * pixel. |
JacobBramley | 2:3c3c41774cdf | 124 | * |
JacobBramley | 2:3c3c41774cdf | 125 | * This update method is good in the following situations: |
JacobBramley | 2:3c3c41774cdf | 126 | * - You have a lot of pixels to drive and don't have enough RAM to buffer |
JacobBramley | 2:3c3c41774cdf | 127 | * them all. |
JacobBramley | 2:3c3c41774cdf | 128 | * - You want to display a frame pattern that can be generated procedurally |
JacobBramley | 2:3c3c41774cdf | 129 | * generated without intensive processing. |
JacobBramley | 2:3c3c41774cdf | 130 | * |
JacobBramley | 2:3c3c41774cdf | 131 | * @param generator A callback which is called to generate a value for each |
JacobBramley | 2:3c3c41774cdf | 132 | * pixel on demand. This function must be fairly fast: if it takes more |
JacobBramley | 2:3c3c41774cdf | 133 | * than about 8-9us, the interface will reset and the display will be |
JacobBramley | 2:3c3c41774cdf | 134 | * corrupted. The exact time limits will vary between WS281x variants. As a |
JacobBramley | 2:3c3c41774cdf | 135 | * rough guide, an LPC1768 at 96MHz can (conservatively) execute about 750 |
JacobBramley | 2:3c3c41774cdf | 136 | * instructions in that time. |
JacobBramley | 2:3c3c41774cdf | 137 | * |
JacobBramley | 2:3c3c41774cdf | 138 | * @param length The number of pixels to write. |
JacobBramley | 2:3c3c41774cdf | 139 | * |
JacobBramley | 2:3c3c41774cdf | 140 | * @param extra An arbitrary value to pass into the generator function. For |
JacobBramley | 2:3c3c41774cdf | 141 | * example, this is a good way to pass an animation time index to the |
JacobBramley | 2:3c3c41774cdf | 142 | * generator function. |
JacobBramley | 2:3c3c41774cdf | 143 | */ |
JacobBramley | 2:3c3c41774cdf | 144 | void update(PixelGenerator generator, uint32_t length, uintptr_t extra); |
JacobBramley | 2:3c3c41774cdf | 145 | |
JacobBramley | 2:3c3c41774cdf | 146 | private: |
JacobBramley | 2:3c3c41774cdf | 147 | BurstSPI spi_; |
JacobBramley | 2:3c3c41774cdf | 148 | ByteOrder byte_order_; |
mcapewel | 3:6f392fcb1d3b | 149 | Protocol protocol_; |
JacobBramley | 2:3c3c41774cdf | 150 | |
JacobBramley | 2:3c3c41774cdf | 151 | static int const latch_time_us_ = 50; |
JacobBramley | 2:3c3c41774cdf | 152 | |
JacobBramley | 2:3c3c41774cdf | 153 | void send_pixel(Pixel& pixel); |
JacobBramley | 2:3c3c41774cdf | 154 | }; |
JacobBramley | 2:3c3c41774cdf | 155 | |
JacobBramley | 2:3c3c41774cdf | 156 | } |
JacobBramley | 2:3c3c41774cdf | 157 | |
JacobBramley | 2:3c3c41774cdf | 158 | #endif |