Actions

EmSys

TM4C123G LaunchPad - UART

From EdWiki

Lab 6: UART

Objective

In this lab you will send data through the UART. The UART is connected to the emulator’s virtual serial port that runs over the debug USB cable.

Procedure

  • Initialize UART and echo characters using polling
  • Use interrupts

Create Lab6 Project

Create a lab6 project with an empty main.c, a startup file and all necessary project and build options as described in the lab3 project.

The initialization sequence for using the UART:

  • Set up the system clock
  • Enable the UART0 and GPIOA peripherals (the UART pins are on GPIO Port A)
  • Configure the pins for the receiver and transmitter using GPIOPinConfigure
  • Initialize the parameters for the UART: 115200, 8-1-N
  • Use simple UARTCharPut() calls to create a prompt.
  • An infinite loop. In this loop, if there is a character in the receiver, it is read, and then written to the transmitter. This echos what you type in the terminal window.

► Expand the project by clicking on the Expand icon.png next to lab6 in the Project Explorer pane. Double click on main.c to open it.
► Copy the following code and paste it into the newly created main.c file.

  1. #include <stdint.h>
  2. #include <stdbool.h>
  3. #include "inc/hw_memmap.h"
  4. #include "inc/hw_types.h"
  5. #include "driverlib/gpio.h"
  6. #include "driverlib/pin_map.h"
  7. #include "driverlib/sysctl.h"
  8. #include "driverlib/uart.h"
  9.  
  10. int main(void)
  11. {
  12.  
  13.     SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
  14.  
  15.     SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
  16.     SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
  17.  
  18.     GPIOPinConfigure(GPIO_PA0_U0RX);
  19.     GPIOPinConfigure(GPIO_PA1_U0TX);
  20.     GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
  21.  
  22.     UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200,(UART_CONFIG_WLEN_8 |
  23.         UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
  24.  
  25.     UARTCharPut( UART0_BASE, 'E' );
  26.     UARTCharPut( UART0_BASE, 'n' );  
  27.     UARTCharPut( UART0_BASE, 't');
  28.     UARTCharPut( UART0_BASE, 'e' );
  29.     UARTCharPut( UART0_BASE, 'r' );
  30.     UARTCharPut( UART0_BASE, ' ' );
  31.     UARTCharPut( UART0_BASE, 'T' );
  32.     UARTCharPut( UART0_BASE, 'e' );
  33.     UARTCharPut( UART0_BASE, 'x' );
  34.     UARTCharPut( UART0_BASE, 't' );
  35.     UARTCharPut( UART0_BASE, ':' );
  36.     UARTCharPut( UART0_BASE, ' ' );
  37.  
  38.     while( 1 ) { 
  39.         if( UARTCharsAvail(UART0_BASE) )
  40.             UARTCharPut( UART0_BASE, UARTCharGet(UART0_BASE) );
  41.     }
  42. }

Terminal Program

If you are running WindowsXP, you can use HyperTerminal as your terminal program. Windows7/8/10 does not have a terminal program built-in, but there are many third-party alternatives. The instructions in the labs utilize PuTTY. You can download PuTTY from here

INCLUDE Path, Driverlib, Debug Config

► Link the TivaWare libdriver.a file to your project
► Add the INCLUDE search paths for the header files
Configure CCS Debugger

Build, Download, and Run the UART Example Code

► Click the Debug button to build and download your program to the TM4C123GH6PM flash memory. We can communicate with the board through the UART, which is connected as a virtual serial port through the emulator USB connection.

► double-click on putty.exe. Make the settings shown below and then click Open. You can find the COM port number for this serial port as described in this link.

When the terminal window opens ► click the Resume button in CCS, then type some characters and you should see the characters echoed into the terminal window.

Using UART Interrupts

Instead of continually polling for characters, we’ll make some modifications to our code to allow the use of interrupts to receive and transmit characters. In the first part of this lab, the only indication we had that our code was running was to open the terminal window to type characters and see them echoed back. In this part of the lab, we’ll add a visual indicator to show that we received and transmitted a character. So we’ll need to add code similar to previous labs to blink the LED inside the interrupt handler.

First, let’s add the code in main() to enable the UART interrupts we want to handle.

► Click on the Terminate button Terminate icon.png to return to the CCS Edit perspective. We need to add two additional header files at the top of the file:

#include "inc/hw_ints.h"
#include "driverlib/interrupt.h"

Now we need to add the code to enable processor interrupts, then enable the UART interrupt, and then select which individual UART interrupts to enable. We will select receiver interrupts (RX) and receiver timeout interrupts (RT). The receiver interrupt is generated when a single character has been received (when FIFO is disabled) or when the specified FIFO level has been reached (when FIFO is enabled). The receiver timeout interrupt is generated when a character has been received, and a second character has not been received within a 32-bit period.

► Add the following code just below the UARTConfigSetExpClk() function call:

IntMasterEnable();
IntEnable( INT_UART0 );
UARTIntEnable( UART0_BASE, UART_INT_RX | UART_INT_RT );

We also need to initialize the GPIO peripheral and pin for the LED.
► Just before the function UARTConfigSetExpClk() is called, add these two lines:

SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOF );
GPIOPinTypeGPIOOutput( GPIO_PORTF_BASE, GPIO_PIN_2 );

► Finally, we can create an empty while(1) loop at the end of main by commenting out the line of code that’s already there:

  1. while( 1 )
  2. {
  3.     //if( UARTCharsAvail(UART0_BASE) )
  4.     //    UARTCharPut( UART0_BASE,UARTCharGet(UART0_BASE) );
  5. }

► Save the changes you made to main.c (but leave it open for making additional edits).

