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
Fork of PixelArray by
Revision 3:6f392fcb1d3b, committed 2014-08-18
- Comitter:
- mcapewel
- Date:
- Mon Aug 18 21:38:40 2014 +0000
- Parent:
- 2:3c3c41774cdf
- Child:
- 4:c3b314df3dfe
- Commit message:
- Add support for WS2811's 400kHz protocol mode.
Changed in this revision
| neopixel.cpp | Show annotated file Show diff for this revision Revisions of this file |
| neopixel.h | Show annotated file Show diff for this revision Revisions of this file |
--- a/neopixel.cpp Fri Aug 01 22:17:23 2014 +0000
+++ b/neopixel.cpp Mon Aug 18 21:38:40 2014 +0000
@@ -5,32 +5,46 @@
namespace neopixel
{
-PixelArray::PixelArray(PinName out, ByteOrder byte_order)
- : spi_(out, NC, NC), byte_order_(byte_order)
+PixelArray::PixelArray(PinName out, ByteOrder byte_order, Protocol protocol)
+ : spi_(out, NC, NC), byte_order_(byte_order), protocol_(protocol)
{
- // 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.
+ if (protocol_ == PROTOCOL_800KHZ) {
+ // 800kHz 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.
+ } else {
+ // 400kHz bit encodings:
+ // '0': --________
+ // '1': -----_____
+ //
+ // Timing requirements are derived from this document:
+ // http://www.adafruit.com/datasheets/WS2811.pdf
+ //
+ // The period is 2.5us, and we use a 10-bit packet for this encoding:
+ // '0': 1100000000 mark: 0.5us, space: 2us
+ // '1': 1111100000 mark: 1.25us, space: 1.25us
+ spi_.frequency(4000000); // 400kHz * 10
+ spi_.format(10); // Send one NeoPixel bit in each packet.
+ }
}
static void SendFourBits(BurstSPI& spi, uint32_t bits)
@@ -49,6 +63,15 @@
spi.fastWrite(base | ac | bd); // 1a01b01c01d0
}
+static void SendEightBits(BurstSPI& spi, uint8_t bits)
+{
+ int zero = 0x300; // Encode zero as 0b1100000000
+ int one = 0x3e0; // Encode one as 0b1111100000
+ for (int i = 1; i < 256; i *= 2) {
+ spi.fastWrite((bits & i) ? one : zero);
+ }
+}
+
void PixelArray::send_pixel(Pixel& pixel)
{
// Pixels are sent as follows:
@@ -62,21 +85,23 @@
// | / / ___________________...
// | / / /
// GRB,GRB,GRB,GRB,...
+ //
+ // For BYTE_ORDER_RGB, the order of the first two bytes are reversed.
- 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);
+ uint8_t byte0 = (byte_order_ == BYTE_ORDER_RGB) ? pixel.red : pixel.green;
+ uint8_t byte1 = (byte_order_ == BYTE_ORDER_RGB) ? pixel.green : pixel.red;
+
+ if (protocol_ == PROTOCOL_800KHZ) {
+ SendFourBits(spi_, (byte0 >> 4) & 0xf);
+ SendFourBits(spi_, (byte0 >> 0) & 0xf);
+ SendFourBits(spi_, (byte1 >> 4) & 0xf);
+ SendFourBits(spi_, (byte1 >> 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);
+ SendEightBits(spi_, byte0);
+ SendEightBits(spi_, byte1);
+ SendEightBits(spi_, pixel.blue);
}
}
--- a/neopixel.h Fri Aug 01 22:17:23 2014 +0000
+++ b/neopixel.h Mon Aug 18 21:38:40 2014 +0000
@@ -31,6 +31,16 @@
BYTE_ORDER_RGB,
};
+/** Set the protocol mode.
+ *
+ * The protocol is named after the clock, as though WS8211 supports only the
+ * 400kHz clock, WS8212 supports both.
+ */
+enum Protocol {
+ PROTOCOL_800KHZ,
+ PROTOCOL_400KHZ,
+};
+
typedef void (*PixelGenerator)(Pixel* out, uint32_t index, uintptr_t extra);
/** Control an array or chain of NeoPixel-compatible RGB LEDs.
@@ -91,7 +101,8 @@
* @param byte_order The order in which to transmit colour channels.
*/
PixelArray(PinName out,
- ByteOrder byte_order = BYTE_ORDER_GRB);
+ ByteOrder byte_order = BYTE_ORDER_GRB,
+ Protocol protocol = PROTOCOL_800KHZ);
/** Update the pixel display from a buffer.
*
@@ -135,6 +146,7 @@
private:
BurstSPI spi_;
ByteOrder byte_order_;
+ Protocol protocol_;
static int const latch_time_us_ = 50;
