Basic communication protocol - UART
Anyone who first enter to the embedded world are either taught or at least heard about the 3 most basic communication protocols: UART, SPI and I2C. These protocols, in other words, are as important as languages in human world.
Basically, different embedded hardwares (micro-controller, sensor, etc) support different ways to interact with. Some of them are only support one protocol, like people who can only speak in their mother language, while other supports several ones. Therefore, having a deep knowledge about them definitely help you a lot in building your own projects, especially if you are an embedded engineer.
Here are 3 all my blogs in “Embedded knowledge: Basic communications” series in case you’ve missed any of them:
In this series, I also share my working experience with these protocols.
Each section is arranged in order, includes explanation why we need to have this and that.
Now, let’s get started!
Let’s begin with a simple case: Ted and Marshall are in a conversation.
Figure 01: Ted and Marshall are in a conversation
In the simplest case, there are 3 pre-conditions for a successful communication:
a. A or B or both are able to speak and hear.
b. A and B are speaking the same language (aka. protocol)
c. An environment for the conversation. This is air in this case.
The exact same things happen when we deal with the microcontroller. In order to transfer data between 2 devices:
a. One or both are able to transfer data (through a logic pin, antenna, …)
b. Both are using the same protocol (UART, I2C, SPI…)
- Wire: UART, I2C, SPI… . The number of wires depends on each protocol.
- Wireless: bluetooth, wifi, NFC, …
Therefore, with UART, we will have
Figure 02: UART
There are many ways to connect 2 microcontrollers in UART protocol themselves. Let’s take a look at some most popular.
Connection - Simplex
Figure 03: Simplex connection
- Data transmission goes only in 1 direction.
- Use 1 wire for data transferring (2 wires if having flow control)
Connection - Half-duplex
Figure 04: Half-duplex connection
- Data transmission goes in both directions but not simultaneously.
- Use 1 wire (2 wires if having flow control).
- 1 pin will be either TX (transmit data) pin or RX (receive data) pin.
- If flow control is enabled, it will be either CTS if its side would like to transfer data or RTS if receiving data. (We will talk about this in section 2.5)
Connection - Full-duplex
Figure 05: Full-duplex connection
- Data transmission goes in both directions and simultaneously.
- Use 2 wires (4 wires if having flow control).
- About flow control, I will explain what this is and why we need it in section 2.5
- The most common way to set up UART is using the full-duplex without flow control.
Figure 06: Full-duplex, no flow control
To make sure the data is correct, A and B must have to have the same 5 configures as below:
Figure 07: UART configurations
Why do we need Start bit and Stop bit?
UART stands for Universal Asynchronous Receiver/Transmitter. Asynchronous means that we are not using a clock signal to synchronize the transmission.
→ Need another way to know when to read the data and when to stop transferring data.
→ Start bit and stop bit: these bits define the beginning and end of the data packet. Therefore, the receiving UART knows when to start reading the bits.
Why do we need Baudrate?
When receiver detect start bit, it will start reading the incoming bits at a specified frequency called BAUD RATE (unit: bit per second) (aka sampling the data on the line with the frequency BAUD RATE)
→ Both UART have to at about the same Baudrate. If not, the data after sampling will return false value leading to wrong data.
Moreover, there is always an error rate when transferring data through UART. The baud rate between the transmitting and receiving UARTs can only differ by about 10% before the timing of bits gets too far off and cause an unacceptable error rate.
Here is an example of UART error rate corresponding to each Baudrate (picture is taken from MSP430FR userguide, pg.579)
Figure 07.1: UART Baudrate and error rate
As can be seen in the table, as Baudrate increases, the error rate is also increased. This is the trade-off between speed and efficiency you will have to accept.
Why do we need parity bit?
What if you want to have a high transfer bit but still want the received data correct?
We will need an error detection method. By using this, we know when the data is wrong and therefore, request the TX side to re-send that data.
The parity bit is the simplest form of error detecting code and only can detect a single bit error. In the production code, we usually implement other methods like CRC, MD5,… to make sure our data is preserved.
I have another article here talking about hashing mechanism (CRC, MD5,..) in case you would like to know more.
And here is the whole communication process between A and B
Figure 08: Full UART transmission process
MCU 1 wants to transfer 8 bits “1 0 1 1 0 0 1 0” to MCU2
1. Transmit pin of MCU1 has to be connected with the Receive pin of MCU2.
2. Both sides has to be config as the same Start bit, Baud rate, Parity and Stop bit.
Step 1: MCU1 has 8bits needed to be sent out.
Step 2: MCU1 creates a full data frame with Start bit – Data – Parity – Stop bit.
Step 3: MCU1 starts generating the signal on its TX pin accordingly to the data frame. Bit width is 1/BAUDRATE.
Step 4: Right at the time MCU2 receives the falling edge on the line, it will start the clock signal to start sampling data. The clock period on MCU2 = bit width on MCU1 = 1/BAUDRATE. That’s why we have to has the same baud rate on both side or MCU2 cannot sampling at the correct frequency, leading to failure in reading data.
There are several ways to config sampling: sampled at the rising edge of the clock (as shown on the picture), sampled at the falling edge or sampled at the middle of the pulse.
Step 5: MCU2 stops the clock which is used to sampling data rafter receiving stop bit. The data will be processed after this step.
In the microcontroller, the UART peripheral will do all for us from step 2 to step 5. All we have to do is the “precondition” and step 1 (which is deciding what we want to send out).
What is UART Bit-bang?
So what if the MCU does not have enough UART module to use? or we want to use another pin for UART which is not supported by the UART peripherals.
We have to create our own UART module, in another word, UART bit-bang.
In UART bit-bang, we have to do all step from 1 to 5 (section 2.3) by ourselves, from either 1 or both sides of 2 MCUs.
- Can use other pins supporting GPIO.
- Fully-control, actually we can do some modifications to make UART protocol more reliable. Considering the case that we are able to change the duration of start-bit from 1 bit to more than 1 bit. This is because sometimes the data line is accidentally pulled to low by some disturbance, long wiring, etc… By doing this we can make it more stable to the disturbance.
- Complicated and can have potential bugs.
What is flow control ?
Let’s consider about another case:
MCU1 transfers data to MCU2. However, MCU2’s processing time is slower than MCU1s.
At some point, MCU2 cannot keep up with this anymore. It either processes data or somehow empty its receive buffer before continuing to receive data. If not, it can be ended up by losing data while MCU1 continues to send out the message while MCU2 are busy with the old data.
→ Using flow control to handle this issue.
Flow control is the method to handle the UART communication between a fast and slow device without the risk of losing data.
MCU2 will use flow-control to create a signal back to MCU1 to stop/pause or resume the transmission.
There are severals way to implement flow-control to our UART protocol, either by using hardware flow-control or software flow-control.
Hardware flow control
Let’s take a look at how we config the hardware flow control in figure 09 and 10.
Figure 09: UART flow control config
Figure 10: UART flow control
A would like to transfer data to B, before sending data, A will check A_CTS (aka B_RTS). If that line is low → B is asserted it → B is still ready to receive more data → A continue to send.
Whenever B want to stop receiving data to process something else, it will de-assert the B_RTS (A_CTS) → A will check that line and stop sending.
Software flow control
Instead of using additional wires for flow control, software flow control start/stop by sending special flow control character on the TX/RX line.
The special flow control characters are usually the ASCII code XON and XOFF (0x11 and 0x13).
When A send XOFF to B, B will stop the transmission until receiving XON from A.
Coming up next!
So we’ve just finished the first article in the Basic Communication Protocol series. We will talk about the SPI protocol in the next article.