Main Error

Dependencies:   BurstSPI

Fork of PixelArray by Jacob Bramley

Committer:
JacobBramley
Date:
Fri Aug 01 22:17:23 2014 +0000
Revision:
2:3c3c41774cdf
Child:
3:6f392fcb1d3b
v1.0

Who changed what in which revision?

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