4 x 4 x 4 LED Cube with Shift Registers

After having previously built a 3 x 3 x 3 LED cube and controlling it via nine anode pins (columns) and three cathode pins (levels) - I hope that makes sense, I am now trying to design a 4 x 4 x 4 cube using two 74HC595 shift registers for the sixteen LED’s of the planes and either four transistors or a 595 / ULN2803 combination for the levels. Initially I have constructed a 4 x 4 matrix with the sixteen cathodes in series with each other and all connected to ground and each of the sixteen SR outputs consecutively connected to the sixteen LED anodes. i.e. daisy chained.

I have been using shiftOut and trying different coding techniques to control the matrix. I have tried -

  1. one dimensional arrays with for loops
  2. two dimensional arrays
  3. bit shifting right and left through bytes
  4. declaring functions that access two dimensional arrays

I have tried having both shift registers clock, latch and data lines connected in parallel but found it too limiting as the two halves of the matrix obviously displayed the same pattern so therefore I am having them daisy chained.

I suppose I am just asking for suggestions as to how other people have approached coding when using SR’s with small cubes like this. Here is a sample of the types of coding I have been trying so far. Not very exciting I know but I’m all out of ideas. With hindsight, maybe this is not a practical way to use SR’s to control a cube, and I haven’t even thought too much about level control yet, vis-à-vis coding. Any suggestions would be greatly appreciated, Pedro.

// EXAMPLE 1
  
  int dataPin = 8;    // connect to pin 14 of the SR     
  int clockPin = 12;  // connect to pin 11 of the SR 
  int latchPin = 11;  // connect to pin 12 of the SR 
  int digit[] = {B10000000,B01000000,B00100000,B00010000,B00001000,B00000100,B00000010,B00000001,};  
  						
  void setup()
  {
      pinMode(dataPin, OUTPUT);      
      pinMode(latchPin, OUTPUT);
      pinMode(clockPin, OUTPUT);
  }
  
  void loop()
  {
      for (int x = 0; x < 7; x++)        
      {
          digitalWrite(latchPin, LOW);            
          shiftOut(dataPin, clockPin, LSBFIRST, digit [x]);          
          digitalWrite(latchPin, HIGH);
          delay(1000);
        
      }
  }
 
 ////////////////////////////////////////////////////////////////
 
 // EXAMPLE 2
 
