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