LED cube,shift registers and fun.

Ive built a 4x4x4 LED cube, (16 column/4 plane) and wired it up to my uno, using all 20 pins.

The first mistake i made was soldering up the LEDs backwards, but its ok, since I can change it in the programming. I experimented with some programs I found on the interwebs, and got them working nicely (I had to do a lot of swapping LOW with HIGH, and 0s and 1s through out the code, but the cube worked great.

Im currently in the process of upgrading the cube with a couple shift registers. I've looked over schematics and pictures of what others have done, And I've opted to piggyback my shift registers (to keep it a small package thats soldered up to wires, not a pcb). I think I've wired it up right, but i havent hooked it up yet.

Im going from using 20 pins to using 4 for the planes, and 3 for the columns, and 2 for power to the shift registers I have resisters on the planes (220 Ohm).

I noticed on the uno board some pins are PWM, and some are not, I was thinking that if I put the planes on pwm pins, then maybe I can add brightness control to the LEDs. is that a good idea

I also noticed on the uno board there is a 5v, and a 3.3v. pin, should i power the shift registers with the 3.3, and use no resisters?

Im also a bit unsure how im going to convert the programs over to the new way (shift registers), changing the plane pins should be easy, but my guess is the 16 pins to 3 pins is going to be a bit difficult (or not, I dont know...).

I was also thinking that if Im using 16 bits of data at a time, why not store the data as hexidecimal, rather than binary? seems it would take up a lot less storage space in hex.

Hippynerd:
I noticed on the uno board some pins are PWM, and some are not, I was thinking that if I put the planes on pwm pins, then maybe I can add brightness control to the LEDs. is that a good idea

Should work well.

Hippynerd:
I also noticed on the uno board there is a 5v, and a 3.3v. pin, should i power the shift registers with the 3.3, and use no resisters?

No, you should power it from 5v and use resistors. (1) If you use 3.3v, the 5v logic coming out of the Arduino would most likely damage the shift registers. (2) The forward voltage of an LED is usually ~2v, so using 3.3v with no current limiting resistors would most likely destroy the LEDs.

Hippynerd:
I was also thinking that if Im using 16 bits of data at a time, why not store the data as hexidecimal, rather than binary? seems it would take up a lot less storage space in hex.

Why would that save space? All numbers are stored in binary in the Arduino anyway. So for example 0xFF and 0b11111111 are the same number, and both take up 1 byte of RAM.

So, converting bit patterns to hex wouldnt save any space in the arduino? it would make the sketch smaller, so I guess it would save a tiny amount of storage space on my computer, but when uploaded to the arduino, it stores it in its memory in binary?

Thanks for tip on the 5 volt issue with the shift registers... that makes sense.

The LEDs im using were salvaged from some flashlights that I converted to UV. Some of the LEDs were running at 4.5v (3aaa batteries w/no resister), others were running on 4.5v with 100 ohm resister(or so, i cant remember for sure), so my guess is these white LEDs were higher voltage.

I hooked the cube back up, and modified a test program, and have some good results!
I have to modify the software for may common anode cube, but that was fairly easy.

The program I used does acutally store the data in hex, so I had to convert hex to bin, then invert, then convert back to hex. I read somewhere about shift register code that inverts for you, I should read up and figure that one out.

This is my code to sequence through each led.

// This Code was modified for common anode LED setup.
// It was originally 8-bit, but I needed 16 bit for 2 8-bit registers.
// Pin usage (pins 6,7,9,10,11,12,13,gnd,5v)
// PWM pins 6,9,10,11, used for planes 
// Pin 7=Data, 12=Clock, 13=Latch 


int dataPin = 7;
int clockPin = 13;
int latchPin = 12;
int cat[] = {11, 10, 9, 6};  //4 layers

byte data;
 
byte dataArray[16];
 
void setup() {
 
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  for (int i = 0; i < 4; i++)
  {
    pinMode(cat[i], OUTPUT);
    digitalWrite(cat[i], LOW);  
  }

  dataArray[0] = 0x8000; //1000 0000
  dataArray[1] = 0x4000; //0100 0000
  dataArray[2] = 0x2000; //0010 0000
  dataArray[3] = 0x1000; //0001 0000
  dataArray[4] = 0x0800; //0000 1000
  dataArray[5] = 0x0400; //0000 0100
  dataArray[6] = 0x0200; //0000 0010
  dataArray[7] = 0x0100; //0000 0001
  dataArray[8] = 0x0080; //1000 0000
  dataArray[9] = 0x0040; //0100 0000
  dataArray[10] = 0x0020; //0010 0000
  dataArray[11] = 0x0010; //0001 0000
  dataArray[12] = 0x0008; //0000 1000
  dataArray[13] = 0x0004; //0000 0100
  dataArray[14] = 0x0002; //0000 0010
  dataArray[15] = 0x0001; //0000 0001
 
  
}

void onebyone()
{
  for (int i = 0; i < 4; i++)
  {
    for (int j = 0; j < 16; j++)
    {
      digitalWrite(cat[i], HIGH);
      
     data = dataArray[j];
 
    //ground latchPin and hold HIGH for as long as you are transmitting
 
    digitalWrite(latchPin, 0);
    //move 'em out
 
    shiftOut(dataPin, clockPin, data);
    //return the latch pin LOW to signal chip that it
    //no longer needs to listen for information
    digitalWrite(latchPin, 1);
    delay(10);
 
  delay(10);
  
  delay(100);
  digitalWrite(cat[i], LOW);
    }
    }
}

void loop()
{
onebyone();
}
 
// the heart of the program
void shiftOut(int dataPin, int clockPin, byte dataOut) {
  // This shifts 8 bits out MSB first,
  //on the rising edge of the clock,
  //clock idles HIGH
 
  //internal function setup
  int i=0;
  int pinState;
 
  //for each bit in the byte myDataOut?
  //NOTICE THAT WE ARE COUNTING DOWN in our for loop
  //This means that %00000001 or "1" will go through such
  //that it will be pin Q0 that lights.
  for (i=7; i>0; i--)
  {
    digitalWrite(clockPin, 0);
 
    //if the value passed to myDataOut and a bitmask result
    // true then... so if we are at i=6 and our value is
    // %11010100 it would the code compares it to %01000000
    // and proceeds to set pinState to 1.
    if (dataOut & (1<<i))
    {
      pinState= 0;
    }
    else
    {
      pinState= 1;
    }
 
    //Sets the pin to LOW or HIGH depending on pinState
    digitalWrite(dataPin, pinState);
    //register shifts bits on upstroke of clock pin
    digitalWrite(clockPin, 1);
  }
}

Hi Hippynerd,

Any chance of some video ? 8) Here is a link to my 3 x 3 x 3 cube (first cube attempt, no shift registers)

