RGB LED Cube
OK so I have finally found some time to begin writing the story of my RGB LED cube, this project was always going to be the next step in the evolution of my LED Cube.
I can only hope that it will be as popular as my original cube, for those of you that followed my original cube project you will probably notice a few similarities.
I built the RGB cube while I was living in the UK for 6 months, so I had access to a limited number of tools and most of the work was done on the dining room table to the dismay of my girlfriend. Working on this project I have learned a lot about animating in colour, software modulation for fading and c++ in general, so hopefully I can teach you readers a thing or two as well. If nothing else at least you will be able to use what I offer here to build one of the greatest light displays you have ever seen! (If I do say so myself :P)..
Before I Begin
Well this is a pretty long article, if you somehow got here and don't know what an RGB LED cube is here is a video, hopefully after watching you will read on to see how I made it.
So first things first, how much time should you set aside? Don't be surprised if it takes you a couple of weeks, I think I spent about 20 hours just soldering LEDs for this project. I also spent about 60-80 hours on the software,
but I guess I will give that to you (well most of it). Next here is a parts list, most of the parts I have used I purchased from ebay, I find that it really is the cheapest place to go for relatively low quantity electronic components,
I did still use farnell a lot because of their next day delivery.
So it turns out I had made a couple of mistakes when building the driver board, as pointed out by a friendly commenter. My cube worked so I wouldn't get too worried if you had used the old values, but you may get better results by changing the current set resistors and the decoupling capacitors.
- If the links for any of the following items go down just check out the NooElec ebay store
- 512 x 10mm, common anode RGB LED - ebay - NooElec - $180 AUD
- 12 x STP16 LED driver - farnell - $40 AUD
- 8 x 2N5195 PNP transistors (next time I am using MOSFETS) - farnell - $15 AUD
- 1 x ChipKIT UNO32 -farnell - $33
- 1 x 5V switched mode PSU - ebay - NooELec - $20 AUD
- 1 x 5v-3.3v DC-DC converter - ebay - $10 AUD
- 12 x 10uF 16V ceramic capacitors - farnell - $3 AUD (THIS SHOULD BE 0.1uF)
- 20 x 100R resistor (STP16 current set & transistor current limit) - farnell - $8 AUD (USE 1K FOR THE CURRENT SET RESISTOR)
- 8 x 1.5K resistor (transistor pull up) - farnell - $4 AUD
- 14 x IDC ribbon cable connector - ebay - $10 AUD
- 1 x Roll 22AWG tinned wire - ebay - $20 AUD
- 14 x pin headers (16x2)
- 16 way ribbon cable
- 12mm ply for the base and jig
- 20x12mm pine for the jig
- screws, solder, bluetack, etc, etc.
- TOTAL $350 AUD
The Cube Assembly
So as you can imagine the assembly of this cube is a little more complicated than my original cube, before I begun the larger 8x8x8 cube I decided to build a little proof of concept cube to test some methods of assembly.
Now because I am using large 10mm LEDs I had to make sure I allowed enough space between each LED, unfortunately this means that I had to use wire to connect each LED rather than using the LED's legs.
For my proof of concept I used protoboard as the base rather than make a jig, I also decided to assemble the cube in layers like I did with the original cube. This was my first mistake, I will only show you one picture and hopefully you can see why this method would be an absolute nightmare when assembling an 8x8x8 cube. Actually I'll show you two, just to show you that I didn't give up, it actually turned out pretty nicely so I gave it to a friend
How Not To Make an LED Cube
Mini RGB Cube
Anyway now I had an idea on how I would not do it, so I sat down with a glass of red wine as inspiration and got thinking. After a few designs in my head I decided that rather than assemble the cube in layers it would be more simple to assemble the cube in panels. So you understand what I mean here is a picture of both the finished product and the proof of concept highlighting the method of assembly. The major advantage of panels over layers (I think) is the fact that the jig I designed is so easy to make, my jig consists of one flat board (I used 12mm ply) and 8 lengths of 20x12mm pine beading.
Panels Versus Layers
The Bends and The Jig
I am very happy with the cleverness of my jig, is was easy to build and I was able to get 8 identical panels of LEDs. The first thing you need to do is bend all of your LEDs, I used a 6" steel ruler for this as it helped get the nice right angles that I wanted, then use some of the 12x20 pine strip for the second bend so that you bend it at the right length. Next trim the three cathodes so you have a couple of mm left to solder, I used finger nail clippers but I would recommend wire cutters if you have them.
Do A Jig
Step 2: Make The Columns
To make a panel you first make eight columns by bluetacking eight LEDs in position as shown in the photo below. Line up each LED to the edge of the board with something flat, then use some pliers to make three straight lengths of wire from your roll. With these three lengths solder the cathodes of the eight LEDs together to complete your column.
Step 2: Make The Panels
When you have 8 columns you are ready to create a panel, turn the columns over and line the top LED up with the edge of the board, tack them in place with bluetack again. You can now trim all 64 LED anodes ready for soldering, straighten another eight pieces of wire and solder the columns together. In this photo the blobs of bluetack give the illusion that the LEDs are not evenly spaced, don't worry they are near perfect.
Step 3: Put It All Together
With your eight panels of 64 LEDs you are now ready to complete the cube, unfortunately this part gets a bit messy. Next time I will rethink this part of the assembly, for now it is all I have to show you but feel free to attempt something different. So I edited my jig slightly and used it to hang the panels from the table ready for soldering. In the picture I have all the panels hanging quite roughly spaced, I actually worked on each panel one at a time soldering as I went. Now here you will see that I ended up with a similar problem to my proof of concept assembly (wires dangling everywhere) this step could definitelly use some improvement but it wasn't all that bad really.
Step 4: Put Down The Soldering Iron
By now you are probably covered in burns and never want to look at a soldering iron again, it's ok just put it down for a while and have a rest. I actually felt sorry for the soldering iron, the one I managed to borrow was older than I am, consequently if you need a decent soldering iron look at a Weller. So your cube is assembled and it looks friken awesome and it is not even turned on yet, I just sat and admired mine while I waited for a new soldering iron tip in the mail.
The Control Board
So up until now I don't think there has been all that much difference between my cube and some others I have seen on the web, but here the design starts to wander off on a different path. Most RGB cubes I have seen rely on
driver boards based about chips that can perform PWM for you like the TLC5940. These chips seem great but im my opinion are just too damn complicated to run, so I decided to stick with the STP16 chips that I knew from my
previous led cube project and I would figure out the PWM in software.
Now I am not going to offer my eagle files like I did for my previous cube because I plan to try and make some money from these cubes at some point (I feel so mean). I also didn't put the schematic in this article because it is so damn big, you can download a high res PDF from here. One mistake to note in the PDF is that the Base and Collectors of the transistors are reversed, hence the mix up with the PCBs later on.
- Scrap that... The gerber files are now available for download on my site, I am still very very slowly working on some form of kit but I have very little time at the moment.
For everyone who feels cheated because you had to make your own PCB, just think of it as a learning experience... -
There are a few differences between this board and the driver for my previous cube, firstly rather than join the 12 chips in one long cascade I created three shorter cascades for the red, green and blue diodes in each LED. The idea here is that I can clock in the red, green and blue data at the same time, reducing the time to load the data into the drivers, hopefully the pictures below give you an idea of what I mean. You will also notice that this time I didn't just pull output enable (OE) to ground, I now control it with a digital IO, this allows me to switch off the drivers when I load in the data which reduces some of the flicker I was getting.
The transistors are also now controlled directly from the digital IO's, this speeds up the refresh process even more. My design focuses on efficiency and speed, though it does mean you will use a few more digital IOs on the chipKIT. You will need 14 spare IOs for the cube, I figure you may as well use them.
I decided to get the boards manufactured for me this time, and I am glad that I did because they turned out beautifully. Initially I ordered a board from batchPcb in America, these guys offer a low cost prototype manufacture but expect to wait about four weeks before you get your boards. I didn't realise when I ordered the boards that they would take so long so I made a second order to a UK company rushPCB, these guys are amazing! they have some insane offer for new customers, 3 boards for 10 quid each with one week turn around, I would definitely recommend checking them out. Somehow the transistors I purchased had a different package to the ones in designSpark so I had to do some nifty bending to get them in place, I think it adds character.
RGB LED Cube Driver Board
Unlike my previous cube I wanted this one to be a completely self contained object, the idea was plug it directly into the wall and it will start producing lovely animations, no PC or external PSU required. So I decided to buy myself
a nice high current PSU I could fit inside the box, now because of the fact that the chipKIT only sports 3.3V IOs, I had to run the cube at 3.3V as I am driving the layers with PNP transistors. Not a problem, except I also wanted to be
able to connect to the chipKIT while running the cube using the usb-serial converter, this requires that the chipkit is powered by 5V through the onboard regulator.
Now lets look at power requirements, as the cube is multiplexed only one layer will ever be on at a certain moment, that is 64 RGB LEDs or 192 diodes. Each diode is going to draw 3.3/100 = 33mA (I = V/R), so if all of the diodes are on at once that is a load of 6.3A! I decided then that I would just avoid any animations that create layers of white (they don't look any good anyway). I ended up sourcing a 25W switch mode power supply for the 5V rail and a 7A 5V-3.3V DC-DC converter for the 3.3V rail, I used double sided tape to attach the DC-DC converter to the side of the switch mode PSU and this is what it looks like.
So the 5V PSU supplies the chipKIT and the DC-DC converter, and the 3.3V PSU supplies the led driver board, don't forget to make sure all of the boards have a common ground and that the power select jumper on the chipKIT is set to reg.
PSU In The Box
Wire It Up
Wire It Up
The box is very similar to the box I built for my previous cube, I used a sheet of ply with 64 holes drilled in it for the base and fed the cathode columns through the holes ready to be wired up. To connect the columns to the driver board
I used lots and lots of ribbon cable, I wont go into all of the details here, I attached idc sockets to one end of the ribbon cables and then soldered the other ends to the cathode column wires (actually that is pretty much all of the details).
I am definitely going to try and rethink this part for next time as it really is a mess, luckily you can not see it, apart from in this photo.
One thing I get a lot of emails about is where all of these wires go, I have painted some pictures to hopefully help you out.
The Wiry Insides
Animations and Code
I'm not sure how this happened, I have not even stared writing the tricky stuff and this article is already huge. Even now that I have begun writing it I still am not really sure how I am going to manage this section, the code and animations
are probably the more complicated concepts in this project. They are also probably the concepts in the highest demand, so I will try and do a good job.
During the research phase of this project I found that there was almost no documentation on how other RGB cubes were animated, most I have seen use the TLC5940 PWM drivers and make reference to some code that must be floating about the Internet. For some reason I am always compelled to do everything my own way even if it is wrong, so here is how I did it.
The chipKIT UNO
The cube is controlled by a chipKIT UNO, a 32bit powerhouse which has quickly become my favorite development board. The board does it all, It multiplexes the cube, It uses Bit Angle Modulation to fade the colours and it generates the animations on the fly. I will go through some of the major parts of the code here and I will also make a reduced version of the code available (remember I want to make money eventually), don't worry what I give you for free will contain a couple of beautiful animations and give you what you need to create your own without too much trouble.
RGB Cube Driver Outputs
Multiplexing and Fading
OK I guess I may as well start at the bottom, quite a lot happens when displaying just a single frame on the cube. Firstly the cube is multiplexed so only one layer is ever on at a moment in time, then each layer is modulated using 8 bit Bit
Angle Modulation (BAM). As you can imagine this requires a fairly fast clock, but before I start talking about the clock rate I will try and help you visualise what is happening with some gifs I made.
Multiplexing is simple enough, all I do is perform all modulations operations one layer at a time, obviously it happens a lot faster on the cube than in the gif.
So to be able to generate a decent range of colours (16.8 million colours) for my effects I use Bit Angle Modulation to fade each diode in each LED. This is a little harder to explain, every time a layer is "on" it is actually just given 8 opportunities to be on, each coloured diode has an associated 8 bit brightness level (or byte). Each layer operation is spit up into 256 interrupts, every 2^nth interrupt the nth brightness bit is loaded into the LED and held until the 2^(n+1)th interrupt when it is replaced. Clear as mud right? hopefully the gif helps, if not well you can trust me it works. This forum post might help you understand BAM, if you read far enough it looks like someone has had some pretty cool ideas on something he coined BAMMAB
Bit Angle Modulation
Interrupt Service Routine
So that is the theory of how I get the animations onto the cube, now I will try and explain some of the code that performs this magic.
So all of the modulation and multiplexing is achieved in my interrupt service routine located in the PDE file, it might seem like I am wasting a lot of time inside my ISR (well I guess I am), but it does what I want so I don't plan on changing it. One thing you may notice about my code is that despite using the chipKIT and the mpide software I did not use any of the Arduino libraries, it is all written from scratch because I needed to squeeze as much out of the chip as possible. I used c++ mostly but had to compile the interrupt service routine in c, that is what all the extern "C" business is about
The line that does all of the work the the ISR is highlighted in green, the layer function loads one bit of one layer onto the cube. Notice it is only called when bit_count is 0, this is what I tried to represent in the gif above.
Here is the layer function which you can find in the cube.cpp file, to speed things up a bit I make use of the PIC's inbuilt LATxSET and LATxCLR registers.
To fill the three cascade chains of STP chips at the same time I check which ones need to be on for the current location and bit and then set them all high
at the same time before I send the CLK pulse.
If you are wondering about the bit shifts (>>16 & >>8) it is because I keep the red, green and blue colour bytes in a 32 bit integer and use the bit shift to get them out i.e. 0x00RRGGBB >> 16 = 0x000000RR. I realise in hindsight that this actually wastes a fair bit of space due to the unused 8 bits in every integer, but that can be a fix for the future.
Create The Colour Wheel
To generate all of the coloured animations I needed a clever way to create the smooth, vibrant colour effect. I was not happy with my first few attempts,
after looking at a colour wheel I realised that my code was picking colours near the centre of the colour wheel which was causing them to appear washed out.]
What I ended up doing is creating a linear array of colours that fade between the three primary colours using sine functions (blue->red->green->blue).
To give you an idea how it looks on a colour wheel I wrote some MATLAB code to demonstrate how my colour array moves around the colour wheel. Creating this MATLAB code and gif probably took longer than the actual colour wheel code for the cube, I hope it wasn't a waste of time. For anyone interested in the MATLAB code I wrote to plot the colours in the gif below you can dowload it here.
Fill The Colour Array
So you have seen it on the colour wheel, now this is how I calculate it. Now this code might look like a horrible mess, but it is beautiful on the inside
and very flexible. I am able to change the length of the colour array or the maximum value of the colours, this might come in handy for anyone using the
TLC5940 which has a 12 bit colour range (I'm just nice like that :P).
Just in case you can not decipher the mess, I will go through one of the more "busy" lines of code so you can see how I use the oscillating sine functions to my advantage. Here I explain line 33 of the above code, blue is a function of phase where maxBitColour = 255 and colourWheelLength = 255 (this works well for my cube).
Colour Wheel Equations
How To Use This Array
Now that there is an array in memory filled with a nice smooth colour transition I had to think how I would use it,
most of my animations select colours from the array based on a looped variable and the location on the cube. Unfortunately
this means I can't always know what position in the array I am accessing, so that I never try to access a location out of the
bounds of the array I wrote a simple function to get colour data from the array safely.
Write Your Own Animations
Well there is quite a lot of code bouncing around to run my RGB cube and I'm sure a few of you would like to have a go at writing your own animations. I have structured the code to be fairly expandable and adaptable, to write your own animations all you have to do is create a new class that inherits from my animation class. "What is this black magic you call inherits" you say? Don't worry it is easy, and this way you can use a whole lot of useful functions and variables I have writen for you to make animating easier.
Step 1: Animation Header File
Firstly I will talk about defining the header file for your animation, c++ uses the header files kind of like a textbook's index for your code (that is how
I understand it anyway). I have highlighted the line in the header below that does the inheriting business (see easy), you do have to write the constructor
and the animate function like I have and you can also write any of your own functions if you need them.
Step 2: Animation Cpp File
Secondly you must write the cpp file for your animation, here you will write what you would actually like the animation to do. An animation is broken up into three stages, the slow stage which you can use to slow down the animation if required, this works by just returning zero and effectively skipping the function call. The second stage is the animation stage where you will create the next frame you want to display on the cube, you create the frame in the temporary array making use of the colour wheel functions and other useful function from my animation class. Finally you ready the frame by copying it into the working array, from here it will be loaded onto the cube the next time the interrupt is called.
Step 3: The PDE File
OK now you have written your amazing new animation you have to add it to the PDE file so that it will actually play on the cube
Firstly you must include the animation in the PDE file.
Next increase the number of animations constant,
Now create a pointer to your animation, take note that you create an "Animation" pointer NOT a "YourAnimation" pointer, this is important for DMA
Finally there are three switch statements that you have to edit for your animation to run correctly.
And you are done! No doubt you will make plenty of mistakes to start off with, I know I did, if you have too much trouble feel free to email me for any advice, otherwise enjoy.
Step 4: Increase The Heap Size
I quickly started to run out of RAM on the chipKIT with the 8x8x8 cube, so I had to first learn and then implement some Dynamic Memory Allocation (DMA).
I also had to increase the default heap size on the chipKIT, now I can't do this step for you so here is what you need to do.
Firstly find the file "chipKIT-UNO32-application-32MX320F128L.ld" in your mpide install directory, it should be buried in the "\hardware\pic32\cores\pic32" folder. Then open the file in notepad and replace the line "PROVIDE(_min_heap_size = 0x800)" with "PROVIDE(_min_heap_size = 0x2000)", that's it. Now you should be able to happily run my code, if you miss this step you won't get any errors, the cube just wont work (it took me a long time to figure out this was why my cube was not working).
Yeh fair enough, if you started to read my attempts at explaining my code but decided you just don't care how it works you can download a reduced version here. This contains three of the animations in my video and all of the code you will need to test your hand at writing your own. Oh and please reference me and my site if you use it in your own projects, it would make me a happy little vegemite.
So if you actually got to the end of the video (it's long I know), you would have seen the video input animations. I am still tossing up how much I want to
give away there, so for now I will just give you some hints. I have written a linux application using the qt creator which can extract pixel data out of
video files using the openCV libraries, honestly it is actually really simple compared to some of the rest of my code, everything you need can be found in
the openCV documentation.
After the code gets the video's pixel data it is just a matter of scaling it to 8x8, sending it to the chipKIT and then performing some transformations to add the 3D effects to the video, easy as pi
The Finished Product!
I think I am actually done.. finally.. I hope you have all enjoyed reading this article a lot more than I enjoyed writing it :P, I can't wait to see what sort
of cubes and animations some of you might create. If there are any gaping holes in the writeup chuck me an email and I will see what I can do, well I can't
think of anything else at the moment so why not watch the video again, thanks for reading..
Mind = Blown
Updated Colour Wheel (March 2013)
While messing about building a new cube I recently discovered that with the latest version of MPIDE the colours from my colour wheel were very washed out and shitty looking. Turns out the sin and cos function included from math.h were not spitting out the right answers. Rather than figure out the problem I decided that I would write some compiler independant functions based on sin and cos approximations. All you need to do is add two functions to the Cube.cpp class.
where DPI = 4/PI and DPI2 = 4/(PI^2) according to a clever approximation I found on the internet here. Just add the following to the Cube.h file.
Finally just replace the instances of sin and cos in the fillColourWheel code with mySin and myCos, and there you have it you should have a nice vibrant cube again. Oh and you should replace the sin and cos functions in the Spiral and Wave animations as well :)
Possible code Issues (April 2013)
I am not sure why, but for some reason my RGB LED cube code will not compile correctly in the latest MPIDE, if you are having trouble just download the 0023-20111221 version of MPIDE and everything should work just fine. I am attempting to figure this out with a shiny new cube that I have built.