/* Copyright (c) 2008 Michael Hanselmann * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * Includes parts of Peter Fleury's great UART library: * http://jump.to/fleury * http://homepage.hispeed.ch/peterfleury/avr-software.html#libs * * Serial protocol: * 'S' 256 * [LED brightness in hex] '\n' */ /* * PD0: AVRRXD * PD1: AVRTXD * PD2: CANINT * PD3: JOYFIRE * PD4: JOY1GND * PD5: JOY2GND * PD6: ROWCLK * PD7: ROWDAT */ #include #include #include #include static const uint8_t level_duration[16] = { 1, 2, 2, 3, 4, 5, 6, 8, 11, 14, 18, 23, 30, 39, 51, 67 }; #define UART_TX_BUFFER_SIZE 8 #define UART_RX_BUFFER_SIZE 64 #define UART_RX_BUFFER_MASK (UART_RX_BUFFER_SIZE - 1) #define UART_TX_BUFFER_MASK (UART_TX_BUFFER_SIZE - 1) #define UART_BUFFER_OVERFLOW 0x0200 #define UART_NO_DATA 0x0100 static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE]; static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE]; static volatile unsigned char UART_TxHead; static volatile unsigned char UART_TxTail; static volatile unsigned char UART_RxHead; static volatile unsigned char UART_RxTail; static volatile unsigned char UART_LastRxError; static volatile uint8_t current_level; static volatile uint8_t current_row; static volatile uint8_t update_state; /* Cache for timer interrupt */ static uint16_t current_level_start; /* 4 bits per LED */ static volatile uint8_t pixmap[16 /* Levels */ * 16 /* Rows */ * 2]; static uint8_t pixmap_in[16 * 16 * 2]; static int scan_fromhex(unsigned char c) { if (c >= '0' && c <= '9') return c - '0'; else if (c >= 'A' && c <= 'F') return c - 'A' + 10; else if (c >= 'a' && c <= 'f') return c - 'a' + 10; else return -1; } static void init_pixmap(void) { memset((void *)pixmap, 0xff, sizeof(pixmap)); } ISR(TIMER0_COMP_vect) { wdt_reset(); if (++current_row == 16) { current_row = 0; } PORTA = 0; PORTC = 0; if (update_state == 1) { memcpy((void *)pixmap, pixmap_in, sizeof(pixmap)); update_state = 2; } if (current_row == 0) { PORTD &= ~(1 << PD4); /*PORTD |= (1 << PD4);*/ PORTD |= (1 << PD7); PORTD |= (1 << PD6); PORTD &= ~(1 << PD6); PORTD &= ~(1 << PD7); } else { /* Next row */ PORTD |= (1 << PD6); PORTD &= ~(1 << PD6); } const uint16_t idx = current_level_start + (current_row * 2); PORTA = pixmap[idx]; PORTC = pixmap[idx + 1]; if (current_row == 0) { if (++current_level == 16) { current_level = 0; } current_level_start = current_level * 16 * 2; } OCR0 = level_duration[current_level]; } ISR(USART_RXC_vect) { unsigned char tmphead; unsigned char data; unsigned char usr; unsigned char lastRxError; /* read UART status register and UART data register */ usr = UCSRA; data = UDR; lastRxError = (usr & (_BV(FE) | _BV(DOR))); /* calculate buffer index */ tmphead = (UART_RxHead + 1) & UART_RX_BUFFER_MASK; if (tmphead == UART_RxTail) { /* error: receive buffer overflow */ lastRxError = UART_BUFFER_OVERFLOW >> 8; } else { /* store new index */ UART_RxHead = tmphead; /* store received data in buffer */ UART_RxBuf[tmphead] = data; } UART_LastRxError = lastRxError; } ISR(USART_UDRE_vect) { unsigned char tmptail; if (UART_TxHead != UART_TxTail) { /* calculate and store new buffer index */ tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK; UART_TxTail = tmptail; /* get one byte from buffer and write it to UART */ UDR = UART_TxBuf[tmptail]; /* start transmission */ } else { /* tx buffer empty, disable UDRE interrupt */ UCSRB &= ~_BV(UDRIE); } } unsigned int uart_getc(void) { unsigned char tmptail; unsigned char data; if (UART_RxHead == UART_RxTail) { /* no data available */ return UART_NO_DATA; } /* calculate /store buffer index */ tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK; UART_RxTail = tmptail; /* get data from receive buffer */ data = UART_RxBuf[tmptail]; return (UART_LastRxError << 8) + data; } unsigned int uart_getc_wait(void) { unsigned int c; do { c = uart_getc(); } while (c & UART_NO_DATA); return c; } void uart_putc(unsigned char data) { unsigned char tmphead; tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK; /* wait for free space in buffer */ while (tmphead == UART_TxTail); UART_TxBuf[tmphead] = data; UART_TxHead = tmphead; /* enable UDRE interrupt */ UCSRB |= _BV(UDRIE); } void uart_puts(const char *s ) { while (*s) uart_putc(*s++); } int main() { wdt_disable(); UCSRA &= ~_BV(U2X); UBRRH = 0; /* 38400 Baud */ UBRRL = 25; /* 57600 Baud */ /*UBRRL = 16;*/ UCSRC = _BV(URSEL) | _BV(UCSZ0) | _BV(UCSZ1); init_pixmap(); /* Configure pins */ /* Cols */ DDRA = 0xff; DDRC = 0xff; PORTA = 0; PORTC = 0; /* Rows */ DDRD = (1 << PD6) | (1 << PD7) | (1 << PD1); PORTD = 0; /* Setup timer */ TCCR0 = (1 << WGM01) | _BV(CS01) | _BV(CS00) ; TCNT0 = 0; OCR0 = 3; TIMSK = (1 << OCIE0); /* Setup 15ms watchdog */ wdt_reset(); wdt_enable(WDTO_15MS); /* Serial */ UCSRB |= (1 << (RXCIE)); /* Enable interrupts */ sei(); while (!(UCSRA & (1<> 8) & 0xff) { /* Problem */ while (!(UCSRA & (1<