Pedro

Hey Pedro, I havnt made any videos yet. I should do a quick little one showing this sequence.

I kinda like that music, pretty groovy. I also notice you have your video listed in category autos.

I started doing some bit programming when my cube had no shift registers, but I never made any videos, and now those programs wont work until I modify them.

I'll probably post some video after I get some more programs working for it, hopefully soon.

I've gone through the code to fix some things, and I notice that I have clock and latch backwards, but when I change it to how it should be, it doenst work right. :frowning:

// This Code was modified for common anode LED setup.
// It was originally 8-bit, but I needed 16 bit for 2 8-bit registers.
// Pin usage (pins 6,7,9,10,11,12,13,gnd,5v)
// PWM pins 6,9,10,11, used for planes 
// Pin 7=Data, 12=Clock, 13=Latch 


int dataPin = 7; // Pin 14 on 74hc595 (ds)
int clockPin = 13; // Pin 12 on 74hc595 (st_cp)
int latchPin = 12; // Pin 11 on 74hc595 (sh_cp)
int cat[] = {11, 10, 9, 6};  //4 layers

byte data;
 
byte dataArray[16];
 
void setup() {
 
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  for (int i = 0; i < 4; i++)
  {
    pinMode(cat[i], OUTPUT);
    digitalWrite(cat[i], LOW);  
  }

  dataArray[0] = 0x8000; //1000 0000
  dataArray[1] = 0x4000; //0100 0000
  dataArray[2] = 0x2000; //0010 0000
  dataArray[3] = 0x1000; //0001 0000
  dataArray[4] = 0x0800; //0000 1000
  dataArray[5] = 0x0400; //0000 0100
  dataArray[6] = 0x0200; //0000 0010
  dataArray[7] = 0x0100; //0000 0001
  dataArray[8] = 0x0080; //1000 0000
  dataArray[9] = 0x0040; //0100 0000
  dataArray[10] = 0x0020; //0010 0000
  dataArray[11] = 0x0010; //0001 0000
  dataArray[12] = 0x0008; //0000 1000
  dataArray[13] = 0x0004; //0000 0100
  dataArray[14] = 0x0002; //0000 0010
  dataArray[15] = 0x0001; //0000 0001
 
  
}

