Notes of PhiL    About    Categories    Tags    Archive    Feed    GitHub Repo

UT.6.03x Embedded Systems - Shape the World - Lab 11: UART - the Serial Interface

OVERVIEW:

I’m writing this blog on my computer and the readers are reading it on their computer. Two computers are different and locate at different places, but the readers can view what is on my page in real time. That’s a way of communication between devices. In this case, it’s all about the internet. But today, I’ll talk about simpler method:
UART (Universal Asynchronous Receiver/Transmitter)

UART OPERATION:

Tiva C-Series has 8 UARTs (UART0-UART7). Here are three of them:

uart-list

The principle of the UART is that data is sent serially (one bit at a time).

The smallest completed unit of serial transmission is a frame. A frame is a 10-bit binary number which contains one start bit (always 0), 8 data bits, and one stop bit (always 1).

transmission

Let’s take a look at the UART Transmitter:

uart-transmitter

It has a TxD shift register, a FIFO (First In, First Out) Buffer, and a UART data register. UART data register is responsible for starting writing the data, and the FIFO buffer is responsible for transmitting the written data into the TxD shift register serially (one bit at a time). There is a flag which controls the writing process in order to prevent overflowing, and it is Transmit FIFO Full Flag (TXFF).

Similarly, the UART Receiver is the same as UART Transmitter: uart-receiver

However, there are extra 4 bits in the FIFO buffer. Those 4 bits are explained in the following section.

UART ERROR FLAGS:

  1. Overrun Error (OE): Set if data has been lost because the input driver latency is too long (In other words, it’s too laggy, or ping is so high).
  2. Break Error (BE): Set if the other device has sent a break.
  3. Parity Error (PE): “It was a problem in the past, so we are not looking at it” - the instructor said.
  4. Framing Error (FE): Set if baud rate doesn’t match.

All flag bits can be cleared by writing any value to the UARTx_RSR_R (x can be from 0 through 7).

BAUD RATE:

Literally, Baud Rate = How many bits we can send in 1 second

Relating the bus clock frequency, the baud rate can be evaluated by the following formula:

Also, recall the frame definition, Baud Rate = 1/t in which t is time for 1 bit in second

For example, assume bus clock frequency = 80 MHz, and the baud rate which we want the UART to be running at is 19200 bits/sec. Therefore, the value of divider is 260.4167.

Conversely, from the divider and the bus clock frequency, we can set up the UART to run at a specific speed. For instance, if I want the UART to run at 19200 bit/sec, and I’ve already had 80-MHz bus clock. Therefore, divider = 260.4167.

  1. Take 260 as the integer part and let it be m. So, we have m = 260.
  2. Take 0.4167 as the decimal part and let it be n. So, we have n = 0.4167.
  3. Save m to IBRD register and n/64 (round to the closest integer, in this case, 27) to FRBR register (see page 900 of the datasheet).
  4. Now, divider = m + n/64.

UART INITIALIZATION:

  1. Turn on the UART clock in the RCGC1 register.
  2. Turn on the clock for the corresponding digital ports in the RCGC2 register.
  3. Set bits TXE, RXE, and UARTEN to 1 to activate, but we should clear UARTEN during initialization.
  4. Enable the transmitted and received pins as digital signals.
  5. Select the alternate functionality (Enable AFSEL and PCTL).

Notes that when initializing the UART, there is no direction register because I/O ports are assigned automatically

For example, in UART1, PC5 is output, and PC4 is input. For more information, visit the datasheet, page 899.

UART I/O:

Basically, the UART I/O functions can be represented by the two following flow charts:

uart-io

RECURSION:

Recursion is a function that calls itself. For a recursion to work, we need:

  1. Base Case (What stops the recursion).
  2. Inductive Step (Repeats over and over again until it meets the base case).

For example, to write a simple recursive program for calculating the factorial of n (n!):

unsigned long Factorial(unsigned long n) {
    // base case
    if (n == 1) {
        return 1;
    }
    // inductive step
    return (n * factorial(n - 1));
}

LAB 11:

In lab 11, we will have fun with UART I/O and integer-string conversion. There are three mistakes that I met during this lab:

  1. I didn’t break the program down correctly (or I was lazy to write subroutines). That made me struggle to change the code. I think a good program is the one that can be edited and updated, not the short but inflexible one. I made this mistake when I decided not to write another function to convert an integer to a string.
  2. UART is also related to GPIO port. I should have enabled the GPIO clock.
  3. The overflowing case output for this lab is **** or *.*** cm. I overthought it and assumed it was a number. In fact, it wasn’t. Output the string as-is.

CODE:

Note that to be able to run and grade the labs, you have to follow the software requirements. Unfortunately, the software and the course don’t support Linux. However, if you follow the official instruction from Texas Instruments, you can upload and run your program on the LaunchPad.

I created a function that converts a number into a string. Doing so helped me do better on UART_ConvertUDec() and UART_ConvertDistance()

/**
 * Puts number into global variable out_str[15]
 *
 * @param  n  32-bit unsigned number to be put in
 */
void PutIntoString(unsigned long n) {
    unsigned short i = 0;
    unsigned char  reverse_str[15];
    short j = 0;

    // check the special case n = 0:
    if (!n) {
        out_str_len = 1;
        out_str[0]  = 0x30;
        return;
    }

    // for other cases:
    while (n) {
        // store the number from right to left into reverse_str:
        reverse_str[j] = n % 10 + 0x30;
        n             /= 10; // cut off the most right digit
        j++;                 // prepare for next digit
    }
    out_str_len = j;         // set out_str_len

    // move back to out_str in right order:
    for (j = out_str_len - 1; j >= 0; j--) {
        out_str[i] = reverse_str[j];
        i++;
    }
}

Since there are too many lines of codes, I think it would be easier to view them on my GitHub

SIMULATOR TESTING:

REAL-BOARD TESTING: