0

3x3x3 cube
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

3x3x3 cube

by bcook65 on Fri Sep 24, 2010 3:06 pm

A while back I had built a 3x3x3 cube using the minipov kit.. is there a for/next loop I can use to repeat any given line in the image table x number of times before it goes to next line?
{ 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 15000 }, ( in know this is wrong but for I=1 to 50, next I)
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 15000 }, ( in know this is wrong but for I=1 to 50, next I)
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },

If so, what would it look like and where would it be placed in the table.
I had found there is definitely a limit on how large an image table can be and hoping this would allow me to get more bang for my buck and allow me to do more varied animations...

just in case you ask, the full code is below

(Edit - moderator - please use the code box when submitting large amounts of code)
Code: Select all | TOGGLE FULL SIZE
/*
LEDcube
Firmware
for use with ATtiny2313
27-August-07

Distributed under Creative Commons 2.5 -- Attib & Share Alike
*/

/*
This test firmware lights up each LED for 1/2 second, starting with the top-front-left corner LED,
and going to the bottom-rear-right corner LED.
*/

/*
to program the ATtiny2313, execute the following two commands:
make ledcube.hex
make program-ledcube
*/


#include // this contains all the IO port definitions
#include // definitions for interrupts
#include // definitions for power-down modes
#include // definitions or keeping constants in program memory


/*
The hardware for this project is as follows:
ATtiny2313 has 20 pins:
pin 1 connects to serial port programming circuitry
pin 2 PD0 - ground for top plane of 3x3 LEDs
pin 3 PD1 - ground for middle plane of 3x3 LEDs
pin 6 PD2 - ground for bottom plane of 3x3 LEDs
pin 7 PD3 - +V for lower-left LED of each plane
pin 10 ground
pin 12 PB0 - +V for upper-right LED of each plane
pin 13 PB1 - +V for upper-middle LED of each plane
pin 14 PB2 - +V for upper-right LED of each plane
pin 15 PB3 - +V for middle-right LED of each plane
pin 16 PB4 - +V for midle-middle LED of each plane
pin 17 PB5 - +V for middle-right LED of each plane -- also connects to serial port programming circuitry
pin 18 PB6 - +V for lower-right LED of each plane -- also connects to serial port programming circuitry
pin 19 PB7 - +V for lower-middle LED of each plane -- also connects to serial port programming circuitry
pin 20 +3v
All other pins are unused

This firmware requires that the clock frequency of the ATtiny
is the default that it is shipped with: 8.0MHz internal oscillator
*/


/*
The C compiler creates code that will transfer all constants into RAM when the microcontroller
resets. Since this firmware has a table (brainwaveTab) that is too large to transfer into RAM,
the C compiler needs to be told to keep it in program memory space. This is accomplished by
the macro PROGMEM (this is used, below, in the definition for the brainwaveTab). Since the
C compiler assumes that constants are in RAM, rather than in program memory, when accessing
the brainwaveTab, we need to use the pgm_read_byte() and pgm_read_dword() macros, and we need
to use the brainwveTab as an address, i.e., precede it with "&". For example, to access
imageTab[3].topRow0, which is a byte, this is how to do it:
pgm_read_byte( &imageTab[3].topRow0 );
And to access imageTab[3].imageDuration, which is a double-word, this is how to do it:
pgm_read_dword( &imageTab[3].imageDuration );
*/


