Fundamentals 16 min read

Master STM32 GPIO: All 8 Modes Explained with Code Samples

This tutorial walks through STM32's eight GPIO operating modes—four inputs and four outputs—detailing their electrical behavior, typical use cases, configuration steps, and providing complete HAL code examples to help embedded developers choose the right mode for reliable designs.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Master STM32 GPIO: All 8 Modes Explained with Code Samples

1. GPIO Working Mode Overview

STM32 GPIO provides eight distinct operating modes, divided into four input modes and four output modes, each tailored to specific electrical characteristics and application scenarios.

2. Input Modes

2.1 Floating Input Mode

The pin is left without internal pull‑up or pull‑down resistors, making it high‑impedance and susceptible to external noise when no external driver is present.

No internal resistors

Very high input impedance

Lowest power consumption

Prone to interference

Typical application: Use when external circuitry already provides a defined pull‑up or pull‑down resistor.

GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_PinState pinState = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);

2.2 Pull‑Up Input Mode

An internal pull‑up resistor (≈30‑50 kΩ) connects the pin to VDD, forcing a default high level when no external signal is present.

Internal pull‑up to VDD

Default state is high

Prevents floating condition

Ideal for active‑low button detection

Typical application: Button detection where the button pulls the line low when pressed.

GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET) {
    // Button pressed – handle event
}

2.3 Pull‑Down Input Mode

An internal pull‑down resistor (≈30‑50 kΩ) ties the pin to GND, giving a default low level when idle.

Internal pull‑down to GND

Default state is low

Prevents floating condition

Suitable for active‑high signals

Typical application: Detecting high‑level signals such as certain sensor outputs.

GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_SET) {
    // High‑level signal detected
}

2.4 Analog Input Mode

Designed for ADC use, this mode disables digital input circuitry and any pull‑up/down resistors, routing the pin directly to the ADC channel.

Digital input disabled

No pull‑up/pull‑down

Signal fed straight to ADC

Lowest power consumption

Typical application: Reading analog sensors (temperature, light, potentiometer) via the ADC.

GPIO_InitTypeDef GPIO_InitStruct = {0};
ADC_HandleTypeDef hadc1;
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_ADC1_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

hadc1.Instance = ADC1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
HAL_ADC_Init(&hadc1);
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
uint32_t adcValue = HAL_ADC_GetValue(&hadc1);

3. Output Modes

3.1 Push‑Pull Output Mode

Both a P‑MOS and N‑MOS are active, allowing the pin to drive both high and low levels with strong drive capability.

Can output both high and low

High drive strength – suitable for LEDs, relays

Defined output levels, no floating state

Not suitable for shared‑line buses

Typical application: LED control, PWM generation, direct digital signaling.

GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); // LED on (active low)
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);   // LED off

3.2 Open‑Drain Output Mode

Only an N‑MOS pulls the line low; a high level requires an external (or internal) pull‑up resistor.

Can actively pull low only

High level needs pull‑up resistor

Enables level translation

Supports wired‑AND (multiple devices share line)

Typical application: I²C bus, multi‑master communication, level shifting.

GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP; // internal pull‑up if external missing
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// Simulate I²C start condition
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET); // SDA low
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET); // SCL low

3.3 Push‑Pull Alternate Function (AF) Output Mode

The pin is driven by an on‑chip peripheral (SPI, USART, etc.) while retaining push‑pull characteristics.

Peripheral controls output

All push‑pull benefits

User cannot manually set level

Ideal for high‑speed communication interfaces

Typical application: SPI MOSI, USART TX, other high‑speed peripherals.

GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1; // USART1 TX
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

3.4 Open‑Drain Alternate Function (AF) Output Mode

Peripheral‑controlled open‑drain output, requiring an external pull‑up for the high state.

Peripheral controls output

All open‑drain characteristics

External pull‑up needed

Supports multi‑master buses (I²C, SMBus)

Typical application: Hardware I²C peripheral pins (SCL, SDA).

GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP; // internal pull‑up if external missing
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; // I²C1
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

4. Mode Selection Recommendations

4.1 Choosing an Input Mode

If external pull‑up/down resistors exist, use floating input.

For button detection with the button tied to ground, use pull‑up input.

For button detection with the button tied to VDD, use pull‑down input.

For ADC analog sampling, use analog input.

4.2 Choosing an Output Mode

General digital output (LEDs, signals): push‑pull.

Shared‑line buses (I²C, single‑wire): open‑drain.

Level translation needs: open‑drain with external pull‑up.

When using on‑chip peripherals (SPI, USART): select the appropriate AF mode.

4.3 Selecting Speed Grades

Low speed for simple signals (LEDs) – reduces EMI and power.

Medium/High speed for ordinary communication.

Very high speed for high‑performance interfaces (high‑speed SPI, SDIO).

5. Common Issues and Precautions

5.1 Why does open‑drain need a pull‑up?

Open‑drain can only pull the line low; without a pull‑up the line stays floating when the transistor is off, preventing a defined high level.

5.2 Can a push‑pull output use a pull‑up?

Technically possible but unnecessary; push‑pull already drives both levels, and an extra pull‑up only adds power consumption.

5.3 Can multiple GPIOs be tied together?

Only if they are all open‑drain. Connecting push‑pull outputs together can cause a short circuit when one drives high and another drives low.

5.4 How to configure alternate‑function mapping?

When using the HAL library, set both the mode (e.g., GPIO_MODE_AF_PP or GPIO_MODE_AF_OD) and the Alternate field to the peripheral’s AF number, consulting the MCU datasheet for the correct mapping.

By understanding these eight GPIO modes and their trade‑offs, developers can reliably select the appropriate configuration for stable embedded systems.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

CHardwareembeddedMicrocontrollerHALGPIOSTM32
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.