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:

  1. GPIO pins can be configured to be input or output
  2. GPIO pins can be enabled or disabled
  3. Input values are readable( typically logic high or low)
  4. Output values are writable and can be read-back
  5. 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:

  1. 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.
  2. Unlock the Port: Unlocking needs only for pins PD7, and PD0 on the TM4C123G; and PD2 on the TM4C1294 boards.
  3. Set Analog Mode: Enable the pins which are used for analog function.
  4. Set Port Control Register: To use internal digital functions, the digital function number must be set in the PCTL register.
  5. Set Alternate Function Register: Set AFSEL to select the I/O pin to the internal digital function.
  6. Set Output Pins: Set the output pins of each GPIO port.
  7. 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).
  8. 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:


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.