What is the difference between push-pull and open-drain GPIO output modes?
In push-pull mode, the GPIO pin actively drives both high and low using a complementary pair of transistors — a PMOS transistor pulls the output to VDD when the output register bit is 1, and an NMOS transistor pulls it to GND when the bit is 0. This gives fast, strong transitions in both directions with well-defined voltage levels. Push-pull is the default output mode for most applications: driving LEDs, chip-select lines, reset pins, and general-purpose control signals. The pin always has a defined state, so no external components are needed.
In open-drain mode, only the NMOS transistor is present. The pin can actively pull the line low, but when the output is "high," the transistor simply turns off, leaving the pin floating (high-impedance). An external pull-up resistor is required to bring the line to a defined high level. This mode is essential for shared buses like I2C, where multiple devices connect to the same SDA/SCL lines. If two push-pull outputs drove the same wire — one high and one low — they would create a bus contention short circuit from VDD to GND through both active transistors, potentially damaging the drivers or causing excessive current draw. Open-drain eliminates this: any device can pull the line low, and the pull-up passively holds it high when no device is pulling down. This also enables wired-AND logic — the line is high only when all devices release it.
A secondary advantage of open-drain is voltage-level translation. The pull-up resistor can be tied to a different voltage rail than the MCU supply. For example, a 3.3V MCU driving an open-drain output with a 5V pull-up can interface directly with 5V logic, provided the MCU's GPIO is 5V-tolerant on that pin (check the datasheet's "FT" marking on STM32).
Source: GPIO Q&A
