#include "../config.h" #include "../makros.h" #include #include #include #include #include "borg_hw.h" /* // those macros get defined via menuconfig, now */ #define TLC_PIN_SIN 0 #define TLC_PIN_SCLK 1 #define TLC_PIN_SOUT 5 #define TLC_PIN_XLAT 2 #define TLC_PIN_BLANK 3 #define TLC_PIN_VPRG 7 #define TLC_PIN_DCPRG 4 #define TLC_PIN_XERR 6 #define COLDDR DDR(TLCPORT) #define ROWDDR DDR(ROWPORT) #define SCLK() { \ TLCPORT |= _BV(TLC_PIN_SCLK); \ TLCPORT &= ~_BV(TLC_PIN_SCLK); \ } #define XLAT() { \ TLCPORT |= _BV(TLC_PIN_XLAT); \ TLCPORT &= ~_BV(TLC_PIN_XLAT); \ } /* more ifdef magic :-( */ #if defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644__) || (__AVR_ATmega1284P__) || defined (__AVR_ATmega1284__) #define OCR0 OCR0A #define TIMER0_COMP_vect TIMER0_COMPA_vect #endif //lookup table uint16_t colormap[256] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,29,31,34,36,39,42,45,48,51,55,58,62,65,69,73,77,81,85,90,94,99,103,108,113,118,123,129,134,140,145,151,157,163,169,176,182,188,195,202,209,216,223,230,238,245,253,261,269,277,285,293,302,310,319,328,337,346,355,365,374,384,394,404,414,424,434,445,455,466,477,488,499,510,522,533,545,557,569,581,593,606,618,631,644,657,670,683,696,710,723,737,751,765,779,794,808,823,838,853,868,883,898,914,930,945,961,978,994,1010,1027,1043,1060,1077,1094,1112,1129,1147,1164,1182,1200,1218,1237,1255,1274,1293,1311,1331,1350,1369,1389,1408,1428,1448,1468,1488,1509,1529,1550,1571,1592,1613,1635,1656,1678,1700,1721,1744,1766,1788,1811,1834,1856,1879,1903,1926,1949,1973,1997,2021,2045,2069,2094,2118,2143,2168,2193,2218,2244,2269,2295,2321,2347,2373,2399,2426,2452,2479,2506,2533,2560,2588,2615,2643,2671,2699,2727,2756,2784,2813,2842,2871,2900,2929,2959,2989,3018,3048,3079,3109,3139,3170,3201,3232,3263,3294,3326,3357,3389,3421,3453,3485,3518,3550,3583,3616,3649,3682,3716,3749,3783,3817,3851,3886,3920,3955,3989,4024,4059,4094}; // buffer which holds the currently shown frame unsigned char framebuf[NUM_ROWS][NUM_COLS]; //row counter static unsigned char row = 0; //switch to next row static void nextrow() { unsigned char i; // short delay loop, to ensure proper deactivation of the drivers for (i = 0; i < 10; i++) asm volatile("nop"); // row 0: initialize first shift register if (row == 0) { #ifndef INVERT_ROWS ROWPORT &= ~(1 << PIN_MCLR); ROWPORT |= (1 << PIN_MCLR); ROWPORT |= (1 << PIN_DATA); ROWPORT |= (1 << PIN_CLK); ROWPORT &= ~(1 << PIN_CLK); ROWPORT &= ~(1 << PIN_DATA); #else ROWPORT&= ~(1<> 4) & 0xF0; //12 TLCPORT &= ~_BV(TLC_PIN_SIN); TLCPORT |= (v & 0x80) >> (7-TLC_PIN_SIN); SCLK(); v <<= 1; //11 TLCPORT &= ~_BV(TLC_PIN_SIN); TLCPORT |= (v & 0x80) >> (7-TLC_PIN_SIN); SCLK(); v <<= 1; //10 TLCPORT &= ~_BV(TLC_PIN_SIN); TLCPORT |= (v & 0x80) >> (7-TLC_PIN_SIN); SCLK(); v <<= 1; //9 TLCPORT &= ~_BV(TLC_PIN_SIN); TLCPORT |= (v & 0x80) >> (7-TLC_PIN_SIN); SCLK(); v <<= 1; //fetch lsb v = (colormap[framebuf[row][y]]) & 0xFF; //8 TLCPORT &= ~_BV(TLC_PIN_SIN); TLCPORT |= (v & 0x80) >> (7-TLC_PIN_SIN); SCLK(); v <<= 1; //7 TLCPORT &= ~_BV(TLC_PIN_SIN); TLCPORT |= (v & 0x80) >> (7-TLC_PIN_SIN); SCLK(); v <<= 1; //6 TLCPORT &= ~_BV(TLC_PIN_SIN); TLCPORT |= (v & 0x80) >> (7-TLC_PIN_SIN); SCLK(); v <<= 1; //5 TLCPORT &= ~_BV(TLC_PIN_SIN); TLCPORT |= (v & 0x80) >> (7-TLC_PIN_SIN); SCLK(); v <<= 1; //4 TLCPORT &= ~_BV(TLC_PIN_SIN); TLCPORT |= (v & 0x80) >> (7-TLC_PIN_SIN); SCLK(); v <<= 1; //3 TLCPORT &= ~_BV(TLC_PIN_SIN); TLCPORT |= (v & 0x80) >> (7-TLC_PIN_SIN); SCLK(); v <<= 1; //2 TLCPORT &= ~_BV(TLC_PIN_SIN); TLCPORT |= (v & 0x80) >> (7-TLC_PIN_SIN); SCLK(); v <<= 1; //1 TLCPORT &= ~_BV(TLC_PIN_SIN); TLCPORT |= (v & 0x80) >> (7-TLC_PIN_SIN); SCLK(); v <<= 1; } //blank outputs of low-side (column) driver TLCPORT |= _BV(TLC_PIN_BLANK); //switch rows nextrow(); //latch data, disable blanking, enable and reset timers XLAT(); TLCPORT &= ~_BV(TLC_PIN_BLANK); //reset timer TCNT0 = 0; } void timer0_off() { cli(); TLCPORT = 0; ROWPORT = 0; #if defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644__) || (__AVR_ATmega1284P__) || defined (__AVR_ATmega1284__) TCCR0A = 0x00; TCCR0B = 0x00; #else TCCR0 = 0x00; #endif //disable timer 1 also TCCR1B &= ~_BV(CS10); sei(); } // initialize timers which trigger the interrupts static void timer0_on() { /* TCCR0: FOC0 WGM00 COM01 COM00 WGM01 CS02 CS01 CS00 * CS02 CS01 CS00 * 0 0 0 stop * 0 0 1 clk * 0 1 0 clk/8 * 0 1 1 clk/64 * 1 0 0 clk/256 * 1 0 1 clk/1024 */ #if defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644__) || (__AVR_ATmega1284P__) || defined (__AVR_ATmega1284__) TCCR0A = 0x02; // CTC Mode TCCR0B = 0x04; // clk/256 TCNT0 = 0; // reset timer OCR0 = 16; // compare with this value TIMSK0 = 0x02; // compare match Interrupt on #else TCCR0 = 0x0C; // CTC Mode, clk/256 TCNT0 = 0; // reset timer OCR0 = 16; // compare with this value TIMSK = 0x02; // compare match Interrupt on #endif } void tlc5940_init() { uint8_t i; //init control port pins COLDDR = 0x00; COLDDR = _BV(TLC_PIN_SCLK) | _BV(TLC_PIN_SIN) | _BV(TLC_PIN_XLAT) | _BV(TLC_PIN_BLANK) | _BV(TLC_PIN_VPRG) | _BV(TLC_PIN_DCPRG); //switch off all outputs and pull-ups //xerr is open-drain, enable PUP //set blank flag (disable led-outputs) //dcprog is high -> use values from dc register //vprg is high -> dot correction mode mode TLCPORT = _BV(TLC_PIN_XERR) | _BV(TLC_PIN_BLANK) | _BV(TLC_PIN_DCPRG) | _BV(TLC_PIN_VPRG); //set max power (6bit * 16 LEDs) TLCPORT |= _BV(TLC_PIN_SIN); for(i = 0; i < 96; i++) SCLK(); XLAT(); //switch to grayscale mode TLCPORT &= ~_BV(TLC_PIN_VPRG); //flush input shift register (12bit * 16 LEDs) TLCPORT &= ~_BV(TLC_PIN_SIN); for(i = 0; i < 192; i++) SCLK(); XLAT(); //one extra clk pulse is needed after switching from dc mode SCLK(); } void test_tlc() { uint8_t i, x; while(1) { //debug: load 100% duty cycle into column driver for(i = 0; i < 16; i++) //16 x 12bit { //shift in 12 bit words for(x = 0; x < 12; x++) { TLCPORT &= ~_BV(TLC_PIN_SIN); TLCPORT |= 1<< TLC_PIN_SIN; SCLK(); } } //blank outputs of low-side (column) driver TLCPORT |= _BV(TLC_PIN_BLANK); //rowswitch nextrow(); //latch data, disable blanking XLAT(); TLCPORT &= ~_BV(TLC_PIN_BLANK); //delay 4096 gsclocks (256) _delay_us(254); } } void borg_hw_init() { //init column driver tlc5940_init(); // switch pins of the row port to output mode ROWDDR = (1 << PIN_MCLR) | (1 << PIN_CLK) | (1 << PIN_DATA); // reset shift registers for the rows ROWPORT = 0; //test tlc chip //test_tlc(); //activate the activator timer0_on(); // activate watchdog timer wdt_reset(); wdt_enable(0x00); // 17ms watchdog }