74HC595 - Bi Colored LED Cube Question

Hello kind people,

I have recently started putting together a bi-colored LED cube. I will be using 4-cascaded '595s to control the 32 anode bunches and 4 arduino pins to directly control the layers through 4 NPN transistors.

My question is about the shiftOut() function. I understand that if i push 16-bit value into two cascaded 595s the first register will simply push the excess values into the second. Could someone please tell me is this holds true for 32-bit values as well? Moreover would shifting this long a value take too long and kill the POV effect?

Would it be better to use 4 seperate output pins for the 4 registers?

Also, I had initially planned to use sets of 4 32-bit long values stored in an array for the patterns and load them on the cube one layer at a time.

Would much appreciate if someone could tell me if this is a viable approach?

If you need to shift data fast, the software-bitbang shiftOut() function is not recommended.

Using the hardware-spi of the chip is actually quite simple. There is a library for that as well if you don't want to do deal with register setup.

thank you madworm...could you please guide me to an appropriate starting point for this?

There is example code in the IDE.

thank you.....

apologies for the naivety but i am a lil new at this. Could some one please advise what datamode should i use for using the SPI library with the 74HC595?

The defaults should work.

You can safely play with MSB / LSB and the clock divider.

Hello kind people,

I have had good luck with fabricating the controller for my 4x4x4 bi-colored led cube with some really helpful inputs from here. While the actual cube is still to be made I wanted to give the code a thought. My set up is:

1.64 common cathode bi colored LEDs stacked in 4x4x4 form with layers sharing common cathodes and columns sharing anodes. So I have 4 ground pins and 32 anode pins (16x2)

2.I have daisy chained 4 74HC595s to be able to drive the anodes using discrete high side switches and 4 2N2222s driven straight from the Arduino for the layers

There is a fairly popular code that I found online and have used before for my single colored cube:

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

#define CUBESIZE 4
#define PLANESIZE CUBESIZE*CUBESIZE
#define PLANETIME 3333 // time each plane is displayed in us -> 100 Hz refresh
#define TIMECONST 20 // 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[] = {
  // blink on and off

  B0001,B0000,B0000,B0000,B0001,B0000,B0000,B0000,B0000,B0000,B0000,B0000,B0000,B0000,B0000,B0000,10,
 
  // this is a dummy element for end of table (duration=0) aka !!!DO NOT TOUCH!!!
  B0000, B0000, B0000, B0000, B0000, B0000, B0000, B0000, B0000, B0000, B0000, B0000, B0000, B0000, B0000, B0000, 0
};

/*
** 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
 ** Note that analog inputs 0-5 are also digital outputs 14-19!
 ** Pin DigitalOut0 (serial RX) and AnalogIn5 are left open for future apps
 */

int LEDPin[] = {
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
int PlanePin[] = {
  16, 17, 18, 19};

// 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], HIGH );
        } 
        else {
          digitalWrite( PlanePin[plane-1], HIGH );
        }

        // 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], LOW );
        // delay PLANETIME us
        delayMicroseconds( PLANETIME );
      } // for plane
    } // while <EndTime
  } 
  while (DisplayTime > 0); // read patterns until time=0 which signals end
}

While I broadly understand the code I have a few specific questions so that I can modify it to be able to work on my shift registered setup:

1.In the line memcpy_P( PatternBuf, PatternTable+PatternIdx, PLANESIZE ) is the entire 16 bit value copied into the PatternBuf array?
2.If yes, then can someone please explain to me how are these 16 bits being loaded individually onto the output ports?
3.If the answer to the previous question is digitalWrite( LEDPin[ledpin++], PatternBuf[patbufidx] & (1 << ledcol) ); then I would really be grateful if someone could explain this to me.

My idea is to be able to modify the code to use 4 32-bit values (each representing one layer) and load them on the shift registers using SPI similar to what the line of code in #3 is doing (if I understand correctly). However, I am not sure if this approach makes sense. I would really appreciate if someone could help me out and point me in the right direction.

Also if this approach is practical then can someone give me an example about how can I modify the part of the code that loads data individually using digitalWrite() to use the SPI.transfer()