soc_esp32::io_mux
IO_MUX: per-pad configuration.
Every ESP32 pad has one register controlling its alternate function, input enable, and pull resistors. Two things about it are traps:
- The register offsets are not linear in the pin number. GPIO0 is at
0x44, GPIO1 at 0x88, GPIO3 at 0x84. The table below is the only correct
way to get from a pin to its register; computing
pin * 4produces plausible addresses that configure the wrong pad. - The “GPIO” function number is not uniform. For most pads it is function 2, for a few it is 0. A driver that hardcodes one value silently puts some pads into a completely different peripheral’s function.
Both used to be duplicated, separately, inside esp32-uart and
esp32-spi.
Offsets confirmed against esp-idf soc/io_mux_reg.h (GPIO_PIN_MUX_REG).
Functions
Section titled “Functions”configure
Section titled “configure”unsafe fn configure(pin: u8, func: u32, input_enable: bool, pull: hal::pinmux::PinPull) -> hal::bus::BusResult<()>Configure a pad: alternate function, input enable, pull resistors.
Read-modify-write, so it does not disturb drive strength or the settings of the other fields.
Safety
Section titled “Safety”Writes the IO_MUX register for pin. The caller must own that pad — two
drivers configuring the same pad race, and the loser gets a peripheral
wired somewhere it does not expect.
References: BusResult, PinPull
gpio_function
Section titled “gpio_function”const fn gpio_function(_pin: u8) -> u32The MCU_SEL value that puts a pad under GPIO-matrix control.
Function 2, for every pad without exception. esp-idf spells this
PIN_FUNC_GPIO and writes it unconditionally in gpio_pad_select_gpio();
every FUNC_<pad>_GPIOn in soc/io_mux_reg.h is 2, including
FUNC_GPIO34_GPIO34 and FUNC_GPIO39_GPIO39.
This used to return 0 for pins 34-39 on the theory that input-only pads have no alternate functions and so start at GPIO. They do have the usual function list, and function 0 on those pads is a different signal entirely – a matrix-routed input on GPIO34-39 would have been wired to the wrong thing.
is_input_only
Section titled “is_input_only”fn is_input_only(pin: u8) -> boolWhether a pad can drive an output at all.
GPIO34-39 are input-only on the classic ESP32: they have no output driver, so routing an output signal there produces a pin that reads as whatever the board pulls it to, with no error from the hardware.
offset
Section titled “offset”fn offset(pin: u8) -> Option<u32>IO_MUX register offset for a GPIO number.
None for GPIO 28-31, which have no IO_MUX register on this chip at all.
GPIO20 and GPIO24 do have registers and are listed here, even though the common ESP32 packages (WROOM, WROVER, PICO-D4) do not bond them to a pin. That is a package property, not a chip property — ESP32-PICO-V3 exposes GPIO20 — and this crate describes the chip. A board that names a pin its package does not carry is the board manifest’s error to make.