ADR 0003: The hf-pincfg X-macro table is the single source of pin truth¶
| Status | Accepted (records the current design) |
| Date | 2026-11-01 |
Context¶
A pin number written in more than one place drifts: the schematic changes, one copy is updated, another is not, and the board misbehaves in a way no compiler catches. Vortex V1 spreads its pins over three chips (ESP32-C6, PCAL95555, TMC9660), which makes copies even easier to get wrong. Pin numbers used to be repeated in this repository's README and docs.
Options¶
- Pins as constants in each manager. Simple; every manager and every document repeats them.
- One table per board, used by the code and by the docs. The board's functional pin map in
hf-pincfg(hf_functional_pin_config_vortex_v1.hpp), written as X-macro rows; everything else reads it.
Decision¶
Option 2:
- Each row of
HF_FUNCTIONAL_GPIO_PIN_LIST/HF_FUNCTIONAL_ADC_CHANNEL_LISTnames a function, its chip, unit, pin, polarity, pull, drive and current. The same rows generate the enums, name tables and mapping arrays. - The managers register from the generated arrays:
GpioManagercreates a pin for each GPIO-category row on whichever chip it is,AdcManagera channel for each ADC row;CommChannelsManagerand the facade look pins up byHfFunctionalGpioPin(GetGpioMapping(),gpio.Get(...)). No manager writes a GPIO number. - The pin map page and the board figure are generated from the same
rows (
hardfoc-docs gen,hardfoc-docs figures), and CI fails if they are stale.
Consequences¶
- Changing a pin is one edit in
hf-pincfg, a submodule bump here, and a docs rebuild. - The pin map is shared by every HardFOC HAL through
hf-pincfg; the board is chosen at build time withHARDFOC_BOARD_VORTEX_V1(set in this repository'sCMakeLists.txt). - The examples that call ESP-IDF directly get their GPIO numbers from
vortex_board_pins.hpp, which reads them from the pin map at compile time andstatic_asserts that each net is an ESP32 pin; there is no second copy.