/* Demonstrate serial RS-232 communication via the 8251 UART/USART*/ // A simple demonstration of the 8251 UART connected to the MIPS // system bus. This program initializes the 8251, transmits a // welcome message, and afterwards echoes the incoming characters. // A small state-machine is used to filter CR-LF, LF-CR, LF, CR, // and replace those by CR-LF. // // TinyMips doesn't support interrupts (yet), so polling is used. // Remember that nCTS must be kept low to enable the transmitter // of the UART 8251. // axxx.xxxx would be mapped to 0xxx.xxxx by the (static) MMU, // but we have disabled the MMU. So, the addresses are unchanged, // and the physical address of the UART is a008.0020 - a008.0024 // #define UART_BASE 0xa0080020 #define UART_DATA (UART_BASE+0) #define UART_CMD (UART_BASE+4) // mode register bits // #define UART_STOP_MASK 0xc0 #define UART_2STOP 0xc0 #define UART_15STOP 0x80 #define UART_1STOP 0x40 #define UART_0STOP 0x00 #define UART_PARITY_MASK 0x30 #define UART_EVEN_PARITY 0x20 #define UART_ODD_PARITY 0x10 #define UART_NO_PARITY 0x00 #define UART_BITS_MASK 0x0c #define UART_8BITS 0x0c #define UART_7BITS 0x08 #define UART_6BITS 0x04 #define UART_5BITS 0x00 #define UART_PRESCALER 0x03 #define UART_X64 0x03 #define UART_X16 0x02 #define UART_X1 0x01 #define UART_SYNC_MODE 0x00 // not implemented // command register bits // #define UART_EH 0x80 // enter hunt-mode: not implemented #define UART_IR 0x40 // internal reset #define UART_RTS 0x20 // 1: nRTS=0 0: nRTS=1 #define UART_ER 0x10 // reset error flags in status register #define UART_SBRK 0x08 // send break, forces TXD low #define UART_RXE 0x04 // receiver enable bit #define UART_DTR 0x02 // 1: nDTR=0 1: nDTR=1 #define UART_TXE 0x01 // transmitter enable bit // status register bits // #define UART_DSR 0x80 #define UART_SYNDET_BD 0x40 #define UART_FE 0x20 #define UART_OE 0x10 #define UART_PE 0x08 #define UART_TXEMPTY 0x04 #define UART_RXRDY 0x02 #define UART_TXRDY 0x01 static int* global; /* * re-configures the UART to the given parameters in async mode */ void uartAsyncMode( int value ) { int* uart = (int*) UART_CMD; // // assuming we don't know the exact status of the UART 8251, // it might be in its internal WAIT_FOR_SYNC_1_AND_2 state. // Therefore, the first two write operations might end up as data // in the SYNC1 and SYNC2 data registers. But the third write // operation is guaranteed to be decoded as an internal-reset command // which re-initializes the 8251 to expect a mode command next. // *uart = UART_IR; *uart = UART_IR; *uart = UART_IR; // now, we can write the mode command requested by the user. // *uart = value & 0xff; } void uartAsync8N2_X1() { uartAsyncMode( UART_2STOP | UART_NO_PARITY | UART_8BITS | UART_X1 ); } /* * write the given data value to the command register. * The user is responsible to provide sensible data values here. * Also, there is no way to check that the UART is actually expecting * a command. */ void uartCommand( int value ) { int *uart = (int *) UART_CMD; *uart = value&0xff; } /* * write the value UART_CMD_ER or 0x10 to the 8251 in command mode, * that is, CnD=1. This resets the receiver error status flags when * the 8251 is in command mode (but no check is made to ensure that * this is actually the case). * * Note that we also set the RXE and TXE command flags, because * the 8251 will not remember its previous state, and it will * also not allow us to read its current state back. Instead, we * should keep the RXE/TXE status somewhere in this driver code, * but so far we do not. Just enabling both seems fine, though. */ void uartResetErrorFlags() { uartCommand( UART_ER | UART_RXE | UART_TXE ); } /* * write the given data character to the transmit buffer of the 8251. * It is the user's responsibility to check that the 8251 is ready * to accept a new data character (i.e., transmitter is enabled and * TXEMPTY). * Actual transmission might be delayed until nCTS is asserted low. */ void uartSendData( char c ) { int *uart = (int *) UART_DATA; *uart = c & 0xff; } /** * reads the 8251 status register. * See the datasheet for the meaning of the individual bits. * Note that SYNDET/BD always reads zero, because the Hades simulation * model of the 8251 does not yet support break-detect or sync mode. */ int uartReadStatus() { int *uart = (int*) UART_DATA; int tmp = 0; tmp = *(uart+1); // *(uart+1) = 0x87; return tmp; } /* returns the error flags, or 0 if no errors set. */ int uartHasError() { int status = uartReadStatus(); int mask = (UART_FE | UART_OE | UART_PE); return (status & mask) != 0; } int uartIsRXRDY() { int status = uartReadStatus(); int mask = UART_RXRDY; return (status & mask) == UART_RXRDY; } int uartIsTXRDY() { int status = uartReadStatus(); int mask = UART_TXRDY; return (status & mask) == UART_TXRDY; } int uartIsTXEMPTY() { int status = uartReadStatus(); int mask = UART_TXEMPTY; return (status & mask) == UART_TXEMPTY; } char uartReadData() { char tmp; int *uart = (int *) UART_DATA; tmp = (*uart) & 0xff; return tmp; } void uartSendCharPolling( char c ) { int tmp = 0; int status = 0; while( !uartIsTXEMPTY() ) { tmp ++; status = uartReadStatus(); } uartSendData( c ); } void uartSendString( char* c ) { char *s; for( s=c; *s != '\0'; s++ ) { uartSendCharPolling( *s ); } } char hex( int digit ) { digit = digit & 0xf; if (digit <= 9) return ('0' + digit); else return ('a' + digit - 10); } void sayHello() { uartSendString( "\n\rHello!" ); uartSendString( "\n\rPlease type a command:\n\r" ); } void errorMessage() { int status = uartReadStatus(); if ((status & UART_FE) != 0) { uartSendString( "\n\rFrame Error!\n\r" ); } else if ((status & UART_OE) != 0) { uartSendString( "\n\rOverrun Error!\n\r" ); } else if ((status & UART_PE) != 0) { uartSendString( "\n\rOverrun Error!\n\r" ); } else { uartSendString( "\n\rUnknown Error:" ); uartSendCharPolling( hex( (status&0xf0)>>4 )); uartSendCharPolling( hex( (status&0x0f) )); } } void echoLoop() { int *global; int count; int status; int rxrdy; int rdata; global = (int*) 0x00001000; *global = 0xdeadcafe; // outer wait loop. Iteration count is repeatedly stored // at *global, last receiver status at *(global+1), last // receiver data at *(global+2). // for( count=0; ; count++ ) { *(global) = count; status = uartReadStatus(); *(global+1) = status; if (uartHasError()) { errorMessage(); uartResetErrorFlags(); // uartSendString( "Back again now...\n\r" ); } rxrdy = uartIsRXRDY(); if (rxrdy) { rdata = uartReadData(); *(global+2) = rdata; uartSendCharPolling( rdata&0xff ); } } } int main( int argc, char** argv ) { int count; int sum, dbg1, dbg2; for( count=0; count < 0x33; count++ ) { sum = sum + count; } dbg1 = count; // initialize the UART // uartAsyncMode( UART_8BITS | UART_2STOP | UART_NO_PARITY | UART_X1 ); uartCommand( UART_ER | UART_RXE | UART_TXE ); sayHello(); echoLoop(); }