To transfer data, computers adopt two method: serial and parallel. In serial communication data is sent a bit at a time (1 line)while in parallel communication 8 or more lines are often used to transfer data. The UART is a form of serial communication
When distance is short, digital signal can be transferred as it is on a single wire and require no modulation. This is how PC keyboard transfer data between the keyboard and motherboard.
For long distances like telephone lines, serial data communication requires a modem to modulate.We will not go into the details of this in this lesson, this shall be left for subsequent lessons.
Synchronous vs. Asynchronous
Serial communication operate in two ways : synchronous and asynchronous. In the synchronous mode, a block of data is sent at a time while in the asynchronous mode, a single byte of data is sent at a time.
It is possible to write code to provide both the synchronous and asynchronous serial communication functions however this could turn out tedious and over complicated therefore, special chips are manufactured to perform these functions. When these chips are added to a microcontroller, they become known as Serial Communication Interface (SCI). The chip that provides the the asynchronous communication (UART) is the main theme of this lesson. The chip for synchronous communication is known as the USART and shall left for another lesson.
Asynchronous Communication Data Framing
The data is received in zeros and ones format, in order to make sense of the data, the sender and the receiver must agree on a set of rules i.e. a protocol, on how data is packed, how many bits constitute a character and when data begins and ends.
The Protocol
- Start and Stop bits
Asynchronous serial communication is widely used in character transfer. Each character is packed between start and stop bits. This is known as the framing.
start bit : Always 1 bit, value is always 0
stop bit: 1 or 2 bits, value is always 1
Lets take an example. Lets say we are transferring ASCII character ‘A’
its binary code is 0100 0001 and 0x41 in hex.Furthermore, it is framed between a start bit and 2 stop bits. This is what its frame will look like.
2. Parity bit
Some systems require parity bit in order to maintain data integrity.The parity bit of a character byte is included in the data frame after the stop bit(s).
3.Rate of data transfer : Baud rate/bps
We shall explain this concept with an example. Lets say we are asked to calculate the number of bits used and time taken in transferring 50 pages of text, each with 80×25 characters. Assuming 8 bits per character and 1 stop bit
solution
For each character a total of 10 bits is used ( 1 start bit, 8 bits character, 1 stop bit).
Therefore total number of bits = 80 x 25 x10 = 20,000 bits per page
50 pages implies, 50×20,000 = 1,000,000 bits.
Therefore it will take 1 million bits to transfer this information.
The time it takes to transfer the entire data using
a. 9600 baudrate implies, 1,000,000 / 9600 = 204 seconds
b. 57,600 baudrate implies 1,000,000 /57,600 = 17 seconds
Baudrate simply means the transfer of bits per second. There are various standardized baudrate we can choose from when we program our serial communication devices. The key thing is, both communication devices must have the same baudrate. We shall see this later on in our example code.
Programming the ARM Cortex-M UART
ARM Cortex – microconrtollers from different vendors come with more than 1 internal UARTs. For instance the the ARM Cortex-M4 Tiva Launchpad from Texas Instrument comes with 8 UARTs.
Two registers are used to set the baudrate:
-UART Integer Baudrate Divisor
-UART Fraction Baudrate Divisor
To get your desired baudrate, its simply SystemClock / (16 x ClkDiv)
SystemClock can be : XTAL,PLL, internal RC etc.
ClkDiv : value we load into the divisor register
Steps to configure UART and Transmit a byte of data
- Provide clock to UART by writing 1 to UART clock gating register
- Provide clock to the GPIO port the UART function is connected .
- Disable the UART by writing 0 to the UART control register.
- Write the integer portion of the Baudrate to the UARTIBRD register.
- Write the fractional portion of the Baudrate to the UARTFBRD register.
- Select the system clock as UART clock source .
Important Registers
Before we move on to provide example source code, there are 3 important registers we need to take a closer look at.
UART Control Register
As mentioned in the earlier section, in calculating the baudrate, the default system clock is divided by 16, however, we can decide to divide it by 8 by the setting the 1 to the HSE bit of the UART control register. The HSE implies, High-Speed-Enable.
Important bits in the UART control register include:
- UARTEN : To enable and disable UART
- HSE : High speed enable, to run high baudrate with low frequency
- RXE: This must be enabled in order to receive data
- TXE: This must be enabled in order to transmit data
UART Line Control Register
This register is used to set the number bits per character i.e. data length
Also used to set the stop bit. This what the register looks like:
The default stop bit is 1 to set the stop bit to 2 set STP2 (D3) bit =1
FEN(D4) : It is known as the FIFO enable.
Because of the 1 byte transfer / receive limitation, the CPU keeps getting interrupted every time a single byte of data is transferred. This could create bottleneck especially in multitasking systems. Therefore cortex -microcontrollers provide FIFO buffers to store data for transmission. The ARM Cortex-M4 TM4C123 provides a 16-bytes FIFO buffer to store data for transmission and another 16-bytes FIFO buffer to save all received data.
When FEN is enabled, we can write up 16-bytes of data block into the transmission FIFO buffer and let it transfer a byte a time.
Also, the developer may set threshold for UART to notify the CPU when level of FIFO passes threshold.
WLEN (D6 – D5) : Word length. this is used to set the number of bits per character. Character data in each frame can be 5,6,7 or 8. Generally, 8 bits is used. The default value is 5 on some cortex-microcontrollers and must be set to 8 simply by setting D5 =1 and D6=1.
UART Data Register
Data to be transmitted is placed in the UART data register
Only the lower 8-bits are used
A write to this register initializes a transmission from the UART
A read receives transmitted bytes. For read, the lower 8-bits hold the received byte, other 4 bits are used for error detection e.g. parity, framing etc.
Programming UART on ARM Cortex-m4 TM4C123 Tiva C LaunchPad
In this example the TM4C123 micocontroller communicates with the PC by means of UART communication protocol. On the PC side, we need to download a serial terminal program to receive and send data from the pc. Tera Term is a highly recommended one, it can be downloaded just by doing a google search. After downloading and installing, follow the setup depicted in the two figures below.
When the program is opened, select the “Serial” radio-button and in the drop-down select “COMx :Stellaris Virtual Serial Port” or any other port name you think relates to your microcontroller (the names in the drop-down vary sometimes)
This is the default setting but just to sure go to Setup -> Serial Port…
and verify.
In the program presented below, when any key is pressed in Tera terminal, the LEDs on the TM4C123 Tiva C launchpad either change color or go off depending on the ascii value of the key pressed .
Note : The pressed key will not be printed in the terminal, just the LEDs will change.
Program :
#include "TM4C123.h" // Device header #include <stdint.h> char UART0Rx(void); void delayMs(int n); int main(void) { char c; SYSCTL->RCGCUART |= 1; /* provide clock to UART0 */ SYSCTL->RCGCGPIO |= 1; /* enable clock to PORTA */ SYSCTL->RCGCGPIO |= 0x20; /* enable clock to PORTF */ /* UART0 initialization */ UART0->CTL = 0; /* disable UART0 */ UART0->IBRD = 104; /* 16MHz/16=1MHz, 1MHz/104=9600 baud rate */ UART0->FBRD = 11; /* fraction part, see Example 4-4 */ UART0->CC = 0; /* use system clock */ UART0->LCRH = 0x60; /* 8-bit, no parity, 1-stop bit, no FIFO */ UART0->CTL = 0x301; /* enable UART0, TXE, RXE */ /* UART0 TX0 and RX0 use PA0 and PA1. Set them up. */ GPIOA->DEN = 0x03; /* Make PA0 and PA1 as digital */ GPIOA->AFSEL = 0x03; /* Use PA0,PA1 alternate function */ GPIOA->PCTL = 0x11; /* configure PA0 and PA1 for UART */ GPIOF->DIR = 0x0E; /* configure Port F to control the LEDs */ GPIOF->DEN = 0x0E; GPIOF->DATA = 0; for(;;) { c = UART0Rx(); /* get a character from UART */ GPIOF->DATA = c << 1; /* shift left and write it to LEDs */ } } /* UART0 Receive */ /* This function waits until a character is received then returns it. */ char UART0Rx(void) { char c; while((UART0->FR & 0x10) != 0); /* wait until the buffer is not empty */ c = UART0->DR; /* read the received data */ return c; /* and return it */ } /* Append delay functions and SystemInit() here */ void delayMs(int n){ int i,j; for(i=0;i<n;i++){ for(j=0;j<3180;j++) {} } }
Add Comment