The GPIO (general purpose input/output) pins of the Pico are the digital pins that can be configured as an input or an output, to read or emit a binary signal (0 V / 3.3 V). In MicroPython, everything goes through the Pin class of the [[micropython-modules-en|machine]] module. Configuring a GPIO correctly is the basic move of any embedded program. Forgetting the mode, mixing up the pulls or ignoring the floating state of an input is the most frequent cause of unpredictable behaviour early in a project.

What is it for?

Every binary sensor and actuator (button, limit switch, LED, relay, buzzer, presence sensor) goes through the GPIO. Three configurations cover the essentials: output (Pin.OUT, driven to 1 or 0), input pulled high (Pin.IN, Pin.PULL_UP), input pulled low (Pin.IN, Pin.PULL_DOWN). Understanding these modes and the wiring that goes with them makes most of the other tutorials readable.

Step by step

Four steps: identify the pin, create the Pin object with its mode, read or write, wire it cleanly.

1. Identify the pins

The Pico exposes pins GP0 to GP28 (the GP numbering, not to be confused with the physical pin numbering). Specifics: GP26 / GP27 / GP28 double as analog inputs (ADC). Some pins carry a bus by default (UART, I2C, SPI). The on-board LED is on GP25 (shorthand "LED").

Every pin runs at 3.3 V and is not 5 V tolerant — see logic levels.

Official Raspberry Pi Pico pinout: the 40 pins with the GPxx numbers used in code, the analog inputs (ADC) and the bus pins (UART, I2C, SPI) marked.|640

Source: Raspberry Pi Ltd — CC BY-ND licence, image unmodified.

2. Create the Pin object with its mode

Unlike Arduino (pinMode inside setup()), you create one object per pin, usually at the top of the program:

from machine import Pin
 
led = Pin(15, Pin.OUT)                 # output
bouton = Pin(14, Pin.IN, Pin.PULL_UP)  # input, internal resistor to 3.3 V
  • Pin.OUT — the pin drives a signal outwards (LED, relay, transistor).
  • Pin.IN, Pin.PULL_UP — input with an internal resistor to 3.3 V. Inverted logic: reads 1 at rest, 0 when connected to GND (typically through a button).
  • Pin.IN, Pin.PULL_DOWN — input with an internal resistor to GND: reads 0 at rest, 1 when brought to 3.3 V. (The Pico offers both pulls internally — an advantage over the Arduino’s AVR, which only has a pull-up.)
  • Pin.IN on its own — a floating input, with no bias: the reading is random if nothing is connected. Keep it for cases with an external resistor.

3. Read or write

while True:
    if bouton.value() == 0:    # button pressed (pull-up: 0 = pressed)
        led.on()
    else:
        led.off()

bouton.value() returns 1 or 0. On the output side, led.value(1)/led.value(0), or the shorthands led.on() / led.off() / led.toggle().

4. Wire it cleanly

  • Output to a LED: a series resistor of 220 Ω to 1 kΩ between the pin and the anode (+) of the LED, cathode (−) to GND. Without a resistor, the LED or the pin gets damaged.
  • Input from a button, PULL_UP: one side of the button to the pin, the other side to GND. Nothing else.
  • Input from a button, Pin.IN alone: an external resistor is needed (~10 kΩ to 3.3 V or to GND) to give a defined rest state.

Setup: LED and resistor on GP15, button between GP14 and GND, on a Raspberry Pi Pico|600

Example — A button that lights a LED

Complete wiring and code to validate Pin.OUT plus Pin.IN plus read and write.

Wiring: LED anode → 220 Ω resistor → GP15; cathode → GND. Button between GP14 and GND (PULL_UP, no external resistor).

from machine import Pin
 
led = Pin(15, Pin.OUT)
bouton = Pin(14, Pin.IN, Pin.PULL_UP)
 
while True:
    if bouton.value() == 0:
        led.on()
    else:
        led.off()

Run it, press the button, and the LED comes on. Release it, and the LED goes out. If the LED stays on permanently, you have probably wired one side of the button to 3.3 V instead of GND.

Pitfalls

A floating pin. An input left in Pin.IN with no pull picks up noise — a random reading that can look as if it responds to a hand passing nearby (a 50 Hz antenna effect). For a button, it is almost always PULL_UP plus a button to GND.

The inverted logic of the pull-up. A button on PULL_UP reads 0 when pressed. Testing if bouton.value() == 1 will light the LED when the button is released — the opposite of what you expect.

A LED with no resistor. A LED connected directly draws an excessive current that burns it out (or damages the pin). Always a series resistor (220 Ω to 1 kΩ for a standard LED on 3.3 V).

Maximum pin current exceeded. A Pico pin delivers about 4 mA by default, about 12 mA at most (the drive strength is adjustable). That is less than an Arduino (20 mA), so you reach for a transistor or a dedicated module even sooner (see off output).

The 5 V reflex. The Pico is not 5 V tolerant: applying 5 V to an input can destroy the pin. Shift the level of a 5 V sensor (voltage divider or level shifter).

Special case — PWM, ADC and buses

Not all pins are equivalent:

  • ADC — GP26 / GP27 / GP28 are the analog inputs ([[micropython-capteur-analogique-en|ADC]]).
  • PWM — on the Pico, every GPIO pin can generate a PWM signal (see PWM) — no dedicated “~” pins as on Arduino.
  • Buses — some pins carry UART, I2C or SPI by default (see communication buses). Using a pin as GPIO makes it unavailable for its bus.

The board’s official pinout is the reference. Keep it within reach.

Where it fits in the project

Mastering these modes on a small isolated setup is the foundation that almost every following tutorial rests on — no point moving on to sensors or actuators before that groundwork is firm.

See also