Lesson 09: GPIO Ports and Configurations
The microprocessors access their I/O (Input/Output) devices either by special I/O instructions that read and write to peripherals located in a separate I/O address space, called "Port Mapped I/O, PMIO", or by using the instructions that are provided to access memory, called "Memory-mapped I/O, MMIO". ARM-based processors use memory-mapped I/O. The I/O ports share the same address space with memory. That means the software can access an I/O port simply by reading from or writing to the appropriate address, and these addresses are usually called "Registers". Most I/O ports can be configured into different I/O functions through the registers, and you can find detailed information about I/O Registers from the microprocessor's datasheet.
Even the accessing I/O register "look" like reads and writes to memory variables, but there are still some differences between the memory and I/O Registers. For example, some bits in the Register are read-only, and some are write-only; some bits can only be cleared or set; some bits cannot be modified, and some are reserved for future use.
General-Purpose Input/Output (GPIO)
GPIO is a generic pin on a microcontroller and is controllable by the program at run time. GPIO pins have no predefined purpose and can be operated as parallel interfaces. It allows the microcontroller to exchange digital information with external devices. For example, GPIO can be used for reading from a temperature sensor and for writing output to an LCD module or LEDs for status.
GPIO pins have the following capabilities:
- GPIO pins can be configured to be input or output
- GPIO pins can be enabled or disabled
- Input values are readable( typically logic high or low)
- Output values are writable and can be read back
- Input pin can be used to trigger the interrupt function
Instead of directly configuring and controlling each individual GPIO pin, we set up a group of GPIO pins (typically 8 GPIO pins) into a PORT. Through the PORT registers, we can control and access multiple GPIO pins at a time.
Texas Instruments Tiva TM4C I/O Ports
The GPIO on the Tiva TM4C family is extremely flexible. Any GPIO can be configured to different functions: it can be an interrupt, edge-triggered on rising, falling, or both, or it can be level-sensitive to high or low values.
Tiva C microcontroller is a low-power ARM Cortex-M4 microprocessor and runs typically at 3.3V, so the logic levels of I/O pins are 3.3V. The drive strength of the outputs of the GPIO is programmable to be 2, 4, or 8 milliamps. All GPIO pins have programmable weak pull-up, pull-down, and open-drain modes.
- Never exceed the input logic high voltage of any pin beyond the VDD limit unless you are sure that the source will not exceed the limit voltage.
- Don't use negative input voltages with any pin. Be sure of polarity.
- Don't stress any GPIO pin beyond 10 ~ 15mA, although the max limit is 25mA. Use external switching devices like FETs, BJTs, and photo-isolators to drive high power loads.
Setup GPIO
There are eight steps to initialize GPIO ports:
- Enable Port Clock: The first step is to activate the clock for the port.
Note: If you access a port without enabling its clock, you will get a hardware fault event when you execute the code. - Unlock the Port: Unlocking needs only for pins PD7, and PD0 on the TM4C123G, and PD2 on the TM4C1294 boards.
- Set Analog Mode: Enable the pins which are used for analog function.
- Set Port Control Register: To use internal digital functions, the digital function number must be set in the PCTL register.
- Set Alternate Function Register: Set AFSEL to select the I/O pin to the internal digital function.
- Set Output Pins: Set the output pins of each GPIO port.
- Set Internal Pull-Up/Down Resister and Open-Drain: Set up the pin's internal pull-up resistor (PUR), and pull-down resistor (PDR), and enable open-drain output (ODR).
- Enable All Pins of Each Port: Enable all GPIO pins, including all regular I/O pins, analog pins, and the pins connected to internal digital functions.
GPIO DATA Register
The TI TM4C microcontroller has a special feature for controlling its pins called the DATA register, one for each set of pins, which is known as a GPIO (General-Purpose Input/Output) port. You can think of the DATA register as a control panel for eight different pins.
This control panel, or DATA register, is used for two main things:
- To check the current state of the pins. This means you can see which pins are getting power and which are not.
- Set the pins to be either on or off if they are being used as output pins, which are like little lights that you can turn on or off.
Here's how it works when you're using a pin as part of a GPIO port:
- If you are sending out information from the pin (like an output), whatever you put in the DATA register is like telling the pin to turn on or off.
- If you are receiving information into the pin (like an input), reading the DATA register is like asking the pin, "Are you on or off?"
Here are some simple examples to understand how to use it:
- To turn on Pin 2 in Port A (akin to turning a switch on), you would do something like this: You take the current settings of Port A, and apply a bit-wise 'or' operation with a mask 1 value to turn on Pin 2.
GPIOA->DATA = GPIOA->DATA | _BIT2; - To turn off Pin 7 in Port B (similar to switching off), you do this: You take the current settings of Port B and apply a bit-wise 'and' operation with a mask 0 value to turn off Pin 7.
GPIOB->DATA = GPIOB->DATA & (~_BIT7); - To see if Pin 2 in Port D is on or off, you do this: Use bit-wise 'and' with a mask 1 value to examine Pin 2 in Port D and verify if it is getting power or not.
if ((GPIOD->DATA & _BIT2) != 0){ } // true: PD2 is logic 1; fslse: PD2 is logic 0
Remember, the _BIT2 or _BIT7 is just a way of referring to Pin 2 or Pin 7 in the DATA register. It's like saying "Pin number 2" or "Pin number 7".
GPIO Addressing Masking (Hardware masking address)
If you write an 8-bit value directly to the DATA register, all eight pins will be modified. If you just want to modify specific pins of this port, you would have to read all the pin's values on the DATA register, then use a bit-wise operator to change the specific bits, and then write the value back out to the port. This is called a read-modify-write operation, and it's fraught with issues. For instance, if an interrupt changed at the pin state in the middle of this process, your code would write the wrong value to the pin.
In the TI TM4C microcontroller series, there is a clever way to update only the pins you want to without affecting the others, and it is called GPIO Address Masking.
On the Tiva TM4C parts, you can use a bit-mask to indicate which bits are to be modified. This is done in hardware by mapping each GPIO port to 256 addresses, which can cover every possible combination of the port pins. Bits [9:2] of the address are used as the bit mask.
For example, if we want to change the state of pins 1, 2, and 5 in GPIO Port D, you would create a bit-mask where bits 1, 2, and 5 are set to '1' and all other bits are set to '0. In binary, this mask is (0010 0110)2, also called mask 1 value. To use this mask, shift the bit-mask value to the left by 2 bits. It will be (00 1001 1000)2 in binary. Then add it with the GPIO base address to get a special address, called the GPIO masking address. When we write a value to this special address, we are telling the microcontroller to only update pins 1, 2, and 5.
GPIO addressing mask can be used on input and output pins.
In C code, a pointer can be used to point to hardware masking addresses.
volatile uint32_t *PD125 = (uint32_t *)GPIOD + (_PIN1 | _PIN2 | _PIN5); // PD1, PD2 and PD5 are output pins
*PD125 = 0xEB; // Only change pins 1, 2, and 5 on port D
*PD125 = 0; // Clear PD1, PD2, PD5 to zero
*PD125 = 0xFF; // Set PD1, PD2, PD5 to one
*PD125 ^= _BIT1; // Toggle PD1
Critical Function GPIO Protection
Some of the pins on the TM4C device are protected against accidental programming:
- For TM4C123G:
- PC3, 2, 1, & 0: JTAG/SWD
- PD7 & PF0: NMI
- For TM4C1294:
- PC3, 2, 1, & 0: JTAG.SWD
- PD7 & PE7: NMI
Any write to the following register for these pins will not be stored unless the GPIOn->LOCK register has been unlocked:
- GPIO Alternate Function Select register (GPIOn->AFSEL)
- GPIO Pull-Up or Pull-Down select register (GPIOn->PUR and GPIOn->PDR)
- GPIO Digital Enable register (GPIOn->DEN)
The following sequence will unlock the GPIO->LOCK register for PF0 using direct register programming:
GPIOF->LOCK = GPIO_LOCK_KEY;
GPIOF->CR |= _PIN0;
GPIOF->LOCK = 0;
Read the GPIOF->LOCK register returns it to lock status.
TM4C GPIOn->DIR Direction Control Register
The GPIOn->DIR register is the data direction register. Bits set to HIGH in the GPIOn->DIR configure the corresponding pin to be output. Clearing a bit configures the pin to be input.
All bits are cleared by a reset. Therefore, GPIO pins are input by default. In the 6th GPIO configuration step, only output pins need to be configured, the input pins do not.
EK-TM4C123GXL LaunchPad
GPIO Ports
The microcontroller on the EK-TM4C123GXL LaunchPad is TM4C123GH6PM. The TM4C123GH6PM GPIO module is comprised of six physical GPIO blocks, each corresponding to an individual GPIO port (Port A, Port B, Port C, Port D, Port E, and Port F).
Figure 1: I/O Port Pins for the TM4C123GH6PM (From http://users.ece.utexas.edu/~valvano/Volume1/E-Book/C6_MicrocontrollerPorts.htm)
Port A ~ Port D have 8-pin I/O on each port; Port E has 6-pins, and Port F has 5-pins.
On the TM4C123G LaunchPad, all inputs of the GPIO are 5V tolerant, except a few GPIOs (PB0, PB1, and PD5). The 5V tolerant feature of Tiva C MCUs comes to aid, allowing us to use legacy external interfaces and devices like sensors, external modules, legacy microcontrollers, etc., without the need for additional logic-level translator circuits. Though most pins are 5V tolerant, it doesn't necessarily mean that the logic level is based on the 5V TTL logic level. The logic level voltage limits are still realized with respect to VDD, 3.3V.
On the TM4C123G microcontrollers, the GPIO Ports can be connected to either the Advanced Peripheral Bus (APB) or the Advanced High-performance Bus (AHB). After reset, the GPIO Ports are connected to the legacy APB bus and through the APB memory aperture. Each GPIO port can be individually configured to use AHB or APB through the "Register 9: GPIO High-Performance Bus Control (GPIOHBCTL), offset 0x06C". The AHB bus provides better back-to-back access performance than the APB bus.
Table 1: GPIO Port's Base Address
APB Bus | AHB Bus | |||
GPIO Port | Base Address | Range | Base Address | Range |
Port A | 0x4000.4000 | 0x4000.4000 ~ 0x4000.4FFF | 0x4005.8000 | 0x4005.8000 ~ 0x4005.8FFF |
Port B | 0x4000.5000 | 0x4000.5000 ~ 0x4000.5FFF | 0x4005.9000 | 0x4005.9000 ~ 0x4005.9FFF |
Port C | 0x4000.6000 | 0x4000.6000 ~ 0x4000.6FFF | 0x4005.A000 | 0x4005.A000 ~ 0x4005.AFFF |
Port D | 0x4000.7000 | 0x4000.7000 ~ 0x4000.7FFF | 0x4005.B000 | 0x4005.B000 ~ 0x4005.BFFF |
Port E | 0x4002.4000 | 0x4002.4000 ~ 0x4002.4FFF | 0x4005.C000 | 0x4005.C000 ~ 0x4005.CFFF |
Port F | 0x4002.5000 | 0x4002.5000 ~ 0x4002.5FFF | 0x4005.D000 | 0x4005.D000 ~ 0x4005.DFFF |
Each GPIO port has 4KB of memory space because each GPIO Port has a large number of special function registers associated with it, and the GPIO Data Register supports bit-specific addressing to allow a single instruction to access from 1-bit to 8-bit data in the memory map.
Registers
The GPIO Ports must be initialized before being used. The basic steps to configure the required PORTn pins to GPIO are given below:
- Enabled the clock to the GPIO Port by setting the corresponding bit in the SYSCTL->RCGCGPIO |= (_PORTs); register. Then, wait for the GPIO clock ready by checking the SYSCTL->PRGPIO register.
- Unlock the port by writing 0x4C4F434B to GPIOn->LOCK register. The step is needed only for PORTC[3:0], PORTD[7], and PORTF[0] on TM4C123G. After unlocking the port, the appropriate bits of the GPIO Commit register (GPIOn->CR) need to be set.
- Disable the analog function of the pin in the Analog Mode Select register (GPIOn->AMSEL) because we want to use the pin for digital I/O. If this pin is connected to the ADC or analog comparator, its corresponding bit in GPIOn->AMSEL must be set as 1. If this pin is used as digital I/O, its corresponding bit must be set as 0.
- Clear bits in the port control register (GPIOn->PCTL) to select regular digital functions. Each GPIO pin needs 4-bit in its corresponding GPIOn->PCTL register. Not every pin can be configured to every alternative function.
- Clear bits in the Alternate Function Select register (GPIOn->AFSEL). If an alternate pin is chosen for a bit, then the PMCn field must be programmed in the GPIOn->PCTL register for the specific peripheral required.
- Set the direction of the GPIO port pins by programming the GPIOn->DIR register. A bit in GPIOn->DIR set to 0 means input and 1 means output.
- Program each pad in the port to have either pull-up, pull-down, or open-drain functionality through the GPIOn_PUR, GPIOn_PDR, and GPIOn_ODR register.
- To enable GPIO pins as digital I/Os, set the appropriate DEN bit in the Digital Enable register (GPIOn_DEN).
The first step must be turning on the clock, and other steps can occur in any order.
After a RESET, the default state is to disable the analog function and disable the alternate function. Therefore, steps 3, 4, and 6 can be skipped.
Address | bit-Field | GPIO Register Name | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | In Assembly | In C | |
$400F.E108 | -- | -- | GPIOF | GPIOE | GPIOD | GPIOC | GPIOB | GPIOA | SYSCTL_RCGCGPIO_R | SYSCTL->RCGCGPIO |= (_PORTs); |
PORTn BaseAddr + $3FC | DATA | DATA | DATA | DATA | DATA | DATA | DATA | DATA | GPIO_PORTn_DATA_R | GPIOn->DATA |
PORTn BaseAddr + $400 | DIR | DIR | DIR | DIR | DIR | DIR | DIR | DIR | GPIO_PORTn_DIR_R | GPIOn->DIR |
PORTn BaseAddr + $420 | SEL | SEL | SEL | SEL | SEL | SEL | SEL | SEL | GPIO_PORTn_AFSEL_R | GPIOn->AFSEL |
PORTn BaseAddr + $50C | ODE | ODE | ODE | ODE | ODE | ODE | ODE | ODE | GPIO_PORTn_ODR_R | GPIOn->ODE |
PORTn BaseAddr + $510 | PUE | PUE | PUE | PUE | PUE | PUE | PUE | PUE | GPIO_PORTn_PUR_R | GPIOn->PUR |
PORTn BaseAddr + $514 | PDE | PDE | PDE | PDE | PDE | PDE | PDE | PDE | GPIO_PORTn_PDR_R | GPIOn->PDR |
PORTn BaseAddr + $51C | DEN | DEN | DEN | DEN | DEN | DEN | DEN | DEN | GPIO_PORTn_DEN_R | GPIOn->DEN |
PORTn BaseAddr + $524 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | GPIO_PORTn_CR_R | GPIOn->CR |
PORTn BaseAddr + $528 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | GPIO_PORTn_AMSEL_R | GPIOn->AMSEL |
31-28 | 27-24 | 23-20 | 19-16 | 15-12 | 11-8 | 7-4 | 3-0 | |||
PORTn BaseAddr + $52C | PMC7 | PMC6 | PMC5 | PMC4 | PMC3 | PMC2 | PMC1 | PMC0 | GPIO_PORTn_PCTL_R | GPIOn->PCTL |
PORTC BaseAddr + $520 | LOCK (write 0x4C4F434B to unlock, other locks) (reads 1 if locked, 0 if unlocked) | GPIO_PORTC_LOCK_R | GPIOC->LOCK | |||||||
PORTD BaseAddr + $520 | LOCK (write 0x4C4F434B to unlock, other locks) (reads 1 if locked, 0 if unlocked) | GPIO_PORTD_LOCK_R | GPIOD->LOCK | |||||||
PORTF BaseAddr + $520 | LOCK (write 0x4C4F434B to unlock, other locks) (reads 1 if locked, 0 if unlocked) | GPIO_PORTF_LOCK_R | GPIOF->LOCK |
* GPIOn ➤ GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, and GPIOF
On-board I/O
- Two USB connectors on the board.
- The top one is an integrated In-Circuit Debug Interface (ICDI), which allows programming and debugging of the onboard TM4C microcontroller.
- The left USB connector allows you to develop USB applications (device or host).
- Switch-selectable power sources
Select one of the two power sources
- Left-Hand DEVICE Position: powered by USB device port
- Right-Hand DEBUG Position: powered by USB debug (ICDI) port
- Reset button
- Two user switches (SW1 and SW2)
- RGB User LED
- Stackable 40-pin BoosterPack XL interface
Sample Firmware Code in Assembly
Launch the Keil μVision5 on your computer and then create a new project. Copy and paste the following source code into your main.s
Please download the definition ZIP file and extract it into the same project folder: TM4C123GH6PM.zip
The following source code is to turn on the onboard switches and RGB LEDs on PORTF
;This is the first ARM Assembly language program you see in the lab
;This program template was created by Airs Lin @ 2017 California State University of Los Angeles.
;When you write your program, you could have your info at the top document block
;For Example: Your Name, Student Number, what the program is for, and what it does etc.
INCLUDE TM4C123GH6PM.s
; Constant Variable Here
STACK_ADDR_123G EQU 0x20008000
LED_R EQU 2_00000010
LED_B EQU 2_00000100
LED_G EQU 2_00001000
SW1 EQU 2_00010000
SW2 EQU 2_00000001
THUMB
; Vector Table Mapped to Address 0 at Reset
; Linker requires __Vectors to be exported
AREA RESET, DATA, READONLY
EXPORT __Vectors
__Vectors
DCD STACK_ADDR_123G ; stack pointer value when stack is empty
DCD Reset_Handler ; reset vector
ALIGN
; The program
; Linker requires Reset_Handler
AREA |.text|, CODE, READONLY
ENTRY ; mark first instruction to execute
EXPORT Reset_Handler
Reset_Handler
; This subroutine grants access to
; floating point coprocessor.
; It is called by the startup code.
LDR R0, =0xE000ED88
; Enable CP10,CP11
LDR R1,[R0]
ORR R1,R1,#0x20
STR R1,[R0]
DSB ; wait for store to complete
ISB ;reset pipeline now the FPU is enabled
;=====================
; 1. Turn on Port F clock in SYSCTL_RCGCGPIO_R, then chcek SYSCTL_PRGPIO_R ready flag
; enable clock to GPIOF at clock gating register
LDR R0, =SYSCTL_RCGCGPIO_R ; RCGC reg. addr.
LDR R1, [R0]
ORR R1, #(GPIO_PORTF)
STR R1, [R0]
LDR R0, =SYSCTL_PRGPIO_R
WAIT4GPIO LDR R1, [R0]
TST R1, #(GPIO_PORTF)
BEQ WAIT4GPIO
; 2. Unlock PF0 and/or PD7 for TM4C123G board
; unlock PortF
LDR R0, =PORT_UNLOCK_CODE
LDR R1, [R0]
LDR R0, =GPIO_PORTF_LOCK_R
STR R1, [R0]
NOP
NOP
LDR R0, =GPIO_PORTF_CR_R ; Enable Commit for PF0
LDR R1, [R0]
ORR R1, #0x01
STR R1, [R0]
; 3. Clear AMSEL to disable analog
LDR R0, =GPIO_PORTF_AMSEL_R
MOV R1, #0x00
STR R1, [R0]
; 4. Clear PCTL to select GPIO
LDR R0, =GPIO_PORTF_PCTL_R
MOV R1, #0x0000
STR R1, [R0]
; 5. Clear AFSEL bits to 0 to select regular I/O
LDR R0, = GPIO_PORTF_AFSEL_R
MOV R1, #0x00
STR R1, [R0]
; 6. Set DIR to 0 for input, 1 for output
; set PORTF pin3-1 as output pins
LDR R0, =GPIO_PORTF_DIR_R
MOV R1, #0x0E ; pin 1, 2 and 3 are output
STR R1, [R0]
; 7. Set PUR bits to 1 to enable internal pull-up
LDR R0, =GPIO_PORTF_PUR_R
MOV R1, #0x11 ; pin 0 and 4 connect with switch
STR R1, [R0]
; 8 Set DEN bits to 1 to enable data pins
LDR R0, =GPIO_PORTF_DEN_R
LDR R1, [R0]
ORR R1, #0x1F
STR R1, [R0]
;;;;;;;;;; Your Main Code Starts from the next line ;;;;;;;;;;;;
DeadLoop B DeadLoop ; Infinite loop to end program
; The constant variable area
; The value will be stored on ROM segment
AREA ConstantVariables, DATA, READONLY
PORT_UNLOCK_CODE DCD 0x4C4F434B
; The variables area
; The variables will be assigned to RAM area
AREA Variables, DATA, READWRITE
END ; End of the program
Keil C Sample Firmware Code
The following source code is to turn on the onboard RGB LEDs and switch button (SW2) on PORTF
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "TM4C123GH6PM.h"
void Setup_GPIO();
void DelayMs(int s);
int main(void)
{
Setup_GPIO();
while(1){
if ( GPIOF->DATA & 0x01 ){
GPIOF->DATA = 0x02;
DelayMs(1000);
GPIOF->DATA = 0x04;
DelayMs(1000);
GPIOF->DATA = 0x08;
DelayMs(1000);
} else {
GPIOF->DATA = 0x0E;
DelayMs(1000);
GPIOF->DATA = 0x00;
DelayMs(1000);
}
}
}
void Setup_GPIO()
{
// GPIO Initialization and Configuration
// 1. Enable Clock to the GPIO Modules (SYSCTL->RCGCGPIO |= (_PORTs);)
SYSCTL->RCGCGPIO |= (_PORTs); |= 0x20;
// allow time for clock to stabilize (SYSCTL->PRGPIO)
while((SYSCTL->PRGPIO & (0x20) ) != (0x20) ){};
// 2. Unlock GPIO only PD7, PF0 on TM4C123G; PD7, PE7 on TM4C1294 (GPIOx->LOCK = 0x4C4F434B; and GPIOx->CR = _PINs;)
GPIOF->LOCK = 0x4C4F434B;
GPIOF->CR |= 0x01;
// 3. Set Analog Mode Select bits for each Port (GPIOn->AMSEL 0=digital, 1=analog)
GPIOF->AMSEL = 0x00;
// 4. Set Port Control Register for each Port (GPIOn->PCTL = PMCn, check the PCTL table)
GPIOF->PCTL = 0x00;
// 5. Set Alternate Function Select bits for each Port (GPIOn->AFSEL 0=regular I/O, 1=PCTL peripheral)
GPIOF->AFSEL = 0x00;
// 6. Set Output pins for each Port (Direction of the Pins: GPIOn->DIR 0=input, 1=output)
GPIOF->DIR = 0x0E; // PF3,PF2,PF1 for Output
// 7. Set PUR bits for internal pull-up, PDR for pull-down reg, ODR for open drain (0: disable, 1=enable)
GPIOF->PUR = 0x01;
// 8. Set Digital ENable register on all GPIO pins (GPIOn->DEN 0=disable, 1=enable)
GPIOF->DEN = 0x0F; // Enable all digital pins on PortF (PF3,PF2,PF1,PF0)
}
void DelayMs(int s)
{
volatile int i, j;
for (i = 0; i < s; i++)
for (j = 0; j < 3180; j++)
{};
}
EK-TM4C1294XL LaunchPad
GPIO Ports
The microcontroller on the EK-TM4C1294XL LaunchPad is TM4C1294NCPDT. The TM4C1294NCPDT GPIO module is comprised of fifteen physical GPIO blocks, each corresponding to an individual GPIO port (Port A, Port B, Port C, Port D, Port E, Port F, PORTG, PORTH, PORTJ, PORTK, PORTL, PORTM, PORTN, PORTP, and PORTQ).
On the TM4C1294 microcontroller, the Advanced High-Performance Bus (AHB) is now the default connection. The movement from APB to AHB reduces the clock latency so you would be getting a better performance for direct GPIO. The base addresses for each GPIO Port are shown in Table 2.
Table 2: GPIO Port's Base Address
APB | AHB Bus | |||
GPIO Port | Base Address | Range | Base Address | Range |
Port A | 0x4005.8000 | 0x4005.8000 ~ 0x4005.8FFF | ||
Port B | 0x4005.9000 | 0x4005.9000 ~ 0x4005.9FFF | ||
Port C | 0x4005.A000 | 0x4005.A000 ~ 0x4005.AFFF | ||
Port D | 0x4005.B000 | 0x4005.B000 ~ 0x4005.BFFF | ||
Port E | 0x4005.C000 | 0x4005.C000 ~ 0x4005.CFFF | ||
Port F | 0x4005.D000 | 0x4005.D000 ~ 0x4005.DFFF | ||
Port G | 0x4005.E000 | 0x4005.E000 ~ 0x4005.EFFF | ||
Port H | 0x4005.F000 | 0x4005.F000 ~ 0x4005.FFFF | ||
Port J | 0x4006.0000 | 0x4006.0000 ~ 0x4006.0FFF | ||
Port K | 0x4006.1000 | 0x4006.1000 ~ 0x4006.1FFF | ||
Port L | 0x4006.2000 | 0x4006.2000 ~ 0x4006.2FFF | ||
Port M | 0x4006.3000 | 0x4006.3000 ~ 0x4006.3FFF | ||
Port N | 0x4006.4000 | 0x4006.4000 ~ 0x4006.4FFF | ||
Port P | 0x4006.5000 | 0x4006.5000 ~ 0x4006.5FFF | ||
Port Q | 0x4006.6000 | 0x4006,6000 ~ 0x4006.6FFF |
Registers
The GPIO Ports must be initialized before being used. The basic steps to configure the required PORTn pins to GPIO are given below:
- Enabled the clock to the GPIO Port by setting the corresponding bit in the SYSCTL->RCGCGPIO |= (_PORTs); register. Then, wait for the GPIO clock to be ready by checking the SYSCTL->PRGPIO register
- Unlock the port by writing 0x4C4F434B to GPIOn[_AHB]->LOCK register. The only needing unlocking on the TM4C1294 is PORTD[7]. After unlocking the port, the appropriate bits of the GPIO Commit register (GPIOn[_AHB]->CR) need to be set.
- Disable the analog function of the pin in the Analog Mode Select register (GPIOn[_AHB]->AMSEL) because we want to use the pin for digital I/O. If this pin is connected to the ADC or analog comparator, the corresponding bit in GPIOn[_AHB]->AMSEL must be set as 1. If this pin is used as digital I/O, its corresponding bit must be set as 0.
- Clear bits in the port control register (GPIOn[_AHB]->PCTL) to select regular digital functions. Each GPIO pin needs 4-bit in its corresponding GPIOn[_AHB]->PCTL register. Not every pin can be configured to every alternative function.
- Clear bits in the Alternate Function Select register (GPIOn[_AHB]->AFSEL). If an alternate pin is chosen for a bit, then the PMCn field must be programmed in the GPIOn[_AHB]->PCTL register for the specific peripheral required.
- Set the direction of the GPIO port pins by programming the GPIOn[_AHB]->DIR register. A bit in GPIOn[_AHB]->DIR set to 0 means input and 1 means output.
- Program each pad in the port to have either pull-up, pull-down, or open-drain functionality through the GPIOn[_AHB]->PUR, GPIOn[_AHB]->PDR, GPIOn[_AHB]->ODR register.
- To enable GPIO pins as digital I/Os, set the appropriate DEN bit in the Digital Enable register (GPIOn[_AHB]->DEN).
The first step must be turning on the clock, and other steps can occur in any order.
After a RESET, the default state is to disable the analog function and disable the alternate function. Therefore, steps 3, 4, and 6 can be skipped.
Address | bit-Field | Register Name | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
in Assembly | in C | |||||||||
$400F.E108 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | SYSCTL_RCGCGPIO_R | SYSCTL->RCGCGPIO |= (_PORTs); |
--- | GPIOQ | GPIOP | GPION | GPIOM | GPIOL | GPIOK | GPIOJ | |||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |||
GPIOH | GPIOG | GPIOF | GPIOE | GPIOD | GPIOC | GPIOB | GPIOA | |||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |||
PORTn BaseAddr + $3FC | DATA | DATA | DATA | DATA | DATA | DATA | DATA | DATA | GPIO_PORTn_AHB_DATA_R | GPIOn->DATA GPIOn_AHB->DATA |
PORTn BaseAddr + $400 | DIR | DIR | DIR | DIR | DIR | DIR | DIR | DIR | GPIO_PORTn_AHB_DIR_R | GPIOn->DIR GPIOn_AHB->DIR |
PORTn BaseAddr + $420 | SEL | SEL | SEL | SEL | SEL | SEL | SEL | SEL | GPIO_PORTn_AHB_AFSEL_R | GPIOn->AFSEL GPIOn_AHB->AFSEL |
PORTn BaseAddr + $50C | ODE | ODE | ODE | ODE | ODE | ODE | ODE | ODE | GPIO_PORTn_AHB_ODR_R | GPIOn->ODR GPIOn_AHB->ODR |
PORTn BaseAddr + $510 | PUE | PUE | PUE | PUE | PUE | PUE | PUE | PUE | GPIO_PORTn_AHB_PUR_R | GPIOn->PUR GPIOn_AHB->PUR |
PORTn BaseAddr + $514 | PDE | PDE | PDE | PDE | PDE | PDE | PDE | PDE | GPIO_PORTn_AHB_PDR_R | GPIOn->PDR GPIOn_AHB->PUR |
PORTn BaseAddr + $51C | DEN | DEN | DEN | DEN | DEN | DEN | DEN | DEN | GPIO_PORTn_AHB_DEN_R | GPIOn->DEN GPIOn_AHB->DEN |
PORTn BaseAddr + $524 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | GPIO_PORTn_AHB_CR_R | GPIOn->CR GPIOn_AHB->CR |
PORTn BaseAddr + $528 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | GPIO_PORTn_AHB_AMSEL_R | GPIOn->AMSEL GPIOn_AHB->AMSEL |
15-14 | 13-12 | 11-10 | 9-8 | 7-6 | 5-4 | 3-2 | 1-0 | |||
PORTn BaseAddr + $FC4 | EDM7 | EDM6 | EDM5 | EDM4 | EDM3 | EDM2 | EDM1 | EDM0 | GPIO_PORTn_AHB_PC_R | |
31-28 | 27-24 | 23-20 | 19-16 | 15-12 | 11-8 | 7-4 | 3-0 | |||
PORTn BaseAddr + $52C | PMC7 | PMC6 | PMC5 | PMC4 | PMC3 | PMC2 | PMC1 | PMC0 | GPIO_PORTn_AHB_PCTL_R | GPIOn->PCTL GPIOn_AHB->PCTL |
PORTD BaseAddr + $520 | LOCK (write 0x4C4F434B to unlock, other locks) (reads 1 if locked, 0 if unlocked) | GPIO_PORTD_AHB_LOCK_R | GPIOn->LOCK GPIOn_AHB->LOCK |
* PORTn[_AHB] ➤ PORTA, PORTB, PORTC, PORTD, PORTE, PORTF, PORTG, PORTH, PORTJ, PORTK, PORTL, PORTM, PORTN, PORTP, and PORTQ
On-board I/O
Sample Firmware Code in Assembly
Launch the Keil μVision5 on your computer and then create a new project. Copy and paste the following source code into your main.s
Please download the definition ZIP file and extract it into the same project folder: TM4C1294NCPDTI.zip
The following source code is to turn on the onboard switches and LEDs on PORTF, PORTN, and PORTJ
;This is the first ARM Assembly language program you see in the lab
;This program template was created by Airs Lin @ 2017 California State University of Los Angeles.
;When you write your program, you could have your info at the top document block
;For Example: Your Name, Student Number, what the program is for, and what it does etc.
INCLUDE TM4C1294NCPDT.s
; Constant Variable Here
STACK_ADDR_123G EQU 0x20008000
LED1_N EQU 2_00000010
LED2_N EQU 2_00000001
LED3_F EQU 2_00010000
LED4_F EQU 2_00000001
SW1_J EQU 2_00000001
SW2_J EQU 2_00000010
THUMB
; Vector Table Mapped to Address 0 at Reset
; Linker requires __Vectors to be exported
AREA RESET, DATA, READONLY
EXPORT __Vectors
__Vectors
DCD STACK_ADDR_123G ; stack pointer value when stack is empty
DCD Reset_Handler ; reset vector
ALIGN
; The program
; Linker requires Reset_Handler
AREA |.text|, CODE, READONLY
ENTRY ; mark first instruction to execute
EXPORT Reset_Handler
Reset_Handler
; This subroutine grants access to
; floating point coprocessor.
; It is called by the startup code.
LDR R0, =0xE000ED88
; Enable CP10,CP11
LDR R1,[R0]
ORR R1,R1,#0x20
STR R1,[R0]
DSB ; wait for store to complete
ISB ;reset pipeline now the FPU is enabled
;=====================
; 1. Turn on Port F clock in SYSCTL_RCGCGPIO_R, tehn check SYSCTL_PRGPIO
; enable clock to GPIOF at clock gating register
LDR R0, =SYSCTL_RCGCGPIO_R ; RCGC reg. addr.
MOV R1, #(GPIO_PORTF :OR: GPIO_PORTJ :OR: GPIO_PORTN)
STR R1, [R0]
LDR R0, =SYSCTL_PRGPIO_R
Wait4GPIO LDR R1, [R0]
TST R1, #(GPIO_PORTF :OR: GPIO_PORTJ :OR: GPIO_PORTN)
BEQ Wait4GPIO
; 2. Unlock PD7 only
; 3. Clear AMSEL to disable analog
MOV R1, #0x00
LDR R0, =GPIO_PORTF_AHB_AMSEL_R
STR R1, [R0]
LDR R0, =GPIO_PORTJ_AHB_AMSEL_R
STR R1, [R0]
LDR R0, =GPIO_PORTN_AHB_AMSEL_R
STR R1, [R0]
; 4. Clear PCTL to select GPIO
MOV R1, #0x0000
LDR R0, =GPIO_PORTF_AHB_PCTL_R
STR R1, [R0]
LDR R0, =GPIO_PORTJ_AHB_PCTL_R
STR R1, [R0]
LDR R0, =GPIO_PORTN_AHB_PCTL_R
STR R1, [R0]
; 5. Clear AFSEL bits to 0 to select regular I/O
MOV R1, #0x00
LDR R0, =GPIO_PORTF_AHB_AFSEL_R
STR R1, [R0]
LDR R0, =GPIO_PORTN_AHB_AFSEL_R
STR R1, [R0]
LDR R0, =GPIO_PORTJ_AHB_AFSEL_R
STR R1, [R0]
; 6. Set DIR to 0 for input, 1 for output
LDR R0, =GPIO_PORTF_AHB_DIR_R
MOV R1, #(BIT4 :OR: BIT0) ; PF4 & PF0 to LED
STR R1, [R0]
LDR R0, =GPIO_PORTN_AHB_DIR_R
MOV R1, #(BIT1 :OR: BIT0) ; PN1 & PN0 to LED
STR R1, [R0]
LDR R0, =GPIO_PORTJ_AHB_DIR_R
MOV R1, #0x00 ; PJ1 & PJ0 to Switch
STR R1, [R0]
; 7. Set PUR bits to 1 to enable internal pull-up
LDR R0, =GPIO_PORTJ_AHB_PUR_R
MOV R1, #(BIT1 :OR: BIT0)
STR R1, [R0]
; 8 Set DEN bits to 1 to enable data pins
LDR R0, =GPIO_PORTF_AHB_DEN_R
LDR R1, [R0]
ORR R1, #0x11
STR R1, [R0]
LDR R0, =GPIO_PORTN_AHB_DEN_R
LDR R1, [R0]
ORR R1, #0x03
STR R1, [R0]
LDR R0, =GPIO_PORTJ_AHB_DEN_R
LDR R1, [R0]
ORR R1, #0x03
STR R1, [R0]
;;;;;;;;;; Your Main Code Starts from the next line ;;;;;;;;;;;;
DeadLoop B DeadLoop ; Infinite loop to end program
; The constant variable area
; The value will be stored on ROM segment
AREA ConstantVariables, DATA, READONLY
PORT_UNLOCK_CODE DCD 0x4C4F434B
; The variables area
; The variables will be assigned to RAM area
AREA Variables, DATA, READWRITE
END ; End of the program
Sample Firmware Code for Keil C
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "TM4C1294NCPDT.h"
void Setup_GPIO();
void DelayMs(int s);
int main(void)
{
Setup_GPIO();
while(1){
GPIOF_AHB->DATA = 0x01;
DelayMs(1000);
GPIOF_AHB->DATA = 0x10;
DelayMs(1000);
GPIOF_AHB->DATA = 0x00;
GPION->DATA = 0x01;
DelayMs(1000);
GPION->DATA = 0x02;
DelayMs(1000);
GPION->DATA = 0x00;
}
}
void Setup_GPIO()
{
// GPIO Initialization and Configuration
// 1. Enable Clock to the GPIO Modules (SYSCTL->RCGCGPIO |= (_PORTs);)
SYSCTL->RCGCGPIO |= (_PORTs); |= 0x1020;
// allow time for clock to stabilize (SYSCTL->PRGPIO)
while((SYSCTL->PRGPIO & (0x1020) ) != (0x1020) ){};
// 2. Unlock GPIO only PD7, PF0 on TM4C123G; PD7, PE7 on TM4C1294 (GPIOx->LOCK = 0x4C4F434B; and GPIOx->CR = _PINs;)
// 3. Set Analog Mode Select bits for each Port (GPIOn[_AHB]->AMSEL 0=digital, 1=analog)
GPIOF_AHB->AMSEL = 0x00;
GPION->AMSEL = 0x00;
// 4. Set Port Control Register for each Port (GPIOn[_AHB]->PCTL = PMCn, check the PCTL table)
GPIOF_AHB->PCTL = 0x00;
GPION->PCTL = 0x00;
// 5. Set Alternate Function Select bits for each Port (GPIOn[_AHB]->AFSEL 0=regular I/O, 1=PCTL peripheral)
GPIOF_AHB->AFSEL = 0x00;
GPION->AFSEL = 0x00;
// 6. Set Output pins for each Port (Direction of the Pins: GPIOn[_AHB]->DIR 0=input, 1=output)
GPIOF_AHB->DIR = 0x11; // PF4,PF0 for Output
GPION->DIR = 0x03;
// 7. Set PUR bits for internal pull-up, PDR for pull-down reg, ODR for open drain (0: disable, 1=enable)
// 8. Set Digital ENable register on all GPIO pins (GPIOn[_AHB]->DEN 0=disable, 1=enable)
GPIOF_AHB->DEN = 0x11; // Enable all digital pins on PortF (PF4, PF0)
GPION->DEN = 0x03; // Enable all digital pins on PortN (PN1, PN0)
}
void DelayMs(int s)
{
volatile int i, j;
for (i = 0; i < s; i++)
for (j = 0; j < 3180; j++){};
}