Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: BurstSPI
Dependents: Nucleo-transfer Nucleo-transfer Nucleo-transfer
Fork of PixelArray by
neopixel.h@2:3c3c41774cdf, 2014-08-01 (annotated)
- 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?
| 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 | |
| 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 | 
