Introduction: Hacking the CharlieCube
This instructable, is about the charliecube, and its about hacking, and how I used a spreadsheet to hack an LED cube.
To start I guess I need to explain what a charliecube is. A charliecube is a 4x4x4 3D RGB LED cube, or 64 RGB LEDs arranged in a 3D cube. Its a particularly interesting way to make an LED cube because it uses very few parts, mostly just the LEDs and microcontroller, it needs no LED drivers, and it even lacks current limiting resistors (LEDs often require resistors to prevent overcurrent damage.)
The charliecube was created by Asher Glick and Kevin Baker, and it is a radically different approach to LED cube design. It does have some inherent flaws, like the lack of current limiting resistors, which may or may not be slowly damaging the LEDs and or microcontroller. This also causes some strangeness in the cube, because red LEDs have a much lower forward voltage, they tend to light when setup this way with other LEDs. You can, and I have built the cube with 16 resistors on the microcontroller pins, this brings things to a much saner current level, but does make the cube notably dimmer.
I have spent quite a bit of time building and programming several of these, Ive figure out a few things along the way, and trying to document things on my LED cube website.
Here are some links to my site, and other helpful sites for background on charliecube and charlieplexing.
I have 2 instructables about the charliecube
https://www.instructables.com/id/Charliecube-Charli...
and
https://www.instructables.com/id/Advanced-Charlicub...
My website about the charliecube:
https://sites.google.com/site/rgbledcubes/home/cha...
Asher Glicks website about the charliecube:
http://aglick.com/charliecube.html
Charlie Allen, and Charlieplexing:
https://en.wikipedia.org/wiki/Charlieplexing/
This is where I first read about the charliecube.
Step 1: Start by Observing, and Exploring...
Observations, facts, and interesting things discovered while hacking about the code.
Charlieplexing generally lights only one LED at a time, multiplexing never lights all at one time, but usually a whole row, or plane can be light at a time. Charlieplexing also requires tri-state logic (5v, ground, or input), where multiplexing only needs binary (5v, or ground).
It can only light one voxel at a time, but it can light up any combo of the 3 LEDs inside each voxel. Most cubes light a whole plane of LEDs at one time, and that sets its duty cycle (4x4x4 are 25%, 8x8x8 is 12.5%, ...)
Every LED can be individually controlled by using the correct two microcontroller pins (with the correct polarity)
Since there are 64 voxels, this gives it a duty cycle of 1/64 at brightest.
There are 3 ways to relate to any specific LED, It can be referenced sequentially from 1 to 192, by it X, Y Z axis co-ordinates, or by the 2 microcontroller pins required to light it up.
There are a couple tables of information that work together in a way that is similar to DNS in computer networks, its a simple translation so that when you say light r123 (red LED at location x=1,y=2=3), the correct microcontroller pins are activated. This table is an ideal place to make changes if you have made a wiring mistake, and its where I made changes to adjust the cube height, but I also had to make many changes to convert the cube to common anode.
Inverting the pins in the program call did not light the cube as you might expect, it was not that simple, but it did get most of the LEDs, which made it easier for me to test, document, and fix the ones that were not right. Out of 192 LEDs, it got all but 48 right. This has to do with the way the cube is wired, the 4 layers of circuitry. It is interesting that inverting the polarity fixed 3/4 of the pins, but not all, and not none.
The sequence of 192 LEDs are organized by color, then in X, Y, and Z co-ordinates, and simple equation can decode this like this: (((color)%3)*64)+(x*16)+(y*4)+z So that you input that you want to light the red LED at the xyz co-ordinates 123, and it knows that red is the last group, so add 2*64 + 1*16 + 2*4 + 3, and that totals 91, it looks up the 91st entry in a table and gets the pin number for high, and low, to turn on only the right LED.
When you test a spire, you can tell that its an ideal number of LEDs controlled with that few number of control pins. Four pins control twelve LEDs. The way it does it is quite simple. you connect on common lead, and the other three are the R, G, and B. leads. If you change the common lead, that will control a different LED (physically higher or lower on the spire), and the other 3 leads will do the R, G and B. You can rotate the spire 4 time, and each time you rotate the spire, it changes height.
When you are going through the sequence, you can see patterns of numbers in groups of four. Each of these 4 numbers are the wires connected to a single spire. I took advantage of this several times fixing mistakes transposing data in the table. I could see how the pattern would be interrupted right at the LED number that wasnt working right. Probably the most interesting patterns are the miswires from inverting pins. Another way to put it would be the the ones that didnt light up right, after swapping common anodes for cathodes.
The tools that I used to accomplish this task (besides the cube, arduino, IDE, computer), were a text editor (like Im using now), and a spreadsheet program (open office calc).
My cube is not aligned like the original cube data, To get my cube to start at the right height, I had to start with 4 different flushbuffer tables (height shift on each, to tune the cube height), I started by changing the pin1, and pin2 order in calling the program, but when that didnt make the anode cube work right, I new I had to build custom maps, but over half was already right, so it wouldnt be as huge of a task as doing them all one by one.
I wrote a program to light up the LEDs in a sequence, based on the way the drawLED program works, looping x, y, and z, then cycling colors. I started with a program to light up a random LED in the cube, stripped out all the random stuff, and plopped in 3 nested loops (x, y, and z), then used a function built-in to the charlieplex.h file to color cycle.
I used this program to watch what LEDs lit, and made notes of the ones that lit in the wrong places, and what places they lit. After I compiled a list, I went through and confirmed each of those lit up the wrong thing with my test program. I used this data, and made a little conversion table. At this point I had all the info to fix everything, I just had to make some tables, swap some data, and test.
I started the process, and got things mostly fixed, and unknowingly bent a wire on the cube just enough to make it short with another wire. It caused a lot of havoc, it made about a dozen LEDs light other extra LEDs, and it made a few LEDs fail to ever light. I re-did my whole process using a spreadsheet, and flipping columns of data, and hand swapping 48 of the 192 data points in the table. and found I was having a lot of problems again. I was almost convinced that I needed to change the physical wiring to get the conversion to work. I noticed that the LEDs that failed to light were all on one spire, and I understood how the spire works, so I considered that it might have some problem. I examined it thoroughly to make sure that all the LEDs were in the right position, and so were all the other spires that were connected to it. I checked the wiring to make sure that I didnt have wires touching, because there are many wires that cross over other wires, that could touch. I found one of the stiffer wires was soldered right next to another stiff wire, and I bent that wire just enough so that it no longer made contact, and the problem when away.
That one short cost me a couple days of wasted work, but ultimately it doenst matter, because in less than a weeks time, Ive hacked this cube and have a working common anode charliecube.
Step 2: Start Hacking the Code...
To modify the code meant converting arduino code, into a spreadsheet,
separating specific data out, manipulating tables, then putting things back together, and pasting back into a text editor. To pad with leading zeros to keep columns lined up, you need to format some columns to use leading zeros, then later you have to swap those zeros for spaces, or the compiler will squeak at you. You also have to be careful when pasting information in the spreadsheet. Sometimes you need to make sure that you only paste the data, not the formula or link. Other times you need to be careful to copy the relationships down a row,column, or matrix. I ended up making several processes, and several spreadsheet sheets for all the data. I needed 8 maps of data (4 for common cathode, and 4 for common anode). I will probably end up changing it to 2 maps, and a line to adjust the starting z value(z=z+1,2,3), and another to inhibit overflow issue(over 192 then z=z-192).
There are several files that contain various bits of code that make this LED cube work, and there are a few tables of information that you could manipulate to change how it works. The cubeplex.h file contains the flushbuffer table, which is what I chose to modify.
Here are a couple sample lines of the flush buffer.
if (_cube_buffer[ 0] != 0)flushElement(copy_frame, 4, 8,_cube_buffer[ 0]);
if (_cube_buffer[ 1] != 0)flushElement(copy_frame,16, 4,_cube_buffer[ 1]);
if (_cube_buffer[ 2] != 0)flushElement(copy_frame,12,16,_cube_buffer[ 2]);
if (_cube_buffer[ 3] != 0)flushElement(copy_frame, 8,12,_cube_buffer[ 3]);
You can see each line is serialized at both ends, but in the middle of the line, there are a pair of numbers that are unique to each line. You may also notice that there are spaces padding the numbers, so that things line up nicely, this is important when you manipulate the data later on.
This table of code sets up a relationship between pairs of number, and the sequence to light each LED. The numbers in the pairs represent the microcontroller pins, but later get translated to port addresses for speedy lighting.
Every LED can be controlled in this table, and no number combinations will be repeated. The sequence should stay the same, but the number pairs that represent microcontroller pins will need to be re-arranged to work with common anode LEDs with the original (common anode) code and wiring. I normally use a text editor for writing programs, but in this case, a text editor wouldnt work very well for manipulating the data. Since I was dealing with a table of numbers, 2 columns by 192 rows, a spreadsheet seem the most appropriate.
This isnt the first time I've done this, this is the second time that I've done this, it was a bit easier this time. The other time that I did this was to create 4 table to compensate for how the cube is oriented with the cube wiring. Depending on how you connect the wires, there are 4 common ways to do it, each table works with each of the 4 ways you can set up those wires.
To make a common anode cube work with the common cathode software, you would naturally assume that inverting the pins would do exactly what you want, but if you look at how complex large numbers of charlieplexed LED schematics look, you would assume that inverting the pins may not do the right thing at all.
When you examine one the the LED spires, you find that it uses 4 pins to light 12 LEDs, this is ideal in that every possible combination of ways to hook up a singe positive, and a single negative lead, will result in an LED being lit. The formula for calculating how many LEDs can be lit from an given number of microcontroller pins, is N squared minus N, or N times (N-1). A single spire has 4 leads, so the maximum it can control is 12 LEDs (4x4 =16, 16 - 4 =12, or 4 times 3 = 12. 4 RGB LEDs means a total of 12 LEDs. The cube is less than ideal, in that it uses 16 pins to control 192 LEDs, yet the max number of LEDs should be a 240, if they were wired in an idea fashion.
When you look at the code, you can see that every 4 lines is a group, because those microcontroller 4 pins control a single spire.
Now lets look at how to go about manipulating the data with a spreadsheet and a text editor, to get the desired results.
Step 3: Work the Data
Its important to start with good table, and the original table is nicely padded with spaces for leading zeros (zeros dont work with the arduino code, but spaces are ignored), On a spreadsheet, space wont transfer over, but we can fix those columns to use 2 leading zeros, which will keep the data lined up nicely.
You can see how the data is nicely lined up in the first image, select the whole table of data (and just the 192 lines of code), and copy that data (ctrl-c)
Open your spreadsheet program, and paste into blank document. You may need to do paste-special, or some other method if it trys to paste the data into one column or cell. I used this window to tell it how to paste the data. I dont want it to automatically figure out that its tab or space delimited, I want to set it to fixed, to line up with my data, then set fixed points around my data, so that I can manipulate the parts that I want, without messing up the numbering (although the numbering could be re-created pretty easily if you make a mistake...)
The second image should show you the import text dialog box, this is where you set it to fixed width, and set the points where you make columns.
Now you have pasted the data, and everything looks great, except for one thing, those spaces that we used to make nice data columns are gone, but we can easily add leading zeros, which do the exact same thing. Start by selecting the 3 columns that make the number pairs, then right click on the column header and select format cells.
You should see something like the third image, where you can select how many leading zeros in the column, change it to two, and click ok. while the columns are selected, go ahead and copy those columns, and paste them into a new column to the right. Now we have all the data in the spreadsheet, we can actually make 8 different sheets (4 for common anode, 4 for common cathode). Lets start by making the 4 common cathode maps.
Each 4 rows represents a spire. to shuffle the data in each group of 4 rows. Its a pretty simple task to do this in a spreadsheet, using those 2 columns that pasted to help.
Select B1, and then click the = sign, or type the = sign in the input line, then click the cell (or type in the cell location, in this case H2). Do this again with D1, and I2 This will change the first line to look like the second line.
Now that the first line is linked to the right cells, we can repeat this down a couple times to get the first 3 lines relative links, because that is what we want.
The 4th picture shows how you select the 3 cells, click the tiny square at the lower right corner, and drag down 2 rows to copy the relative links down.
The fourth row is just like doing the first row, except for doing one row down, you do 3 rows up (B4=H1), and D4=I1)
Now you should have the first 4 rows adjusted, we just need to repeat this pattern all the way down to 192, and it will complete this table. Select the 12 cells (B1-D4), click on the square in the lower right corner, and drag down to the bottom of the spreadsheet (192 cells) see the 5th image
Now we have created a whole new table that will work if your wiring is off by 90 degrees. We need to do this 2 more times to make the other 2 tables. You can start with the original, and shift 2, then shift 3 for the last one. You could just take this one, and make a new sheet and do the exact same procedure on it to shift it one cell. Either way, and you should end up with 4 tables, each table works for each of the 4 ways the cube can be wired.
Note: when you paste the data, be very careful to only paste-special, and select numbers and text, but nothing else. see the sixth image.
To put the tables back, I had to do a bit of messing about to replace the leading zeros for spaces. text editors are good at that sort of thing, so I did it in a new text document, before pasting it into the cubeplex.h.
Start by copying the new table of data, then past that into a new blank text editor. It will look horrible, dont worry, we will fix that up real quick. First do a search and replace, and replace all the tabs ("\t") with nothing (leave the replace blank), that will help a lot! now we need to replace some spaces with zeros. Change the ""\t" to ",0", and replace that with ", ", this should take out the leading zeros, and put spaces in. This will keep all the numbers lined up, in case you need to do this again. Now you can copy the whole document, and paste it into the cubeplex.h file. You will need to repeat this process for the other 2 sheets, put them all in the cubeplex.h file, and comment out the ones you dont use. (only use one flushbuffer table, comment any other ones out.
Now we can move on to the real interesting part, making the common anode maps. What I did was use the map that works with my cubes orientation. I had to try each of the 4 new tables, and I used the fountain program, and slowed it down a lot, so I could see it light the first sequence of 4 steps. You can see where it starts, if its not the bottom, use a different map, until it starts at the bottom. It should start at the bottom, then go up one, then two, then the top then start working down around the outside and down.
Once you have the right map for your cube, go back to your spreadsheet, and find that map, start a new sheet, and copy that maps data (just the text and numbers, no formula or anything). Copy column B and paste it to an empty column to the left, copy column D, and paste it into column B, copy the the copy of column B, into column D. Now you have a table for common anode LEDs, but they are only 3/4 right, and we dont know which ones are wrong. Since most are right, its a real good start, we should be able to tell when we try out this code. You need to copy the data to the cubeplex.h file using the same procedure we did before.
To figure out which pairs were wrong, I wrote a simple program that sequences turning on and and off each LED 1 through 192, but the program that lights up the LEDs uses X, Y and Z co-ordinates. So I looked for a program that was close to what I wanted to do, and modified it to suit my needs. There is a program called chaseTheDot, that comes with the cube software, I changed it to SeqTheDot, and removed the random, and plugged in nest of 3 loops
to sequence the X, Y, and Z, and added a few features. Here is my test code:
/******************************** Sequence THE DOT ****************************\
| |
| |
| Hacked up by hippynurd@gmail.com to suit his testing needs. |
| Inspired By: Jonah Glick |
| Written By: Asher Glick |
\******************************************************************************/
void SeqTheDot() {
continuePattern = true;
int animationSpeed = 200; // change this to speed up or down.
// color= green; // change this to set a specific color or comment it out to cycle.
int xpos = 0;
int ypos = 0;
int zpos = 0;
while (continuePattern) {
// switch(random(0,6)) {
// Instead of random, we want to sequence, so we increment x each loop
// and increment each y at max x, and reset x to 0, at each y max we
// increment the z and reset the y, and the x.
for (xpos; xpos < 4; xpos++) {
for (ypos; ypos < 4; ypos++) {
for (zpos; zpos < 4; zpos++) {
// drawLed(color,1,1,3); // use this one to light up a specific LED
drawLed(color,xpos,ypos,zpos);
flushBuffer();
clearBuffer();
delay(animationSpeed);
} zpos=0;
} ypos=0;
} xpos=0;
} color=nextColor(color); }
The program will go through each LED 1 time, each time it gets to the end of the cube, it changes colors, it does the 7 colors that are built in (red, purple, teal, yellow, blue, green, and white). When it does the secondary colors, its mixing 2 LEDs. when it does white, its only
Now upload the sketch to your cube, and take notes when it fails to light the correct LED. Note the position and color that it lights, We will use this info later to edit the table.
Go back to the spreadsheet, it should have the last sheet still open in it. Delete the extra column if you havnt already, then copy the 3 columns of data, and paste them off to the side. If we make a mistake (its real easy to do...) you can always copy the data in these columns back, and start over. Remember, when doing this copy only text and numbers, just the data.
Now go to that list, start at the top, your list should have where it was supposed to light, and where it did light, note where it was supposed to light, scroll down to that line in the code, and copy the 3 columns of data on the right in that row. Scroll down to that LEDs sequence number and paste it into column B (it should fill in B, C, and D). There are 48 of them, take your time with each one, its easy to mess it up.
When you are done, you should have everything mapped out correctly, copy the new table to your cubeplex.h file, using the same method as previously used, comment out the others, and upload the sketch. If you did everything right, it should work, I didnt do everything right and I had to repeat the process a couple times before I got them all lighting up the right LEDs in the right sequence.
Once I had it right, I was able to make 4 tables like I did for the common cathode versions, then I was able to use the program diff to find the difference between the two files, and have a complete list of the changes.
You could use the cube the way it is, but I did not notice that the common anode cube is upside down from the common cathode cube, Most people wont notice that its upside down, but I do, so I had to change that, with the spreadsheet, it was quick and easy. Make a new sheet, copy the last table over, then copy the 3 columns like we have done so many times before. Now what we want to do is re-order each group of 4, so that instead of 4,3,2,1, it does 1,2,3,4. To accomplish this, select cell B1, click the =, click the cell H4, hit enter, then click the corner square and drag over 2 cells to copy the formula over, or click D1, and click the =, then click I4, and hit enter. Now we can do the same with B2, and H3, then B3, and H2, B4, and H4. Click the corner on each and drag the formula over, or do the D column cells one at a time. At that point you should have the right formula in the first 4 rows. now select those 12 cells, click the corner square, and drag all the way down. This should put things in the right order, now copy the data, and paste it to the cubeplex.h file using the method previously mentioned. Repeat that process for each of the common anode data sets, and copy them over using the same method previously mentioned. Now you have a total 0f 8 sets of data, 4 for common anode, 4 for common cathode.
Step 4: Now Enjoy Your Common Anode Charliecube.
Here is the common anode cube running the test program.
Step 5: Time Lapse Video of Making a Charliecube Spire...
Just for fun im including this quick little time lapse video of me making a charliecube spire. I wish I could really make them this fast.