TM4C123G LaunchPad - Initialization and GPIO

From EdWiki

Lab 3: Initialization and GPIO


In this lab we’ll learn how to initialize the clock system and the GPIO peripheral using TivaWare. We’ll then use the GPIO output to blink an LED on the evaluation board.


  • Configure the system clock
  • Enable and configure GPIO
  • Use a software delay to toggle an LED on the evaluation board

Create lab3 Project

Ccs new project 2.png

► On the CCS menu bar select File New CCS Project. Make the selections shown below. Make sure to uncheck the “Use default location” checkbox and select the correct path to the project folder as shown. In the variant box, just type “123G” to narrow the results in the right-hand box. In the Project templates and examples window, select Empty Project (with main.c). Click Finish.

When the wizard completes, click the Expand icon.png next to lab3 in the Project Explorer pane to expand the project. Note that Code Composer has automatically added a mostly empty main.c file to your project as well as the startup file.

Header Files

► Delete the current contents of main.c. TivaWare™ is written using the ISO/IEC 9899:1999 (or C99) C programming standards along with the Hungarian standard for naming variables. The C99 C programming conventions make better use of available hardware, including the IEE754 floating point unit. To keep everything looking the same, we’re going to use those guidelines.

► Type (or copy/paste) the following lines into main.c to include the header files needed to access the TivaWare APIs as well as a variable definition:

  1.  #include <stdint.h>
  2.  #include <stdbool.h>
  3.  #include "inc/hw_memmap.h"
  4.  #include "inc/hw_types.h"
  5.  #include "driverlib/sysctl.h"
  6.  #include "driverlib/gpio.h"
  8.  uint8_t ui8PinData = 2;

The use of the < > restricts the search path to only the specified path. Using the " " causes the search to start in the project directory. For includes like the two standard ones, you want to assure that you’re accessing the original, standard files … not one’s that may have been modified.

stdint.h: Variable definitions for the C99 standard Boolean definitions for the C99 standard

hw_memmap.h: Macros defining the memory map of the Tiva C Series device. This includes defines such as peripheral base address locations such as GPIO_PORTF_BASE.

hw_types.h: Defines common types and macros

sysctl.h: Defines and macros for System Control API of DriverLib. This includes API functions such as SysCtlClockSet and SysCtlClockGet.

gpio.h: Defines and macros for GPIO API of DriverLib. This includes API functions such as GPIOPinTypePWM and GPIOPinWrite.

uint8_t ui8PinData = 2; : Creates an integer variable called ui8PinData and initializes it to 2. This will be used to cycle through the three LEDs, lighting them one at a time. Note that the C99 type is an 8-bit unsigned integer and that the variable name reflects this.

You will see question marks to the left of the include lines in main.c displayed in the edit pane, telling us that the include files can’t be found. We’ll fix this later.

main() Function

Let’s drop in a template for our main function.

► Leave a line for spacing and add this code after the previous declarations:

  1. int main( void )
  2. {
  3. }

If you type this in, notice that the editor will automatically add the closing brace when you add the opening one.

Clock Setup

Configure the system clock to run using a 16MHz crystal on the main oscillator, driving the 400MHz PLL. The 400MHz PLL oscillates at only that frequency, but can be driven by crystals or oscillators running between 5 and 25MHz. There is a default /2 divider in the clock path and we are specifying another /5, which totals 10. That means the System Clock will be 40MHz.

► Enter this single line of code inside main():


Note that the crystal attached to the main oscillator inputs is 16MHz, while the crystal attached to the real-time clock (RTC) inputs is 32,768Hz.

GPIO Configuration

Before calling any peripheral specific driverLib function, we must enable the clock for that peripheral. If you fail to do this, it will result in a Fault ISR (address fault).This is a common mistake for new Tiva C Series users. The second statement below configures the three GPIO pins connected to the LEDs as outputs. The excerpt below of the LaunchPad board schematic shows GPIO pins PF1, PF2 and PF3 are connected to the LEDs.

► Leave a line for spacing, then enter these two lines of code inside main() after the line in the previous step.

SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOF );

The base addresses of the GPIO ports listed in the User Guide are shown below. Note that they are all within the memory map’s peripheral section shown in module 1. APB refers to the Advanced Peripheral Bus, while AHB refers to the Advanced High-Performance Bus. The AHB offers better back-to-back performance than the APB bus. GPIO ports accessed through the AHB can toggle every clock cycle vs. once every two cycles for ports on the APB. In power sensitive applications, the APB would be a better choice than the AHB. In our labs, GPIO_PORTF_BASE is 0x40025000.

GPIO Port A (APB): 0x4000.4000
GPIO Port A (AHB): 0x4005.8000
GPIO Port B (APB): 0x4000.5000
GPIO Port B (AHB): 0x4005.9000
GPIO Port C (APB): 0x4000.6000
GPIO Port C (AHB): 0x4005.A000
GPIO Port D (APB): 0x4000.7000
GPIO Port D (AHB): 0x4005.B000
GPIO Port E (APB): 0x4002.4000
GPIO Port E (AHB): 0x4005.C000
GPIO Port F (APB): 0x4002.5000
GPIO Port F (AHB): 0x4005.D000

while() Loop

