BADASS Display: Coding Conundrums - Embedded.com

BADASS Display: Coding Conundrums

Happy Monday (or whatever day it happens to be when you read this)! I just spend a jolly happy weekend programming some new test-pattern lighting effects into my Bodacious Acoustic Diagnostic Astoundingly Superior Spectromatic (BADASS) Display.

Note: If you're planning on attending ESC Boston, which will take place May 6-7, 2015, then I'll be happy to chat about my BADASS Display in excruciating detail to anyone who doesn't manage to get out of the way fast enough (LOL).

As I mentioned in my previous column on this topic — BADASS Display: It's alive! It's alive! — my chum Duane Benson has taken the circuit for my original spectrum analyzer breadboard prototype and replicated it as a custom shield. I'm currently waiting for this little rascal to come back from the board shop. In the meantime, as you can see in This Video, I'm having a lot of fun just playing around with different effects.

I have a couple of ideas for additional algorithms that might look rather tasty. For example, I'm thinking of a “raindrops” effect where we pick a column at random and a short trail of white dots falls from top to bottom ending in a “splash.” We could have several of these falling at the same time. We could even tie it to the Internet such that this effect automatically comes on whenever it's raining outside.

Another idea is a “fireworks” effect. In this case, we'd pick a column at random and a short trail of white dots would rise from the bottom to some random height, at which point there would be an “explosion” of colored pixels radiating out in different directions. The color and size of each explosion could also be random.

And yet another idea is to have one or more snake-like creatures meandering their way around the pixel array. Ooh! Ooh! Now I come to think about it, what about implementing a version of Conway's Game of Life? Do you have any ideas for additional effects? If so, it would be great if you could post them in the comments below.

Now, I must admit to being quite proud of myself because I'm a hardware design engineer by trade — when it comes to programming, I pretty much make things up as I go along; which leads me to the fact that I wouldn’t mind a bit of help in the form of someone who actually knows what they are doing taking a look at my code and offering some advice on how I can make it leaner, meaner, and more efficient.

If you Click Here, you'll be presented with an ASCII text file containing the program running in the video above (in fact there are three “rainbow” effects in this code — vertical (column-by-column), horizontal (row-by-row), and diagonal — but I only activated the diagonal version in the video).

Now, I'm using NeoPixel Strips from Adafruit to power my display. In fact, I have 16 strips, each boasting 16 NeoPixel elements, thereby giving me an array of 256 pixels.

On the off-chance you haven't used these little scamps yourself; it might be a good idea for me to explain a couple of things before you start dissecting my code. First we use the following #include statement to access Adafruit's NeoPixel library.

#include

