diff --git a/src/borg_hw/borg_hw_andreborg.c b/src/borg_hw/borg_hw_andreborg.c index f665601..b32ee8f 100644 --- a/src/borg_hw/borg_hw_andreborg.c +++ b/src/borg_hw/borg_hw_andreborg.c @@ -6,52 +6,48 @@ #include #include "borg_hw.h" -/* - // those macros get defined via menuconfig, now - - // 16 columns total directly controlled, therefore 2 ports - #define COLPORT1 PORTA - #define COLDDR1 DDRA - - #define COLPORT2 PORTC - #define COLDDR2 DDRC - - // the other port controls the shift registers - #define ROWPORT PORTD - #define ROWDDR DDRD - - // both clock and reset are connected to each shift register - // reset pin is negated - #define PIN_MCLR PD4 - #define PIN_CLK PD5 - - // these are the individual data input pins for the shift registers - #define PIN_DATA1 PD6 - #define PIN_DATA2 PD7 -*/ #define COLDDR1 DDR(COLPORT1) #define COLDDR2 DDR(COLPORT2) #define ROWDDR DDR(ROWPORT) -#if defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644__) || (__AVR_ATmega1284P__) || defined (__AVR_ATmega1284__) -/* more ifdef magic :-( */ -#define OCR0 OCR0A -#define TIMER0_COMP_vect TIMER0_COMPA_vect +#if defined(__AVR_ATmega164__) || \ + defined(__AVR_ATmega164P__) || \ + defined(__AVR_ATmega324__) || \ + defined(__AVR_ATmega324P__) || \ + defined(__AVR_ATmega644__) || \ + defined(__AVR_ATmega644P__) || \ + defined(__AVR_ATmega1284__) || \ + defined(__AVR_ATmega1284P__) +# define TIMER0_OFF() TCCR0A = 0; TCCR0B = 0 +# define TIMER0_CTC_CS256() TCCR0A = _BV(WGM01); TCCR0B = _BV(CS02) +# define TIMER0_RESET() TCNT0 = 0 +# define TIMER0_COMPARE(t) OCR0A = t +# define TIMER0_INT_ENABLE() TIMSK0 = _BV(OCIE0A) +# define TIMER0_ISR TIMER0_COMPA_vect +#else // ATmega16/32 +# define TIMER0_OFF() TCCR0 = 0 +# define TIMER0_CTC_CS256() TCCR0 = _BV(WGM01) | _BV(CS02) +# define TIMER0_RESET() TCNT0 = 0 +# define TIMER0_COMPARE(t) OCR0 = t +# define TIMER0_INT_ENABLE() TIMSK = _BV(OCIE0) +# define TIMER0_ISR TIMER0_COMP_vect #endif + // buffer which holds the currently shown frame unsigned char pixmap[NUMPLANE][NUM_ROWS][LINEBYTES]; -// display a row -static void rowshow(unsigned char row, unsigned char plane) { + +// switch to next row +static void nextrow(uint8_t row) { //reset states of preceding row COLPORT1 = 0; COLPORT2 = 0; // short delay loop, to ensure proper deactivation of the drivers unsigned char i; - for (i = 0; i < 20; i++) { + for (i = 0; i < 10; i++) { asm volatile("nop"); } @@ -63,11 +59,6 @@ static void rowshow(unsigned char row, unsigned char plane) { ROWPORT |= (1 << PIN_CLK); ROWPORT &= ~(1 << PIN_CLK); ROWPORT &= ~(1 << PIN_DATA1); - - // depending on the currently drawn plane, display the row for a - // specific amount of time - static unsigned char const ocr0_table[] = {5, 8, 20}; - OCR0 = ocr0_table[plane]; } else if (row == 8) { // row 8: initialize second shift register ROWPORT &= ~(1 << PIN_MCLR); @@ -86,75 +77,65 @@ static void rowshow(unsigned char row, unsigned char plane) { for (i = 0; i < 20; i++) { asm volatile("nop"); } +} + + +// show a row +static void rowshow(unsigned char row, unsigned char plane) { + // depending on the currently drawn plane, display the row for a specific + // amount of time + static unsigned char const ocr_table[] = {2, 5, 22}; + + TIMER0_COMPARE(ocr_table[plane]); // output data of the current row to the column drivers COLPORT1 = pixmap[plane][row][0]; COLPORT2 = pixmap[plane][row][1]; } -// depending on the plane this interrupt gets triggered at 50 kHz, 31.25 kHz or -// 12.5 kHz -ISR(TIMER0_COMP_vect) { + +// interrupt handler +ISR(TIMER0_ISR) { static unsigned char plane = 0; static unsigned char row = 0; - // reset watchdog - wdt_reset(); - - // output current row according to current plane - rowshow(row, plane); - // increment both row and plane - if (++row == NUM_ROWS) { - row = 0; - if (++plane == NUMPLANE) { - plane = 0; + if (++plane == NUMPLANE) { + plane = 0; + if (++row == NUM_ROWS) { + // reset watchdog + wdt_reset(); + + row = 0; } + nextrow(row); } + + // output current row according to current plane + rowshow(row, plane); } + +// disables timer, causing the watchdog to reset the MCU void timer0_off() { cli(); - COLPORT1 = 0; COLPORT2 = 0; ROWPORT = 0; - -#if defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644__) || (__AVR_ATmega1284P__) || defined (__AVR_ATmega1284__) - TCCR0A = 0x00; - TCCR0B = 0x00; -#else - TCCR0 = 0x00; -#endif + TIMER0_OFF(); sei(); } + // initialize timer which triggers the interrupt 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 = 0x03; // clk/64 - TCNT0 = 0; // reset timer - OCR0 = 20; // compare with this value - TIMSK0 = 0x02; // compare match Interrupt on -#else - TCCR0 = 0x0B; // CTC Mode, clk/64 - TCNT0 = 0; // reset timer - OCR0 = 20; // compare with this value - TIMSK = 0x02; // compare match Interrupt on -#endif + TIMER0_CTC_CS256(); // CTC mode, prescaling conforms to clk/256 + TIMER0_RESET(); // set counter to 0 + TIMER0_COMPARE(20); // compare with this value first + TIMER0_INT_ENABLE(); // enable Timer/Counter0 Output Compare Match (A) Int. } + void borg_hw_init() { // switch column ports to output mode COLDDR1 = 0xFF; @@ -174,5 +155,5 @@ void borg_hw_init() { // activate watchdog timer wdt_reset(); - wdt_enable(0x00); // 17ms watchdog + wdt_enable(WDTO_15MS); // 15ms watchdog }