// table of values for 3x3x3 LEDs
// 0 is off, 1 is on for each LED
// last element must have 0 duration
struct imageElement {
unsigned char topRow0;
unsigned char midRow0;
unsigned char botRow0;
unsigned char topRow1;
unsigned char midRow1;
unsigned char botRow1;
unsigned char topRow2;
unsigned char midRow2;
unsigned char botRow2;
unsigned long int imageDuration; // Duration for this element to be displayed before going to next element (divide by 10,000 to get seconds)
} const imageTab[] PROGMEM = {

// flash cube on and off
{ 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },

// four corners
{ 0b101, 0b000, 0b101, 0b000, 0b010, 0b000, 0b101, 0b000, 0b101, 25000 },
{ 0b000, 0b000, 0b000, 0b000, 0b010, 0b000, 0b000, 0b000, 0b000, 25000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 25000 },
{ 0b101, 0b000, 0b101, 0b000, 0b010, 0b000, 0b101, 0b000, 0b101, 25000 },
{ 0b000, 0b000, 0b000, 0b000, 0b010, 0b000, 0b000, 0b000, 0b000, 25000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 25000 },

// makezine code
{ 0b000, 0b000, 0b000, 0b000, 0b010, 0b000, 0b000, 0b000, 0b000, 25000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 50000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b100, 30000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 30000 },
{ 0b111, 0b111, 0b111, 0b111, 0b101, 0b111, 0b111, 0b111, 0b111, 30000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 30000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b100, 30000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 20000 },
{ 0b111, 0b111, 0b111, 0b111, 0b101, 0b111, 0b111, 0b111, 0b111, 20000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 20000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b100, 20000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 20000 },
{ 0b111, 0b111, 0b111, 0b111, 0b101, 0b111, 0b111, 0b111, 0b111, 10000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 10000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b100, 10000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 10000 },
{ 0b111, 0b111, 0b111, 0b111, 0b101, 0b111, 0b111, 0b111, 0b111, 10000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 25000 },

// diamond
{ 0b010, 0b101, 0b010, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b101, 0b000, 0b101, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b010, 0b101, 0b010, 15000 },
{ 0b000, 0b000, 0b000, 0b010, 0b101, 0b010, 0b000, 0b000, 0b000, 15000 },

{ 0b010, 0b101, 0b010, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b101, 0b000, 0b101, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b010, 0b101, 0b010, 15000 },
{ 0b000, 0b000, 0b000, 0b010, 0b101, 0b010, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
// light up the layers in succession
{ 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 15000 },
{ 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 15000 },
{ 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },

{ 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 15000 },
{ 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 15000 },
{ 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },

{ 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 15000 },
{ 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 15000 },
{ 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },

{ 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 15000 },
{ 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 15000 },
{ 0b111, 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 0b000, 15000 },
{ 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 15000 },
{ 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 15000 },

// spin cross plane 1
{ 0b000, 0b010, 0b000, 0b000, 0b111, 0b000, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b100, 0b010, 0b001, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b001, 0b010, 0b100, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b000, 0b111, 0b000, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b100, 0b010, 0b001, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b001, 0b010, 0b100, 0b000, 0b010, 0b000, 10000 },
// spin cross plane 2
{ 0b000, 0b010, 0b000, 0b000, 0b111, 0b000, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b100, 0b010, 0b001, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b001, 0b010, 0b100, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b000, 0b111, 0b000, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b100, 0b010, 0b001, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b001, 0b010, 0b100, 0b000, 0b010, 0b000, 10000 },

{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b100, 0b000, 0b010, 0b010, 0b010, 0b000, 0b001, 0b000, 10000 },
{ 0b000, 0b000, 0b000, 0b010, 0b111, 0b010, 0b000, 0b000, 0b000, 10000 },
{ 0b000, 0b001, 0b000, 0b010, 0b010, 0b010, 0b000, 0b110, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },

{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b100, 0b000, 0b010, 0b010, 0b010, 0b000, 0b001, 0b000, 10000 },
{ 0b000, 0b000, 0b000, 0b010, 0b111, 0b010, 0b000, 0b000, 0b000, 10000 },
{ 0b000, 0b001, 0b000, 0b010, 0b010, 0b010, 0b000, 0b110, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },

{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b100, 0b000, 0b010, 0b010, 0b010, 0b000, 0b001, 0b000, 10000 },
{ 0b000, 0b000, 0b000, 0b010, 0b111, 0b010, 0b000, 0b000, 0b000, 10000 },
{ 0b000, 0b001, 0b000, 0b010, 0b010, 0b010, 0b000, 0b110, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },

{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0 }, // this is a dummy element for end of table (duration=0)
};


// This function delays the specified number of 1/10 milliseconds
void delay_one_tenth_ms(unsigned long int ms) {
unsigned long int timer;
const unsigned long int DelayCount=87; // this value was determined by trial and error

while (ms != 0) {
// Toggling PD6 is done here to force the compiler to do this loop, rather than optimize it away
for (timer=0; timer <= DelayCount; timer++) {PIND |= 0b01000000;};
ms--;
}
}


// This function displays a 3x3x3 image by multiplexing through the images for the 3 planes.
// The multiplex rate is about 111Hz.
// This function also acts as a delay for the Duration specified.
void displayImage(int index) {
unsigned long int duration = pgm_read_dword( &imageTab[index].imageDuration );
for (int i=0; i<(duration/(90*3*2)); i++) {
PORTB |= pgm_read_byte( &imageTab[index].topRow0 ) | (pgm_read_byte( &imageTab[index].midRow0 )<<3 ) | (pgm_read_byte( &imageTab[index].botRow0 )<<6 );
PORTD |= ( ( pgm_read_byte( &imageTab[index].botRow0 ) & 0b100 ) ) << 1;
PORTD &= ~(1<<PD0); // turn on top plane
delay_one_tenth_ms(30);
PORTD |= (1<<PD0); // turn off top plane
PORTB &= ~( pgm_read_byte( &imageTab[index].topRow0 ) | (pgm_read_byte( &imageTab[index].midRow0 )<<3 ) | (pgm_read_byte( &imageTab[index].botRow0 )<<6 ) );
PORTD &= ~( ( ( pgm_read_byte( &imageTab[index].botRow0 ) & 0b100 ) ) << 1);

PORTB |= pgm_read_byte( &imageTab[index].topRow1 ) | (pgm_read_byte( &imageTab[index].midRow1 )<<3 ) | (pgm_read_byte( &imageTab[index].botRow1 )<<6 );
PORTD |= ( ( pgm_read_byte( &imageTab[index].botRow1 ) & 0b100 ) ) << 1;
PORTD &= ~(1<<PD1); // turn on middle plane
delay_one_tenth_ms(30);
PORTD |= (1<<PD1); // turn off middle plane
PORTB &= ~( pgm_read_byte( &imageTab[index].topRow1 ) | (pgm_read_byte( &imageTab[index].midRow1 )<<3 ) | (pgm_read_byte( &imageTab[index].botRow1 )<<6 ) );
PORTD &= ~( ( ( pgm_read_byte( &imageTab[index].botRow1 ) & 0b100 ) ) << 1);

PORTB |= pgm_read_byte( &imageTab[index].topRow2 ) | (pgm_read_byte( &imageTab[index].midRow2 )<<3 ) | (pgm_read_byte( &imageTab[index].botRow2 )<<6 );
PORTD |= ( ( pgm_read_byte( &imageTab[index].botRow2 ) & 0b100 ) ) << 1;
PORTD &= ~(1<<PD2); // turn on bottom plane
delay_one_tenth_ms(30);
PORTD |= (1<<PD2); // turn off bottom plane
PORTB &= ~( pgm_read_byte( &imageTab[index].topRow2 ) | (pgm_read_byte( &imageTab[index].midRow2 )<<3 ) | (pgm_read_byte( &imageTab[index].botRow2 )<<6 ) );
PORTD &= ~( ( ( pgm_read_byte( &imageTab[index].botRow2 ) & 0b100 ) ) << 1);
}
}


int main(void) {
int j ;
DDRB = 0xFF; // set all PortB pins as outputs
DDRD = 0x7F; // set all PortD pins as outputs
PORTB = 0x00; // all PORTB output pins Off
PORTD = 0b00000111; // PORTD3 output pin Off, PORTD2 and PORTD1 and PORTD0 on (grounds)


// loop through entire Image Table of Image Elements
// each Image Element consists of a 3 planes of 3x3 LED (each LED on or off) data and a Duration
for (;;) {
j = 0;
do {
displayImage(j);
j++;
} while (pgm_read_byte(&imageTab[j].imageDuration) != 0); // 0 signifies end of table
}

// Shut down everything and put the CPU to sleep
MCUCR |= 0b00100000; // SE=1 (bit 5)
MCUCR |= 0b00010000; // SM1:0=01 to enable Power Down Sleep Mode (bits 6, 4)
delay_one_tenth_ms(10000); // wait 1 second
PORTB = 0x00; // turn off all PORTB outputs
PORTD = 0x00; // turn off all PORTD outputs
DDRB = 0x00; // make PORTB all inputs
DDRD = 0x00; // make PORTD all inputs
sleep_cpu(); // put CPU into Power Down Sleep Mode
}



Hope that makes sense
thanks
Bill
BCook65
Electricity is your friend and your friend needs a hug... :O

bcook65
 
Posts: 108
Joined: Sat Apr 03, 2010 1:25 pm

Re: 3x3x3 cube

by mtbf0 on Fri Sep 24, 2010 5:58 pm

that's not supported in the code for the 3x3 cube. take a look at my cootie cage project for an idea of how it might be done. since only the low order 3 bits are used for the leds, any byte with a value greater than seven could be interpreted as a command. keep in mind, though, that every time you add code to implement a new feature, you reduce the amount of memory available for your patterns. only 2k available for the whole shooting match. atmel now makes an attiny4313 which is a 4k version of the 2313, but the only guy that has them for sale is selling them on ebay in the uk. soon as mouser or digikey has stock i'll be getting some. love to hack my minipovs.

good luck.
"i want to lead a dissipate existence, play scratchy records and enjoy my decline" - iggy pop, i need more
User avatar
mtbf0
 
Posts: 1645
Joined: Sat Nov 10, 2007 12:59 am
Location: oakland ca

Re: 3x3x3 cube

by bcook65 on Fri Sep 24, 2010 10:16 pm

code view.. wow.. they think of everything..lol
BCook65
Electricity is your friend and your friend needs a hug... :O

bcook65
 
Posts: 108
Joined: Sat Apr 03, 2010 1:25 pm

Please be positive and constructive with your questions and comments.