0

I would like to control a string of WS2812/NeoPixels from a SBC like a BeagleBone or C.H.I.P. I realize someone has gone through the trouble to come up with a way to drive the WS2812 string from a BeagleBone directly with the PMU, but I would like to have an Arduino like a Pro Mini do the signal generation, while the SBC would direct the Arduino what to display.

I found the node-pixel setup with I2C backpack on the arduino, but it requires on the SBC side NodeJS, Johnny-Five and other libraries that I would have no other use for. It seems overkill.

Is there some commonly used protocol over I2C for controlling NeoPixels (with the arduino being the I2C slave), or will I be better off developing my own simple protocol?

On the SBC side, I would likely be coding either in C/C++ or Python.

3
  • You could use APA102 led strips, they use an "spi-like" protocol (see datasheet) which is much less time-restrictive. Using the right parts is IMHO a better solution than adding more parts to get something working.
    – Paul
    Nov 7, 2016 at 17:54
  • Plus, NeoPixel's timing constraints are so bad that you can't even generate the pixels on the go. You need to put the whole strip in memory, before writing it. The APA102 led strips can be "streamed", pixel by pixel. So you can "calculate-send, calculate-send, calculate-send" to theoretically drive limitless strips witouth using limitless memory ;)
    – Paul
    Nov 7, 2016 at 17:57
  • @Paul wrote: “NeoPixel's timing constraints are so bad that you can't even generate the pixels on the go”. No, they aren't so bad. See: NeoPixels Revealed: How to (not need to) generate precisely timed signals. Nov 7, 2016 at 19:06

2 Answers 2

0

If it helps simplify your project, I wrote a small library that outputs to NeoPixels using the SPI hardware. The code to send one byte is simply this on the Atmega328P:

void sendByte (byte b)
  {
    // send one byte to the Neopixels - note that the "off" gap is partly handled by the loop overhead
    //   gaps measured empirically to be 1.7 µs to 2 µs, so we don't need to add any more of our own
    for (byte bit = 0; bit < 8; bit++) 
      {
      if (b & 0x80) // is high-order bit set?
        SPI.transfer (0b11111100);  // 1 bit - 750 ns on + 250 ns off (acceptable "on" range 550 ns to 850 ns)
      else
        SPI.transfer (0b11100000);  // 0 bit - 375 ns on + 625 ns off (acceptable "on" range 200 ns to 500 ns)
      b <<= 1; // shift next bit into high-order position
    } // end of for each bit
} // end of sendByte

One pixel is 3 bytes (green / red / blue):

void sendPixel (const byte r, const byte g, const byte b) 
  {
  sendByte (g);        // NeoPixel wants colors in green-then-red-then-blue order
  sendByte (r);
  sendByte (b);
  } // end of sendPixel

The timing issue arises because the pixels "latch" if around 9µs elapses with no data. Thus you either precompute the data to be sent, or decide what to send very quickly.


Under the circumstances, using I2C, you would need to precompute the data, these is no way you could receive I2C on the fly and send it out to the Neopixels with them latching.


Is there some commonly used protocol over I2C for controlling NeoPixels ?

Not that I am aware of. I suggest you either send the pixel data (which would be a lot, and have to be broken into smallish packets), or send a "pattern number" and have the receiver generate the data.

Be aware that the standard I2C library has a 32-byte buffer so you can't send hundreds of bytes in a single I2C transaction.

1
  • Fortunately, this particular project is only using 3 to 5 LEDs and I can have the Arduino hold pre-computed patterns to be selected by the host controller. [I am using FastLED for the actual NeoPixel signalling.] Nov 7, 2016 at 21:24
0

You should break your project up into smaller parts.

  1. Consider using other led strips, that can be driven directly. Consider using ready-made parts or opensource code (google).
  2. Make an Arduino drive a NeoPixel Ledstrip. (Check adafruit libraries/NeoPixel guide)(Sanity/wiring check)
  3. Communicate with Arduino and Beaglebone over I2C. Try sending "Hi" and respond "Ok".
  4. Think of a protocol, how to indicate start/stop of a message.
  5. Send the "color bytes" using said protocol.
  6. Unpack the color bytes and put them in a pixel array (See NeoPixel library).
  7. Run "ledstrip.show();”

Please atleast try to do these steps. If one fails, you can create a question with details on what you have tried or what isn't working.

Maybe "nodepixel" already has the Arduino code for you. You then only need to know what bytes to send over I2C, which you can do with any programming language that supports I2C access on your platform.

1
  • Appreciate the response, but I have success on steps 1, 2, 3 and 7. Steps 4, 5, and 6 constitute the heart of my question -- is there a popular/standard/common protocol, or is it simply better that I "think of a protocol" myself. Nov 7, 2016 at 19:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.