post / 2024.02.15
MicroPython Function Reference
This article collects the parts of MicroPython’s machine module that are most useful on a Raspberry Pi Pico (RP2040). Everything has been checked against the official MicroPython documentation.
machine: Hardware-Related Functions
There are two numbering schemes for pins:
- GPIO number (GP0–GP29): the one used in code;
Pin(25)means GP25. - Physical pin number: the 40 header positions on the board. These are not the same as GPIO numbers, so be careful when wiring.
class Pin
Constructor machine.Pin(id, mode=-1, pull=-1, value=None)
| Parameter | Meaning |
|---|---|
id | Pin identifier. On the Pico, 0–29 (GP0–GP29) |
mode | None / Pin.IN(0) / Pin.OUT(1) / Pin.OPEN_DRAIN(2) |
pull | Internal pull resistor, valid only in input mode: None / Pin.PULL_UP(1) / Pin.PULL_DOWN(2) |
value | Valid only for output/open-drain mode; initial level: 0 low, 1 high |
Note that it is
Pin.PULL_DOWN, notPin.DOWN.
Pin.init(mode=-1, pull=-1, value=None)
Re-initialise the pin. Only the arguments you pass are changed; everything else keeps its current state.
Pin.value([x])
- With no argument: returns the current pin level (0 or 1).
- With an argument: writes the level. The argument is converted to a boolean (
Truesets 1,Falsesets 0).
Pin.on() / Pin.off() and Pin.high() / Pin.low()
on(),high(): drive the pin high (1).off(),low(): drive the pin low (0).
These four are meaningful only in output/open-drain mode. low() and high() are not part of the core API, but they are available on the Pico (rp2 port).
Pin.toggle()
Flips the output level from 0 to 1 or 1 to 0. toggle() is available on the rp2, esp32, and several other ports; where it is missing, use Pin.value(not Pin.value()) instead.
from machine import Pin
import time
led = Pin(25, Pin.OUT) # the on-board LED of a Pico is GP25
while True:
led.toggle()
time.sleep(1) # flip once per second
Pin.irq(handler=None, trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING)
Configures an external interrupt. The callback runs whenever the trigger condition occurs.
handler: the callback, which must accept onePinargument.trigger: the condition, and multiple values can be OR-ed with|:
| Constant | Trigger |
|---|---|
Pin.IRQ_FALLING | falling edge |
Pin.IRQ_RISING | rising edge |
Pin.IRQ_LOW_LEVEL | low level |
Pin.IRQ_HIGH_LEVEL | high level |
def on_press(pin):
print("Button pressed")
button = Pin(15, Pin.IN, Pin.PULL_UP)
button.irq(handler=on_press, trigger=Pin.IRQ_FALLING)
class PWM
PWM (pulse-width modulation) switches a pin on and off rapidly to emulate intermediate voltages. It is used for dimming LEDs, controlling motor speed, and driving servos.
machine.PWM(pin, freq=..., duty_u16=...)
Creates a PWM output on the given pin; pin is a Pin object.
Common methods
| Method | Purpose |
|---|---|
PWM.freq([value]) | get/set the frequency in Hz, roughly 8 Hz – 62.5 MHz (at a 125 MHz CPU clock) |
PWM.duty_u16([value]) | get/set the duty cycle as 0–65535, the ratio value / 65535 |
PWM.duty_ns([value]) | get/set the high time within one period, in nanoseconds |
PWM.deinit() | stop the PWM output |
The upper bound of
duty_u16is 65535, not 65536. Passing 65536 overflows.
RP2040 has 8 independent PWM slices with 2 channels each, 16 channels in total. The two channels of a slice must share a frequency but may have different duty cycles.
Example: breathing LED
from machine import Pin, PWM
import time
led = PWM(Pin(25))
led.freq(1000) # 1 kHz
duty = 0 # duty cycle in percent
step = 1
while True:
duty += step
if duty >= 100:
duty = 100
step = -1
elif duty <= 0:
duty = 0
step = 1
# convert percent to the 0-65535 range, without overflowing
led.duty_u16(int(duty / 100 * 65535))
if duty % 5 == 0:
print(duty) # convenient for plotting
time.sleep(0.01) # roughly a 2-second round trip
Example: button-controlled LED (with software debouncing)
from machine import Pin
import time
button = Pin(15, Pin.IN, Pin.PULL_UP) # reads 0 while pressed
led_board = Pin(25, Pin.OUT) # on-board LED
led_ext = Pin(16, Pin.OUT) # external LED
while True:
led_ext.off()
if button.value() == 0: # possibly pressed
time.sleep(0.01) # wait 10 ms and check again to filter bounce
if button.value() == 0: # confirmed
led_board.toggle()
led_ext.on()
print("The button is pressed.")
while button.value() == 0: # wait for release
time.sleep(0.01)
A mechanical button bounces for a few milliseconds when pressed or released, and the CPU can read that as several presses. Software debouncing means: after detecting a change, wait about 10 ms and read the pin again to confirm.
class ADC
The ADC (analog-to-digital converter) turns an analog voltage into a digital reading.
machine.ADC(id)
id may be a Pin object or a channel number:
- On the Pico, channels 0–3 map to GP26–GP29 (GP29 is wired to VSYS on the board);
- Channel 4 is the on-chip temperature sensor, also reachable as
ADC.CORE_TEMP.
ADC.read_u16()
Returns the reading as an integer in 0–65535, spanning the input range 0–3.3 V.
from machine import ADC, Pin
adc = ADC(Pin(26)) # equivalent to ADC(0)
value = adc.read_u16() # 0 - 65535
voltage = value / 65535 * 3.3 # convert to volts
print(voltage, "V")
The range is 0–65535. The RP2040’s ADC hardware is only 12-bit (0–4095); MicroPython scales it linearly to 16 bits, so the lowest few bits carry no real precision.
Summary
| Task | Key point |
|---|---|
| Digital I/O | Pin(id, mode, pull); read with value(), write with value() / on() / off() / toggle() |
| Interrupts | Pin.irq(handler, trigger); the callback must take one Pin argument |
| Dimming / speed control | PWM(pin) + freq() + duty_u16(); duty is capped at 65535 |
| Reading analog input | ADC(Pin(26)) + read_u16(), returning 0–65535 |
| Button bounce | after detecting a change, wait 10 ms and confirm |
Author: 孤筝
Title: MicroPython Function Reference
Published: 2024-02-15
Updated: 2026-10-05
License: CC BY-NC-SA 4.0
Sponsor / I took a taxi home for sixty or seventy dollars!


When will I have a drink and discuss the details again?