GPIO & PWM on Raspberry Pi Pico W
GPIO & PWM on Raspberry Pi Pico W
Control LEDs, read buttons, use ADC, and generate PWM with MicroPython.
GPIO in MicroPython
All GPIO operations on the Pico W use the machine module:
from machine import Pin, ADC, PWM
The Pico W has 26 multi-function GPIO pins exposed on the header. Each can be configured as digital input, digital output, or connected to peripherals (SPI, I2C, UART, ADC, PWM).
Digital Output
from machine import Pin
led = Pin(15, Pin.OUT) # Configure GPIO 15 as output
led.on() # Set HIGH (3.3 V)
led.off() # Set LOW (0 V)
led.toggle() # Flip current state
led.value(1) # Same as on()
led.value(0) # Same as off()
Digital Input
from machine import Pin
btn = Pin(14, Pin.IN, Pin.PULL_UP) # Input with pull-up resistor
state = btn.value() # Returns 1 (high) or 0 (low)
# With pull-up: reads 1 when open, 0 when button connects pin to GND
if btn.value() == 0:
print("Button pressed!")
Pull options:
Pin.PULL_UP߀” internal pull-up, reads 1 when nothing connectedPin.PULL_DOWN߀” internal pull-down, reads 0 when nothing connected- No pull (omit) ߀” floating input, unreliable without external resistor
Interrupts
from machine import Pin
def button_pressed(pin):
print("Interrupt! Pin:", pin)
btn = Pin(14, Pin.IN, Pin.PULL_UP)
btn.irq(trigger=Pin.IRQ_FALLING, handler=button_pressed)
IRQ_FALLING fires when the pin transitions from HIGH to LOW (button pressed with pull-up). IRQ_RISING fires on LOW߆’HIGH.
Analog Input (ADC)
The Pico W has 3 ADC channels plus one for internal temperature:
| ADC | GPIO | Notes |
|---|---|---|
| ADC0 | GPIO 26 | External input |
| ADC1 | GPIO 27 | External input |
| ADC2 | GPIO 28 | External input |
| ADC3 (4) | Internal | CPU temperature sensor |
from machine import ADC
adc = ADC(26) # ADC on GPIO 26
raw = adc.read_u16() # Returns 0߀“65535 (16-bit scaled)
voltage = raw * (3.3 / 65535)
Reading the Internal Temperature
from machine import ADC
sensor = ADC(4) # Internal temperature sensor
raw = sensor.read_u16()
voltage = raw * (3.3 / 65535)
temp_c = 27 - (voltage - 0.706) / 0.001721
print(f"CPU temp: {temp_c:.1f} ?°C")
PWM Output
Any GPIO pin supports PWM on the Pico W. Each PWM slice covers two pins and they share frequency.
from machine import PWM, Pin
pwm = PWM(Pin(15))
pwm.freq(1000) # 1000 Hz frequency
pwm.duty_u16(32768) # 50% duty cycle (0߀“65535)
# Fade LED in
for duty in range(0, 65535, 256):
pwm.duty_u16(duty)
sleep_ms(5)
pwm.deinit() # Release the PWM pin when done
Servo Control
A servo expects a 50 Hz PWM signal with pulse width 1߀“2 ms:
from machine import PWM, Pin
from time import sleep
servo = PWM(Pin(15))
servo.freq(50)
def set_angle(angle):
# Map 0߀“180 degrees to 1߀“2 ms pulse (at 50 Hz = 20 ms period)
min_duty = int(65535 * 1 / 20) # 1 ms / 20 ms
max_duty = int(65535 * 2 / 20) # 2 ms / 20 ms
duty = min_duty + int((max_duty - min_duty) * angle / 180)
servo.duty_u16(duty)
set_angle(0)
sleep(1)
set_angle(90)
sleep(1)
set_angle(180)