# 3X3 LED Cube Programming tips (Arduino based)

How to make that cube do what you want it to!

I followed the instructable here and built a 3x3 LED cube run by an Arduino. I was delighted! But it could only do one routine. Again and again and again and again and again.... So I decided to try and program a different routine. I needed a change. Do you?

If you study the code in the cube's Arduino sketch you can see all the instructions right in front of you. To me, it looks like the Matrix, streaming by in all its digital confusability. I needed a graphic interface to help me code the routines. I FOUND ONE!!! But it wrote code that contained extra information that I did not want. How to rewrite all those instructions? Read on!

Be prepared, this is a twisted solution, combining an (apparently) anonymous website with a macro in my word processor, but in the end I have come up with a routine that is very powerful indeed!
Remove these ads by Signing Up

## Step 1: Graphic pattern generator

I searched and searched for "LED Cube Programmers" on the web. I found some, but they were for PIC based cubes. I changed the title of my search to "LED Cube Pattern Generator" and BINGO! I finally found this one, and it allowed my simple mind to grasp the relationship between little flashing lights and gobs of 1's and 0's. I could punch little buttons on the screen and see a simulation of what I was doing! Just what I wanted. This generator allows one to use a cube of any size! Press the "new" button and you will be prompted to set up your cube.

'Insert' creates a new frame, just like a simple animation program. We are going to make a 'flip book,' in effect. Each page is programmed and then you hit the insert button to add another frame. Notice the speed parameter near the bottom of the window marked 'frames.' F and E mean 'Fill' and 'Erase.' Program a few frames and hit the 'Play' button. Your animation will be shown in the 'preview' window. Simple! When you are done and want to save your new light show, hit the 'File' button. You will see the buttons marked 'New',' to Code',' Load' and 'Save' appear. Press 'To Code,' and a window will open, asking you to choose in which order you wish to display your data. You can go back and change this later if you get it wrong. Just choose one for now.

You will then see a window with all your animation's coded bytes.

## Step 2: Clean up that code, please!

I select all the code in the window and copy. Ok, now here comes the fun part. Open your word processor and paste that code in a new document. I use Libre Office, and have not tried this on other software. You may be able to improve on my crazy method, please share any tips!

## Step 3: Rewrite that mess a little bit.

This is what the pattern generator gives me, and it has some extra information I do not want in my sketch, so we need to remove some characters and make it easier for us to use later. First, get rid of the first and last rows of information, all we want is everything in between those two rows. It should look like this:

## Step 4: The Solution!

This is a very short example, so there are not many brackets, but if you program a longer animation removing all those brackets would take too much time. Being an inventor (always looking for a solution, probably due to laziness in my case) I set out to find a different way to accomplish that. The solution? MACRO! I did a search and found out why my "record macro" button was not active in LibreOffice: Here is the answer to that question, follow the instructions and you can then record a macro. What this does is allow us to execute a series of edits once, record those actions as a single command and then perform the edit on the entire document quickly. I'll try and guide us through one example of an edit using my macro and LibreOffice.

First I clicked on Record Macro (see pics)
Next I selected all the text using ctrl A
Then I used Find and Replace to edit out the characters in my program information.

In the find and replace menu, enter the open bracket   '{'  at the beginning of the text lines like this: Search for {
in the replace line, leave a blank. Click on 'replace all'. You will get a report of how many symbols were replaced.
That's one! Now we repeat that sequence with the next symbol, the close bracket   ' }' (no quote) and replace it also with a blank.
Next symbol to replace is the '0' followed by lower case letter 'b' (0b) with an upper case 'B' instead. Have a look at the pictures in this step to see what my text is looking like.

After this last Find and Replace step, we click on the button that says 'stop recording,' in order to make this editing function a macro. (see pictures here) You will be prompted to save the macro, try to remember what you call it!

Now erase all the text and save the document as a blank slate for your routine. I called my document 'blank slate' (duh.)
Next time I want to program I can skip the steps to create a new macro, it should already be there for me to use. I can program short routines and save them as text files, then piece together the snippets into a longer routine at a later time.

## Step 5: Using the macro function to edit another animation

Now we have programmed our word processor to edit the information generated by the pattern generator into a more friendly format that can be used in our sketch. Let's try the whole procedure so far:

Generate a new animation, say three frames of blinks anywhere. Click on New and enter the number of diodes in your cube. Mine is 3,3,3.

Next I will turn on all the lights in the first frame of our animation.
Next step: add another frame with the 'insert' button. Turn off all but one light anywhere.
Click 'insert' once more and add one more frame, all off.

Now we have a new sequence of three frames, time to generate the code.

Click 'File' and then 'To Code' to see the code window.

Select one of the options offered, I chose 'Depth, Height, Width'  (you may have to experiment here)

Select everything inside the code window and copy.

Paste into our word processor document.

Remove the first and last lines as we did earlier.

Select all the text.

Now we want to run that macro. Under 'tools/macro/run macro' we see a list to choose from. You will need to find your macro, probably at the last entry in the list, look around and see if you can find it. This part is difficult for me to describe. I felt that it should have been easier to find, but then I am new to macros. The macro should appear in the window on the right once you have found it.
Click on it and hit run.