void onebyone()
{
  for (int i = 0; i < 4; i++)
  {
    for (int j = 0; j < 16; j++)
    {
      digitalWrite(cat[i], HIGH);
      
     data = dataArray[j];
 
    //ground latchPin and hold HIGH for as long as you are transmitting
 
    digitalWrite(latchPin, LOW);
    //move 'em out
 
    shiftOut(dataPin, clockPin, data);
    //return the latch pin LOW to signal chip that it
    //no longer needs to listen for information
    digitalWrite(latchPin, HIGH);
    delay(10);
 
  delay(10);
  
  delay(100);
  digitalWrite(cat[i], LOW);
    }
    }
}

void loop()
{
onebyone();
}
 
// the heart of the program
void shiftOut(int dataPin, int clockPin, byte dataOut) {
  // This shifts 16 bits out MSB first,
  //on the rising edge of the clock,
  //clock idles HIGH
 
  //internal function setup
  int i=0;
  int pinState;
 
  //for each bit in the byte myDataOut?
  //NOTICE THAT WE ARE COUNTING DOWN in our for loop
  //This means that %00000001 or "1" will go through such
  //that it will be pin Q0 that lights.
  for (i=15; i>0; i--)
  {
    digitalWrite(clockPin, LOW);
 
    //if the value passed to myDataOut and a bitmask result
    // true then... so if we are at i=6 and our value is
    // %11010100 it would the code compares it to %01000000
    // and proceeds to set pinState to 1.
    if (dataOut & (1<<i))
    {
      pinState= 0;
    }
    else
    {
      pinState= 1;
    }
 
    //Sets the pin to LOW or HIGH depending on pinState
    digitalWrite(dataPin, pinState);
    //register shifts bits on upstroke of clock pin
    digitalWrite(clockPin, HIGH);
  }
}

I finally got this working right! I ended up doubling the array (and lots of other things) to get it working right.

Ive made a bunch of bit patterns using my old program (when the cube used 20 pins), now I have to figure out how to make that program work with shiftout, or make this program use my bit data, or make a new program based a little on both programs.

// This program runs a 4x4x4 LED cube with 2 shift registers. 
// Data is stored as bytes (2 bytes per layer, 4 layers)
// The program lights up each LED, one at a time, in a sequence.
// Questions? hippynurd@gmail.com 

int dataPin = 7; //Data
int clockPin = 12; // Clock
int latchPin = 13; // Latch
int cat[] = {11, 10, 9,  6};  //4 layer pins

byte data1; 
byte data2; 
byte dataArray1[16];
byte dataArray2[16];
 
