Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Netduino Controlled LED Cube

Commercial LED cubes have been around for a while now and can be quite large and capable of some interesting displays. This project is on a smaller scale and goes through the steps required to build a Netduino Mini-controlled 512 LED cube (8 x 8 x 8).

Clearly, the Mini does not have 512 pins and so we use Persistence of Vision to control the LEDs in the cube. The result is that seven pins on the Netduino Mini can control 512 LEDs.

At the end of this article you should be able to create a cube capable of the following:

Bill of Materials

Description

Quantity

LEDs (I chose blue)

512

74HC595 Shift Registers

8

74HC238 3 to 8 line decoder

1

Netduino Mini

1

16 Pin DIL Socket (0.3")

9

24 Pin DIL Socket (0.6")

1

TIP122 NPN Transistor

8

100nF Ceramic Capacitor

10

2.2K Resistor

8

68 Ohm 0.25W Resistor (you may need to change these depending upon the LED you choose)

64

8 Way Single Row Socket

9

36 Way Header Strip (Straight)

3

2 Way Single Row Socket

2

2 Way PCB Mount Terminal Connector

1

8 Way Cable (ribbon or alarm)

2.5m

Wire

Miscellaneous

Pad board 160 x 115 Hole

1

Hex PCB spacer and screw (M3 threaded)

4

 

The following items are also required:

  • 5V Power capable of delivering 2A
  • Solder (I used about 15 metres over the life of this project).
  • One 30cm x 30cm piece of wood
  • Drill and wood drill bits (4mm – 5mm)
  • Some cardboard and tape
  • A fair amount of patience
  • Good attention to detail

You may need to shop around for the LEDs. I went to my preferred supplier and was quoted 18.5 pence each. By going on eBay I managed to negotiate the price down to 2.5 pence each including delivery. You are buying in bulk so don’t be afraid to ask for a good bulk price. Also, buy a few more than you need in case you have a faulty part or break a few.

Building the Cube

This is probably the most time consuming part of the project requiring a lot of patience and testing. The aim of the project is to convert these 512 blue LEDs:

image

Into this:

image

Shaping the LEDs

The exact dimensions of the cube depend upon the length of the legs on the LEDs. The legs are soldered together with the cathodes of the LEDs forming a horizontal plane and the anodes vertically connecting the layers. Each of the layers are configured into a common cathode display.

Take one of the LEDs and bend the cathode at a point as close to the body of the LED as possible. The cathode should be at 90 degrees to the anode and parallel to the flat base of the LED. This allows the horizontal legs to be soldered together to form the common cathode.

Shaping the anode is a little more difficult. The anodes connect the horizontal layers and so need to be shaped to ensure that each LED in the layer is directly above the corresponding LED in the layer below. Otherwise, each layer will be slightly offset from the one beneath it.

To achieve this, bend the anode in the opposite direction as described for the cathode. Then, still working with the anode, start about 2mm along the leg. Finally, bend the top 2-3mm through and fashion an angle at 90 degrees pointing back to the LED body. The end result should look like this:

image

The horizontal leg is the cathode and the vertical leg is the anode. When these are connected it should look like this:

imageimage

Notice how the shaped anode allows the LEDs to be placed above each other.

Now repeat this process for the remaining 511 LEDs.

Building a Layer

Our next task is to connect the LEDs together. This is best achieved by using a template for the individual layers. Use a piece of wood with a grid of holes drilled into it as the template.

Measure the distance from the center of the now horizontal cathode to the end of the leg and subtract about 2mm. This will tell you how far apart the LEDs are in the horizontal plane. The 2mm will be used to overlap with the neighboring LED and will connect the cathodes. Now drill an 8 x 8grid of holes, each of which are distance of your choosing apart.  Here they are 20mm apart.

image

The holes need to be large enough to hold the LEDs securely but should not be so small that the LEDs are wedged into the hole and difficult to remove.

Take eight of the LEDs and place them along the top row with the cathodes all pointing to either the right or the left. If all are pointing to the right, the cathodes of seven LEDs will overlap slightly with the next LED to the right. The rightmost cathode will go off into space. Solder the cathodes together.

image

Now let’s add the remaining LEDs in the layer. I started on the left because I hold the soldering iron in my right hand. Take another seven LEDs and place these under the top row and down the far left column. The cathode of each first LED should overlap the cathode of the LED in the top layer. Solder these together.

image

Repeat with the remaining columns. At this point, you should have a horizontal row of LEDs connected together with eight strings of seven LEDs hanging from it. Eventually you should have something looking like this:

image

Now test the layer using a power supply and current limiting resistor. A 5V supply and a 68 Ohm resistor are adequate. Ground the cathode of the LED pointing off into space. Now touch each leg of the LEDs in turn with the positive output of the supply (through the current limiting resistor, of course). Each LED should light up and as you touch the anode.

One final bit of soldering is needed to add a stiffening wire to the layer. Cut and strip a piece of wire. The wire should be long enough to cross the entire layer. Place the stripped wire on the cathodes of the LEDs at the bottom of the string and solder it on to each.

At this point you will have one complete layer. Remove the layer from the template. This should be done carefully so that you do not put too much stress on the joints. Gently lifting it up with a screwdriver should help. Don’t hurry. Put this layer to one side and repeat another seven times.

Connecting the Layers - The Cube Appears

Now that all of the layers are built, test them again. This repeated test may save you future pain. Just imagine how difficult it will be to fix a bad joint in the middle of the cube. Check that the LEDs are still connected and none of the joints were broken when layers were removed from the template.

Now drop one of the layers back into the template. What we now need to do is to place a second layer on top of the first so that the anodes of the layer in the template touch the anodes of the LEDs in the upper layer. Once in place, we need to solder the anodes together, and so need a way of supporting the top layer whilst connecting the LEDs. A strip of cardboard can accomplish this. Cut the cardboard into strips (making sure the cardboard is the height needed to support the layer) and bind the strips together with tape. Two of these strips should be enough to support the layer. Here’s how it looked when several layers had already been connected:

image

Now that you have the layer supported, solder the anode of each LED in the top layer to the anode of the corresponding LED in the layer directly beneath it. Once this has been done, test each LED. Connect the cathode of the bottom layer to ground and touch each of the legs on the top layer in turn with the positive supply (going through the current limiting resistor). The LED on the bottom layer should light up. Repeat for each LED in the layer. Move the cathode to the top layer and repeat the test—this time the LED on the top layer should light. Again, repeat for each LED in the layer.

Now add the remaining layers. Just for safety, test every layer in the cube as it is built up. This repeated testing sounds like a big pain, but trust me it's worth it. At this point you will have a cube of LEDs looking something like this:

image

Now trim the cathodes that are still flying off into space.

Building the Controller Board

The controller board will allow any of the 512 LEDs in the cube to be turned on by a Netduino Mini using only seven pins.

Persistence of Vision

Connecting the anode to a positive supply while grounding the layer in which the LED is located can turn on any LED. You can also do this with more than one LED in a layer, and so within a layer can turn on 0 to 64 LEDs. To light the entire cube, we need to switch on each layer in turn while doing so fast enough to give the impression of static image. This is where the principle of Persistence of Vision comes into play.

The basic algorithm is as follows:

  • Layer = 0
  • Repeat
    • Connect the anodes of the desired LEDs in Layer to positive supply
    • Connect Layer to ground (this turns the layer on)
  • Move to next Layer

If we do this fast enough, the human eye will see a single image as when watching TV or a movie.

Our basic building blocks for the controller are as follows:

  • Microcontroller (a Netduino Mini) to run the whole show
  • Hardware to select the layer to be turned on (74HC238 and TIP122 transistors)
  • Hardware to turn on the LEDs (Shift registers)

Shift Registers

The shift registers determine which LEDs are turned on. The board has a series of eight cascaded 74HC595 registers. This allows us to control 64 LEDs (8 chips x 8 outputs). The following schematic shows how two of these registers should be wired together:

image

The above should be repeated until you have eight shift registers cascaded.

The output from the register is 5V and will give more than enough power to burn out an LED, so we need to put a current limiting resistor in the circuit. A 68 Ohm resistor is required for the LEDs in this project—make sure you verify the value you choose against the LEDs used.

Putting this together gives the following layout:

image

Each socket holds a 74HC595 shift register. The connections are identical for each register with the data cascaded into the next register. So if we look at the bottom left socket you will see the following:

  • Below the socket there is a connector that allows the output to be connected to the LEDs in the cube.
  • Above the connector are the resistors that limit the current flowing through the LEDs.
  • The socket above that will hold the 74HC595 shift register.
  • To the left of the socket is a 100nF capacitor. This smooths out the power supplied to the shift register and is connected between the power input and ground and placed as close to the IC as possible.

The following colors have been used:

  • Red = Power
  • Blue = SPI and cascaded data
  • Yellow = RCK
  • White = SPI clock

Note that the connectors and current limiting resistor are slightly offset as output 0 is on pin 15 and this is routed on the underside of the board. The remaining connections are a direct one to one path from the pin to the resistor/connector.

The microcontroller uses the Serial Peripheral Interface (SPI) bus to tell the shift registers which LED to turn on. The data from the registers is cascaded and so we can store 64 bits of information (1 bit for each LED in a layer). With logic 1 turning a particular LED on and 0 turns the LED off.

Layer Switching

The layer switching logic allows the controller to connect any one of the layers to ground (using a common cathode). Coupling this with the LED selection logic above allows us to turn on any one of the LEDs in the cube. This is achieved by using a transistor as a switch. The TIP122 was selected because it is capable of sinking 2A. This may seem like a lot considering the 25mA for each LED, but remember that we potentially have 64 LEDs being turned on at once. This means we may be drawing 1.6A of current. If you use a different LED, you will need to verify that the shift registers, power supply, and the transistor are capable of dealing with the amount of power you will be drawing.

The schematic for the layer switching looks like this:

image

The 74HC238 has three input signals. These represent a binary number 0-7. The chip converts this number into eight output lines. 0 turns on line 0, 1 turns on line 1 etc. The output from each line (0 through 7) is then fed in the base of a TIP122 transistor. This turns on the appropriate layer by connecting the layer through to ground.

One line for the Netduino Mini controls enable line on the 72HC238 chip. This allows us to turn all of the outputs off whilst a new value is being loaded into the chip. This line is used to make sure that the transitions between the states are “invisible.” Without this there is the chance that the viewer may see a flickering effect when new values are loaded into both the 74HC595s and the 74HC238.

The Completed Controller Board

The completed controller board looks something like this:

image

Note that there are a pair of connectors to the top right and bottom left of the Netduino Mini. The pair at the top right breakout the COM1 port. The two at the bottom left allow grounding of an FTDI lead (connected to the controller board) and also one socket that is not connected. This allows the 5V lead on the FTDI connector to have a place to live and not be in danger of touching something it shouldn’t.

And on the underside:

image

Connecting the Cube and Controller

The final task (from a hardware point of view) is to connect the cube to the controller board. I tried both ribbon cable and alarm cable. The alarm cable was a little more difficult to connect but was flexible. The ribbon cable was easier to work with but was not as flexible. The principle is the same whichever you chose.

Place the cube on a flat surface (the anodes touching the surface) with one face of the cube facing you. The connections should be made so that the lower back left corner is co-ordinate (0, 0, 0). The co-ordinates increase moving to the right, towards you and up. So looking at the controller board above, shift register 0 connects to the LEDs farthest away from you with output 0 from the register connecting to the LED to the far left. Cut and make the 8 cables according to this pattern varying the lengths to suit the location of the controller board with respect to the cube. Each cable will need a single eight-way socket on one end with the other end connected to the appropriate LED.

The layer selection logic should be connected using a similar cable. Each layer should be connected to a TIP122 with layer 0 being the bottom layer.

The cube will then look like this:

image

Connecting it up to the controller:

image

I found it easier to be consistent and wire each plug and LED identically, and so all of the connections above have a black wire to the right of the connector. It helps with connecting things up later.

If we have everything connected then we only need one more thing...

Software

The software running the cube needs to perform two main tasks:

  • Work out which LEDs are turned on
  • Run the display (cube)

These two tasks need to be performed at the same time (or so fast that they appear to run at the same time). Luckily the .NET Micro Framework has a built in mechanism to allow us to do this—threading. Threading allows us to do this by running two tasks interleaved. So task 1 will run for a while, the system will then switch and run task 2 for a while, then back to task 1 and so on.

To do this, the software is split into two parts, the main program that decides what to display and a separate class that runs the display.

LEDCube Class

This class has only one purpose in life, to output data to the controller board and so “run” the display. It is a relatively simple class containing the following methods:

  • Constructor
  • Buffer update method
  • Display Buffer method

The constructor sets everything up by instantiating an instance of the SPI class and setting the buffer (which contains the data to be displayed) to be empty, effectively clearing the cube:

public LEDCube()
{
    config = new SPI.Configuration(SPI_mod: SPI.SPI_module.SPI1,
                                   ChipSelect_Port: Pins.GPIO_PIN_20,
                                   ChipSelect_ActiveState: false,
                                   ChipSelect_SetupTime: 0,
                                   ChipSelect_HoldTime: 0,
                                   Clock_IdleState: true,
                                   Clock_Edge: true,
                                   Clock_RateKHz: 100);    spi = new SPI(config);
    buffer = new byte[64];
    for (int index = 0; index < buffer.Length; index++)
    {
        buffer[index] = 0;
    }
}

The buffer is 64 bytes of data, 8 rows of 8 bytes. Each byte corresponds to a vertical layer in the cube.

The UpdateBuffer method allows the calling program to change what is displayed in the cube. A little control is needed here to ensure that the pattern displayed in the cube is consistent, and so locking is used to ensure that the buffer cannot be updated part way through a display cycle:

public void UpdateBuffer(byte[] newValues)
{
    lock (buffer)
    {
        for (int index = 0; index < buffer.Length; index++)
        {
            buffer[index] = newValues[index];
        }
    }
} 

The final method in this class is the method spawned off into it’s own thread:

public void DisplayBuffer()
{
    while (true)
    {
        lock (buffer)
        {
            byte[] displayData = new byte[8];            for (int row = 0; row < 8; row++)
            {
                int offset = row * 8;                for (int index = 0; index < 8; index++)
                {
                    displayData[index] = buffer[offset + index];
                }                enable.Write(true);
                bit0.Write((row & 1) != 0);
                bit1.Write((row & 2) != 0);
                bit2.Write((row & 4) != 0);
                spi.Write(displayData);
                enable.Write(false);
            }
        }
    }
}

This method again uses the lock statement to lock the buffer. This means we cannot update the buffer until a full cube of data has been displayed. The method takes a block of eight bytes representing a layer and then writes this to the shift registers using SPI. Note that the spi.Write is embedded in the write to the enable line. This ensures that all of the layers are turned off whilst we are updating the shift registers.

Wrapping all of this in the LEDCube class means that we now have a very simple class where we can spawn the DislpayBuffer method into its own thread.

Main Program

The main program sets the cube up and then controls what is actually shown in the cube. The first thing we need to do is to set up a buffer to store the cube display and then spawn off the DisplayBuffer into its own thread.

private static LEDCube cube = new LEDCube();
private static byte[] newFrame = new byte[64];
ClearCube();
Cube.UpdateBuffer(newFrame);
Thread display = new Thread(new ThreadStart(cube.DisplayBuffer));
display.Start(); 

The ClearCube method is trivial and simply sets all of the bytes in newFrame to zero. At this point we have a cube with a whole lot of nothing going on. The next thing we need to do is to add some effects.

Making it Rain

Now that we have the mechanism to control the cube, we simply need to work out what we want to display. The rain effect in the opening video illustrates the majority of the techniques used to control the cube.

The rain algorithm is as follows:

  • Set up the cube with a number of rain drops
  • Repeat
    • Count the drops in the bottom layer
    • Move drops down one layer
    • Add the number of drops that have disappeared back into the top layer

To do this we will create two methods:

  • AddDrops
  • Rain

private static void AddDrops(int count, int plane = -1)
{
    for (int drops = 0; drops < count; drops++)
    {
        bool findingSpace = true;
        while (findingSpace)
        {
            int x = rand.Next() % 8;
            int y = rand.Next() % 8;
            int z;            if (plane == -1)
            {
                z = rand.Next() % 8;
            }
            else
            {
                z = plane;
            }            int position = (z * 8) + y;
            byte value = (byte) ((1 << x) & 0xff);
            if ((newFrame[position] & value) == 0)
            {
                newFrame[position] |= value;
                findingSpace = false;
            }
        }
    }
}

AddDrops simply adds a specified number of rain drops to the buffer. It also makes sure that if asked for 10 it will always add 10 by checking to see if one exists in the location it wanted to use (check out the findingSpace variable):

private static void Rain(int noDrops, int cycles)
{
    ClearCube();
    AddDrops(noDrops);
    cube.UpdateBuffer(newFrame);
    for (int currentCycle = 0; currentCycle < cycles; currentCycle++)
    {
        int bitCount = 0;
        for (int plane = 0; plane < 8; plane++)
        {
            byte value = 1;
            for (int bit = 0; bit < 8; bit++)
            {
                if ((newFrame[56 + plane] & value) > 0)
                {
                    bitCount++;
                }
                value <<= 1;
            }
        }
        for (int plane = 7; plane > 0; plane--)
        {
            for (int currentByte = 0; currentByte < 8; currentByte++)
            {
                newFrame[(plane * 8) + currentByte] = newFrame[((plane - 1) * 8) + currentByte];
            }
        }
        for (int b = 0; b < 8; b++)
        {
            newFrame[b] = 0;
        }
        AddDrops(bitCount, 0);
        cube.UpdateBuffer(newFrame);
        Thread.Sleep(75);
    }
}

Rain adds the specified number of drops to the newFrame, shows the drops, and then moves them all down by one horizontal plane. Before doing this, it counts how many drops are going to fall out of the cube (the number in the bottom horizontal plane). After all the drops have moved down one plane it adds the drops which have disappeared out of the bottom of the cube back in at the top in random positions.

We can display this by adding the following to the main program:

while (true)
{
    Rain(10, 60000);
} 

Full source code at http://netduinoledcontrol.codeplex.com/.

If you add your own effects, remember to consider the rating of the equipment and parts used. Turning on a full horizontal layer consumes 1.6A for the LEDs alone. Things can get warm/hot if every LED in the cube is turned on at the same time so avoid such effects.

Conclusion

When I started out on this project I was not sure how fast the Netduino Mini could control the cube. It has proven that it is up to the task of keeping the display running whilst also being able to work on the upcoming “frame.” If you have gone this far and built a cube then how about expanding it:

  • Add some filters and a microphone and make the display respond to its environment
  • Connect the cube to a PC using Bluetooth
  • Add an MP3 player module and write software to synchronise the display to the music

Where will you take it?

About The Author

Mark Stevens is a software engineer and self-confessed technology addict. Mark started in the computer industry in the 1980s and at the age of 16 wrote a disk operating system for a then state of the art 8-bit microprocessor (despite the fact the machine already had one). He did it for fun and has been hooked on IT ever since then. Mark currently writes line of business applications for Win32, ASP.NET, and Silverlight platforms. He has recently taken up microelectronics as a hobby and has since discovered that his wife does not like the smell of solder. Marks’ current exploits, thoughts, and contact information can be found on his blog.

 

Tags:

Follow the Discussion

  • @awsomedevsignerilija injac Ilija Injac

    That's amazing! I love this thing! Will you sell one?

  • Clint RutkasClint I'm a "developer"

    @ilija injac: we have all the instructions to build it yourself!

  • Pedro LamasPedro Lamas Pedro Lamas

    I have to tell you, I really like this one! Smiley

  • Great work Mark.

  • new2STLnew2STL xkcd.com

    Long, long time ago (when I still had a lot of hair ...) I made a 10x10 matrix of LED's, but sir, you pwned! Gread work!Cool

  • Impressive. Most impressive.

  • Thanks for all of the positive comments.  It really was fun to do.

    Regards,
    Mark

  • This so cool I started building one of these 2 weeks ago and figured I would build the cube then look for a way to get it working great timing THANKS!

  • IanIan

    Great work! What size LEDs did you use - 5mm or 8mm? What did the total size of your cube end up being? I built a 3x3x3 last week using 3mm LEDs I had in stock. Now I really want something bigger!

    BTW, You have my dream job...

  • Masini InchirieriMasini Inchirieri

    Now imagine the cube loaded in the trunk of a car and connected to a BBS Amplifier. That would be like so extreme <a href="http://www.inchirieriauto.com">:)</a>

  • @Ian: I used 5mm LEDs and this gave me a cube which was 16 cm along each edge.  There is a little bit of play in the dimensions as you are manually shaping the legs.

  • PatriciaPatricia

    Hola, muy buen proyecto, me pregunto si funcionará igual con una tarjeta netduino de tamaño normal y en que varían las terminales, ojalá pueda contestarme, Gracias

  • [quote]

    Hello, very good project, I wonder if it will work like a normal sizedcard netduino and varying terminals, hopefully I can answer, Thanks

  • @PatyTo: Yes it will work with both the standard Netduino and the Netduino Plus.  In fact the original code was developed on the Netduino Plus.  I moved to the Mini as the Mini could be embedded in the project easily.

    Regards,
    Mark

  • PeterPeter

    Sorry but i am about to build the led cube myself and just looked at your circuit and noticed that you connected the active low pin to VCC, the clock to ground and didnt use a lot of the neccessary pins at all????

  • EricEric

    Inspring project! I am in the process of building the cube myself and I got confused by the Netduino mini pinning names as they do not match the pinning I got from the netduino mini schematics. The diagram I got from the open source project lists names such as PWM0 for the IO. You are using GPIO7. Is PWM0 the same as GPIO7?

  • Genius!!!!! ^.^ 

  • bossmanbossman

    Sell one? You dumbass, this explains how to make it!

  • Blogger BontangBloggerbont​ang Komunitas Blogger Bontang

    Good Job n Amazing work ,... I really like this one!

  • NinethSenseNinethSense

    Its cool. I am jealous.

  • kalravkalrav

    Can you give me a prat no from http://in.rsdelivers.com

  • SpeedySpeedy

    This is an awesome project! I have made the cube and working on the controller board. I am planning on hooking it up to a netduino, not the mini. Is there anything that needs to be changed in order for the program to work? After looking at the schematics, the pins do not match up exactly. Could you tell me which pins on the mini you connected the 74HC595s and the 74HC238 to? Thank you!

  • keyurkeyur

    these great job done by u, very nice, i like it.
    please send me complete program code of 8x8x8 led cube in speedy. because my in a some error occurs. which type of software you used in led cube? plz tell me. fast reply......

  • AlexAlex

    Nice. But 74HC595 max rated at 70mA, isn't it? So, 70*8=0.56A per layer, 8.75mA per led. But you have made with 25mA per led. Hmm?!. Where am I wrong?

  • suprasupra

    Can I used 74HC154 instead of 74HC238?

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.