That 'should' clean up the code in one step!

## Step 6: What do I do now?

Now we have a programmed sequence of frames, and transformed the code to a format that will let us run it inside our Arduino sketch. 'What sketch' you ask? The Arduino sketch I use to drive my cube looks like this:

/*
Based on ledcube.c from Make: September 7, 2007 weekend podcast
http://blog.makezine.com/archive/2007/09/make_a_pocket_led_cube_we.html

Custom animation programmed by Mark Boszko, http://stationinthemetro.com
*/

#include <avr/pgmspace.h>        // allows use of PROGMEM to store patterns in flash

#define CUBESIZE 3
#define PLANESIZE CUBESIZE*CUBESIZE
#define PLANETIME 3333          // time each plane is displayed in us -> 100 Hz refresh
#define TIMECONST 5          // multiplies DisplayTime to get ms - why not =100?

// LED Pattern Table in PROGMEM - last column is display time in 100ms units
// TODO this could be a lot more compact but not with binary pattern representation
prog_uchar PROGMEM PatternTable[] = {

B101, B010, B101, B000, B000, B000, B000, B000, B000, 50 ,
B000, B000, B000, B000, B010, B000, B000, B000, B000, 50 ,
B000, B000, B000, B000, B000, B000, B101, B010, B101, 50 ,
B000, B000, B000, B000, B010, B000, B000, B000, B000, 50 ,
}

/*
** Defining pins in array makes it easier to rearrange how cube is wired
** Adjust numbers here until LEDs flash in order - L to R, T to B
** Pin DigitalOut0 (serial RX) and AnalogIn5 are left open for future apps
*/

//int LEDPin[] = {16, 3, 1, 15, 4, 6, 14, 5, 7};
int LEDPin[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10};

//int PlanePin[] = {19, 18, 17};
int PlanePin[] = {13, 12, 11};

// initialization
void setup()
{
int pin;      // loop counter
// set up LED pins as output (active HIGH)
for (pin=0; pin<PLANESIZE; pin++) {
pinMode( LEDPin[pin], OUTPUT );
}
// set up plane pins as outputs (active LOW)
for (pin=0; pin<CUBESIZE; pin++) {
pinMode( PlanePin[pin], OUTPUT );
}
}

// display pattern in table until DisplayTime is zero (then repeat)
void loop()
{
// declare variables
byte PatternBuf[ PLANESIZE ];      // saves current pattern from PatternTable
int PatternIdx;
byte DisplayTime;        // time*100ms to display pattern
unsigned long EndTime;
int plane;      // loop counter for cube refresh
int patbufidx;   // indexes which byte from pattern buffer
int ledrow;    // counts LEDs in refresh loop
int ledcol;    // counts LEDs in refresh loop
int ledpin;    // counts LEDs in refresh loop

// Initialize PatternIdx to beginning of pattern table
PatternIdx = 0;
// loop over entries in pattern table - while DisplayTime>0
do {
// read pattern from PROGMEM and save in array
memcpy_P( PatternBuf, PatternTable+PatternIdx, PLANESIZE );
PatternIdx += PLANESIZE;
// read DisplayTime from PROGMEM and increment index
DisplayTime = pgm_read_byte_near( PatternTable + PatternIdx++ );
// compute EndTime from current time (ms) and DisplayTime
EndTime = millis() + ((unsigned long) DisplayTime) * TIMECONST;

// loop while DisplayTime>0 and current time < EndTime
while ( millis() < EndTime ) {
patbufidx = 0;    // reset index counter to beginning of buffer
// loop over planes
for (plane=0; plane<CUBESIZE; plane++) {
// turn previous plane off
if (plane==0) {
digitalWrite( PlanePin[CUBESIZE-1], LOW );
} else {
digitalWrite( PlanePin[plane-1], LOW );
}

// load current plane pattern data into ports
ledpin = 0;
for (ledrow=0; ledrow<CUBESIZE; ledrow++) {
for (ledcol=0; ledcol<CUBESIZE; ledcol++) {
digitalWrite( LEDPin[ledpin++], PatternBuf[patbufidx] & (1 << ledcol) );
}
patbufidx++;
}

// turn current plane on
digitalWrite( PlanePin[plane], HIGH );
// delay PLANETIME us
delayMicroseconds( PLANETIME );
}    // for plane
}    // while <EndTime
} while (DisplayTime > 0);        // read patterns until time=0 which signals end
}

## Step 7: Modifying the sketch

There a three things I changed in that sketch to make it run on my cube.
1.  The settings for HIGH and LOW level states
2.  The order of the output pins
3.  The data for the routine, which is what this is all really about!

Let's look at this in detail. I have highlighted the words HIGH and LOW here. I reversed them from the original program. You may or may not have too. Experiment.

