Serial communication(UART) serves an important purpose of communicating with the external devices just using two pins (RX and TX).This tutorial focuses on Programming UART aka Serial communication in ARM7 Microcontrollers.I assume that you are familiar with the working principle behind Serial communication in Microcontrollers, so let's not waste time with the introductions.
UART IN ARM MICROCONTOLLERS:
ARM controllers consists of two in built UART's namely UART0 & UART1.Both the UART's are similar in nature except modem interface which is present in UART1.In this tutorial we focus on programming UART0 and you can learn UART1 by yourself.
REGISTERS USED:
Here is the list of registers used to Program UART0
U0RBR:
UART0 Receiver Buffer register is used to store the received data from external devices via RXD0 pin.
U0THR:
UART0 Transmit Buffer Register used to hold the data which is about to transmit to external devices from the Microcontroller.
U0LCR:
UART0 Line Control register is used to assign the format such as word length, parity, stop bits etc of the data that is to be transmitted or received.DLAB bit of this register plays a significant role, it must be 1 to access Baud rate generation registers (U0DLM & U0DLL) whereas it should be 0 to access TX and RX registers (U0RBR & U0THR).
U0LSR:
UART0 Line Status Register is a read only register which is used to understand the status such as Transmission complete, Receive complete etc of the UART0.
U0DLM & U0DLL:
These two registers are used to generate the required Baud rate for the serial communication to take place.These Two register UART0 Divisor Latch MSB (U0DLM) & UART0 Divisor Latch LSB (U0DLL) together forms a 16 bit register which holds a divisor value to generate baud rate from VPB clock.
BAUD RATE GENERATION IN UART0:
As i said above the two registers U0DLM & U0DLL holds the 16 bit value for baud rate generation and we have to determine this value and load in these registers to generate required baud rate.The value in these registers will divide the VPB clock to generate the required baud rate clock for the UART and it must be 16x of the desired baud rate.
Here we are about to use standard "9600" as Baud rate.Since it must be 16x of desired rate for calculation
Required Baud Rate = 16 x Desired Baud Rate
Required Baud Rate = 16 x 9600
Required Baud Rate = 153600
We are using external crystal frequency of 20MHz, and by default Peripheral Clock is 1/4 th of the processor clock fed in to the controller.
VPB Clock or Peripheral Clock = 20MHz/4 = 5MHz
To obtain the value of the U0DLM & U0DLL
Value = 5MHz / Desired Baud Rate
Value = 5000000/153600 = 32.5
Value =33
33 Equivalent Hex value is 0x21.So the values of U0DLM & U0DLL are
U0DLM= 0x00
U0DLL= 0x21
STEPS TO PROGRAM UART:
- Assign the format of the data to be transmitted or received using U0LCR register.
- Make the DLAB bit in the U0LCR register to access the Baud rate registers U0DLM & U0DLM to set the desired baud rate.
- After setting the baud rate make the DLAB bit low to access the U0THR and U0RBR to send and receive data .
- Then preform either transmit or receive operation using your microcontroller.
- You can determine the status of the UART0 using the U0LSR register.
CODE:
The below code was built using Keil uVision 4.This code was built in way to send three characters "SND" initially and then display the received characters in a LCD.
#includevoid delay(void)!void receive(void)!void transmit(void)!char c!void lcd(unsigned char a,int b)!int main(void) { PINSEL0|=(1<<0)|(1<<2)!//Selecting pin functions PINSEL2=0!IODIR1=0x03ff0000!//Setting Directions for LCD lcd(0x38,0)!lcd(0x0f,0)!U0LCR=(1<<7)!//Making DLAB bit as '1' U0DLL=0x21!//Baud Rate Value U0LCR=0x03!//DLAB as 0 and word length selection delay()!transmit()!while(1) { receive()!//Infinite receive loop } } void delay(void) //Software Delay { unsigned int i!for(i=0;i<=3000;i++)!} void lcd(unsigned char a,int b) //LCD subroutine { IOSET1=a<<16!IOSET1=b<<24!IOSET1=1<<25!delay()!IOCLR1=1<<25!IOCLR1=b<<24!IOCLR1=a<<16!} void receive(void) //Receive subroutine { while(!(U0LSR&(1<<0)))!//Status check c=U0RBR!lcd(c,1)!} void transmit(void) //Transmit subroutine for "SND" { U0THR='S'!while(!(U0LSR&(1<<5)))!//Status check U0THR='N'!while(!(U0LSR&(1<<5)))!U0THR='D'!while(!(U0LSR&(1<<5)))!}