71 lines
2.8 KiB
Python
71 lines
2.8 KiB
Python
|
|
"""ESP32 GPIO Matrix output signal source IDs.
|
||
|
|
|
||
|
|
Lifted from the ESP32 Technical Reference Manual (Espressif ESP32 TRM
|
||
|
|
section 4.11, "IO_MUX and GPIO Matrix"). Each output GPIO has a
|
||
|
|
configuration register `GPIO_FUNCx_OUT_SEL_CFG_REG[x]` whose low 9
|
||
|
|
bits (`FUNCx_OUT_SEL`) select one of 256 internal peripheral signals
|
||
|
|
to drive the pin. The constants below name the signals that velxio
|
||
|
|
actually emulates today; add more here when a new peripheral wants
|
||
|
|
to participate in the SignalRouter.
|
||
|
|
|
||
|
|
The signal ID range mirrors the QEMU plugin's interpretation of
|
||
|
|
`gpio_out_sel`; the existing worker code at
|
||
|
|
`esp32_worker.py:_refresh_ledc_gpio_map` already reads these values
|
||
|
|
out of the matrix via `qemu_picsimlab_get_internals(2)`.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
|
||
|
|
# ── LEDC (PWM peripheral) ─────────────────────────────────────────────────
|
||
|
|
# High-speed channels (group 0): signals 72-79 → ledc channel 0-7
|
||
|
|
# Low-speed channels (group 1): signals 80-87 → ledc channel 0-7
|
||
|
|
SIG_LEDC_HS_CH0_OUT_IDX = 72 # add N for HS channel N (0..7)
|
||
|
|
SIG_LEDC_HS_CH_LAST = 79
|
||
|
|
SIG_LEDC_LS_CH0_OUT_IDX = 80 # add N for LS channel N (0..7)
|
||
|
|
SIG_LEDC_LS_CH_LAST = 87
|
||
|
|
|
||
|
|
|
||
|
|
def ledc_signal_for_channel(channel: int) -> int:
|
||
|
|
"""Map a velxio-style unified LEDC channel index (0..15) to its
|
||
|
|
GPIO Matrix signal source id.
|
||
|
|
|
||
|
|
The ESP32 LEDC hardware has two channel groups: 8 high-speed (HS)
|
||
|
|
and 8 low-speed (LS). velxio unifies them into a single 0..15
|
||
|
|
space where ch 0-7 = HS, ch 8-15 = LS (matches the encoding the
|
||
|
|
QEMU plugin emits on the 0x5000 duty callback).
|
||
|
|
"""
|
||
|
|
if not 0 <= channel < 16:
|
||
|
|
raise ValueError(f"ledc channel out of range: {channel}")
|
||
|
|
if channel < 8:
|
||
|
|
return SIG_LEDC_HS_CH0_OUT_IDX + channel
|
||
|
|
return SIG_LEDC_LS_CH0_OUT_IDX + (channel - 8)
|
||
|
|
|
||
|
|
|
||
|
|
def channel_for_ledc_signal(signal_id: int) -> int | None:
|
||
|
|
"""Inverse of :func:`ledc_signal_for_channel`. Returns None when
|
||
|
|
the signal id is not an LEDC channel."""
|
||
|
|
if SIG_LEDC_HS_CH0_OUT_IDX <= signal_id <= SIG_LEDC_HS_CH_LAST:
|
||
|
|
return signal_id - SIG_LEDC_HS_CH0_OUT_IDX
|
||
|
|
if SIG_LEDC_LS_CH0_OUT_IDX <= signal_id <= SIG_LEDC_LS_CH_LAST:
|
||
|
|
return 8 + (signal_id - SIG_LEDC_LS_CH0_OUT_IDX)
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
# ── Sentinel for "GPIO not routed to any peripheral" ──────────────────────
|
||
|
|
# When `gpio_out_sel[N]` carries this value the pin is driven by
|
||
|
|
# normal GPIO output (the value in the GPIO_OUT_REG bit N), not a
|
||
|
|
# peripheral signal.
|
||
|
|
SIG_GPIO_DIRECT_OUT_IDX = 256
|
||
|
|
|
||
|
|
|
||
|
|
__all__ = [
|
||
|
|
"SIG_LEDC_HS_CH0_OUT_IDX",
|
||
|
|
"SIG_LEDC_HS_CH_LAST",
|
||
|
|
"SIG_LEDC_LS_CH0_OUT_IDX",
|
||
|
|
"SIG_LEDC_LS_CH_LAST",
|
||
|
|
"SIG_GPIO_DIRECT_OUT_IDX",
|
||
|
|
"ledc_signal_for_channel",
|
||
|
|
"channel_for_ledc_signal",
|
||
|
|
]
|