Firmware System

Lighting it up

Github Repo

The NS_Rainbow library

To control the LED matrices, we use the NS_Rainbow library that accomodates the hardware we bought. On the 8x8 display, the cells are numbered 0-63. The NS_Rainbow API provides the following methods:

show()
setBrightness(int val)
setColor(int cell, int r, int g, int b)
clear()


The Squares display Squares.ino

Gallery

The Squares display lights up the LEDs with square patterns accoring to beats detected by our audio processing. The Arduino reads in from Serial the output of our audio analysis in real time. You can refer to this section to see how Processing outputs to Serial. After reading in the encoded value from Processing into the variable pattern, the Arduino figures out to which pattern to light up by deducting powers of 2 from pattern. For example, if the third bit is on, it will light up the BIG_SQUARE:


if (pattern >= 8) {
  lightUp(BIG_SQUARE, SIZES[0]);
  pattern -= 8;
}
								

The displays are statically set, holding the indicies of the LEDs that should be lit. For example:


int SMALL_SQUARE[12] = {18,19,20,21,26,29,34,37,42,43,44,45};
								

lightUp takes in the array that dictates which cell to light up, as well as the size of that array. It then iteratively lights up each cell. The colors int r, g, b are initialized to 50. They are changed each time through the loop().


The Waves display Waves.ino

Gallery

The Waves display has four faces of the cube act as one continuous scrolling text marquee. This display is independent of any audio analysis.

The full pattern is hardcoded as an 8x32 2D array as it should appear originally across all 4 faces if the faces were in a line. Each element is a 0 or 1, corresponding to if that LED should initially be off or on. For example, this is the representation of a wave pattern:


int wave[8][32] = {
                    {0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0},
                    {0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0},
                    {0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0},
                    {1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0},
                    {1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0},
                    {1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
                    {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1},
                    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}
                  };
								

scrollingTextArray(int pattern[][32]) takes as an input this hard coded pattern. The goal is to have, for each row, every column shift to the next column, with the last column wrapping around and going into the first column, and have this shifting continue until the column reaches its original column once again.

This scrolling is accomplished by first looping through the width of the display: the number of columns, in this case 32. The current iteration is saved as the ith iteration. Every increment of this loop represents the entire display being shifted over by one column.

Within this outer loop, the current shifted over light pattern needs to be displayed onto the LED matrices. This is accomplished by looping through the 8 rows of the entire display. Then, within the current row, the LEDs of that row are set to display what the hardcoded pattern has as the display for the LED i columns over from the current column. The shifted over pattern is displayed after which matrix each LED belongs to is calculated.


void scrollingMarqueeArrays(int pattern[][32]) {
  for (int i = totalWidth - 1; i >= 0; i--) {  // loop through overall width
      for (int j = 0; j < matrixDimen; j++) {  // loop through every row of pattern
            for (int k = 0; k < totalWidth; k++) { // loop through every pixel of row
                int originalCol = k - i;
                if (originalCol < 0) {
                    originalCol = totalWidth - 1 + originalCol;
                }
                                                      
				int v = pattern[j][originalCol]; // value from original column

				... // calculate which matrix the current pixel is a part of
            }
      }
	
      ... // display the current pattern on the matrices
   }
}
								

One iteration of scrollingTextArray(int pattern[][32]) scrolls through the entire display once. Thus, scrollingTextArray(int pattern[][32]) is called within loop() to have the display constantly scrolling.


DIY Matrix Controldiymatrix.ino

Although we did not use the LED matrix we soldered ourselves in the final version of Cube Lite, the DIY matrix did create the need for its own firmware, as it does not work with the NS_Rainbow library. The control system reflects how the hardware is implmemented for the electrical system of the DIY matrix.

The LEDs can be individually accessed by row and column number: each row, 0 through 7, contains 8 LEDs, also indexed 0 through 7. Thus, light patterns can be encoded as an array of numbers whose binary representation corresponds to the intended display, with 0 representing off and 1 on. The indices of the array represent the rows. For example, a small square that lights up the middle four LEDs can be encoded as:


const int SQUARE_1 [] = {0,0,0,24,24,0,0,0};
								
24 is 00011000 in binary, so this array translates to having the middle two LEDs of the middle two rows lit.

Sending the desired pattern to the LEDs is done through displayPatterns(int pattern[]), called in loop(). This function loops through pattern to set the rows one at a time. For each row, shiftOut is used to shift the bits of the pattern for that row to the Arduino output pin that is connected to the SERIAL data input pin of the electrical circuit's shift register. After shifting all of the bits, a clock signal is sent to the Arduino output pin that is connected to the CLK pin of the circuit's decade counter to increment the counter's count, grounding the next row of LEDs so its pattern can be set.