2011-12-21 04:54:48 +00:00
|
|
|
#include "../config.h"
|
|
|
|
#include "../makros.h"
|
|
|
|
|
|
|
|
#include <avr/interrupt.h>
|
|
|
|
#include <avr/io.h>
|
|
|
|
#include <avr/wdt.h>
|
2012-05-21 23:06:33 +00:00
|
|
|
#include <util/delay.h>
|
2011-12-21 04:54:48 +00:00
|
|
|
#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
|
|
|
|
|
2011-12-21 06:47:22 +00:00
|
|
|
#define COLDDR DDR(TLCPORT)
|
2011-12-21 04:54:48 +00:00
|
|
|
#define ROWDDR DDR(ROWPORT)
|
|
|
|
|
|
|
|
#define SCLK() { \
|
2011-12-21 06:47:22 +00:00
|
|
|
TLCPORT |= _BV(TLC_PIN_SCLK); \
|
|
|
|
TLCPORT &= ~_BV(TLC_PIN_SCLK); \
|
2011-12-21 04:54:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define XLAT() { \
|
2011-12-21 06:47:22 +00:00
|
|
|
TLCPORT |= _BV(TLC_PIN_XLAT); \
|
|
|
|
TLCPORT &= ~_BV(TLC_PIN_XLAT); \
|
2011-12-21 04:54:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* more ifdef magic :-( */
|
2012-02-12 20:47:55 +00:00
|
|
|
#if defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644__)
|
2011-12-21 04:54:48 +00:00
|
|
|
#define OCR0 OCR0A
|
2012-03-23 01:27:59 +00:00
|
|
|
#define TIMER0_COMP_vect TIMER0_COMPA_vect
|
2011-12-21 04:54:48 +00:00
|
|
|
#endif
|
|
|
|
|
2012-05-21 23:06:33 +00:00
|
|
|
//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};
|
|
|
|
|
2011-12-21 04:54:48 +00:00
|
|
|
// buffer which holds the currently shown frame
|
2012-05-21 23:06:33 +00:00
|
|
|
unsigned char framebuf[NUM_ROWS][NUM_COLS];
|
2011-12-21 04:54:48 +00:00
|
|
|
|
2012-05-21 23:06:33 +00:00
|
|
|
//row counter
|
|
|
|
static unsigned char row = 0;
|
2011-12-21 04:54:48 +00:00
|
|
|
|
2012-05-21 23:06:33 +00:00
|
|
|
//switch to next row
|
|
|
|
static void nextrow() {
|
|
|
|
unsigned char i;
|
2011-12-21 04:54:48 +00:00
|
|
|
|
|
|
|
// 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<<PIN_DATA);
|
|
|
|
ROWPORT|= (1<<PIN_CLK);
|
|
|
|
ROWPORT&= ~(1<<PIN_CLK);
|
|
|
|
ROWPORT|= (1<<PIN_DATA);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
// remaining rows: just shift forward
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ROWPORT |= (1 << PIN_CLK);
|
|
|
|
ROWPORT &= ~(1 << PIN_CLK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-21 06:51:46 +00:00
|
|
|
//this int runs with multiples of half the frequency of timer 1,
|
|
|
|
//meaning that new row data gets laoded every 2n pwm periods of the tlc
|
2011-12-21 06:47:22 +00:00
|
|
|
ISR(TIMER0_COMP_vect ) {
|
2012-05-21 23:06:33 +00:00
|
|
|
uint8_t y, x, v;
|
2011-12-21 04:54:48 +00:00
|
|
|
|
|
|
|
// reset watchdog
|
|
|
|
wdt_reset();
|
2012-05-21 23:06:33 +00:00
|
|
|
|
|
|
|
//increment & wrap row counter
|
|
|
|
if (++row == NUM_ROWS) row = 0;
|
2011-12-21 04:54:48 +00:00
|
|
|
|
2012-05-21 23:06:33 +00:00
|
|
|
//shift pixmap as 12 bit words into device
|
|
|
|
for(y = 0; y < 16; y++) //16 x 12bit
|
|
|
|
{
|
|
|
|
//fetch msb
|
|
|
|
v = (colormap[framebuf[row][y]] >> 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;
|
|
|
|
}
|
|
|
|
|
2011-12-21 06:47:22 +00:00
|
|
|
//blank outputs of low-side (column) driver
|
|
|
|
TLCPORT |= _BV(TLC_PIN_BLANK);
|
|
|
|
|
2012-05-21 23:06:33 +00:00
|
|
|
//switch rows
|
|
|
|
nextrow();
|
2011-12-21 04:54:48 +00:00
|
|
|
|
2011-12-21 06:47:22 +00:00
|
|
|
//latch data, disable blanking, enable and reset timers
|
2011-12-21 04:54:48 +00:00
|
|
|
XLAT();
|
2011-12-21 06:47:22 +00:00
|
|
|
TLCPORT &= ~_BV(TLC_PIN_BLANK);
|
2012-05-21 23:06:33 +00:00
|
|
|
|
|
|
|
//reset timer
|
|
|
|
TCNT0 = 0;
|
2011-12-21 04:54:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void timer0_off() {
|
|
|
|
cli();
|
|
|
|
|
2011-12-21 06:47:22 +00:00
|
|
|
TLCPORT = 0;
|
2011-12-21 04:54:48 +00:00
|
|
|
ROWPORT = 0;
|
|
|
|
|
2012-02-12 20:47:55 +00:00
|
|
|
#if defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644__)
|
2011-12-21 04:54:48 +00:00
|
|
|
TCCR0A = 0x00;
|
|
|
|
TCCR0B = 0x00;
|
|
|
|
#else
|
|
|
|
TCCR0 = 0x00;
|
|
|
|
#endif
|
|
|
|
|
2011-12-21 06:47:22 +00:00
|
|
|
//disable timer 1 also
|
|
|
|
TCCR1B &= ~_BV(CS10);
|
|
|
|
|
2011-12-21 04:54:48 +00:00
|
|
|
sei();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-21 06:47:22 +00:00
|
|
|
// initialize timers which trigger the interrupts
|
2011-12-21 04:54:48 +00:00
|
|
|
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
|
|
|
|
*/
|
|
|
|
|
2012-02-12 20:47:55 +00:00
|
|
|
#if defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644__)
|
2011-12-21 04:54:48 +00:00
|
|
|
TCCR0A = 0x02; // CTC Mode
|
|
|
|
TCCR0B = 0x04; // clk/256
|
|
|
|
TCNT0 = 0; // reset timer
|
2012-05-21 23:06:33 +00:00
|
|
|
OCR0 = 16; // compare with this value
|
2011-12-21 04:54:48 +00:00
|
|
|
TIMSK0 = 0x02; // compare match Interrupt on
|
|
|
|
#else
|
|
|
|
TCCR0 = 0x0C; // CTC Mode, clk/256
|
|
|
|
TCNT0 = 0; // reset timer
|
2012-05-21 23:06:33 +00:00
|
|
|
OCR0 = 16; // compare with this value
|
2011-12-21 04:54:48 +00:00
|
|
|
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
|
2011-12-21 06:47:22 +00:00
|
|
|
TLCPORT = _BV(TLC_PIN_XERR) | _BV(TLC_PIN_BLANK) | _BV(TLC_PIN_DCPRG) | _BV(TLC_PIN_VPRG);
|
2011-12-21 04:54:48 +00:00
|
|
|
|
|
|
|
//set max power (6bit * 16 LEDs)
|
2011-12-21 06:47:22 +00:00
|
|
|
TLCPORT |= _BV(TLC_PIN_SIN);
|
2011-12-21 04:54:48 +00:00
|
|
|
for(i = 0; i < 96; i++) SCLK();
|
|
|
|
XLAT();
|
|
|
|
|
|
|
|
//switch to grayscale mode
|
2011-12-21 06:47:22 +00:00
|
|
|
TLCPORT &= ~_BV(TLC_PIN_VPRG);
|
2011-12-21 04:54:48 +00:00
|
|
|
|
|
|
|
//flush input shift register (12bit * 16 LEDs)
|
2011-12-21 06:47:22 +00:00
|
|
|
TLCPORT &= ~_BV(TLC_PIN_SIN);
|
2011-12-21 04:54:48 +00:00
|
|
|
for(i = 0; i < 192; i++) SCLK();
|
|
|
|
XLAT();
|
|
|
|
|
|
|
|
//one extra clk pulse is needed after switching from dc mode
|
|
|
|
SCLK();
|
|
|
|
}
|
|
|
|
|
2012-05-21 23:06:33 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-21 04:54:48 +00:00
|
|
|
|
|
|
|
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;
|
2012-05-21 23:06:33 +00:00
|
|
|
|
|
|
|
//test tlc chip
|
|
|
|
//test_tlc();
|
2011-12-21 04:54:48 +00:00
|
|
|
|
|
|
|
//activate the activator
|
|
|
|
timer0_on();
|
|
|
|
|
|
|
|
// activate watchdog timer
|
|
|
|
wdt_reset();
|
|
|
|
wdt_enable(0x00); // 17ms watchdog
|
|
|
|
}
|