106 lines
3 KiB
C
106 lines
3 KiB
C
/*
|
|
* økoyono MiniLEDCube
|
|
*
|
|
* By Kai Lauterbach (klaute at web dot de) 11/2011
|
|
*
|
|
* Based on http://mosfetkiller.de/?s=miniledcube
|
|
*
|
|
* License: General Public License (GPL v3)
|
|
*
|
|
*/
|
|
|
|
#include "main.h"
|
|
|
|
/*! \brief Initialize the AVR.
|
|
*/
|
|
static inline void init(void)
|
|
{
|
|
// Init ports
|
|
DDRB = 0xFF; // PB0-PB7: LED 1-8 (Kathode)
|
|
PORTB = 0xFF; // HIGH
|
|
DDRD = 0x78; // PD6: LED 9 (Kathode); PD5-PD3: A-C (Anode)
|
|
PORTD = 0x40;
|
|
// Setup Timer-Interrupt "TIMER1" compare match
|
|
// Refresh-rate is 100Hz of the whole LEDCube.
|
|
// The timer fires at 300Hz.
|
|
// Set the compare value to
|
|
// 625d = 0x271
|
|
OCR1A = 0x271;
|
|
// Set prescaler to 64 and CTC mode
|
|
TCCR1B = (1 << CS11) | (1 << CS10) | (1 << WGM12);
|
|
sei(); // Enable interrupts global
|
|
}
|
|
|
|
|
|
/*! \brief Main loop
|
|
*/
|
|
int __attribute__((OS_main)) main()
|
|
{
|
|
uint8_t level = 0x00;
|
|
uint8_t frmnum = 0x00;
|
|
uint8_t delay = 0x00;
|
|
// Initialize the AVR and the USB connection.
|
|
init();
|
|
init_usb();
|
|
|
|
// main loop
|
|
for (;;) {
|
|
usbPoll(); // keep connected
|
|
|
|
if (TIFR & (1 << OCF1A)) {
|
|
TIFR = (1 << OCF1A);
|
|
cli();
|
|
|
|
if (!(--delay)) { // decrease the counter and check if we are done with waiting
|
|
if (frmnum == MAX_EEPROM_FRAMES) {
|
|
if (mode == MODE_ANIMATION_SINGLE) {
|
|
mode = MODE_ANIMATION_STOP; // stop the animation after we have reached the 31th frame
|
|
}
|
|
|
|
frmnum = 0; // always start at the first frame
|
|
} else {
|
|
if (mode) {
|
|
// if we are in an animation mode we have to load a frame out of the eeprom
|
|
// and increase the counter
|
|
frame.all = eeprom_read_dword(&eep_anim[frmnum]);
|
|
frmnum++;
|
|
}
|
|
}
|
|
|
|
// Just shift right by 24 instead of 27 to multiply the delay by 8.
|
|
// Possible delays are 8 16 24 32 and so on. A zero delay isn't possible.
|
|
// Zero means that a delay of 255 happens because the delay variable was decreased first before testing
|
|
// it's zero value.
|
|
delay = frame.bytes[3] & 0xf8;
|
|
}
|
|
|
|
// PORTD = __, 9, C, B, A, D+, D-, __
|
|
PORTD &= ~((1 << PORTD5) | (1 << PORTD4) | (1 << PORTD3) | (1 << PORTD2)); // delete bit 3 to 6 (bit 3 to 5 = layer 0 to 2
|
|
// PORTB = 1..8
|
|
uint32_t tmp_frame = (frame.all >> (uint8_t)(level * 9));
|
|
// 0 = led is on, 1 = led is off
|
|
PORTB = ~((uint8_t)tmp_frame);
|
|
|
|
if (!(tmp_frame & 0x100)) {
|
|
PORTD |= (1 << PORTD6); // turn the 9th LED off
|
|
} else {
|
|
PORTD &= ~(1 << PORTD6); // turn the 9th LED on
|
|
}
|
|
|
|
// set the current level to high
|
|
// at this point the LED pins are up to date so it's
|
|
// safe to re-enable the level wire (A/B/C)
|
|
// this prevents weird LED flashing which is not defined
|
|
// in the animation frame
|
|
PORTD |= ((1 << level) << 3); // set the current level
|
|
// rotate through the 3 level
|
|
level++;
|
|
|
|
if (level > 2) {
|
|
level = 0;
|
|
}
|
|
|
|
sei();
|
|
}
|
|
}
|
|
}
|