UART
UART
Hi again guys! In this tutorial we will go through the basics of UART(SERIAL) programming for LPC214x
family of microcontrollers. If you are new to UART, you can go through the basic UART tutorial which I’ve
posted @ Basic Uart Tutorial.
Introduction
Here is a quick recap of UART basics :
Uart uses TxD(Transmit) Pin for sending Data and RxD(Receive) Pin to get data. UART sends & receives
data in form of chunks or packets. These chunks or packets are also referred to as ‘transmission characters’.
The structure of a UART data packet is as shown below :
Now , Lets start with the main Tutorial. LPC214x has 2 UART blocks which are UART0 and UART1. For
UART0 the TxD pin is P0.0 and RxD pin is P0.1 and similarly for UART 1 the TxD pin is P0.8 and RxD pin is
P0.9 as shown in the table below :
Pins:
TxD
RxD
UART0
P0.0
P0.1
UART1
P0.8
P0.9
Note 1: Both UART0 & UART1 blocks internally have a 16-byte FIFO (First In First Out) structure to hold the
Rx and Tx data. Each byte in this FIFO represents a character which was sent or received in order. Both
blocks also contain 2 registers each, for data access and assembly.
Tx has THR(Transmit Holding Register) and TSR(Transmit Shift Register) – When we write Data to be
sent into THR it is then transferred to TSR which assembles the data to be transmitted via Tx Pin.
Similarly Rx has RSR(Receive Shift Register) and RBR(Receive Buffer Register) – When a valid data is
Received at Rx Pin it is first assembled in RSR and then passed in to Rx FIFO which can be then accessed
via RBR.
Note 2: The 4 mentioned UART Pins on LPC214x are 5V tolerant .. still make sure you are using 3.3v
Voltage-level for UART communication. Hence , if you have RS232 to serial TTL module make sure it
has MAX3232 =OR= if you are using FTDI’s FT232R based USB to serial TTL module make sure it is
configured for 3.3v I/O.
Note 3: UART1 on LPC214x features a full blown modem interface which includes additional Control and
Status pins which are found on a PC’s RS-232(Serial) port. But sadly most new mid-end to high-end PCs
don’t have RS-232 port these days and hence we have to use other options like FTDI’s USB to TTL converter
so that we can interface our microcontroller to a PC or a laptop using USB.
2) U0THR – Transmit Holding Register (WRITE ONLY!): U0THR contains the top most byte in Tx FIFO
and in this case its the newest(latest) transmitted data. As in the case with U0RBR , we must set DLAB=0 to
access U0THR for write operation.
2) U0FDR – Fractional Divider Register : This register is used to set the prescale value for baud rate
generation. The input clock is the peripheral clock and output is the desired clock defined by this register.
This register actually holds to different 4-bit values (a divisor and a multiplier) for prescaling which are:
1. Bit [3 to 0] – DIVADDVAL : This is the prescale divisor value. If this value if 0 then fractional baud rate
generator wont have any effect on Uart Baud rate.
2. Bit [7 to 4] – MULVAL : This is prescale multiplier value. Even if fractional baud rate generator is not used
the value in this register must be more than or equal to 1 else UART0 will not operate properly.
3. Other Bits reserved.
Remark from Usermanual : “If the fractional divider is active (DIVADDVAL > 0) and DLM = 0, the value of
the DLL register must be 2 or greater!”
Control and Status Registers :
1) U0FCR – FIFO Control Register : Used to control Rx/Tx FIFO operations.
1. Bit [1 to 0] – Word Length Select : Used to select the length of an individual data chunk. [00] for 5 bit
character length. Similarly [01] , [10] , [11] for 6 , 7 , 8 bit character lengths respectively.
2. Bit 2 – Stop bit select : 0 for using 1 stop bit and 1 for using 2 stop bits.
3. Bit 3 – Parity Enable : 0 to disabled Partiy generation & checking and 1 to enable it.
4. Bit [5 to 4] – Parity Select : [00] to Odd-parity , [01] for Even-parity , [10] for forced “1″(Mark) parity and [11]
for forced “0″(Space) parity.
5. Bit 6 – Break Control : 0 to disable break transmission and 1 to enable it. TxD pin will be forced to logic 0
when this bit is 1!
6. Bit 7 – Divisior Latch Access bit : 0 to disable access to divisor latches and 1 to enable access.
3) U0LSR – Line Status Register : used to read the status of Rx and Tx blocks.
1. Bit 0 – Receiver Data Ready(RDR) : 0 means U0RBR is empty(i.e Rx FIFO is empty) and 1 means U0RBR
contains valid data.
2. Bit 1 – Overrun Error(OE) : 0 means Overrun hasn’t occured and 1 means Overrun has occured. Overrun is
the condition when RSR(Receive Shift Register)[See note 1] has new character assembled but the RBR
FIFO is full and the new assembled character is eventually lost since no data is written into FIFO if its full.
(Note: Reading U0LSR clears this bit)
3. Bit 2 – Parity Error(PE) : 0 mean no parity error and 1 mean a parity error has occured. When the value of
the parity bit in the recieved character is in wrong state then a parity error occurs. (Note: Reading U0LSR
clears this bit)
4. Bit 3 – Framing Error(FE) : 0 means no framing error has occured and 1 means that a framing error has
taken place. Framing error occurs when the stop bit of a received character is zero. (Note: Reading U0LSR
clears this bit)
5. Bit 4 – Break Interrupt : 0 means no Break Interrupt occures and 1 means that it has occured. A Break
Interrupt occurs when the RxD line is pulled low (i.e all 0s) i.e held in spacing state for 1 full character after
which Rx Block goes into Idle state. Rx Block gets back to active state when RxD pin is pulled high (i.e all 1s)
i.e held in marking state for 1 full character. (Note: Reading U0LSR clears this bit)
6. Bit 5 – Transmit Holding Register Empty(THRE) : 0 means U0THR contains valid data and 1 means its
empty.
7. Bit 6 – Transmitter Empty (TEMT) : 0 means U0THR and/or U0RSR contains valid data and 1 means that
both U0THR and U0RSR are empty.
8. Bit 7 – Error in RX FIFO(RXFE) : 0 means that U0RBR has no Rx Errors or Rx FIFO is disabled(i.e 0th bit in
U0FCR is 0) and 1 means that U0RBR has atleast one error. (Note:This bit is cleared only if U0LSR is read
and there are no other subsequent errors in Rx FIFO .. else this bit will stay 1)
4) U0TER – Transmit Enable Register : This register is used to enable UART transmission. When bit-7 (i.e
TXEN) is set to 1 Tx block will be enabled and will keep on transmitting data as soon as its ready. If bit-7 is
set to 0 then Tx will stop transmission. Other bits are reserved.
2) U0IIR – Interrupt Identification Register: Refer User Manual when in doubt. In some application the
usage of this register might get a bit complicated.
1. Bit 0 – Interrupt Pending : 0 means atleast one interrupt is pending , 1 means no interrupts are pending.
Note: This bit is ACTIVE LOW!
2. Bits [3 to 1] – Interrupt Identification : [011] is for Receive Line Status(RLS) , [010] means Receive Data
Available(RDA) , 110 is for Character Time-out Indicator(CTI) , [001] is for THRE Interrupt.
3. Bits [7 to 6] – FIFO Enable.
4. Bit 8 – ABEOInt : 1 means Auto Baud Interrupt has successfully ended and 0 otherwise.
5. Bit 9 – ABTOInt : 1 means Auto Baud Interrupt has Timed-out.
6. All others bits are reserved.
As it can been seen this formula has 2 prominent parts which are : A Base value and aFractional
Multiplier i.e:
Where PCLK is the Peripheral Clock value in Hz , U0DLM and U0DLL are the divisor registers which we saw
earlier and finally DIVADDVAL and MULVAL are part of the Fractional baudrate generator register.
U0DLLPCLK in Hertz
= x Desired_BaudRate
16
But I’d recommend that stay away from above method, if possible, as it works only for particular
bauds given a specific PCLK value and moreover U0DLL might get out of range i.e. > 255 in which
case you have to start increasing DLM and recompute a new value for U0DLL.
2) The more involved method(Recommended):
Now lets see three examples for calculating Baud Rates Manually using some finetuning :
In these method we again start with DLM=0 , DIVADDVAL=0 and MULVAL=1 and get an initial value for
DLM. If you are lucky you will get a very close baudrate to the desired one. If not then we perform some
finetuning using DLM , MULVAL and DIVADDVAL and get a new value for DLM. There is on one single
method to perform finetuning and one can also make an algorithm for computing the best match given the
desired baudrate and PCLK. The finetuning method which I have given below is a basic one suitable for
beginners(in my opinion :P).
We get U0DLL = 195.3125 , since it must be an integer we use 195. With U0DLL = 195 our actual baud rate
will be = 9615.38 with an error of +15.28 from 9600. Now all we have to do is to get this error as low as
possible. This can be done by multiplying it by a suitable fraction defined using MULVAL and DIVADDVAL –
as given in equation. But since MULVAL & DIVADDVAL can be maximum 15 we don’t have much control
over the fraction’s value. Note: As per my convention I calculate BaudRate Error as = Actual BaudRate
– Desired BaudRate.
PCLK = 30 x 106 Hz
U0DLL = 183
U0DLM = 0
MULVAL = 15
DIVADDVAL = 0
PCLK = 60 x 106 Hz
U0DLL = 110
U0DLM = 1
MULVAL = 15
DIVADDVAL = 0
Note : 9600 is pretty famous Baud rate in embedded projects. Some of the standard Baud rates that can be
used are : 2400 , 4800 , 7200 , 9600 , 14400 , 19200 , 28800 , 38400 , 57600 , 115200 , 230400 , etc..
Now , as seen in Ex. 2 – in order to get 9600(9605 actually) bauds at 60Mhz PCLK we must use the following
settings for baud generation :
Now , lets make a function named “InitUART0()” which will configure and initialize UART0 as required :
void InitUART0(void)
{
PINSEL0 = 0x5; /* Select TxD for P0.0 and RxD for P0.1 */
U0LCR = 3 | (1<<7) ; /* 8 bits, no Parity, 1 Stop bit | DLAB set to 1 */
U0DLL = 110;
U0DLM = 1;
U0LCR = (15<<4); /* MULVAL=15(bits - 7:4) , DIVADDVAL=0(bits - 3:0) */
}
Once this is done you are now ready to transfer data using U0RBR and U0THR registers.
Scenario 1 : Your PC/Laptop already has a serial port. In this case you will need a RS232 to TTL converter.
If your development board has on-board RS232 to TTL chip (like Max232) .. then you just need to plugin the
serial cable on both sides. Just make sure that serial port is for UART0.
Scenario 2 : Your PC/Laptop doesn’t have a serial port and you are using USB to Serial converter based on
FTDI’s chip.
If you are using a separate converter then in both cases the TTL side of the converter will have 3 pins at bare
minimum which are: TX , RX and GND. Connect your MCU RX to TX of converter and MCU TX to RX of
converter. Finally connect GND on both sides. Make sure you module supports 3.3v voltage-levels.
Please refer to the connection diagrams & terminal software configuration(and COM ports) as given in Basic
Uart Tutorial.
Here is a configuration screenshot for terminal software PuttyTel which we will be using for examples :
Note : You can get PuttyTel from Here. Direct download link : Here. You can also use other similar terminal
software as well.
Source Code Examples
Now its time to actually use UART in real life! Lets do some communication between your lpc2148 MCU and
PC/Laptop. Before we get into actual examples for LPC2148 , first lets define 2 functions which will be used
to Read and Write Data from UART block.
U0Read() – Read Data from UART0:
#define RDR (1<<0) // Receiver Data Ready
char U0Read(void)
{
while( !(U0LSR & RDR ) ); // wait till any data arrives into Rx FIFO
return U0RBR;
}
Example 1 :
If everything goes good then you will see a text saying “Hello from LPC2148!” on a new line repeatedly.
Attention Plz! : The source for function initClocks() and other functions used by it is given in the
downloadable ‘.ZIP’ Project File which is attached below. The given code below is just a snippet from the
actual Project source file. This is also Valid for Example 2.
/*
(C) Umang Gajera | Power_user_EX - www.ocfreaks.com 2011-13.
More Embedded tutorials @ www.ocfreaks.com/cat/embedded
LPC2148 Basic UART Tutorial - Example 1 Source Code.
License : GPL.
*/
#include <lpc214x.h>
int main(void)
{
char msg[] = { 'H','e','l','l','o',' ','f','r','o','m',' ','L','P','C','2','1','4','8','\0' };
int c=0; // counter
for(;;)
{
while( msg[c]!='\0' )
{
U0Write(msg[c]);
c++;
}
U0Write(NEW_LINE); //get to the next line below
c=0; // reset counter
}
return 0;
}
void initUART0(void)
{
PINSEL0 = 0x5; /* Select TxD for P0.0 and RxD for P0.1 */
U0LCR = 3 | (1<<7) ; /* 8 bits, no Parity, 1 Stop bit | DLAB set to 1 */
U0DLL = 110;
U0DLM = 1;
U0FDR = (MULVAL<<4) | DIVADDVAL; /* MULVAL=15(bits - 7:4) , DIVADDVAL=0(bits - 3:0) */
U0LCR &= 0x0F; // Set DLAB=0 to lock MULVAL and DIVADDVAL
//BaudRate is now ~9600 and we are ready for UART communication!
}
Here is a snippet of Example 2 : (full source code given in project files – attached below)
/*
(C) Umang Gajera | Power_user_EX - www.ocfreaks.com 2011-13.
More Embedded tutorials @ www.ocfreaks.com/cat/embedded
#include <lpc214x.h>
int main(void)
{
initClocks(); // Set CCLK=60Mhz and PCLK=60Mhz
initUART0();
while(1)
{
char c = U0Read(); // Read Data from Rx
if( c == ENTER ) // Check if user pressed Enter key
{
U0Write(NEW_LINE); // Send New Line ASCII code change line
}
else
{
U0Write(c); // Write it to Tx to send it back
}
}
return 0;
}
char U0Read(void)
{
while( !(U0LSR & RDR ) ); // wait till any data arrives into Rx FIFO
return U0RBR;
}