UART (universal asynchronous receiver/transmitter)
Un receptor/transmisor asíncrono, es un modulo utilizado para realizar comunicaciones series de tipo asíncrona donde los datos son enviados sin una señal de reloj externa.
En una transmisión asíncrona, los datos son divididos en palabras de una longitud fija, generalmente octetos, a los cuales se le agregan al comienzo códigos de sincronismo y luego al final del word se pueden agregar espacios, con lo cual permite al receptor identificar un nuevo código de sincronismo.
Como se comentó arriba, las palabras suelen ser octetos, este tipo de comunicación asíncrona se denomina orientada a caracter y uno de los estándar mas comunes es el RS-232 (Recommended Standard 232).
RS-232
El estándar RS-232 es una norma para el intercambio de datos entre dos dispositivos denominados DTE (Equipo terminal de datos) con un DCE (Equipo de comunicación de datos), A pesar de que este estándar soporta comunicación síncrona, su uso mas habitual es en comunicaciones asíncronas por ejemplo el implementado en una PC.
En el caso habitual de una PC llamaremos a la misma DTE, donde el DCE generalmente era el modem, en el caso de comunicarse dos PC entre si (DTE con DTE) no habrá modem, con lo cual la conexión se llamará Null Modem, en estos casos el cable que une las dos computadoras, debe unir las señales de manera cruzada, es decir por ejemplo que la señal denominada TxD en una de las PC debe unirse con la denominada RxD de la otra PC.
Señales
Denominación |
Descripción |
Origen |
Conector |
||
|
|
DTE |
DCE |
DB25 |
DB9 |
Common Ground (GND) |
|
|
|
7 |
5 |
Transmitted Data (TxD) |
Datos enviados desde DTE a DCE |
X |
|
2 |
3 |
Received Data (RxD) |
Datos enviados del DCE a DTE |
|
X |
3 |
2 |
Request To Send (RTS) |
Solicitud (0 lógico o voltaje positivo ) de DTE preparar al DCE a recibir un dato. |
X |
|
4 |
7 |
Clear To Send (CTS) |
Respuesta del RTS por parte del DCE al DTE, para que este último transmita. |
|
X |
5 |
8 |
Data Terminal Ready (DTR) |
Solicitud del DTE de que está listo para conectarse |
X |
|
20 |
4 |
Data Set Ready (DSR) |
Solicitud del DCE indicando que el DCE esta listo para recibir comandos o datos del DTE |
|
X |
6 |
6 |
Data Carrier Detect (DCD) |
Señal del DCE cuando la conexión ha sido establecida con el equipamiento remoto |
|
X |
8 |
1 |
Ring Indicator (RI) |
Señal del DCE cuando se detecto una señal de ring en la linea telefónica |
|
X |
22 |
9 |
UART en el LPC2114
El microcontrolador implementa dos UART compatibles con el el estándar 16550 (UART0 y UART1) Si bien ambas UART poseen todos los registros internos y modo de configuración igual a la conocida 16550 que encontramos en las PCs, solo la UART1 implementan todos los pies de entrada/salida, mientras que la UART0 solo posee los necesarios para una comunicación de 3 lineas (Rx y Tx).
Lineas de comunicación
UART0
Señal |
Tipo |
Pin |
RxD0 |
Entrada |
21 |
TxD0 |
Salida |
19 |
UART1
Señal |
Tipo |
Pin |
RxD1 |
Entrada |
34 |
TxD1 |
Salida |
33 |
CTS1 |
Entrada |
37 |
DCD1 |
Entrada |
41 |
DSR1 |
Entrada |
38 |
DTR1 |
Salida |
39 |
RI1 |
Entrada |
45 |
RTS1 |
Salida |
35 |
Características
- FIFO de Recepción y Transmisión de 16 byte.
- Registro conforme al estándar 550.
- Trigger de recepción a los 1,4,8 y 14 bytes.
- Generador de baud rate incorporado.
Registros de la UART
Ambos módulos UART poseen una serie de registros para leer o escribir los datos que transitan por el enlace como así también registros para configurar la UART y leer el estado de la misma.
Para que ambos módulos sean compatible con el estándar 550, los mismos son de 8 bits, si bien están dispuestos cada 4 bytes, solo se utiliza el menos significativo.
Nombre |
bit7 |
bit6 |
bit5 |
bit4 |
bit3 |
bit2 |
bit1 |
bit0 |
Modo |
Dirección |
U0RBR |
Registro de Recepción |
R |
0E000C000 DLAB = 0 |
|||||||
U0THR |
Registro de Transmisión |
W |
0E000C000 DLAB = 0 |
|||||||
U0DLL |
DLR Menos significativo |
R/W |
0E000C000 DLAB = 1 |
|||||||
U0DLM |
DLR Mas significativo |
R/W |
0E000C004 DLAB = 1 |
|||||||
U0IER |
N/A |
Rx |
THRE |
RBR |
R/W |
0E000C004 DLAB = 0 |
||||
U0IIR |
FIFO |
N/A |
Ident.Int |
I.Pen |
R |
0E000C008 |
||||
U0FCR |
trigger |
N/A |
R.Tx |
R.Rx |
Hab |
W |
0E000C008 |
|||
U0LCR |
DLAB |
Break |
Paridad |
H.Par |
Stop |
Largo |
W/R |
0E000C00C |
||
U0LSR |
RXFE |
TEMT |
THRE |
BI |
FE |
PE |
OE |
RDR |
R |
0E000C014 |
RBR/THR Registro de Recepción y Transmisión
- La misma posición de memoria es utilizada por dos registros, a cual accederemos, depende del tipo de operación realizada sobre esa memoria.
- Operación de lectura, estaremos accediendo al registro de recepción el cual posee el byte recibido mas antiguo contenido en la FIFO, en caso de configurar una trama menor a 8 bits de datos, los bits mas altos de este registro permanecerán en 0.
- Operación de escritura, el registro será colocado en la FIFO para ser transmitido.
En ambos casos el DLAB (Divisor Latch Access Bit) debe ser cero
Nombre |
bit7 |
bit6 |
bit5 |
bit4 |
bit3 |
bit2 |
bit1 |
bit0 |
Modo |
Dirección |
U0RBR |
Registro de Recepción |
R |
0E000C000 DLAB = 0 |
|||||||
U0THR |
Registro de Transmisión |
W |
0E000C000 DLAB = 0 |
DLR (Divisor Latch Register)
- Esta compuesto en realidad por dos registros de 8 bits cada uno el LSB y MSB, donde el LSB comparte la dirección de memoria con el registro de recepción y transmisión y el MSB lo hace con el registro de habilitación de interrupción.
El valor total formado por los dos registros, tendrá una longitud de 16bits y es el divisor del VPB que se deberá configurar para determinar el baud rate de la transmisión y/o recepción.
El baud rate será calculado como:
VPB baud rate = ---------- DLR x 16
Conociendo la velocidad con la cual deseamos transmitir y la frecuencia del VPB, podemos despejar el DLR, el cual nos dará un valor de 16 bits, guardando en DLL el byte menos significativo y en DLM el mas significativo.
Nombre |
bit7 |
bit6 |
bit5 |
bit4 |
bit3 |
bit2 |
bit1 |
bit0 |
Modo |
Dirección |
U0DLL |
DLR Menos significativo |
R/W |
0E000C000 DLAB = 1 |
|||||||
U0DLM |
DLR Mas significativo |
R/W |
0E000C004 DLAB = 1 |
IER Registro de habilitación de interrupción
Este registro es el usado para habilitar las diferentes interrupciones que puede realizar la UART según distintos eventos
- bit 0 RBR habilita la generación de una interrupción cuando hay un dato disponible para leer
- bit 1 THRE habilita la generación de la interrupción cuando la FIFO de transmisión se ha vaciado, el estado de esta interrupción puede ser leída en el bit 5 del U0LSR
- bit 2 Rx Line Status habilita la generación de una interrupción por Rx, el estado de esta interrupción puede ser leída de U0LSR[4:1].
Nombre |
bit7 |
bit6 |
bit5 |
bit4 |
bit3 |
bit2 |
bit1 |
bit0 |
Modo |
Dirección |
U0IER |
N/A |
Rx |
THRE |
RBR |
R/W |
0E000C004 DLAB = 0 |
IIR Registro de identificación de Interrupción
- Muestra el estado de las interrupciones, pudiendo leer el origen y la prioridad de una interrupción pendiente, las interrupciones son congeladas en un acceso a la U0IIR, si ocurriera alguna interrupción en el momento en que se accede, esta se reflejara recién la próxima vez
- bit 0 interrupción pendiente 0 = al menos una interrupción está pendiente, las interrupciones pendientes pueden ser leídas en U0IIR[3:1]
- bits 1 a 3 identificación de interrupción:
bits |
Prioridad |
Denominación |
Descripción |
Reset |
011 |
1 |
Receive Line Status (RLS) |
Es generada por cuatro condiciones de error, (OE) overrun error, (PE) Parity error, (FE) Framing error o error de trama y (BI) break interrupt |
leyendo el U0LSR |
010 |
2a |
Receive Data Available (RDA) |
Se activa cuando la FIFO de lectura llegue a la cantidad establecida en U0FCR[7:6]. |
leyendo U0RBR o modificando la FIFO a un valor mas alto |
110 |
2b |
Character Time-out Indicator (CTI) |
Ocurre cuando hay al menos un carácter en la FIFO de recepción y no ocurrió ninguna actividad en la misma por 3,5 a 4,5 tiempos de caracter, esta interrup., permite leer uno o varios datos que quedaron en la FIFO pero que por su cantidad no llega a generar una RDA |
leyendo el URBR |
001 |
3 |
THRE Interrupt |
Es activada cuando la FIFO de transmisión se vacía |
leyendo el U0IIR o escribiendo el U0THR |
- bit 6 a 7 FIFO equivalente al los bits correspondiente al FCR[6:7]
Nombre |
bit7 |
bit6 |
bit5 |
bit4 |
bit3 |
bit2 |
bit1 |
bit0 |
Modo |
Dirección |
U0IIR |
FIFO |
N/A |
Ident.Int |
I.Pen |
R |
0E000C008 |
FCR Registro de Control de FIFO
- bit 0 habilitar FIFO, activo por alto, habilita las dos FIFO (recepción y transmisión), este bit además habilita el resto de la configuración de este registro
- bit 1 borrar FIFO de Rx, un 1 es este bit borra toda la FIFO de recepción, luego de esto, es puesto a 0 por la misma UART
- bit 2 borrar FIFO de Tx, un 1 es este bit borra toda la FIFO de transmisión, luego de esto, es puesto a 0 por la misma UART
- bit 6 a 7 Selector del nivel de trigger de Rx, selecciona a cuantos caracteres recibidos se activará la interrupción RDA
- 00: trigger nivel 0 (1 caracter)
- 01: trigger nivel 1 (4 caracteres)
- 10: trigger nivel 2 (8 caracteres)
- 11: trigger nivel 3 (14 caracteres)
Nombre |
bit7 |
bit6 |
bit5 |
bit4 |
bit3 |
bit2 |
bit1 |
bit0 |
Modo |
Dirección |
U0FCR |
trigger |
N/A |
R.Tx |
R.Rx |
Hab |
W |
0E000C008 |
LCR Registro de Control de Linea
Determina el formato de los datos a transmitir o recibir
- bits 0 a 1 Selección del largo del word
- 00: 5 bit de largo
- 01: 6 bit de largo
- 10: 7 bit de largo
- 11: 8 bit de largo
- bits 2 Largo del bit de stop
- 0: 1 bit de stop
- 1: 2 bit de stop ( 1.5 en caso de 5 bit de largo )
- bit 3 Habilitar Paridad esto significa que con 1, estos agregando un bit extra a los datos, el valor de este bit depende de la selección de paridad (bit 4:5)
- bits 4 a 5
- 00: paridad impar
- 01: paridad par
- 10: fuerza a 1 el bit de paridad
- 11: fuerza a 0 el bit de paridad
- bit 6: Control de Corte, cuando se configura a 1, fuerza al pin de transmisión a un valor lógico 0
- bit 7: bit de acceso al divisor de latch (DLAB) este bit en 1 permite el acceso a los registro del divisor de latch ( DLL y DLM )
Nombre |
bit7 |
bit6 |
bit5 |
bit4 |
bit3 |
bit2 |
bit1 |
bit0 |
Modo |
Dirección |
U0LCR |
DLAB |
Break |
Paridad |
H.Par |
Stop |
Largo |
W/R |
0E000C00C |
LSR Registro de Estado de la Linea
- es un registro de solo lectura que provee acceso a estado del bloque de transmisión y recepción
- bit 0: Receiver Data Ready (RDR), un 1 en este bit indica que hay un dato dentro de la FIFO sin leer.
- bit 1: Overrun error (OE), se activa en el caso de que un nuevo caracter es recibido y la FIFO se encuentra llena, el caracter se pierde y se activa el OE
- bit 2: Parity Error (PE), se activa cuando la verificación de la paridad en el caracter recibido falla
- bit 3: Framing Error (FE), ocurre cuando en e bit de stop se lee un 0, esto puede ocurrir cuando no está correctamente sincronizado el receptor con respecto al transmisor queda a la espera de recibir todos 1
- bit 4: Break Interrupt (BI): se activa cuando recibe 0 durante el periodo de un dato (bit de start + datos + bit de stop) en este caso el receptor
- bit 5: Transmitter Holding Empty (THRE), un 0 indica que el registro de transmisión contiene datos 1 indica que este registro está vacío
- bit 6: Transmitter Empty (TEMT) un 1 indica que se transmitieron todos los datos
- bit 7: Error in Rx FIFO (RXFE) ocurre cuando el dato leído posee algún error (FE,PE o BI)
Nombre |
bit7 |
bit6 |
bit5 |
bit4 |
bit3 |
bit2 |
bit1 |
bit0 |
Modo |
Dirección |
U0LSR |
RXFE |
TEMT |
THRE |
BI |
FE |
PE |
OE |
RDR |
R |
0E000C014 |
Ejemplo UART
El ejemplo siguiente implementa una transmisión de la UART0, transmitiendo por polling las letras del abecedario La transmisión se realiza a 9600 baudios formato de la trama 8N1 (8 bit de datos, sin paridad y un bit de stop)
Los archivos fuentes pueden ser descargados de aqui
/* programa principal de prueba escribir sobre la uart mediante polling */ //-------------------Oscilador-------------- #define FOSC 14745600 //Frecuencia del cristal en Hz #define PLL_M 4 //Multiplicador del PLL #define VPBDIV_VAL 4 //Divisor #define UART_BAUD(Baud) (unsigned int)(((FOSC * PLL_M / VPBDIV_VAL) / ((Baud) * 16.0)) + 0.5) #include "main.h" int main (void) { unsigned char carac; /* inicializar UART */ UART_Init(); /* configurar el baud rate a 9600 baudios */ UART_BaudRateConfig(UART_BAUD(9600)); /* Configuración del registro de control */ UART0_LCR = 0x03; /* 00000011 8 bits sin paridad y 1 bit de stop */ /* Configuración de la FIFO */ UART0_FCR = 0x07; /* 00000111 activar fifo, reset de fifo Tx y Rx, trigger FIFO Rx = 1 caracter */ while(1) { for(carac='a';carac<='z';carac++) { UART_ByteSend(&carac); } } return 0; } /* ---------------------------------------------------------------------------- * inicializar UART * ----------------------------------------------------------------------------*/ void UART_Init() { PCB_PINSEL0 |= 0x00000005; UART0_IER = 0x00; // Deshabilita todas las interrupciones UART0_IIR = 0x00; // Borrar identificaciones de interrupciones UART0_LSR = 0x00; // Borra el "line status register" UART0_RBR = 0x00; // Borra el "receive register" } /* ---------------------------------------------------------------------------- * inicializar Baud Rate * ----------------------------------------------------------------------------*/ void UART_BaudRateConfig(unsigned int BaudRate) { UART0_LCR |= (1<<7); //DLAB en 1; UART0_DLL = (unsigned char) (BaudRate >> 0); UART0_DLM = (unsigned char) (BaudRate >> 8); UART0_LCR &= ~(1<<7); //DLAB en 0; } /* ---------------------------------------------------------------------------- * enviar un byte * ----------------------------------------------------------------------------*/ void UART_ByteSend(unsigned char *Data) { while((UART0_LSR & (1 << 5)) == 0); //Esperar hasta que al menos 1 posición de la FIFO esté libre. UART0_THR = *Data; } /* ---------------------------------------------------------------------------- * recibir un byte * ----------------------------------------------------------------------------*/ unsigned char UART_ByteReceive() { while((UART0_LSR & (1 << 0)) == 0); //Esperar hasta que haya un dato disponible. return (UART0_RBR); //Retorna el caracter. }