From f0efc593eaf5639f598cbbcf0bc07ac6c1818db8 Mon Sep 17 00:00:00 2001 From: Gavan Fantom Date: Mon, 23 May 2011 21:41:17 +0000 Subject: [PATCH] Use interrupts and buffer the UART receive side too. --- uart.c | 72 +++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 21 deletions(-) diff --git a/uart.c b/uart.c index 5f13ace..b73241b 100644 --- a/uart.c +++ b/uart.c @@ -26,11 +26,15 @@ #define U0THRE ((UREG(LSR) & (1<<5))) /* UART0 transmitter holding register is empty */ #define U0DR ((UREG(LSR) & (1<<0))) /* UART0 data ready */ -#define UART_BUFSIZE 128 +#define UART_TXBUFSIZE 128 +#define UART_RXBUFSIZE 128 -char uart_txbuf[UART_BUFSIZE]; +char uart_txbuf[UART_TXBUFSIZE]; +char uart_rxbuf[UART_RXBUFSIZE]; volatile int uart_txread; volatile int uart_txwrite; +volatile int uart_rxread; +volatile int uart_rxwrite; volatile bool tx_running; void __attribute__((interrupt("IRQ"))) uart_interrupt_handler(void); @@ -47,15 +51,17 @@ void init_uart(void) uart_txread = 0; uart_txwrite = 0; + uart_rxread = 0; + uart_rxwrite = 0; tx_running = FALSE; interrupt_register(UART0, uart_interrupt_handler); - UREG(IER) = 0x02; /* THRE interrupt enable */ + UREG(IER) = 0x03; /* RBR and THRE interrupt enable */ } void putch(char c) { /* Wait for space in the buffer */ - while (uart_txread == ((uart_txwrite+1) % UART_BUFSIZE)); + while (uart_txread == ((uart_txwrite+1) % UART_TXBUFSIZE)); if (uart_txread == uart_txwrite) { if (U0THRE) { @@ -66,12 +72,12 @@ void putch(char c) { } uart_txbuf[uart_txwrite] = c; - uart_txwrite = (uart_txwrite + 1) % UART_BUFSIZE; + uart_txwrite = (uart_txwrite + 1) % UART_TXBUFSIZE; if (!tx_running) { if (uart_txread != uart_txwrite) { tx_running = TRUE; - uart_txread = (uart_txread + 1) % UART_BUFSIZE; + uart_txread = (uart_txread + 1) % UART_TXBUFSIZE; UREG(THR) = c; } } @@ -86,29 +92,48 @@ void __attribute__((interrupt("IRQ"))) uart_interrupt_handler(void) * to treat them as such in this handler, so let the compiler * have an easier time. */ - int local_txwrite = uart_txwrite; - int local_txread = uart_txread; + int local_txwrite; + int local_txread; + int local_rxwrite; + int local_rxread; source = UREG(IIR); - /* For now we assume that all interrupts are actually THR empty - * interrupts. Actually check this when we do more things with - * the UART - */ + switch (source & 0x0e) { + case 0x4: /* Receive Data Available */ + case 0xc: /* Character Time-out Indicator */ + local_rxwrite = uart_rxwrite; + local_rxread = uart_rxread; + while (U0DR) { + unsigned char c = UREG(RBR); + if (local_rxread != + ((local_rxwrite+1) % UART_RXBUFSIZE)) { + uart_rxbuf[local_rxwrite] = c; + local_rxwrite = (local_rxwrite + 1) % + UART_RXBUFSIZE; + } + } + uart_rxwrite = local_rxwrite; + break; - if (U0THRE) { + case 0x2: /* THRE interrupt */ + local_txwrite = uart_txwrite; + local_txread = uart_txread; for (i = 0; (i < 16) && (local_txwrite != local_txread); i++) { UREG(THR) = uart_txbuf[local_txread]; - local_txread = (local_txread + 1) % UART_BUFSIZE; + local_txread = (local_txread + 1) % UART_TXBUFSIZE; active = TRUE; } + uart_txread = local_txread; + if (!active) + tx_running = FALSE; + break; + + case 0x6: /* Receive Line Status */ + default: /* Anything else */ + break; } - uart_txread = local_txread; - - if (!active) - tx_running = FALSE; - interrupt_clear(); } @@ -148,8 +173,13 @@ void puthex(unsigned int n) { } char getch(void) { - while (!U0DR) { + char c; + + while (uart_rxread == uart_rxwrite) { FP0XVAL ^= 0x04000000; } - return UREG(RBR); + + c = uart_rxbuf[uart_rxread]; + uart_rxread = (uart_rxread + 1) % UART_RXBUFSIZE; + return c; }