The test program, uart-loop.c
is a simple
polling loop back driver of the UART. Characters are read and
immediately echoed back.
A volatile
structure is declared for the UART
registers, with #define
d constants for the base
address and the register bits of interest.
#define BASEADDR 0x90000000 #define BAUD_RATE 9600 #define CLOCK_RATE 100000000 // 100 Mhz struct uart16450 { volatile unsigned char buf; // R/W: Rx & Tx buffer when DLAB=0 volatile unsigned char ier; // R/W: Interrupt Enable Register volatile unsigned char iir; // R: Interrupt ID Register volatile unsigned char lcr; // R/W: Line Control Register volatile unsigned char mcr; // W: Modem Control Register volatile unsigned char lsr; // R: Line Status Register volatile unsigned char msr; // R: Modem Status Register volatile unsigned char scr; // R/W: Scratch Register }; #define UART_LSR_TEMT 0x40 // Transmitter serial register empty #define UART_LSR_THRE 0x20 // Transmitter holding register empty #define UART_LSR_DR 0x01 // Receiver data ready #define UART_LCR_DLAB 0x80 // Divisor latch access bit #define UART_LCR_8BITS 0x03 // 8 bit data bits
The utility functions to set and clear flags in the UART (see Section 6.5) are reused here, modified for C rather
than C++ and volatile
register arguments. They
are included from the file binutils.c
#include "bitutils.c"
The main program declares a pointer to the UART register structure,
uart
, at the base address. Initialization
requires setting the divisor latch, to divide the main clock down to
16 x the baud rate and setting 8-bit data.
volatile struct uart16450 *uart = (struct uart16450 *)BASEADDR; unsigned short int divisor; divisor = CLOCK_RATE/16/BAUD_RATE; // DL is for 16x baud rate set( &(uart->lcr), UART_LCR_DLAB ); // Set the divisor latch uart->buf = (unsigned char)( divisor & 0x00ff); uart->ier = (unsigned char)((divisor >> 8) & 0x00ff); clr( &(uart->lcr), UART_LCR_DLAB ); set( &(uart->lcr), UART_LCR_8BITS ); // Set 8 bit data packet
The remainder of the program is a perpetual loop:
Wait for a character in the read buffer (flag
DR
of the line status register is set).
Read the character from the buffer and print it.
Wait for the transmit buffer to clear (flags
TEMT
and THRE
of the line
status register are set).
Write the character back.
while( 1 ) { unsigned char ch; do { // Loop until a char is available ; } while( is_clr(uart->lsr, UART_LSR_DR) ); ch = uart->buf; simputs( "Read: '" ); // Log what was read simputc( ch ); simputs( "'\n" ); do { // Loop until the transmit register is free ; } while( is_clr( uart->lsr, UART_LSR_TEMT | UART_LSR_THRE ) ); uart->buf = ch; }
The source code for the UART loopback program may be found in
progs-or32/uart-loop.c
in the distribution. It
will be built using the OpenRISC 1000 tool chain as part of the overall
system build.