← index #17515PR #17692
Related · high · value 0.965
QUERY · ISSUE

Add Pin.mode() and Pin.alt() support for all applicable ports

openby sfe-SparkFroopened 2025-06-17updated 2025-06-19
enhancement

Description

Request

Pin.mode() is currently only supported on cc3200 and stm32 ports, according to the current docs. The first part of this request is to implement that method on all other applicable ports (eg. rp2).

The second part of this request is to implement a similar Pin.alt() method for all applicable ports (eg. rp2), that can be used to either get or set the alt value of the Pin object.


Motivation

I'm writing an ST7789 display driver. Yes, there are many out there, but none fit the needs of my application perfectly.

For example, many ST7789 breakout boards include an SD card slot that shares the same SPI bus, but none of the existing ST7789 MicroPython drivers (that I know of) allow both the display and SD card to be used simultaneously. The DC pin of the ST7789 typically shares the MISO pin. The DC pin has to be driven by the host microcontroller, meaning its mode must be set to OUT. However for the SD card, the mode must be set to ALT, and the alt must be set to ALT_SPI (at least, in the case of the rp2 port); having the mode changed to OUT causes the SD card to stop functioning.

My solution is to have my ST7789 driver save the DC pin's mode and alt values before communicating with the ST7789, then restore them after. However, there is no built-in way to get the mode and alt values of the pin directly. Instead, I convert the pin to a string and parse/extract the mode and alt values from there. This works, but the string parsing isn't an efficient solution. Having direct access to the values would be very helpful.

For reference, here's a snippet of my code that saves and restores the mode and alt values:

# There's no way to get the mode and alt of a pin directly, so we
# convert the pin to a string and parse it. Example formats:
# "Pin(GPIO16, mode=OUT)"
# "Pin(GPIO16, mode=ALT, alt=SPI)"
pinStr = str(pin)

# Extract the "mode" parameter from the pin string
if "mode=" in pinStr:
    # Split between "mode=" and the next comma or closing parenthesis
    modeStr = pinStr.split("mode=")[1].split(",")[0].split(")")[0]

    # Look up the mode in Pin class dictionary
    mode = Pin.__dict__[modeStr]
else:
    # No mode specified, just set to None
    mode = None

# Extrct the "alt" parameter from the pin string
if "alt=" in pinStr:
    # Split between "alt=" and the next comma or closing parenthesis
    altStr = pinStr.split("alt=")[1].split(",")[0].split(")")[0]

    # Look up the alt in Pin class dictionary (with "ALT_" prefix)
    alt = Pin.__dict__["ALT_" + altStr]
else:
    # No alt specified, just set to None
    alt = None

#########################
# Communicate with ST7789
#########################

# Restore the pin to its original mode and alt
pin.init(mode=mode, alt=alt)

Code Size

This feature should be always enabled for all ports that support it, to ensure compatibility with drivers that make use of it. I do not expect this to have a significant impact on code size.

Implementation

I hope the MicroPython maintainers or community will implement this feature

Code of Conduct

Yes, I agree

CANDIDATE · PULL REQUEST

rp2: Fix RP2350 and RP2350B pin alt functions.

closedby Gadgetoidopened 2025-07-16updated 2025-11-23
port-rp2

RP2350 builds were using the incomplete rp2_af.csv alt function table which broke pins > 31 in RP2350B (48-pin QFN-80) builds:

>>> machine.Pin(31)
Pin(GPIO31, mode=IN, pull=PULL_DOWN)

>>> machine.Pin(32)
Pin(GPIO32, mode=ALT, pull=PULL_DOWN, alt=31)

UART_AUX (alt function 11) and PIO2 (alt function 8, directly conflicting the RP2040 function GPIO_FUNC_GPCK) were also missing.

Changes

