/* uart.c */ /* This file is part of the AVR-Crypto-Lib. Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de) 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 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* USART-Init beim ATmegaXX */ #include "config.h" #include #include #include #include "hexdigit_tab.h" #include "uart.h" #ifdef ATMEGA128 #define UCSRB UCSR0B #define UCSRC UCSR0C #define UDR UDR0 #define UBRRH UBRR0H #define UBRRL UBRR0L #define URSEL UMSEL #define USART_UDRE_vect USART0_UDRE_vect #define USART_RXC_vect USART0_RX_vect #define UCSRA UCSR0A #endif #ifdef ATMEGA644 #define UCSRB UCSR0B #define UCSRC UCSR0C #define UDR UDR0 #define UBRRH UBRR0H #define UBRRL UBRR0L #define URSEL UMSEL00 #define USART_UDRE_vect USART0_UDRE_vect #define USART_RXC_vect USART0_RX_vect #define UDRIE UDRIE0 #define TXEN TXEN0 #define UMSEL UMSEL0 #define RXEN RXEN0 #define RXCIE RXCIE0 #define UCSZ0 UCSZ00 #define UCSRA UCSR0A #define UDRE UDRE0 #define RXC RXC0 #endif #ifdef AT90USB162 #define UCSRB UCSR1B #define UCSRC UCSR1C #define UDR UDR1 #define UBRRH UBRR1H #define UBRRL UBRR1L #define URSEL UMSEL10 #define USART_UDRE_vect USART1_UDRE_vect #define USART_RXC_vect USART1_RX_vect #define UDRIE UDRIE1 #define TXEN TXEN1 #define UMSEL UMSEL1 #define RXEN RXEN1 #define RXCIE RXCIE1 #define UCSZ0 UCSZ10 #define UCSRA UCSR1A #define UDRE UDRE1 #define RXC RXC1 #endif #ifdef UART_XON_XOFF #ifdef UART_INTERRUPT void uart_insertc(char c); #else #define uart_insertc uart_putc #endif /* UART_INTERRUPT */ #endif #define UART_BAUD_CALC(UART_BAUD_RATE,F_OSC) ((F_OSC)/((UART_BAUD_RATE)*16L)-1) #ifdef UART_XON_XOFF typedef enum{go=1,nogo=0} gonogo; static gonogo txon=go; static gonogo rxon=go; #endif #ifdef UART_INTERRUPT volatile static char rxbuf[UART_RXBUFSIZE]; volatile static char txbuf[UART_TXBUFSIZE]; volatile static char *volatile rxhead, *volatile rxtail; volatile static char *volatile txhead, *volatile txtail; #ifdef UART_HOOK void (*uart_hook) (uint8_t) = (void*)0; /* this is a pointer to a function ;-) */ #endif ISR(USART_UDRE_vect) { #ifdef UART_LEDS PORTC ^= 0x01; #endif if ( txhead == txtail ) { UCSRB &= ~(1 << UDRIE); /* disable data register empty IRQ */ } else { #ifdef UART_XON_XOFF while(txon==nogo) ; #endif UDR = *txtail; /* schreibt das Zeichen x auf die Schnittstelle */ if (++txtail == (txbuf + UART_TXBUFSIZE)) txtail = txbuf; } } ISR(USART_RXC_vect) { int diff; char c; #ifdef UART_HOOK static volatile uint8_t hook_running=0; #endif #ifdef UART_LEDS PORTC ^= 0x02; #endif c=UDR; #ifdef UART_XON_XOFF if (c==XON){ txon=go; return; } if (c==XOFF){ txon=nogo; return; } #endif /* buffer full? */ diff = rxhead - rxtail; if (diff < 0) diff += UART_RXBUFSIZE; /* diff is the amount of bytes in buffer */ if (diff < UART_RXBUFSIZE -1) { // buffer NOT full #ifdef UART_HOOK if(!hook_running && uart_hook){ uint8_t t=c; hook_running = 1; sei(); /* reenable interrupts, avoid recursion!!! */ do { uart_hook(t); } while(uart_getc_nb((char*)&t)); hook_running = 0; } else { *rxhead = c; ++rxhead; if (rxhead == (rxbuf + UART_RXBUFSIZE)) rxhead = rxbuf; } #else *rxhead = c; ++rxhead; if (rxhead == (rxbuf + UART_RXBUFSIZE)) rxhead = rxbuf; #endif } else { //reads the buffer to clear the interrupt condition } #ifdef UART_XON_XOFF if((diff > UART_XON_XOFF_THRESHOLD_1) && (rxon==go)){ rxon=nogo; uart_insertc(XOFF); } if((diff < UART_XON_XOFF_THRESHOLD_2) && (rxon==nogo)){ rxon=go; uart_insertc(XON); } #endif } #endif // UART_INTERRUPT void uart_init() { PORTD |= 0x01; //Pullup an RXD an UCSRB |= (1<>8); UBRRL=(uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)); #ifdef UART_INTERRUPT // init buffers rxhead = rxtail = rxbuf; txhead = txtail = txbuf; // activate rx IRQ UCSRB |= _BV(RXCIE) | _BV(UDRIE); sei(); // #ifdef ATMEGA644 // UCSRB |= _BV(UDRIE); // #endif #endif // UART_INTERRUPT } #ifdef UART_INTERRUPT #ifdef UART_XON_XOFF void uart_insertc(char c){ volatile int diff; do { diff = txhead - txtail; if ( diff < 0 ) diff += UART_TXBUFSIZE; } while ( diff >= UART_TXBUFSIZE -1 ); cli(); if (--txtail == (txbuf-1)) txtail += UART_TXBUFSIZE; *txtail = c; UCSRB |= (1 << UDRIE); /* enable data register empty IRQ */ sei(); } #endif /* UART_XON_XOFF */ void uart_putc(char c) { volatile int diff; /* buffer full? */ do { diff = txhead - txtail; if ( diff < 0 ) diff += UART_TXBUFSIZE; } while ( diff >= UART_TXBUFSIZE -1 ); cli(); *txhead = c; if (++txhead == (txbuf + UART_TXBUFSIZE)) txhead = txbuf; UCSRB |= (1 << UDRIE); /* enable data register empty IRQ */ sei(); } #else // WITHOUT INTERRUPT void uart_putc(char c) { while (!(UCSRA & (1<>4))); uart_putc(pgm_read_byte(hexdigit_tab_P + ((*((uint8_t*)buf))&0xf))); uart_putc(' '); buf=(uint8_t*)buf+1; } } #ifdef UART_INTERRUPT char uart_getc(void) { char val; while(rxhead==rxtail) ; val = *rxtail; ++rxtail; if (rxtail == (rxbuf + UART_RXBUFSIZE)) rxtail = rxbuf; return val; } #else // WITHOUT INTERRUPT char uart_getc(void) { char t; while (!(UCSRA & (1<