Finally, create a while(1) loop to send a “1” and “0” to the selected GPIO pin, with an equal delay between the two.

SysCtlDelay() is a loop timer provided in TivaWare. The count parameter is the loop count, not the actual delay in clock cycles. Each loop is 3 CPU cycles.

To write to the GPIO pin, use the GPIO API function call GPIOPinWrite. Make sure to read and understand how the GPIOPinWrite function is used in the datasheet. The third data argument is not simply a 1 or 0, but represents the entire 8-bit data port. The second argument is a bit-packed mask of the data being written.

In our example below, we are writing the value in the ui8PinData variable to all three GPIO pins that are connected to the LEDs. Only those three pins will be written to based on the bit mask specified. The final instruction cycles through the LEDs by making ui8PinData equal to 2, 4, 8, 2, 4, 8 and so on. Note that the values sent to the pins match their positions; a “one” in the bit two position can only reach the bit two pin on the port.

Now might be a good time to look at the Datasheet for your Tiva C Series device. Check out the GPIO chapter to understand the unique way the GPIO data register is designed and the advantages of this approach.

► Leave a line for spacing, and then add this code after the code in the previous step.

  1. while( 1 ) {
  2.     GPIOPinWrite( GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, ui8PinData );
  3.     SysCtlDelay( 2000000 );
  5.     GPIOPinWrite( GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, 0x00 );
  6.     SysCtlDelay( 2000000 );
  8.     if( ui8PinData == 8 ) {
  9.         ui8PinData = 2;
  10.     } else {
  11.         ui8PinData = ui8PinData*2;
  12.     }
  13. }

If you find that the indentation of your code doesn’t look quite right,

► select all of your code by clicking CTRL-A and then right-click on the selected code. Select Source → Correct Indentation. Notice the other great stuff under the Source and Surround With selections.

► Click the Save button to save your work. Your code should look something like this:

  1. #include <stdbool.h>
  2. #include "inc/hw_memmap.h"
  3. #include "inc/hw_types.h"
  4. #include "driverlib/sysctl.h"
  5. #include "driverlib/gpio.h"
  7. uint8_t ui8PinData = 2;
  9. int main( void )
  10. {
  13.     SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOF );
  16.     while( 1 ) {
  17.         GPIOPinWrite( GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, ui8PinData );
  18.         SysCtlDelay( 2000000 );
  20.         GPIOPinWrite( GPIO_PORTF_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, 0x00 );
  21.         SysCtlDelay(2000000);
  23.         if(ui8PinData == 8) { 
  24.             ui8PinData=2;
  25.         } else { 
  26.             ui8PinData = ui8PinData*2;
  27.         }
  28.     }
  29. }

If you’re having problems, you can copy/paste this code into main.c.

If you were to try building this code now (please don’t), it would fail. Note the question marks next to the include statements … CCS has no idea where those files are located … we still need to set our build options.

NOTE: There is a delay of 3 to 6 clock cycles between enabling a peripheral and being able to use it. In most cases, the amount of time required by the API coding itself prevents any issues, but there are situations where you may be able to cause a system fault by attempting to access the peripheral before it becomes available.

A good programming habit is to interleave your peripheral enable statements as follows:

Enable ADC
Enable GPIO
Config ADC
Config GPIO

This interleaving will prevent any possible system faults without incorporating software delays.

Startup Code

In addition to the main file you have created, you will also need a startup file specific to the tool chain you are using. This file contains the vector table, startup routines to copy initialized data to RAM and clear the bss section, and default fault ISRs. The New Project wizard automatically added a copy of this file into the project for us.

► Double-click on tm4c123gh6pm_startup_ccs_gcc.c in your Project Explorer pane and take a look around. Don’t make any changes at this time. Close the file.

Set the Build Options

► Right-click on Lab3 in the Project Explorer pane and select Properties. Expand Build → GNU Compiler, Click Directoris. In the bottom, include search path pane, click the Add button and add the following search path:


Remember that those are braces, not parentheses. This is the path we created earlier by using the vars.ini file in the lab2 project. Since those paths are defined at the workspace level, we can simply use it again here.

► Click OK.

After a moment, CCS will refresh the project and you should see the question marks disappear from the include lines in main.c.

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

It can be easy to get confused and mistakenly build or work on the wrong project or file.To reduce that possibility, ► right-click on lab2 and select Close Project. This will collapse the project and close any open files you have from the project. You can open it again at any time. ► Click on the lab3 project name to make sure the project is active. It will say lab3 [Active – Debug]. This tells you that the lab3 project is active and that the build configuration is debug.

Compile, Download and Run the Code

Debug icon.png

► Compile and download your application by clicking the Debug button on the menu bar. If you are prompted to save changes, do so. If you have any issues, correct them, and then click the Debug button again. After a successful build, the CCS Debug perspective will appear.

Resume icon.png

► Click the Resume button to run the program that was downloaded to the flash memory of your device. You should see the LEDs flashing. If you want to edit the code to change the delay timing or which LEDs that are flashing, go ahead. If you suspend the code and get the message “No source available for …”, simply close that editor tab. The source code for that function is not present in our project. It is only present as a library file.

Terminate icon.png

► Click on the Terminate button to return to the CCS Edit perspective.

You’re done.