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.
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 off3.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 low3.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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
