borgware-2d/uart/uart.c

189 lines
3.5 KiB
C

/* USART-Init beim ATmegaXX */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include "config.h"
#include "uart.h"
#ifdef ATMEGA128
#define UCSRB UCSR0B
#define UCSRC UCSR0C
#define UDR UDR0
#define UBRRH UBRR0H
#define UBRRL UBRR0L
#define URSEL UMSEL
#endif
#define UART_BAUD_CALC(UART_BAUD_RATE,F_OSC) ((F_OSC)/((UART_BAUD_RATE)*16L))
#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;
ISR(USART_UDRE_vect) {
#ifdef UART_LEDS
PORTC ^= 0x01;
#endif
if ( txhead == txtail ) {
UCSRB &= ~(1 << UDRIE); /* disable data register empty IRQ */
} else {
UDR = *txtail; /* schreibt das Zeichen x auf die Schnittstelle */
if (++txtail == (txbuf + UART_TXBUFSIZE)) txtail = txbuf;
}
}
ISR(USART_RXC_vect) {
int diff;
#ifdef UART_LEDS
PORTC ^= 0x02;
#endif
/* buffer full? */
diff = rxhead - rxtail;
if ( diff < 0 ) diff += UART_RXBUFSIZE;
if (diff < UART_RXBUFSIZE -1) {
// buffer NOT full
*rxhead = UDR;
if (++rxhead == (rxbuf + UART_RXBUFSIZE)) rxhead = rxbuf;
} else {
UDR; //reads the buffer to clear the interrupt condition
}
}
#endif // UART_INTERRUPT
void uart_init() {
PORTD |= 0x01; //Pullup an RXD an
UCSRA = 0;
UCSRB |= (1<<TXEN); //UART TX einschalten
UCSRC |= (1<<URSEL)|(3<<UCSZ0); //Asynchron 8N1
UCSRB |= ( 1 << RXEN ); //Uart RX einschalten
// UBRRH=(uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)>>8);
// UBRRL=(uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU));
UBRRL = 8;
#ifdef UART_INTERRUPT
// init buffers
rxhead = rxtail = rxbuf;
txhead = txtail = txbuf;
// activate rx IRQ
UCSRB |= (1 << RXCIE);
#endif // UART_INTERRUPT
}
#ifdef UART_INTERRUPT
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<<UDRE))); /* warten bis Senden moeglich */
UDR = c; /* schreibt das Zeichen x auf die Schnittstelle */
}
#endif // UART_INTERRUPT
void uart_putstr(char *str) {
while(*str) {
uart_putc(*str++);
}
}
void uart_putstr_P(PGM_P str) {
char tmp;
while((tmp = pgm_read_byte(str))) {
uart_putc(tmp);
str++;
}
}
void uart_hexdump(char *buf, int len)
{
unsigned char x=0;
char sbuf[3];
while(len--){
itoa(*buf++, sbuf, 16);
if (sbuf[1] == 0) uart_putc(' ');
uart_putstr(sbuf);
uart_putc(' ');
if(++x == 16) {
uart_putstr_P(PSTR("\r\n"));
x = 0;
}
}
}
#ifdef UART_INTERRUPT
char uart_getc()
{
char val;
while(rxhead==rxtail) ;
val = *rxtail;
if (++rxtail == (rxbuf + UART_RXBUFSIZE)) rxtail = rxbuf;
return val;
}
#else // WITHOUT INTERRUPT
char uart_getc()
{
while (!(UCSRA & (1<<RXC))); // warten bis Zeichen verfuegbar
return UDR; // Zeichen aus UDR zurueckgeben
}
#endif // UART_INTERRUPT
// returns 1 on success
#ifdef UART_INTERRUPT
char uart_getc_nb(char *c)
{
if (rxhead==rxtail) return 0;
*c = *rxtail;
if (++rxtail == (rxbuf + UART_RXBUFSIZE)) rxtail = rxbuf;
return 1;
}
#else // WITHOUT INTERRUPT
char uart_getc_nb(char *c)
{
if (UCSRA & (1<<RXC)) { // Zeichen verfuegbar
*c = UDR;
return 1;
}
return 0;
}
#endif // UART_INTERRUPT