void setup() {
 
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  for (int i = 0; i < 4; i++)
  {
    pinMode(cat[i], OUTPUT);
    digitalWrite(cat[i], LOW); // Inverted for common anode 
  }
// Data: Its currently stored as single bytes, but I want double
// bytes (16bit), This uses 2 arrays for each layer of 16 LEDs.

  //Using Hex decimal
  dataArray1[0] = 0x80; //1000 0000
  dataArray1[1] = 0x40; //0100 0000
  dataArray1[2] = 0x20; //0010 0000
  dataArray1[3] = 0x10; //0001 0000
  dataArray1[4] = 0x08; //0000 1000
  dataArray1[5] = 0x04; //0000 0100
  dataArray1[6] = 0x02; //0000 0010
  dataArray1[7] = 0x01; //0000 0001
  dataArray1[8] = 0x00; //1000 0000
  dataArray1[9] = 0x00; //0100 0000
  dataArray1[10] = 0x00; //0010 0000
  dataArray1[11] = 0x00; //0001 0000
  dataArray1[12] = 0x00; //0000 1000
  dataArray1[13] = 0x00; //0000 0100
  dataArray1[14] = 0x00; //0000 0010
  dataArray1[15] = 0x00; //0000 0001
  dataArray2[0] = 0x00; //1000 0000
  dataArray2[1] = 0x00; //0100 0000
  dataArray2[2] = 0x00; //0010 0000
  dataArray2[3] = 0x00; //0001 0000
  dataArray2[4] = 0x00; //0000 1000
  dataArray2[5] = 0x00; //0000 0100
  dataArray2[6] = 0x00; //0000 0010
  dataArray2[7] = 0x00; //0000 0001
  dataArray2[8] = 0x80; //1000 0000
  dataArray2[9] = 0x40; //0100 0000
  dataArray2[10] = 0x20; //0010 0000
  dataArray2[11] = 0x10; //0001 0000
  dataArray2[12] = 0x08; //0000 1000
  dataArray2[13] = 0x04; //0000 0100
  dataArray2[14] = 0x02; //0000 0010
  dataArray2[15] = 0x01; //0000 0001


}

void onebyone()
{
  for (int i = 0; i < 4; i++)
  {
    for (int j = 0; j < 16; j++)
    {
      digitalWrite(cat[i], HIGH);  // Inverted  for common anode
      
     data1 = dataArray1[j];
     data2 = dataArray2[j];
 
    //ground latchPin and hold low for as long as you are transmitting
 
    digitalWrite(latchPin, 0);
    //move 'em out
 
    shiftOut(dataPin, clockPin, data1);
    shiftOut(dataPin, clockPin, data2);
    //return the latch pin high to signal chip that it
    //no longer needs to listen for information
    digitalWrite(latchPin, 1);
    delay(100);
 
  delay(100);
  
  delay(100);
  digitalWrite(cat[i], LOW);   // Inverted for common anode
    }
    }
}

void loop()
{
onebyone();
}
 
// the heart of the program
void shiftOut(int dataPin, int clockPin, byte dataOut) {
  // This shifts 8 bits out MSB first,
  //on the rising edge of the clock,
  //clock idles low
 
  //internal function setup
  int i=0;
  int pinState;
 
  //for each bit in the byte myDataOut?
  //NOTICE THAT WE ARE COUNTING DOWN in our for loop
  //This means that %00000001 or "1" will go through such
  //that it will be pin Q0 that lights.
  for (i=7; i>0; i--)
  {
    digitalWrite(clockPin, 0);
 
    //if the value passed to myDataOut and a bitmask result
    // true then... so if we are at i=6 and our value is
    // %11010100 it would the code compares it to %01000000
    // and proceeds to set pinState to 1.
    if (dataOut & (1<<i))
    {
      pinState= 0;  // Inverted for common anode
    }
    else
    {
      pinState= 1;  // Inverted for common anode
    }
 
    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(dataPin, pinState); // this is where data is sent to the shift register.
    //register shifts bits on upstroke of clock pin
    digitalWrite(clockPin, 1);
  }
}

Im trying to get the old 4x4x4 program working with the new cube (I modded the program to work with my common anode cube), and it was working fine, till I converted the cube over to shift registers.

Here is what im working on:

#include <avr/pgmspace.h> // alHIGHs use of PROGMEM 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 100 // 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
// Common anode, so we send plane pin high, and column pin low to light.


// 1= off, 0=on
// First group of each block is the right plane
// first 4 groups of 4 character blocks is bottom plane second is second layer, ...
// first character in segment is front plane