boards/*._af.csv: Add separate alt-functions tables for RP2040,
RP2350 and RP2350B.

CMakeLists.txt: Pick correct _af.csv to pass into make-pins.py.

boards/make-pins.py: handle CORESIGHT and XIP_CS1 alt functions.

machine_pin.c: Add PIO2, CORESIGHT and XIP_CS1 alt functions.

Testing

UART_AUX

I tested UART_AUX on an RP2350B board with the following code and a Raspberry Pi Debug Probe:

from machine import Pin, UART

uart = UART(0, 115200, tx=34, rx=35)

print(Pin(34), Pin(35))

The pins are correctly configured as UART_AUX (presumably this always worked?) thanks to the use of UART_FUNCSEL_NUM, but configuring as UART AUX is now enabled in machine.Pin too.

To be totally sure this worked, I set up UART 0 on pins 0 and 1, then changed them with machine.Pin():

from machine import Pin, UART

uart = UART(0, 115200, tx=0, rx=1)

Pin(0, mode=Pin.IN)
Pin(1, mode=Pin.IN)

TX = Pin(34, mode=Pin.ALT, alt=Pin.ALT_UART_AUX)
RX = Pin(35, mode=Pin.ALT, alt=Pin.ALT_UART_AUX)

B-variant Build

I set up a generic B-variant for testing, built against the vanilla RPI_PICO2 board with:

make BOARD=RPI_PICO2 BOARD_VARIANT=B

And the following config:

ports/rp2/boards/RPI_PICO2/mpconfigvariant_B.cmake

set(PICO_BOARD "pico2b")
set(PICO_BOARD_HEADER_DIRS ${CMAKE_CURRENT_LIST_DIR})
set(PICO_NUM_GPIOS 48)
set(MICROPY_BOARD_PINS "${MICROPY_BOARD_DIR}/pins_b.csv")

ports/rp2/boards/RPI_PICO2/pico2b.h:

#include "boards/pico2.h"

// Required to enable 48-pin B variant
#undef PICO_RP2350A

ports/rp2/boards/RPI_PICO2/pins_b.csv:

GP0,GPIO0
GP1,GPIO1
GP2,GPIO2
GP3,GPIO3
GP4,GPIO4
GP5,GPIO5
GP6,GPIO6
GP7,GPIO7
GP8,GPIO8
GP9,GPIO9
GP10,GPIO10
GP11,GPIO11
GP12,GPIO12
GP13,GPIO13
GP14,GPIO14
GP15,GPIO15
GP16,GPIO16
GP17,GPIO17
GP18,GPIO18
GP19,GPIO19
GP20,GPIO20
GP21,GPIO21
GP22,GPIO22
GP25,GPIO25
GP26,GPIO26
GP27,GPIO27
GP28,GPIO28
GP29,GPIO29
GP30,GPIO30
GP31,GPIO31
GP32,GPIO32
GP33,GPIO33
GP34,GPIO34
GP35,GPIO35
GP36,GPIO36
GP37,GPIO37
GP38,GPIO38
GP39,GPIO39
GP40,GPIO40
GP41,GPIO41
GP42,GPIO42
GP43,GPIO43
GP44,GPIO44
GP45,GPIO45
GP46,GPIO46
GP47,GPIO47
LED,GPIO25

Trade-offs and Alternatives

I'm not sure we need CORESIGHT and XIP_CS1 alt functions but they are included for completeness. They needed fixups in make-pins.py because it naively chops the first portion of the signal name off and tries to use that as the GPIO function.

UART_AUX is more interesting, it gives some more UART options on alt-function 11, but also needs special casing to ensure GPIO_FUNC_UART_AUX is used in place of GPIO_FUNC_UART. eg:

const machine_pin_af_obj_t pin_GPIO14_af[] = {
    AF(1, SPI , 1), // SPI1_SCK
    AF(2, UART, 0), // UART0_CTS
    AF(3, I2C , 1), // I2C1_SDA
    AF(4, PWM , 7), // PWM7_A
    AF(5, SIO , 0), // SIO
    AF(6, PIO0, 0), // PIO0
    AF(7, PIO1, 1), // PIO1
    AF(8, PIO2, 2), // PIO2
    AF(9, GPCK, 0), // GPCK_GPIN1
    AF(10, USB , 0), // USB_VBUS_EN
    AF(11, UART_AUX, 0), // UART0_TX
};

The addition of a PIO2 alt function constant might be a separate and important fix for RP2350 variants in general (and may conflict, I need to check that but I've run out of day). Edit: I checked. I don't think anyone has caught this, though there are other outstanding issues with PIO2.

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied