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 a 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 data register is eight bits wide and is used to:
- Read the value on those GPIO ports including input and output pins.
- Program the value on those GPIO ports that are configured as outputs.
When the port pin is configured as GPIO port, the GPIOn->DATA register is used to read and write data on the registers. If the pin is configured as a digital output pin, the data written to the GPIOn->DATA register reflects on the corresponding output pin. A read from GPIOn->DATA register returns the last bit value written if the respective pins are configured as outputs, or it returns the value on the corresponding input pins when these are configured as inputs.
GPIO Addressing Masking (Hardware masking address)
GPIO Address masking is a somewhat unusual technique for programming the GPIO port pins. Each GPIO port has a DATA register address. If you write an 8-bit value directly to the DATA register and all eight pins will be modified. If you just want to modify specific bits of this port, you would have to read the value on the port pins, 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.
For example, set PA1 to logic 1:
GPIOA->DATA = GPIOA->DATA | _BIT1;
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 modify the value on GPIO Port D pins 1, 2, and 5 only, the bit-mask value, in this case, is (0010 0110)2 in a binary number (bit 1, 2, and 5 are set to "1", other bits are set to "0"). Then convert the value to a bit-mask address by shifting the bit-mask value to the left by 2-bits. It will be (00 1001 1000)2 in binary. You can use a bit-mask to indicate which bits are to be modified and if you look at the diagram:
GPIO addressing mask can be used on input and output pins.
In C code, pointers can be used to point to hardware mask 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
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-bits 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-pate 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-pate 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++){}; }