So I am new to this and trying to learn about registers and UARTs and have been given the following code to study.
#include <stdint.h>
typedef volatile struct {
uint32_t DR;
uint32_t RSR_ECR;
uint8_t reserved1[0x10];
const uint32_t FR;
uint8_t reserved2[0x4];
uint32_t LPR;
uint32_t IBRD;
uint32_t FBRD;
uint32_t LCR_H;
uint32_t CR;
uint32_t IFLS;
uint32_t IMSC;
const uint32_t RIS;
const uint32_t MIS;
uint32_t ICR;
uint32_t DMACR;
} pl011_T;
enum {
RXFE = 0x10,
TXFF = 0x20,
};
pl011_T * const UART0 = (pl011_T *)0x101f1000;
pl011_T * const UART1 = (pl011_T *)0x101f2000;
pl011_T * const UART2 = (pl011_T *)0x101f3000;
static inline char upperchar(char c) {
if((c >= 'a') && (c <= 'z')) {
return c - 'a' + 'A';
} else {
return c;
}
}
static void uart_echo(pl011_T *uart) {
if ((uart->FR & RXFE) == 0) {
while(uart->FR & TXFF);
uart->DR = upperchar(uart->DR);
}
}
void c_entry() {
for(;;) {
uart_echo(UART0);
uart_echo(UART1);
uart_echo(UART2);
}
}
I am just wondering if someone could explain how the pl011
DR
and FR
registers transmit and receive data over the associated UART peripheral.
Any help at all would be much appreciated.
There's some nice documentation on this UART here - http://infocenter.arm.com/help/topic/com.arm.doc.ddi0183g/DDI0183G_uart_pl011_r1p5_trm.pdf
The way this program works is influenced by whether the UART is in FIFO
mode or not. I have not read enough of the doco to know which is the default state. The operation of the Tx and Rx differ slightly depending on this mode. It looks like the code is working only on single words, so possibly it's not in FIFO mode (or it doesn't matter for this code).
FR
is the UART Flag Register (AKA UARTFR
). This contains a bunch of bits that can be queried to see what the state of the UART is. Two important ones for this question are:
TXFF
is a bit in FR
, it becomes 1
when the transmit buffer is full.RXFE
is a bit in FR
, it becomes 1
when the receive buffer is emptyDR
is the UART Data Register (AKA UARTDR
). This holds the data to be transmitted, and data that has been received.
So Looking at the main working part of the code ~
static void uart_echo( pl011_T *uart )
{
if ( ( uart->FR & RXFE ) == 0 ) // While the receive buffer is NOT empty
{
while( uart->FR & TXFF ); // Do <nothing> while the Tx buffer is full
// Read the content of the Data Register, converting it to uppercase(),
// then make a write to the DR, which initiates a transmit
uart->DR = upperchar(uart->DR);
}
}
So this function is echoing back whatever it reads, but in uppercase. The program is calling this for each of the three UART's, in turn.