Next, we might a statement like the following to declare (instantiate? I'm not sure what the right word is here) a NeoPixel strip called “strip”:

Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, 25,…

The first parameter — 16 in this example — specifies the number of NeoPixel elements in the strip. The second parameter — 25 in this example — specifies the number of the Arduino's digital output pin we intend to use to drive the strip. We don’t need to worry about any remaining parameters here.

The important thing to note at this stage is that the act of instantiating a NeoPixel strip automatically creates an array in memory. This array has the same number of elements as the number of NeoPixels in our strip — 16 in our example — numbered from 0 to 15. Each of these elements has three byte-sized sub-elements, which are used to store that pixel's red, green, and blue (RGB) values. Now consider the following command:

strip.setPixelColor ( 6, 255, 127, 63);

This loads the seventh element of our array in the Arduino's memory with RGB values of 255, 127, and 63, respectively. but it doesn't actually change the values that are currently being displayed. This means that we can happily take our time deciding what values we wish to display and loading them into our array using a series of “strip.setPixelColor()” commands. When we are ready to actually display these values, we use the following command:

strip.show();

This causes the Arduino to stream the RGB values associated with all 16 pixel elements out of the associated pin (the neoPixels forming the strip are daisy-chained together).

OK, returning to My Code, you will see that I've instantiated 16 NeoPixel strips called strip0, strip1, strip2… strip15 as follows:

Adafruit_NeoPixel strip0 = Adafruit_NeoPixel(16, pinsStrips[0]…
Adafruit_NeoPixel strip1 = Adafruit_NeoPixel(16, pinsStrips[1]…
Adafruit_NeoPixel strip2 = Adafruit_NeoPixel(16, pinsStrips[2]…
       :
Adafruit_NeoPixel strip15 = Adafruit_NeoPixel(16, pinsStrips[15]…

As you'll see, this makes my lowest-level functions look a tad ungainly, because I have to do things like the following:

strip0.setPixelColor(row,R,G,B);
strip1.setPixelColor(row,R,G,B);
strip2.setPixelColor(row,R,G,B);
       :
Strip15.setPixelColor(row,R,G,B);

What I would prefer is to declare my strips in such a way that I could re-write the above code snippet as follows:

for (int i = 0, i < 16; i++)
  strip[i].setPixelColor(row,R,G,B);

The problem is that I don't have a clue how to do this. Furthermore, although it seems to me that this new version should end up occupying less space in the Arduino's memory, I do wonder if it might be slower than my current incarnation. Do you have any thoughts on this?

Another big one for me is my diagonal rainbow effect. My pixels are numbered [0,0] in the lower left-hand corner to [15,15] in the upper right-hand corner. My 16 x 16 array has 31 diagonal “slices” — the first has just one element at [0,0]; the second has two elements at [0,1] and [1,0]; the third has three elements at [0,2], [1,1], and [2,0]; and so forth. As you'll see in my code, I created a three-dimensional array called “xyDiagCells” to hold these values as global variables.

The problem here is that this has sucked up a lot of my available global variable space. Ideally, I'd like to be able to generate the XY coordinates of the cells forming each diagonal algorithmically, but I'm finding it difficult to wrap my brain around the way in which I might achieve this.

I could go on and on, but I think you get the drift. If you have a moment and you are up for a challenge, I'd love for you to take a look at My Code and offer any advice on how you would improve on it so as to consume less memory and fewer clock cycles. Any suggestions will be very gratefully received.


Join over 2,000 technical professionals and embedded systems hardware, software, and firmware developers at ESC Boston May 6-7, 2015, and learn about the latest techniques and tips for reducing time, cost, and complexity in the development process.

Passes for the ESC Boston 2015 Technical Conference are available at the conference's official site, with discounted advance pricing until May 1, 2015. Make sure to follow updates about ESC Boston's talks, programs, and announcements via the Destination ESC blog on Embedded.com and social media accounts Twitter, Facebook, LinkedIn, and Google+.

The Embedded Systems Conference, EE Times, and Embedded.com are owned by UBM Canon.

20 thoughts on “BADASS Display: Coding Conundrums

  1. “MaxnnYou did mention in your previous column that you were considering (at least theoretically) a single strip of 256 LEDs. Just looing at your conundrum, it seems to me that the single array would have been easier to manipulate.nnThat being said, I e

    Log in to Reply
  2. “In hindsight (the one exact science) I sort of wish I had done the single 256 strand — of course this would have involved the first 16-element strand going bottom to top, linking to the next one going top to bottom, and so forth — so there would have be

    Log in to Reply
  3. “I've refactored your code to use loops & was going to email it but the link doesn't work (there's no “To:” value in it). I can post it here but that might be a bit much. In essence instead of 16 different Adafruit_NeoPixel variables (strip0, strip1, .

    Log in to Reply
  4. “Looks like the approach that I'd use except that I'm not sure the compiler would like it. The problem is that when you declarennAdafruit_NeoPixel strips[numCols]; nnthe compiler doesn't know how big to make the array because it doesn't know how many L

    Log in to Reply
  5. “I'm ruunning at the 800KHz data rate — I'm not sure what would happen if I added 15 x 33mm = 495mm down, plus 50mm across = 545mm = 21.5 inches of wire.”

    Log in to Reply
  6. “I don't remember if it has been mentioned before, but with two wireless remotes (analog!) you could do some classic video games, like “pong”.”

    Log in to Reply
  7. “I first thought of using a wireless connection to a smartphone or tablet, but that would be an insult to someone with your abounding creativity. Much better would be a couple of sonic screwdrivers, or possibly a light saber. I'm thinking a nine-axis senso

    Log in to Reply
  8. “n@Max,nI figured out how to do an array. You need to declare the array like this…nnAdafruit_NeoPixel strip[16] = {ntAdafruit_NeoPixel(numRows, pinsStrips[0], NEO_GRB + NEO_KHZ800),n…ntAdafruit_NeoPixel(numRows, pinsStrips[15], NEO_GRB + NEO_K

    Log in to Reply
  9. “That is the advantage of needing two or more “controllers” for the classic games like “pong”. The internal circuit can be the same, but you can have as many controllers with different shell designs as you have time to create.”

    Log in to Reply
  10. “I had a couple thoughts on how to do the diagonal rainbow.nnThe first approach that I though of was to use a 16 x 16 array of bytes with each byte being an index into an array containing the colors you want to use. Something like thisnnbyte colors[3][

    Log in to Reply
  11. “Hi Elizabeth — I just tried this and it works (hurray!) — making this change in the declaration and then modifying my low-level functions in which I previously had to use switch/case statements reduced the overall program size from 7,662 bytes to 6,716

    Log in to Reply
  12. “Max…I'm not familiar with connecting NeoPixel strips, but surely it is possible to take a wire from the output at the top of the first NeoPixel strip to the input at the bottom of the 2nd strip to create your one long strip without taking them off? As

    Log in to Reply
  13. “Bear in mind that if the neopixels regenerate the signal (they seem to ahve shif registers in them) you only need to wory about getting from the top of one string to the bottom of the next one….”

    Log in to Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.