/* cube */ #define LAYERs 4 #define COLs 4 #define ROWs 4 /* global variable definitions */ unsigned char LEDs[LAYERs][COLs * ROWs]; unsigned char pwmpos = 0; // actual step of the PWM unsigned char layer = 1; // actual controlled layer /* * cmp_carry_shift_left compares the two parameters * which results in the carry bit to be set/unset * that carry bit is rotated into para_io * the complete function consumes only 2 cycles */ static inline unsigned char cmp_carry_shift_left ( unsigned char para_io, unsigned char cmp_para_1, unsigned char cmp_para_2 ) { asm volatile ( // compare the parameters // (get the carry flag set/unset) "cp %r[cmp2], %r[cmp1]" "\n\t" // rotate carry bit into paramter "rol %r[out]" "\n\t" // output operand : [out] "+r" (para_io) // input operands : [in] "r" (para_io), [cmp1] "r" (cmp_para_1), [cmp2] "r" (cmp_para_2) ); return para_io; } /* * The timer3 overflow interrupt routine builds the pin states * to be output. the actual output is done in the beginning * (of the next execution) of the routine to achieve a more * constant time behaviour */ ISR ( SIG_OVERFLOW3 ) { static unsigned char porta, portc, portf; PORTB = 0x80; // turn on pin B7 for measuring the time consumption PORTA = porta; // turn on the pins of PORTA and B in resull of PORTC = portc; // the previous cycles outcome PORTF = portf; pwmpos++; if ( pwmpos >= 128 ) pwmpos = 0; if ( pwmpos == 0 ) { layer++; if (layer == LAYERs) { layer = 0; PORTB |= 0x10; // get an impulse on Pin B4 as debug output PORTB &= ~0x10; // -"- PORTA = 0; PORTC = 0; } portf = 1 << layer; PORTB |= 0x40; // get an impulse on Pin B6 as debug output PORTB &= ~0x40; // -"- } porta = cmp_carry_shift_left ( porta, LEDs[layer][ 7], pwmpos ); // LED at A7 porta = cmp_carry_shift_left ( porta, LEDs[layer][ 6], pwmpos ); // LED at A6 porta = cmp_carry_shift_left ( porta, LEDs[layer][ 5], pwmpos ); porta = cmp_carry_shift_left ( porta, LEDs[layer][ 4], pwmpos ); porta = cmp_carry_shift_left ( porta, LEDs[layer][ 3], pwmpos ); porta = cmp_carry_shift_left ( porta, LEDs[layer][ 2], pwmpos ); porta = cmp_carry_shift_left ( porta, LEDs[layer][ 1], pwmpos ); porta = cmp_carry_shift_left ( porta, LEDs[layer][ 0], pwmpos ); // LED at A0 portc = cmp_carry_shift_left ( portc, LEDs[layer][15], pwmpos ); // LED at C7 portc = cmp_carry_shift_left ( portc, LEDs[layer][14], pwmpos ); // LED at C6 portc = cmp_carry_shift_left ( portc, LEDs[layer][13], pwmpos ); portc = cmp_carry_shift_left ( portc, LEDs[layer][12], pwmpos ); portc = cmp_carry_shift_left ( portc, LEDs[layer][11], pwmpos ); portc = cmp_carry_shift_left ( portc, LEDs[layer][10], pwmpos ); portc = cmp_carry_shift_left ( portc, LEDs[layer][ 9], pwmpos ); portc = cmp_carry_shift_left ( portc, LEDs[layer][ 8], pwmpos ); // LED at C0 PORTB &= ~0x80; } void serialEvent() { static unsigned char RX_pos = 0; unsigned char rx_char; PORTB |= 0x08; // turn on B3 as debug output rx_char = (unsigned char)Serial.read(); if ( rx_char == 0xFF ) { // if FF is rxed, a new buffer is expected RX_pos = 0; } else { ( (unsigned char *) LEDs )[RX_pos] = rx_char % 128; RX_pos = ( RX_pos >= LAYERs * COLs * ROWs ) ? 0 : RX_pos + 1; } PORTB &= ~0x08; // turn off B3 as debug output } void setup() { unsigned char i; // Initialize port directions and output values DDRA = 0xFF; PORTA = 0xFF; // first 8 LEDs DDRC = 0xFF; PORTC = 0xFF; // second 8 LEDs DDRF = 0x0F; PORTF = 0x01; // 4 layers DDRB = 0xFF; PORTB = 0x00; // debug output LEDs // Initialize timer TCCR3A = (1 << WGM31) | (1 << WGM30) | (0x00 << COM3B0); TCCR3B = (0x01 << CS30) | (1 << WGM32) | (1 << WGM33); TIMSK3 |= 1 << TOIE3; OCR3A = 0xFF; // */ // init LEDs array for ( i = 0; i < LAYERs * COLs * ROWs; i++ ) ( (unsigned char *) LEDs )[i] = 1; // Enable interrupts sei(); // listen on RS232 for new data Serial.begin(115200); } void loop() { PORTB ^= 0x02; // debug output (toggles pin B1 if nothing else is done) }