TI ARM Tiva TM4C123G - 1.0 Register Addresses, Function, Macros & Header Files
The aim of the following exercises is to provide the beginning steps to familiarize with Embedded System programming concepts.
In this particular exercise you will learn how to program the TM4C123G to toggles the red LED ON & OFF by using register addresses. Same code will be modify to include function, macros and/or header files to simply things.Objective:
Provide an Assembly Language example to blink an LED in the TM4C123G microcontroller.
Explain the concept of Macros.
Explain the concept of Header Files.
Reference Documents:
TM4C123G datasheet
User Manual - Board Overview, p.4
It shows the location of the Red-Green-Blue (RGB) User LED to be manipulated.
User Manual - Schematics, p.20
The schematic shows where the three LEDs (Red, Green & Blue) are connected to the microcontroller: PF1, PF2, & PF3. The “P” stands for “port” and the letter “F” stands for the block F, one of the six blocks of the General-Purpose Input/Outputs (GPIOs) module. The numbers 1, 2, & 3 represent the pins (or bit in register to be manipulated - explained later).
The TM4C123G datasheet provides a series of steps to Initialize and Configure GPIO pins of a particular block. In specific the following section:
General-Purpose Input/Outputs (GPIOs) - Initialization and Configuration, p. 657
As a summary these are the steps to follow:
STEP 1. Enable signal clock to the appropriate GPIO module.
STEP 2. Set the direction of the pins either as input or output.
STEP 3A. Enable the corresponding GPIO line with an alternate function.
STEP 3B. Selects the specific peripheral signal for the corresponding selected GPIO line.
STEP 4. Set the drive strength for each of the pins through the GPIODR2R, GPIODR4R, and GPIODR8R registers.
STEP 5. Configure SW1 & SW0 by enabling the pull up resistor.
STEP 6. Set up GPIO pins as digital I/Os.
STEP 7: Enable and configure the GPIO Interrupt options
I will summarize those steps with a visual representation for better understanding of the procedure and to easily go through the datasheet. Eventually each step will be part of an entire source code for you to use. Complete source code is at the end of this article.
Note: For the purpose of this tutorial we are going to use IAR as our integrated development environment tool (IDE).
GPIOF Initialization and Configuration
General-Purpose Input/Outputs (GPIOs) module, Port F.
DATA SHEET, p.656.
This section describes the steps to follow to access and configure the GPIO pins of a particular block. In our case the block we want to manipulate is block F: Base Address: 0x400FE000.
STEP 1. Enable signal clock to the appropriate GPIO module.
Datasheet - General-Purpose Input/Output Run Mode Clock Gating Control (RCGCGPIO), offset 0x608, p.340
It’s telling you that to enable the clock and access to the GPIO Port F module, bit 5 in the RCGCGPIO register must be set to 1. Go to address: 0x400FE608U (Base + Offset) and set up bit 5 to one.
Code:
//Clock Gating Register
*((unsigned int *) 0x400FE608U) = 0x20U;
Note: Review Binary / Hex numbers & Pointers if you didn’t understand the previous sentence.
STEP 2. Set the direction of the pins either as input or output.
Datasheet - GPIO Direction (GPIODIR), offset 0x400. Page 663
Base: 0x4002.5000 / Offset: 0x400
To blink an LED you will like to use the pins 1, 2 & 3 as outputs. Therefore, pins 1, 2 & 3 in the GPIODIR register needs to be set as 1. Again, go to address 0x40025400U (Base + Offset) and set up bits 1, 2, & 3 to one. (e.i. from 0x0000.0000 to 0x0000.000E).
Code:
//GPIODIR Register
*((unsigned int *)0x40025400U) = 0x0EU;
STEP 3A. Enable the corresponding GPIO line with an alternate function.
STEP 4. Set the drive strength for each of the pins through the GPIODR2R, GPIODR4R, and GPIODR8R registers.
STEP 5. Configure SW1 & SW0 by enabling the pull up resistor.
Note: STEPs 3 - 5 would be skipped since those are features not needed at the moment.
STEP 6. Set up GPIO pins as digital I/Os.
To enable GPIO pins as digital I/Os, set the appropriate DEN bit in the GPIODEN register.
Datasheet - GPIO Digital Enable (GPIODEN), offset 0x51C. Page 682
GPIO Port F (APB) Base: 0x4002.5000 / Offset 0x51C.
Enable GPIODEN register pins 1, 2, & 3 as digital pins by setting pins 1, 2, & 3 from 0 to 1. Same thing, go to address 0x4002551CU (Base + Offset) and set up bits 1, 2, & 3 to one. (e.i. 0x0000.0000 to 0x0000.000E).
Code:
//GPIODEN Register
*((unsigned int *) 0x4002551CU) = 0x0EU;
STEP 7: GPIO Data (GPIODATA), offset 0x000, p.662
Not part of the Initialization and Configuration section but important to discuss.
- The GPIO bits are connected to the CPU through a bunch of wires called “bus”.
- Each bit is connected to both a dedicated “data line” and a dedicated “address line”.
- A bit data value can be changed only when the connected “address line” is one,
otherwise the bit is unaffected regardless of the value of the attached data line.
Basically, what we have been doing so far.
Reference: Embedded Systems Programming Lesson 7 Arrays and Pointer Arithmetic
- For example: To isolate the three GPIO bits connected to the LEDs you could write to the address ending with an offset of: 0x039 and change their data value.
Actually, any of the 256 addresses where A5, A4 & A3 are one. If you wish to simplify things just set up all to ones ( e.i. an offset address of 0x3FC ( 1111111100)).
With this information on hands you can now manipulate the LEDs through the GPIODATA register. Values written in the GPIODATA register are transferred onto the GPIO port pins if the respective pins have been configured as outputs. Wish we already did.
So, it’s a matter of going to address 0x40025039U and set bits 1, 2 & 3 of the GPIODATA register to one if you want to turn ON the LEDs or zero to turn them OFF.
Code:
*((unsigned int *)0x400253FCU) = 0x02U;
*((unsigned int *)0x400253FCU) = 0x02U;
Complete Code/*
This program toggles the red LED ON & OFF by using register addresses.
The other LEDs (Blue & Green) can be configured as well.
All LEDs are high active (a "1" turns ON the LED).
PF1 - red LED
PF2 - blue LED
PF3 -green LED
*/
int main()
{
//Clock Gating Register
*((unsigned int *)0x400FE608U) = 0x20U; //enable clock signal to GPIOF
//GPIODIR Register
*((unsigned int *)0x40025400U) = 0x0EU; //Setting bits 3-1 as outputs
//GPIODEN Register
*((unsigned int *)0x4002551CU) = 0x0EU; //Setting bits 3-1 as digital pins
while (1) {
//*((unsigned int *)0x400253FCU) = 0x02U; //Setting bit 1 to turn Red LED ON
//*((unsigned int *)0x400253FCU) = 0x04U; //Setting bit 2 to turn Blue LED ON
*((unsigned int *)0x400253FCU) = 0x08U; //Setting bit 3 to turn Green LED ON
//Offset: 0x3FC - Bit banding
int counter = 0;
while (counter < 1000000) {
++counter;
}
*((unsigned int *)0x400253FCU) = 0x00U; //Turn OFF LED
counter = 0;
while (counter < 1000000) {
++counter;
}
}
//return 0;
}
/* This program toggles the red LED ON & OFF by using register addresses. The other LEDs (Blue & Green) can be configured as well. All LEDs are high active (a "1" turns ON the LED). PF1 - red LED PF2 - blue LED PF3 -green LED */ int main() { //Clock Gating Register *((unsigned int *)0x400FE608U) = 0x20U; //enable clock signal to GPIOF //GPIODIR Register *((unsigned int *)0x40025400U) = 0x0EU; //Setting bits 3-1 as outputs //GPIODEN Register *((unsigned int *)0x4002551CU) = 0x0EU; //Setting bits 3-1 as digital pins while (1) { //*((unsigned int *)0x400253FCU) = 0x02U; //Setting bit 1 to turn Red LED ON //*((unsigned int *)0x400253FCU) = 0x04U; //Setting bit 2 to turn Blue LED ON *((unsigned int *)0x400253FCU) = 0x08U; //Setting bit 3 to turn Green LED ON //Offset: 0x3FC - Bit banding int counter = 0; while (counter < 1000000) { ++counter; } *((unsigned int *)0x400253FCU) = 0x00U; //Turn OFF LED counter = 0; while (counter < 1000000) { ++counter; } } //return 0; }
Plug your Tiva TM4C123G LaunchPad to your PC.
(Make sure the Power Select switch is to the right).
Copy and Paste the code onto your development environment tool and run the program. LEDs should be blinking.
By now you are able to turn ON and OFF an LED by programming the Tiva TM4C123G LaunchPad using register addresses.
Function
I would like to simplify the code a little bit for future benefits. Right now it’s a small program but eventually it will be larger. To reduce the size of the code and make debugging easier I will make use of Function.
Code with a function:
void delay() {
int counter = 0;
while (counter < 1000000) {
++counter;
}
}
int main()
{
//Clock Gating Register
*((unsigned int *)0x400FE608U) = 0x20U;
//GPIODIR Register
*((unsigned int *)0x40025400U) = 0x0EU;
//GPIODEN Register
*((unsigned int *)0x4002551CU) = 0x0EU;
while (1) {
//*((unsigned int *)0x400253FCU) = 0x02U; //Red LED
//*((unsigned int *)0x400253FCU) = 0x04U; //Blue LED
*((unsigned int *)0x400253FCU) = 0x08U; //Green LED
delay();
*((unsigned int *)0x400253FCU) = 0x00U;
delay();
}
Note: Review Functions in C for an overview of functions declaration and definition.
I just replace the two while statements:
while (counter < 1000000) {
++counter;
}
with one single function definition called delay:
void delay() {
int counter = 0
while (counter < 1000000) {
++counter;
}
}
MACROS:
With the same aim of functions let's simplify further the code by using macros. Typing *((unsigned int *)0x400253FCU) = 0x08U over and over it’s time-consuming and error-prone. To avoid this we are going to use macros to define one readable constant name and use it later. It’s better to handle constant names instead of *((unsigned int *)0x400253FCU).
/*Macro Definition*/
#define RCGCGPIO *((unsigned int *)0x400FE608U)
#define GPIO_DIR *((unsigned int *)0x40025400U)
#define GPIO_DEN *((unsigned int *)0x4002551CU)
#define GPIO_DATA *((unsigned int *)0x400253FCU)
void delay() {
int counter = 0
while (counter < 1000000) {
++counter;
}
}
int main()
{
RCGCGPIO = 0x20U; //Enable Clock Gating Register
GPIO_DIR = 0x0EU; //set pins 1, 2 & 3 as output.
GPIO_DEN = 0x0EU; //set pins 1, 2 & 3 as digital output.
while (1) {
GPIO_DATA = 0x02U; //Red LED ON
delay();
GPIO_DATA = 0x00U; //Red LED OFF
delay();
}
}
Note: Read C Preprocessor: Macros and Header Files for an overview of macros.
HEADER FILES
One last simplification. Let's use a header file.
Microcontrollers vendors already provide C function declaration, “struct” and “macro” definitions in a separate file. Therefore, no need to invest in defining the macros by your own. In the case of the Tiva TM4C123G LaunchPad there are two different header files that you can use.
HEADER FILE with MACROS definition
The one from Texas Instrument through the TivaWare software suite which includes the “tm4c123gh6pm.h” header file. In this header file, each register is defined with his own name (Macros). For example, the Direction Register of Port F is referred to as GPIO_PORTF_DIR_R and the data register of Port F is referred to as GPIO_PORTF_DATA_R. This file can be found at the installation folder: C:\ti\TivaWare_C_Series-2.2.0.295\inc
With this in mind we just need to remove the macro definitions of our previous program and replace it with a single line statement: #include “LM4F120H5QR.h”.
That is… from this
/*Macro Definition*/ #define RCGCGPIO *((unsigned int *)0x400FE608U) #define GPIO_DIR *((unsigned int *)0x40025400U) #define GPIO_DEN *((unsigned int *)0x4002551CU) #define GPIO_DATA *((unsigned int *)0x400253FCU)
To one single line statement:
#include “LM4F120H5QR.h”
In your IAR Embedded Workbench IDE make one of the include paths be "inc" folder. And add LM4F120H5QR.h to it.
Example Code (w/ the names as specify in the macro header file):
#include “tm4c123gh6pm.h” // “Header File with macros”
void delay() {
int counter = 0;
while (counter < 1000000) {
++counter;
}
}
int main()
{
SYSCTL_RCGCGPIO_R = 0x20U; //Enable Clock Gating Register
GPIO_PORTF_DIR_R = 0x0EU; //set pins 1, 2 & 3 as output.
GPIO_PORTF_DEN_R = 0x0EU; //set pins 1, 2 & 3 as digital output.
while (1) {
GPIO_DATA = 0x02U; //Red LED ON
delay();
GPIO_DATA = 0x00U; //Red LED OFF
delay();
}
}
HEADER FILE w/ STRUCT definition
On the other hand, the IAR IDE tool provide <TM4C123GH6PM.H> as a header file where each port is defined as a pointer to a struct with the registers as the members of the struct, For example, the Direction Register of Port A is referred to as GPIOA → DIR and the Data Register of Port F is referred to as GPIOF → DATA and so on. In the IAR IDE tool this file can be found in the system directory folder: C:\Program Files (x86)\IAR Systems\Embedded Workbench 8.4\arm\inc\TexasInstruments
Example CODE (w/ the name as specify in the struct header file):
#include “TM4C123GH6PM.H” // “Header File with struct”
void delay() {
int counter = 0;
while (counter < 1000000) {
++counter;
}
}
int main()
{
SYSCTL → RCGCGPIO |= 0x20U; //Enable Clock Gating Register
GPIOF → DIR = 0x0E; //set pins 1, 2 & 3 as output.
GPIOF → DEN = 0x0EU; //set pins 1, 2 & 3 as digital output.
while (1) {
GPIOF → DATA = 0x02U; //Red LED ON
delay();
GPIOF → DATA = 0x00U; //Red LED OFF
delay();
}
}
Comments