//Collumn spin Clockwise 360
B0111,B1011,B1101,B1110,B0111,B1011,B1101,B1110,B0111,B1011,B1101,B1110,B0111,B1011,B1101,B1110,01,
B1111,B0011,B1100,B1111,B1111,B0011,B1100,B1111,B1111,B0011,B1100,B1111,B1111,B0011,B1100,B1111,01,
B1111,B1100,B0011,B1111,B1111,B1100,B0011,B1111,B1111,B1100,B0011,B1111,B1111,B1100,B0011,B1111,01,
B1110,B1101,B1011,B0111,B1110,B1101,B1011,B0111,B1110,B1101,B1011,B0111,B1110,B1101,B1011,B0111,01,

B1101,B1101,B1011,B1011,B1101,B1101,B1011,B1011,B1101,B1101,B1011,B1011,B1101,B1101,B1011,B1011,01,
B1011,B1011,B1101,B1101,B1011,B1011,B1101,B1101,B1011,B1011,B1101,B1101,B1011,B1011,B1101,B1101,01,




// 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[] = {11, 10, 9, 6};
int dataPin = 7; //Data  I added these for Shift Register
int clockPin = 12; // Clock 
int latchPin = 13; // Latch

// initialization
void setup()
{
int pin; // loop counter
// set up LED pins as output (active LOW)
//for (pin=0; pin<PLANESIZE; pin++) {
//  pinMode( LEDPin[pin], OUTPUT ); Edited out because we dont use them pins
// setup Shift Register pins instead of 16 arduino pins.
{
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}
// set up plane pins as outputs (active HIGH)
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], LOW );
} else {
digitalWrite( PlanePin[plane-1], LOW );
}

// load current plane pattern data into ports
// Plane pins are taken care of above, this routine handles the 16
// LED pins(columns), originally 16 pins are now going to 2 shift registers
// using dataPin, clockPin, latchPin. 
/* Original code
ledpin = 0;
for (ledrow=0; ledrow<CUBESIZE; ledrow++) {
for (ledcol=0; ledcol<CUBESIZE; ledcol++) {
digitalWrite( LEDPin[ledpin++], PatternBuf[patbufidx] & (1 << ledcol) );
}
patbufidx++;
}
*/
// hrm. gotta figure out how to jamb 2 bytes of patternbuf
shiftOut( dataPin, clockPin, PatternBuf[patbufidx]);
shiftOut( dataPin, clockPin, PatternBuf[patbufidx+1]);
}
//patbufidx++; //tying to pass 2 8bits, instead of 16 bits)
}


// turn current plane on HIGH in my case of common anode.
digitalWrite( PlanePin[plane], HIGH );
// delay PLANETIME us
delayMicroseconds( PLANETIME );
} // for plane
} // while <EndTime
} while (DisplayTime > 0); // read patterns until time=0 which signals end
}

void shiftOut(int dataPin, int clockPin, byte dataOut) {
 // we add shiftout to move bits out pin 7 instead of the 16 pins
 // previously used.
  // This shifts 8 bits out MSB first,
  //on the rising edge of the clock,
  //clock idles low
 // Somehow, gotta get
  //internal function setup
  int i=0;
  int pinState;
 
  //for each bit in the byte myDataOut?
  //NOTICE THAT WE ARE COUNTING DOWN in our for loop
  //This means that %00000001 or "1" will go through such
  //that it will be pin Q0 that lights.
  for (i=7; i>0; i--)
  {
    digitalWrite(clockPin, 0);
 
    //if the value passed to myDataOut and a bitmask result
    // true then... so if we are at i=6 and our value is
    // %11010100 it would the code compares it to %01000000
    // and proceeds to set pinState to 1.
    if (dataOut & (1<<i))
    {
      pinState= 0;  // Inverted for common anode
    }
    else
    {
      pinState= 1;  // Inverted for common anode
    }
 
    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(dataPin, pinState); // this is where data is sent to the shift register.
    //register shifts bits on upstroke of clock pin
    digitalWrite(clockPin, 1);
  }
}