Now we need to write the UART interrupt handler. The interrupt handler needs to read the UART interrupt status register to know which specific interrupt event(s) just occurred. This value is then used to clear the interrupt status bits (we only enabled RX and RT interrupts, so those are the only possible sources for the interrupt). The next step is to receive and transmit all the characters that have been received. After each character is “echoed” to the terminal, the LED is blinked for about 1 millisecond.

► Insert this code below the include statements and above main():

  1. void UARTIntHandler(void)
  2. {
  3.     uint32_t ui32Status;
  4.     ui32Status = UARTIntStatus( UART0_BASE, true ); //get interrupt status
  5.  
  6.     UARTIntClear( UART0_BASE, ui32Status ); //clear the asserted interrupts
  7.  
  8.     while( UARTCharsAvail(UART0_BASE)) { //loop while there are chars
  9.         UARTCharPutNonBlocking( UART0_BASE, UARTCharGetNonBlocking(UART0_BASE) );
  10.         //echo character
  11.         GPIOPinWrite( GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2 ); //blink LED
  12.         SysCtlDelay( SysCtlClockGet() / (1000 * 3) ); //delay ~1 msec
  13.         GPIOPinWrite( GPIO_PORTF_BASE, GPIO_PIN_2, 0 ); //turn off LED
  14.      }
  15. }

We’re almost done. We’ve added all the code we need. The final step is to insert the address of the UART interrupt handler into the interrupt vector table.

► Open the tm4c123gh6pm_startup_ccs_gcc.c file. Add the UART interrupt handler prototype:

extern void UARTIntHandler(void);

On about line 94, you’ll find the interrupt vector table entry for “UART0 Rx and Tx”. It’s just below the entry for “GPIO Port E”. The default interrupt handler is named IntDefaultHandler.

► Replace this name with UARTIntHandler so the line looks like:

UARTIntHandler, // UART0 Rx and Tx

Save your work. Your main.c code should look like this.

  1. #include <stdint.h>
  2. #include <stdbool.h>
  3. #include "inc/hw_ints.h"
  4. #include "inc/hw_memmap.h"
  5. #include "inc/hw_types.h"
  6. #include "driverlib/gpio.h"
  7. #include "driverlib/interrupt.h"
  8. #include "driverlib/pin_map.h"
  9. #include "driverlib/sysctl.h"
  10. #include "driverlib/uart.h"
  11.  
  12. void UARTIntHandler(void)
  13. {
  14.     uint32_t ui32Status;
  15.     ui32Status = UARTIntStatus( UART0_BASE, true ); //get interrupt status
  16.  
  17.     UARTIntClear( UART0_BASE, ui32Status ); //clear the asserted interrupts
  18.  
  19.     while( UARTCharsAvail(UART0_BASE) ) { //loop while there are chars
  20.         UARTCharPutNonBlocking( UART0_BASE, UARTCharGetNonBlocking(UART0_BASE)); //echo character
  21.         GPIOPinWrite( GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2 ); //blink LED
  22.         SysCtlDelay( SysCtlClockGet() / (1000 * 3) ); //delay ~1 msec
  23.         GPIOPinWrite( GPIO_PORTF_BASE, GPIO_PIN_2, 0 ); //turn off LED
  24.     }
  25. }
  26.  
  27. int main(void) 
  28. {
  29.     SysCtlClockSet( SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ );
  30.  
  31.     SysCtlPeripheralEnable( SYSCTL_PERIPH_UART0 );
  32.     SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOA );
  33.  
  34.     GPIOPinConfigure( GPIO_PA0_U0RX );
  35.     GPIOPinConfigure( GPIO_PA1_U0TX );
  36.     GPIOPinTypeUART( GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1 );
  37.  
  38.     SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOF ); //enable GPIO port for LED
  39.     GPIOPinTypeGPIOOutput( GPIO_PORTF_BASE, GPIO_PIN_2 ); //enable pin for LED PF2
  40.  
  41.     UARTConfigSetExpClk( UART0_BASE, SysCtlClockGet(), 115200,
  42.            (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
  43.  
  44.     IntMasterEnable(); //enable processor interrupts
  45.     IntEnable( INT_UART0 ); //enable the UART interrupt
  46.     UARTIntEnable( UART0_BASE, UART_INT_RX | UART_INT_RT ); //only enable RX and TX interrupts
  47.  
  48.     UARTCharPut( UART0_BASE, 'E' );
  49.     UARTCharPut( UART0_BASE, 'n' );
  50.     UARTCharPut( UART0_BASE, 't' );
  51.     UARTCharPut( UART0_BASE, 'e' );
  52.     UARTCharPut( UART0_BASE, 'r' );
  53.     UARTCharPut( UART0_BASE, ' ' );
  54.     UARTCharPut( UART0_BASE, 'T' );
  55.     UARTCharPut( UART0_BASE, 'e' );
  56.     UARTCharPut( UART0_BASE, 'x' );
  57.     UARTCharPut( UART0_BASE, 't' );
  58.     UARTCharPut( UART0_BASE, ':' );
  59.     UARTCharPut( UART0_BASE, ' ' );
  60.  
  61.      while( 1 ) //let interrupt handler do the UART echo function
  62.     {
  63.         // if (UARTCharsAvail( UART0_BASE) )
  64.         //     UARTCharPut( UART0_BASE, UARTCharGet(UART0_BASE) );
  65.     }
  66. }

► Click the Debug button to build and download your program to the TM4C123GH6PM memory.

► If you’ve closed it, open Hyperterminal or puTTY, and configure it as before.

► Click the Resume button. Type some characters and you should see the characters echoed into the terminal window. Note the LED.

► Close puTTY or HyperTerminal. Click the Terminate button to return to the CCS Edit perspective.

► Close the Lab6 project and minimize Code Composer Studio.

You’re done.