// initialization
void setup()
{
int pin;      // loop counter
// set up LED pins as output (active HIGH)
for (pin=0; pin<PLANESIZE; pin++) {
pinMode( LEDPin[pin], OUTPUT );
}
// set up plane pins as outputs (active LOW)
for (pin=0; pin<CUBESIZE; pin++) {
pinMode( PlanePin[pin], OUTPUT );

This is the order of the outputs the cube is made after. The first row {16, 3, 1, ...} is simply an example. My numbers are directly underneath that row. {2, 3, 4, ...} be sure to include a space after the comma.
Next is the pins for the plane. Same here, first row is an example, next row is the real deal. You can invert your cube with these numbers. Cool!

//int LEDPin[] = {16, 3, 1, 15, 4, 6, 14, 5, 7};
int LEDPin[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10};

//int PlanePin[] = {19, 18, 17};
int PlanePin[] = {13, 12, 11};

The third change is the animation data, the information we have generated and processed so lovingly. Simply copy it from your word processor document and paste it into the program. Like this:
{
B101, B010, B101, B000, B000, B000, B000, B000, B000, 50 ,
B000, B000, B000, B000, B010, B000, B000, B000, B000, 50 ,
B000, B000, B000, B000, B000, B000, B101, B010, B101, 50 ,
B000, B000, B000, B000, B010, B000, B000, B000, B000, 50 ,
B101, B000, B000, B010, B000, B000, B101, B000, B000, 50 ,
B000, B000, B000, B000, B010, B000, B000, B000, B000, 50 ,
B000, B000, B101, B000, B000, B010, B000, B000, B101, 50 ,
B000, B000, B000, B000, B010, B000, B000, B000, B000, 50 ,
B101, B010, B101, B000, B000, B000, B000, B000, B000, 50 ,
B000, B000, B000, B000, B010, B000, B000, B000, B000, 40 ,
B000, B000, B000, B000, B000, B000, B101, B010, B101, 40 ,
B000, B000, B000, B000, B010, B000, B000, B000, B000, 40 ,
B101, B000, B000, B010, B000, B000, B101, B000, B000, 40 ,
}

See that bracket at the beginning and end of this numerical data? Make sure you include them in the complete sketch.

Load up the sketch and it should run!
I have included an example to show that it DOES work!
Have fun programming your own personal show on that cube. It is a super toy and a great learning tool.

## Step 8: Conclusion

Have you ever tried to write instructions about how to fold a paper airplane? How can something so simple become so difficult? This may seem as difficult to some of you. I understand completely. To my twisted ways of thinking it makes sense, but my mother always said I was "special." So... If you need help, ask. There are programmers out there and people who can teach us ALL a lot about this subject. All I can say is, hack it!

Give it a try and share some of your own routines here!
Enjoy.
stringstretcher (author) 6 months ago

rkshirsarar,

if you look at this site, designed by my friend to program these cubes, you will see the pin numbers in his setup code located in the code examples he provides. He uses these pins for his setup and it works great!

int g1=4;
int g2=3;
int g3=2 (pins 4,3,2 for the transistors, 5-13 for the anodes, as stated there)

A fantastic programming interface! Try it!!

http://www.ledcube3d.tk/

rkshirsagar6 months ago

Could you tell which pins of Arduino are connected to transistors and which pins are connected to anode of led's, I mean the schematic of the cube.

stringstretcher (author) 11 months ago

If anyone tries this... you should have a look at this fantastic online programmer for 3x3x3 cubes: http://ledcube.tk

Lots of great features, and no more need for this workaround!

Thanks Satvik for the coding and work there. You've done a great job!

8 months ago

Hy,

http://ledcube.tk I have done the led cube and I uploaded the code from the site but I have to change something in the code to make it work something like (a1),etc.CAn u help me please?

baitun1 year ago
It doesn't work for 4x4x4 cube.
arjan9011 year ago
i have a question about the code.
When i want to upload it to my arduino, i get an error on line:
int LEDPin[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10};

it says:
sketch_jan07a:34: error: expected ',' or ';' before 'int'
sketch_jan07a.ino: In function 'void setup()':
sketch_jan07a:45: error: 'LEDPin' was not declared in this scope
sketch_jan07a.ino: In function 'void loop()':
sketch_jan07a:95: error: 'LEDPin' was not declared in this scope

what can be the problem?
stringstretcher (author)  arjan9011 year ago
Your first error indicates a problem *before* inserting the changed lines. Check everything VERY carefully from the beginning and see if you can find a missing semicolon.
Eduort2 years ago
Hi, this is very interesting, but i have a question, is posible to program 2 or 3 routines and start them whit a button? thanks for afterhand
stringstretcher (author)  Eduort2 years ago
I never thought of that... why not? It is a matter of storing the routines as data, and then using a switch to select the data set, or the switch could select the starting point of the routine with case switch commands. There are others out there who are brazilians of times better at this than I am. We will have to seek the answer!!
Hanni432 years ago
Great able ,been looking for the led generator & everytime go to Download more junk seems to be getting downloaded than the program, where did you get it Wout all the other advertisers junk..Thanks for sharing project & time finding the way to go..D
stringstretcher (author) 2 years ago
I couldn't understand how to embed a video in any of the steps. Here is a link to one showing a short routine done using this method.