Add Pin.mode() and Pin.alt() support for all applicable ports
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
stm32: Add method for statically configuring pin alternate function
Works with pins declared normally in mpconfigboard.h, eg. (pin_XX)
Provides new mp_hal_pin_config_alt_static(pin_obj, mode, pull, fn, type) function
declared in pin_static_af.h to allow configuring pin alternate functions by name
eg.
mp_hal_pin_config_alt_static(MICROPY_HW_FMC_SDCLK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, FMC, SDCLK);
For a full usage example see: #3940