I've taken the shiftout that I have working (from the previous post). put it in the 4x4x4 cube code, and am trying to convert the bit that turns the pins on (was pins 0-15) to serialize the data to the shift registers.

I think what this does is takes 2 8bit fields of data, and send them to the individual 16 pins (LEDPin(), but what I need is that data sent to the shift registers.

Original code:

ledpin = 0;
for (ledrow=0; ledrow<CUBESIZE; ledrow++) {
for (ledcol=0; ledcol<CUBESIZE; ledcol++) {
digitalWrite( LEDPin[ledpin++], PatternBuf[patbufidx] & (1 << ledcol) );
}
patbufidx++;
}

Heres my mess of code that doesnt work.

// hrm. gotta figure out how to jamb 2 bytes of patternbuf
shiftOut( dataPin, clockPin, PatternBuf[patbufidx]);
shiftOut( dataPin, clockPin, PatternBuf[patbufidx+1]);
}
//patbufidx++; //tying to pass 2 bytes, instead of 16 bits)
}

It gives me this error:
PatternsSR.cpp: In function ‘void loop()’:
PatternsSR.cpp:137:1: error: expected ‘while’ before ‘}’ token
PatternsSR.cpp:137:1: error: expected ‘(’ before ‘}’ token
PatternsSR.cpp:137:1: error: expected primary-expression before ‘}’ token
PatternsSR.cpp:137:1: error: expected ‘)’ before ‘}’ token
PatternsSR.cpp:137:1: error: expected ‘;’ before ‘}’ token
PatternsSR.cpp: At global scope:
PatternsSR.cpp:138:1: error: expected declaration before ‘}’ token

This is line 137:
void shiftOut(int dataPin, int clockPin, byte dataOut) {

I could use some help, I think its close to working, but I think maybe im missing something obvious.

I finally got it working right!!!
I only have a tiny snippet of data for testing purposes, but it looks like its going to work!

#include <avr/pgmspace.h> // alHIGHs use of PROGMEM 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 100 // 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
// Common anode, so we send plane pin high, and column pin low to light.


// 1= off, 0=on
// First group of each block is the right plane
// first 4 groups of 4 character blocks is bottom plane second is second layer, ...
// first character in segment is front plane


//Collumn spin Clockwise 360
B0111,B1011,B1101,B1110,B0111,B1011,B1101,B1110,B0111,B1011,B1101,B1110,B0111,B1011,B1101,B1110,01,
B1111,B0011,B1100,B1111,B1111,B0011,B1100,B1111,B1111,B0011,B1100,B1111,B1111,B0011,B1100,B1111,01,
B1111,B1100,B0011,B1111,B1111,B1100,B0011,B1111,B1111,B1100,B0011,B1111,B1111,B1100,B0011,B1111,01,
B1110,B1101,B1011,B0111,B1110,B1101,B1011,B0111,B1110,B1101,B1011,B0111,B1110,B1101,B1011,B0111,01,

B1101,B1101,B1011,B1011,B1101,B1101,B1011,B1011,B1101,B1101,B1011,B1011,B1101,B1101,B1011,B1011,01,
B1011,B1011,B1101,B1101,B1011,B1011,B1101,B1101,B1011,B1011,B1101,B1101,B1011,B1011,B1101,B1101,01,




// 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[] = {11, 10, 9, 6};
int dataPin = 7; //Data  I added these for Shift Register
int clockPin = 12; // Clock 
int latchPin = 13; // Latch

// initialization
void setup()
{
int pin; // loop counter
// set up LED pins as output (active LOW)
//for (pin=0; pin<PLANESIZE; pin++) {
//  pinMode( LEDPin[pin], OUTPUT ); Edited out because we dont use them pins
// setup Shift Register pins instead of 16 arduino pins.
{
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}
// set up plane pins as outputs (active HIGH)
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
int pinState;

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

// load current plane pattern data into ports
// Plane pins are taken care of above, this routine handles the 16
// LED pins(columns), originally 16 pins are now going to 2 shift registers
// using dataPin, clockPin, latchPin. 
// Original code
//ledpin = 0;
//for (ledrow=0; ledrow<CUBESIZE; ledrow++) {
//for (ledcol=0; ledcol<CUBESIZE; ledcol++) {
//digitalWrite( LEDPin[ledpin++], PatternBuf[patbufidx] & (1 << ledcol) );
//}
//patbufidx++;
//}

// I used code from shiftout, to redo this to serialize the plane data

    digitalWrite(latchPin, 0);
    //move 'em out
ledpin = 0;
for (ledrow=0; ledrow<CUBESIZE; ledrow++) {
for (ledcol=0; ledcol<CUBESIZE; ledcol++) {
  
 digitalWrite(clockPin, 0);
   
// digitalWrite( dataPin, PatternBuf[patbufidx] & (1 << ledcol) );
if (PatternBuf[patbufidx] & (1 << ledcol))
    {
      pinState= 1;  // Inverted for common anode
    }
    else
    {
      pinState= 0;  // Inverted for common anode
    }
 
    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(dataPin, pinState); // this is where data is sent to the shift register.
    //register shifts bits on upstroke of clock pin
    digitalWrite(clockPin, 1);

ledpin++;
}
patbufidx++;
}
    digitalWrite(latchPin, 1);

// turn current plane on HIGH in my case of common anode.
digitalWrite( PlanePin[plane], HIGH );
// delay PLANETIME us
delayMicroseconds( PLANETIME );
} // for plane
} // while <EndTime
} while (DisplayTime > 0); // read patterns until time=0 which signals end
}