int pinMatrix[4][4] = {{B10000000,B01000000,B00100000,B00010000},
                       {B00001000,B01000100,B00100010,B00010001},
                       {B10000001,B01000010,B00100100,B00011000},
                       {B11000000,B01100110,B10011001,B00011000}};
  void loop()
    { 
      digitalWrite(latchPin, LOW);            
      shiftOut(dataPin, clockPin, LSBFIRST,pinMatrix[3][2] );
      digitalWrite(latchPin, HIGH);           
      delay(1000);                   

 /////////////////////////////////////////////////////////////////

 // EXAMPLE 3
 
 int pinMatrix[4][4] = {{B10000000,B01000000,B00100000,B00010000},
                        {B00001000,B01000100,B00100010,B00010001},
                        {B10000001,B01000010,B00100100,B00011000},
                        {B11111001,B10011111,B11111111,B00000000}};
                       
 void loop()
    { 
     inner();
     delay(100);
     outer();
     delay(100); 
      
    } 
void inner()
{
      digitalWrite(latchPin, LOW);            
      shiftOut(dataPin, clockPin, LSBFIRST,pinMatrix[3][2] );
      digitalWrite(latchPin, HIGH);           
      delay(100);
}

void outer()
{
      digitalWrite(latchPin, LOW);            
      shiftOut(dataPin, clockPin, LSBFIRST,pinMatrix[3][3] );
      digitalWrite(latchPin, HIGH);           
      delay(100);
}


 /////////////////////////////////////////////////////////////////

 // EXAMPLE 4

int digit = B10000000;

void loop()
  {
      for (int x = 0; x < 7; x++)        
      {
          digitalWrite(latchPin, LOW);            
          shiftOut(dataPin, clockPin, LSBFIRST, digit >> x);          
          digitalWrite(latchPin, HIGH);
          delay(1000);
        
      }
  }

Thats prettymuch how I did mine. After I converted mine to use shift registers (it was originally directly connected, and only used one resistor per plane. It was very few parts, but it used all the io pins.

Converting it to shift registers mean that I went from lighting 1 led at a time, to lighting 16 LEDs at a time. which means you really need to add 4 transistors (one for each plane) to handle the current from 16 LEDs.

I think that the original program that I used was modified from a 3x3x3 code to 4x4x4 before I got it. When i upgraded the cube to use shift registers, I modified that program to use stuff from shift out.

Ive since modified that program to work on my new cube (transistor cube), but its still a bit buggy.

I've attached the program, you are welcome to do whatever you like with it. I think this version is setup for common cathode, you may need to modify a few things for it to work with your cube.

_4Cubed_CC_pde.pde (21.2 KB)

Well, originally I was using a couple arrays for my animations as well. However I quikcly ran out of memory, so I tried the progmem function. It went a little better, but after a couple of more arrays the cube became glitchy and buggy as well. So my conclusion, you can't use any large number of arrays in the code and possibly 1 large array like hippynerd has the same problems.

Thank you for replying Hippynerd and WonderTiger. I will have a look through both your codes and see what I can pick up from them.
Interesting to see your use of direct port manipulation WonderTiger. Thanks again to both of you.

If you are not looking to change brightness of each LED individually, you can use MAX7219, but this will limit your design in the future if you decide to do that.

Thanks mkjzz,
yes I have played around with Max7219 and 8 x 8 matrices, but I would have a good long hard think about how to use them for a cube, but well worth thinking about, thanks for your suggestion
Pedro.

MAX7219 would be a neat trick for 4x4x4 cube. Perhaps wire 1/2 of each plane as a digit.

Well you can also adjust the brightness via my given code. The code I gave you was a bit easier (because its easier to understand without the brightness control)then Im using, because I can also change the brightness of the leds(in the first 5 seconds I use brightness control to let my cube flash): - YouTube

CrossRoads:
MAX7219 would be a neat trick for 4x4x4 cube. Perhaps wire 1/2 of each plane as a digit.

In theory it could drive all the LEDs in the cube, the wiring would be tricky though.

I have been having a goggle, and I found this 4 x 4 x 4 LED cube using a picaxe microcontroller. I'm not sure if this could be adopted to Arduino but it looks interesting. Anybody up for a conversion 8)

Pedro147:
I have been having a goggle, and I found this 4 x 4 x 4 LED cube using a picaxe microcontroller. I'm not sure if this could be adopted to Arduino but it looks interesting. Anybody up for a conversion 8)

4x4x4 LED Cube using 08M2 and MAX7219 | PICAXE Forum

That is cool!

If we think of 4x4x4 as 64 LEDs and think in rows and columns, build a layer of abstraction in software that turns rows and columns into x, y, z, we might have something going :slight_smile:

Then, from 4x4x4 as building block, we can build a much more complicated cubes, or something like 4x4x8, etc.

I couldnt download the schematic to see how that cube is built, but from the description, it sounds like how most cubes are made in planar fashion, but each plane is split in half (8 groups of 8 LEDs).

Its not as hard to build as you might think. My transistor cube breaks up plane into 4 lines, if you did the same thing, only connected 2 lines together on each side, you have the same thing as he is describing (2 lines of 4 LEDs is 1/2 plane).

In the picture below you can see 16 LEDs that are made up of 4 lines of 4 LEDs. 4 of these make one 4x4x4 cube. Im using RGB LEDs, but you could do the same thing with single color LEDs.

If you connect 2 of these lines together, you make 1/2 plane. You could connect them horizontally, or vertically, either way should work.

Come to think of it, if MAX7219 is used, each plane needs 10 wires, 8 for anodes, 2 for common cathodes. For next plane, the 8 anodes wire can be wired together, only the 2 common cathode wires need to be separate.

So maybe wiring isn't that bad at all . . . no resistors, 7 more of it, we got a 8x8x8 cube with 8 MAX7219s

Exactly. Just need each 4x4x4 seperated electrically from the others.