soc_esp32::gpio_matrix
The GPIO matrix: routing peripheral signals to arbitrary pads.
This is what makes the ESP32 unusual. Rather than each pad having a short fixed list of functions, a 256×40 crossbar connects almost any peripheral signal to almost any pad, in either direction. It costs a couple of clock cycles of latency compared to the IO_MUX direct path, which is why the high-speed peripherals also have “native” pads that bypass it.
Two register files, indexed differently, which is the easiest thing here to get wrong:
GPIO_FUNCn_IN_SEL_CFG_REGat0x130 + 4n, where n is the signal index. Says which pad a peripheral input reads from.GPIO_FUNCn_OUT_SEL_CFG_REGat0x530 + 4n, where n is the GPIO number. Says which peripheral signal a pad drives.
The 256 input registers occupy 0x130..0x530, which is exactly where the
output registers begin — a useful check that both constants are right.
Confirmed against esp-idf soc/gpio_reg.h and soc/gpio_sig_map.h.
Functions
Section titled “Functions”connect_input
Section titled “connect_input”unsafe fn connect_input(signal_idx: u32, pin: u8, invert: bool) -> hal::bus::BusResult<()>Route a peripheral input so it reads from pin.
Safety
Section titled “Safety”Writes the matrix register for signal_idx. Two peripherals cannot share
an input signal index, so the caller must own the controller.
References: BusResult
connect_output
Section titled “connect_output”unsafe fn connect_output(pin: u8, signal_idx: u32, peripheral_oe: bool, invert: bool) -> hal::bus::BusResult<()>Route a peripheral output so it drives pin.
peripheral_oe selects who controls the pad’s output enable. For a normal
output the peripheral does, and this is true. For an open-drain line
driven by a peripheral – I2C – it is also the peripheral: the controller
releases the line by de-asserting its own output enable, which is exactly
how it generates a logical 1 and how it lets a slave stretch the clock.
Forcing OEN_SEL on instead would hand output-enable to the GPIO_ENABLE
register and pin the line permanently driven or permanently released.
Safety
Section titled “Safety”Writes the matrix register for pin.
References: BusResult
set_drive
Section titled “set_drive”unsafe fn set_drive(pin: u8, drive: hal::pinmux::PinDrive) -> hal::bus::BusResult<()>Set a pad’s output driver to push-pull or open-drain.
Safety
Section titled “Safety”Writes GPIO_PINn_REG for pin, read-modify-write so the interrupt
configuration in the same register survives.
References: BusResult, PinDrive
signal_index
Section titled “signal_index”fn signal_index(signal: hal::pinmux::Signal) -> Option<u32>Peripheral signal index for a [Signal], as used by both register files.
None if this chip has no such controller. Values from esp-idf
soc/gpio_sig_map.h; input and output indices coincide for every signal
below, which is true on the classic ESP32 but is not a general rule.
References: Signal
Constants
Section titled “Constants”IN_CONST_ONE
Section titled “IN_CONST_ONE”const IN_CONST_ONE: u32;IN_SEL value that feeds a peripheral input a constant 1.
IN_CONST_ZERO
Section titled “IN_CONST_ZERO”const IN_CONST_ZERO: u32;IN_SEL value that feeds a peripheral input a constant 0.
SIG_GPIO_OUT
Section titled “SIG_GPIO_OUT”const SIG_GPIO_OUT: u32;The OUT_SEL value meaning “this pad is driven by the GPIO_OUT register”,
i.e. it is a plain software-controlled GPIO rather than a peripheral pin.