Use interrupts and buffer the UART receive side too.
This commit is contained in:
72
uart.c
72
uart.c
@@ -26,11 +26,15 @@
|
|||||||
#define U0THRE ((UREG(LSR) & (1<<5))) /* UART0 transmitter holding register is empty */
|
#define U0THRE ((UREG(LSR) & (1<<5))) /* UART0 transmitter holding register is empty */
|
||||||
#define U0DR ((UREG(LSR) & (1<<0))) /* UART0 data ready */
|
#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_txread;
|
||||||
volatile int uart_txwrite;
|
volatile int uart_txwrite;
|
||||||
|
volatile int uart_rxread;
|
||||||
|
volatile int uart_rxwrite;
|
||||||
volatile bool tx_running;
|
volatile bool tx_running;
|
||||||
|
|
||||||
void __attribute__((interrupt("IRQ"))) uart_interrupt_handler(void);
|
void __attribute__((interrupt("IRQ"))) uart_interrupt_handler(void);
|
||||||
@@ -47,15 +51,17 @@ void init_uart(void)
|
|||||||
|
|
||||||
uart_txread = 0;
|
uart_txread = 0;
|
||||||
uart_txwrite = 0;
|
uart_txwrite = 0;
|
||||||
|
uart_rxread = 0;
|
||||||
|
uart_rxwrite = 0;
|
||||||
tx_running = FALSE;
|
tx_running = FALSE;
|
||||||
interrupt_register(UART0, uart_interrupt_handler);
|
interrupt_register(UART0, uart_interrupt_handler);
|
||||||
|
|
||||||
UREG(IER) = 0x02; /* THRE interrupt enable */
|
UREG(IER) = 0x03; /* RBR and THRE interrupt enable */
|
||||||
}
|
}
|
||||||
|
|
||||||
void putch(char c) {
|
void putch(char c) {
|
||||||
/* Wait for space in the buffer */
|
/* 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 (uart_txread == uart_txwrite) {
|
||||||
if (U0THRE) {
|
if (U0THRE) {
|
||||||
@@ -66,12 +72,12 @@ void putch(char c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uart_txbuf[uart_txwrite] = c;
|
uart_txbuf[uart_txwrite] = c;
|
||||||
uart_txwrite = (uart_txwrite + 1) % UART_BUFSIZE;
|
uart_txwrite = (uart_txwrite + 1) % UART_TXBUFSIZE;
|
||||||
|
|
||||||
if (!tx_running) {
|
if (!tx_running) {
|
||||||
if (uart_txread != uart_txwrite) {
|
if (uart_txread != uart_txwrite) {
|
||||||
tx_running = TRUE;
|
tx_running = TRUE;
|
||||||
uart_txread = (uart_txread + 1) % UART_BUFSIZE;
|
uart_txread = (uart_txread + 1) % UART_TXBUFSIZE;
|
||||||
UREG(THR) = c;
|
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
|
* to treat them as such in this handler, so let the compiler
|
||||||
* have an easier time.
|
* have an easier time.
|
||||||
*/
|
*/
|
||||||
int local_txwrite = uart_txwrite;
|
int local_txwrite;
|
||||||
int local_txread = uart_txread;
|
int local_txread;
|
||||||
|
int local_rxwrite;
|
||||||
|
int local_rxread;
|
||||||
|
|
||||||
source = UREG(IIR);
|
source = UREG(IIR);
|
||||||
|
|
||||||
/* For now we assume that all interrupts are actually THR empty
|
switch (source & 0x0e) {
|
||||||
* interrupts. Actually check this when we do more things with
|
case 0x4: /* Receive Data Available */
|
||||||
* the UART
|
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++) {
|
for (i = 0; (i < 16) && (local_txwrite != local_txread); i++) {
|
||||||
UREG(THR) = uart_txbuf[local_txread];
|
UREG(THR) = uart_txbuf[local_txread];
|
||||||
local_txread = (local_txread + 1) % UART_BUFSIZE;
|
local_txread = (local_txread + 1) % UART_TXBUFSIZE;
|
||||||
active = TRUE;
|
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();
|
interrupt_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,8 +173,13 @@ void puthex(unsigned int n) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char getch(void) {
|
char getch(void) {
|
||||||
while (!U0DR) {
|
char c;
|
||||||
|
|
||||||
|
while (uart_rxread == uart_rxwrite) {
|
||||||
FP0XVAL ^= 0x04000000;
|
FP0XVAL ^= 0x04000000;
|
||||||
}
|
}
|
||||||
return UREG(RBR);
|
|
||||||
|
c = uart_rxbuf[uart_rxread];
|
||||||
|
uart_rxread = (uart_rxread + 1) % UART_RXBUFSIZE;
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user