test

Dependencies:   BurstSPI

Fork of PixelArray by Jacob Bramley

Revision:
3:6f392fcb1d3b
Parent:
2:3c3c41774cdf
Child:
4:c3b314df3dfe
--- 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);
     }
 }