Yes Hippynerd,

that's a neat bit of code that I also used after I found it somewhere online. Looks like your doing a good job modifying it to allow for shift registers (I'm certainly not that clever yet :disappointed_relieved: ) Keep up the good work and still waiting for that video clip

Pedro.

Thanks Pedro :smiley:
Im just happy that it works, converting it to serial for the shift registers was harder than I thought it was going to be, but it was worth it because now I can use the spare pins for switches, and a speaker.

I'll try to get a video up today. I dont have a lot of data for the cube yet, so it will be a short video.

space.h> // alHIGHs use of PROGMEM to st

Lol, someone did Find and Replace of 'LOW' :wink:

Yep, All the programs I've tried are for common cathode, and my cube is common anode. I actually had to replace LOW with GGG, HIGH with LOW, then GGG with HIGH. Some programs I was able to get working by doing a similar thing with 0s and 1s.

Pedro147:
Yes Hippynerd,

that's a neat bit of code that I also used after I found it somewhere online. Looks like your doing a good job modifying it to allow for shift registers (I'm certainly not that clever yet :disappointed_relieved: ) Keep up the good work and still waiting for that video clip

Pedro.

Heres the video!

Bonus video, finding buried treasure for the microcontroller junkie.

The display board looks like it does serial transfer for IR data/button data, and for display data. I've taken some buttons off for my next experiments.

The laser diode and caddy could be fun, I have to figure out how and what all the wires do.

The I think the power supply does 24/12/5v. The display board/front panel wants 24v

The motors might be useful for POV projects. I might also be able to use the laser diode caddy for POV projects

Thanks for the upload, I always like to see a bit of cube action 8) and good work on recycling the guts of that trashed DVD player... always love a few free parts,

Pedro.

I just found a datasheet on the driver/controller for the display

It also turns out the that board has 2 16meg memory chips, but I wasnt able to find out anything about the other chips on that board.

It would be neat to store 16 megs of data, and make the display scroll information or something.

I also found that the board has print next to the wires, which make things easier, they are:
INIR
VCC
Data In
CLK
STB
Data Out

So, I know its a TOPRO tp6312 chip, and I know what wires are what, how do I figure out how to make it display stuff?

I made a fritzing image for a schematic.
I never made a breadboard, my shift registers are piggybacked, and soldered to wires from an old ribbon cable that has SIP header pins plugged into the connecter, to connect to the arduinos connector. and a couple scrap wires connected to pins to provide + and GND to the shift registers.