1 · Platform Detection
Explicit Detection
| Keywords/Patterns |
Platform |
| Raspberry Pi, RPi, BCM2835, BCM2711, BCM2712, config.txt, dtoverlay, gpiozero, RPi.GPIO, pigpio, /boot/firmware/ |
RPi |
| ESP32, ESP-IDF, WROOM, WROVER, menuconfig, sdkconfig, Arduino (with ESP context), esp_err_t, gpio_config(), ESP32-S2, S3, C3, C6 |
ESP32 |
Model/Variant Detection
RPi Variants:
| Identifier |
Models Covered |
Key Differences |
| rpi3 |
Pi 3B/3B+ |
UART/BT conflict on mini-UART, 2× PWM channels, config at /boot/config.txt |
| rpi4 |
Pi 4B |
4× PWM channels, dual SPI, config at /boot/firmware/config.txt |
| rpi5 |
Pi 5 |
RP1 southbridge (different peripheral base), 4× PWM, config at /boot/firmware/config.txt |
| rpi_zero2w |
Zero 2W |
Same SoC as Pi 3, UART/BT conflict, limited current budget |
ESP32 Variants:
| Identifier |
Key Differences |
| esp32 |
34 GPIO, dual-core, ADC2 conflicts with WiFi, Hall sensor on GPIO36/39 |
| esp32s2 |
43 GPIO, single-core, no Bluetooth, native USB, no ADC2/WiFi conflict |
| esp32s3 |
45 GPIO, dual-core, BLE5, native USB, no ADC2/WiFi conflict |
| esp32c3 |
22 GPIO, single-core RISC-V, BLE5 only, no ADC2/WiFi conflict |
| esp32c6 |
30 GPIO, RISC-V, WiFi 6, 802.15.4, no ADC2/WiFi conflict |
ESP32 Modules:
| Module |
Additional Reserved Pins |
| WROOM |
GPIO6–11 (flash SPI) |
| WROVER |
GPIO6–11 (flash SPI) + GPIO16–17 (PSRAM) |
Ambiguity Rules
- If platform cannot be determined from context: ask the user. NEVER silently default to a platform.
- If platform is detected but variant is unknown: ask the user for model/variant. Default to most conservative variant if user declines (rpi3 for RPi, esp32 + WROOM for ESP32).
- Unsupported platforms (RP2040/Pico, STM32, Arduino AVR, BeagleBone): state that the platform is not yet supported, list supported platforms, offer to help if user switches.
2 · Reference Loading
ALWAYS load the platform pin database. Load other files only when their trigger condition is met.
| File |
Trigger |
| references/platforms/rpi-pins.md |
Platform is RPi (any variant) |
| references/platforms/esp32-pins.md |
Platform is ESP32 (any variant) |
| references/platforms/esp32-specifics.md |
ESP32 detected AND any of: strapping pins mentioned, deep sleep, flash/PSRAM, ADC2, boot issues |
| references/platforms/rpi-overlays.md |
RPi detected AND any of: device tree, dtoverlay, overlay, kernel module, /boot/ config |
| references/protocol-quick-ref.md |
Any protocol mentioned: I2C, SPI, UART, PWM, 1-Wire, CAN, Modbus, ADC, DAC |
| references/electrical-constraints.md |
Current limits, voltage levels, pull-ups/pull-downs, power supply, level shifting mentioned |
| references/common-devices.md |
Specific sensor, module, display, or breakout board mentioned by name or part number |
3 · Core Workflow
Step 1 — Parse
Extract from the user's request:
- Target platform and variant (or flag as unknown)
- Required protocols and their quantities (e.g., "2× I2C", "1× SPI")
- Named devices/modules (e.g., "BME280", "SSD1306", "NeoPixel")
- Existing pin commitments ("I'm already using GPIO17 for...")
- Special requirements (deep sleep wake, interrupt-capable, analog input, high-speed)
- Framework preference (gpiozero, RPi.GPIO, Arduino, ESP-IDF) or "not specified"
Step 2 — Detect
Apply Section 1 rules. Result: confirmed platform + variant + module type, OR ask the user.
Step 3 — Load
Apply Section 2 table. Load all triggered reference files before proceeding.
Step 4 — Gather
If any critical information is missing (platform, protocol count, or device identity), ask ONE concise follow-up question covering all gaps. If information is merely ambiguous but reasonable defaults exist, proceed and list assumptions in the output. Never ask more than one follow-up message.
Step 5 — Generate
Assign pins using platform-specific strategy:
RPi strategy:
- Assign hardware-native pins first (I2C → GPIO2/3, SPI0 → GPIO7–11, UART → GPIO14/15)
- Prefer GPIO12/13 for hardware PWM
- Never assign GPIO0 or GPIO1 (I2C EEPROM reserved)
- Use clean GPIOs for general digital I/O: 5, 6, 16, 17, 22, 23, 24, 25, 26, 27
- Note all pins that pull high/low at boot
- Track cumulative current draw against 50mA GPIO budget
ESP32 strategy:
- Never assign flash SPI pins (GPIO6–11; also GPIO16–17 on WROVER)
- Warn if assigning strapping pins (GPIO0, 2, 5, 12, 15) — add boot-state note for each
- Elevate GPIO12 (MTDI) to a stronger warning: wrong state at boot can set flash voltage to 1.8V and brick the module
- Use conventional I2C pins (GPIO21 SDA, GPIO22 SCL) unless conflict exists
- Use native SPI pins: VSPI (GPIO5/18/19/23) or HSPI (GPIO12/13/14/15) — note strapping overlap on HSPI
- If WiFi is enabled, avoid ADC2 channels entirely (esp32 variant only)
- Assign input-only pins (GPIO34–39) only for inputs, never outputs or bidirectional
- Prefer RTC-capable GPIOs for deep-sleep wake sources
- Reserve GPIO1/3 (UART0 TX/RX) for debug serial unless user explicitly reassigns
- Note that any output-capable GPIO supports PWM via LEDC — no dedicated PWM pins needed
Step 6 — Validate
Invoke the validation script:
python scripts/validate_pinmap.py --format json <<'EOF'
<input JSON>
EOF
If validation returns errors: reassign conflicting pins and re-validate. Loop a maximum of 3 times. If still failing after 3 attempts, present the best result with remaining warnings explained.
If validation returns warnings only: include warnings in output, proceed.
Step 7 — Output
Generate the response using Section 4 format. Then invoke the generation script:
python scripts/generate_config.py --format json --framework <framework> <<'EOF'
<input JSON>
EOF
Include all script outputs in the structured response.
4 · Output Format
Pin Assignment Table
- RPi columns: Function | GPIO (BCM) | Physical Pin | Alt Mode | Notes
- ESP32 columns: Function | GPIO | Notes | Strapping? | RTC Channel?
- Sort by function group (I2C, SPI, UART, PWM, digital I/O, analog)
Configuration
- RPi: config.txt lines (dtoverlay, dtparam, gpio= directives). Note correct path for variant.
- ESP32: menuconfig/sdkconfig.defaults lines (if Arduino: note that most config is in code)
Initialization Code
- RPi: provide both gpiozero and RPi.GPIO versions unless user specified one
- ESP32: provide both Arduino and ESP-IDF versions unless user specified one
- Always include: pin mode setup, pull-up/pull-down config, protocol init with correct pins, brief comments
Wiring Notes
- Human-readable wiring instructions using physical pin numbers AND GPIO numbers
- Include: pull-up resistor values for I2C/1-Wire, power rail connections, level shifter notes if mixing voltages, decoupling caps for sensitive devices
Warnings
- Pin conflicts detected during validation
- Strapping pin usage (ESP32)
- Current budget concerns
- UART/Bluetooth conflicts (RPi 3/4/Zero2W)
- PWM/audio conflicts (RPi)
- ADC2/WiFi conflicts (ESP32)
- Deprecated library warnings (e.g., RPi.GPIO on Pi 5)
Alternatives
- For every conflict that was auto-resolved, explain: original pin → replacement pin and why
- If multiple valid assignments exist, briefly note the top alternative
5 · Critical Rules
Universal
- Always present GPIO numbers prominently — never reference physical pin numbers only
- Never silently assign a reserved or restricted pin — always warn
- Check I2C device address collisions when multiple I2C devices share a bus
- Include pull-up/pull-down notes for every protocol that requires them
- Respect per-platform current limits and warn when cumulative draw approaches budget
- Warn about deprecated libraries (RPi.GPIO on Pi 5 has limited support; suggest gpiozero or lgpio)
- If the user's request exceeds available pins, say so and suggest multiplexing (I2C expander, SPI daisy-chain)
RPi-Specific
- Use BCM numbering by default. If user requests BOARD numbering, provide both.
- Never assign GPIO0 or GPIO1 — reserved for HAT EEPROM I2C
- On Pi 3/4/Zero 2W: UART0 (GPIO14/15) is linked to Bluetooth by default. Warn and explain dtoverlay=miniuart-bt or dtoverlay=disable-bt
- Prefer GPIO12/13 for hardware PWM (PWM0/PWM1). GPIO18 is PWM-capable but conflicts with PCM/audio.
- PWM on GPIO18 + audio output = conflict. Warn if both are needed.
- Total GPIO current budget: 50mA across all pins. Track and warn.
- SPI0 claims GPIO7–11 (CE1, CE0, MISO, MOSI, SCLK). Do not assign these for other use when SPI0 is active.
- Config.txt path: /boot/config.txt on Pi 3 and older, /boot/firmware/config.txt on Pi 4/5 with Bookworm+
ESP32-Specific
- Flash SPI pins (GPIO6–11) are never available. On WROVER modules, GPIO16–17 are also reserved (PSRAM).
- Strapping pins (GPIO0, 2, 5, 12, 15): warn on every use with the required boot state for each.
- GPIO12 (MTDI) gets an elevated warning: if pulled high at boot, flash voltage switches to 1.8V — can brick 3.3V flash modules. Advise efuse or boot-fix if user must use it.
- ADC2 (GPIO0, 2, 4, 12–15, 25–27) is unavailable when WiFi is active — this applies to the original ESP32 variant only, not S2/S3/C3/C6.
- GPIO34–39 are input-only: no internal pull-ups, no output mode. Assign only for input signals.
- For deep-sleep wake: use RTC GPIOs only (GPIO0–21, 25–27 on ESP32). Check per-variant RTC GPIO list.
- UART0 (GPIO1 TX, GPIO3 RX) is the default debug/programming port. Do not reassign without explicit user intent.
- Any output-capable GPIO can generate PWM via LEDC peripheral — no special pin selection needed.
- Maximum source current per pin: 40mA (recommended 20mA). Total chip limit varies by variant.
6 · Script Interface
validate_pinmap.py
Location: scripts/validate_pinmap.py
CLI usage:
python scripts/validate_pinmap.py --format json [--verbose] < input.json
python scripts/validate_pinmap.py --help
Input JSON schema:
{
"platform": "rpi | esp32",
"variant": "rpi3 | rpi4 | rpi5 | rpi_zero2w | esp32 | esp32s2 | esp32s3 | esp32c3 | esp32c6",
"module": "WROOM | WROVER | null",
"wifi_enabled": true,
"pins": [
{
"gpio": 17,
"function": "I2C_SDA | I2C_SCL | SPI_MOSI | SPI_MISO | SPI_SCLK | SPI_CS | UART_TX | UART_RX | PWM | DIGITAL_IN | DIGITAL_OUT | ANALOG_IN | 1WIRE | CAN_TX | CAN_RX",
"protocol_bus": 0,
"device": "BME280",
"pull": "up | down | none",
"notes": ""
}
]
}
Output JSON schema:
{
"valid": true,
"errors": [
{
"gpio": 6,
"code": "RESERVED_PIN | CONFLICT | INPUT_ONLY_AS_OUTPUT | STRAPPING_UNACKNOWLEDGED | ADC2_WIFI | CURRENT_EXCEEDED",
"message": "Human-readable error",
"severity": "error"
}
],
"warnings": [
{
"gpio": 12,
"code": "STRAPPING_PIN | UART_BT_CONFLICT | PWM_AUDIO_CONFLICT | DEPRECATED_LIB | CURRENT_WARNING | BOOT_STATE",
"message": "Human-readable warning",
"severity": "warning"
}
],
"summary": {
"total_pins": 8,
"errors": 0,
"warnings": 2,
"current_draw_ma": 32
}
}
Exit codes: 0 = valid (warnings ok), 1 = errors found, 2 = invalid input
generate_config.py
Location: scripts/generate_config.py
CLI usage:
python scripts/generate_config.py --format json --framework arduino|espidf|gpiozero|rpigpio [--verbose] < input.json
python scripts/generate_config.py --help
Input JSON schema: same as validate_pinmap.py input, plus:
{
"platform": "rpi | esp32",
"variant": "rpi3 | rpi4 | rpi5 | rpi_zero2w | esp32 | esp32s2 | esp32s3 | esp32c3 | esp32c6",
"module": "WROOM | WROVER | null",
"wifi_enabled": true,
"pins": [],
"framework": "arduino | espidf | gpiozero | rpigpio"
}
Output JSON schema:
{
"config_lines": ["dtoverlay=i2c1", "dtparam=spi=on"],
"init_code": "# Full initialization code as a single string with newlines",
"wiring_notes": [
"Connect BME280 SDA to GPIO2 (physical pin 3). Add 4.7kΩ pull-up to 3.3V."
],
"warnings": ["GPIO12 is a strapping pin — see boot state notes"],
"alternatives": [
{
"original_gpio": 12,
"alternative_gpio": 17,
"reason": "Avoids MTDI strapping pin risk"
}
]
}
Exit codes: 0 = success, 1 = generation error, 2 = invalid input
7 · Requirements
- Python 3.9+ (standard library only — no pip packages required)
8 · Example
User request: "Set up a weather station with BME280 temperature sensor and SSD1306 OLED display on Raspberry Pi 4"
Generated pinmap (excerpt):
{
"platform": "rpi",
"variant": "rpi4",
"pins": [
{"gpio": 2, "function": "I2C_SDA", "protocol_bus": 1, "device": "BME280+SSD1306", "pull": "external_up"},
{"gpio": 3, "function": "I2C_SCL", "protocol_bus": 1, "device": "BME280+SSD1306", "pull": "external_up"},
{"gpio": 17, "function": "DIGITAL_OUT", "device": "Status LED", "pull": "none"}
]
}
Generated initialization code (gpiozero, excerpt):
from gpiozero import LED
import smbus2
bus = smbus2.SMBus(1) # I2C bus 1: SDA=GPIO2, SCL=GPIO3
# BME280 at 0x76, SSD1306 at 0x3C — shared I2C bus, no conflict
status_led = LED(17)
1---2name: gpio-config3description: Assigns, validates, and generates code for GPIO pin configurations on Raspberry Pi and ESP32 embedded projects. Activates for queries about GPIO pins, wiring, pin mapping, pin conflicts, I2C, SPI, UART, PWM, 1-Wire, CAN, ADC configuration, device tree overlays, config.txt, sdkconfig, strapping pins, boot pins, flash voltage, or connecting sensors, displays, and modules such as BME280, SSD1306, DHT22, LoRa, GPS, MCP2515, and NeoPixels. Covers Pi 3, Pi 4, Pi 5, Zero 2W, ESP32, ESP32-S2, ESP32-S3, ESP32-C3, and ESP32-C6. Produces platform-specific config files and initialization code for Python gpiozero, RPi.GPIO, Arduino, and ESP-IDF frameworks. Also activates when a device and board are named without mentioning GPIO, e.g. 'BME280 on a Pi 4' or 'connect a GPS to my ESP32', or when pin selection or pin safety questions arise.4license: MIT. See LICENSE in repository root.5---6
7## 1 · Platform Detection
8
9### Explicit Detection
10
11| Keywords/Patterns | Platform |
12|---|---|
13| Raspberry Pi, RPi, BCM2835, BCM2711, BCM2712, config.txt, dtoverlay, gpiozero, RPi.GPIO, pigpio, /boot/firmware/ | RPi |
14| ESP32, ESP-IDF, WROOM, WROVER, menuconfig, sdkconfig, Arduino (with ESP context), esp_err_t, gpio_config(), ESP32-S2, S3, C3, C6 | ESP32 |
15
16### Model/Variant Detection
17
18**RPi Variants:**
19
20| Identifier | Models Covered | Key Differences |
21|---|---|---|
22| rpi3 | Pi 3B/3B+ | UART/BT conflict on mini-UART, 2× PWM channels, config at /boot/config.txt |
23| rpi4 | Pi 4B | 4× PWM channels, dual SPI, config at /boot/firmware/config.txt |
24| rpi5 | Pi 5 | RP1 southbridge (different peripheral base), 4× PWM, config at /boot/firmware/config.txt |
25| rpi_zero2w | Zero 2W | Same SoC as Pi 3, UART/BT conflict, limited current budget |
26
27**ESP32 Variants:**
28
29| Identifier | Key Differences |
30|---|---|
31| esp32 | 34 GPIO, dual-core, ADC2 conflicts with WiFi, Hall sensor on GPIO36/39 |
32| esp32s2 | 43 GPIO, single-core, no Bluetooth, native USB, no ADC2/WiFi conflict |
33| esp32s3 | 45 GPIO, dual-core, BLE5, native USB, no ADC2/WiFi conflict |
34| esp32c3 | 22 GPIO, single-core RISC-V, BLE5 only, no ADC2/WiFi conflict |
35| esp32c6 | 30 GPIO, RISC-V, WiFi 6, 802.15.4, no ADC2/WiFi conflict |
36
37**ESP32 Modules:**
38
39| Module | Additional Reserved Pins |
40|---|---|
41| WROOM | GPIO6–11 (flash SPI) |
42| WROVER | GPIO6–11 (flash SPI) + GPIO16–17 (PSRAM) |
43
44### Ambiguity Rules
45
461. If platform cannot be determined from context: ask the user. NEVER silently default to a platform.
472. If platform is detected but variant is unknown: ask the user for model/variant. Default to most conservative variant if user declines (rpi3 for RPi, esp32 + WROOM for ESP32).
483. Unsupported platforms (RP2040/Pico, STM32, Arduino AVR, BeagleBone): state that the platform is not yet supported, list supported platforms, offer to help if user switches.
49
50## 2 · Reference Loading
51
52ALWAYS load the platform pin database. Load other files only when their trigger condition is met.
53
54| File | Trigger |
55|---|---|
56| references/platforms/rpi-pins.md | Platform is RPi (any variant) |
57| references/platforms/esp32-pins.md | Platform is ESP32 (any variant) |
58| references/platforms/esp32-specifics.md | ESP32 detected AND any of: strapping pins mentioned, deep sleep, flash/PSRAM, ADC2, boot issues |
59| references/platforms/rpi-overlays.md | RPi detected AND any of: device tree, dtoverlay, overlay, kernel module, /boot/ config |
60| references/protocol-quick-ref.md | Any protocol mentioned: I2C, SPI, UART, PWM, 1-Wire, CAN, Modbus, ADC, DAC |
61| references/electrical-constraints.md | Current limits, voltage levels, pull-ups/pull-downs, power supply, level shifting mentioned |
62| references/common-devices.md | Specific sensor, module, display, or breakout board mentioned by name or part number |
63
64## 3 · Core Workflow
65
66### Step 1 — Parse
67
68Extract from the user's request:
69- Target platform and variant (or flag as unknown)
70- Required protocols and their quantities (e.g., "2× I2C", "1× SPI")
71- Named devices/modules (e.g., "BME280", "SSD1306", "NeoPixel")
72- Existing pin commitments ("I'm already using GPIO17 for...")
73- Special requirements (deep sleep wake, interrupt-capable, analog input, high-speed)
74- Framework preference (gpiozero, RPi.GPIO, Arduino, ESP-IDF) or "not specified"
75
76### Step 2 — Detect
77
78Apply Section 1 rules. Result: confirmed platform + variant + module type, OR ask the user.
79
80### Step 3 — Load
81
82Apply Section 2 table. Load all triggered reference files before proceeding.
83
84### Step 4 — Gather
85
86If any critical information is missing (platform, protocol count, or device identity), ask ONE concise follow-up question covering all gaps. If information is merely ambiguous but reasonable defaults exist, proceed and list assumptions in the output. Never ask more than one follow-up message.
87
88### Step 5 — Generate
89
90Assign pins using platform-specific strategy:
91
92**RPi strategy:**
931. Assign hardware-native pins first (I2C → GPIO2/3, SPI0 → GPIO7–11, UART → GPIO14/15)
942. Prefer GPIO12/13 for hardware PWM
953. Never assign GPIO0 or GPIO1 (I2C EEPROM reserved)
964. Use clean GPIOs for general digital I/O: 5, 6, 16, 17, 22, 23, 24, 25, 26, 27
975. Note all pins that pull high/low at boot
986. Track cumulative current draw against 50mA GPIO budget
99
100**ESP32 strategy:**
1011. Never assign flash SPI pins (GPIO6–11; also GPIO16–17 on WROVER)
1022. Warn if assigning strapping pins (GPIO0, 2, 5, 12, 15) — add boot-state note for each
1033. Elevate GPIO12 (MTDI) to a stronger warning: wrong state at boot can set flash voltage to 1.8V and brick the module
1044. Use conventional I2C pins (GPIO21 SDA, GPIO22 SCL) unless conflict exists
1055. Use native SPI pins: VSPI (GPIO5/18/19/23) or HSPI (GPIO12/13/14/15) — note strapping overlap on HSPI
1066. If WiFi is enabled, avoid ADC2 channels entirely (esp32 variant only)
1077. Assign input-only pins (GPIO34–39) only for inputs, never outputs or bidirectional
1088. Prefer RTC-capable GPIOs for deep-sleep wake sources
1099. Reserve GPIO1/3 (UART0 TX/RX) for debug serial unless user explicitly reassigns
11010. Note that any output-capable GPIO supports PWM via LEDC — no dedicated PWM pins needed
111
112### Step 6 — Validate
113
114Invoke the validation script:
115
116```bash
117python scripts/validate_pinmap.py --format json <<'EOF'
118<input JSON>
119EOF
120```
121
122If validation returns errors: reassign conflicting pins and re-validate. Loop a maximum of 3 times. If still failing after 3 attempts, present the best result with remaining warnings explained.
123
124If validation returns warnings only: include warnings in output, proceed.
125
126### Step 7 — Output
127
128Generate the response using Section 4 format. Then invoke the generation script:
129
130```bash
131python scripts/generate_config.py --format json --framework <framework> <<'EOF'
132<input JSON>
133EOF
134```
135
136Include all script outputs in the structured response.
137
138## 4 · Output Format
139
140### Pin Assignment Table
141
142- RPi columns: Function | GPIO (BCM) | Physical Pin | Alt Mode | Notes
143- ESP32 columns: Function | GPIO | Notes | Strapping? | RTC Channel?
144- Sort by function group (I2C, SPI, UART, PWM, digital I/O, analog)
145
146### Configuration
147
148- RPi: config.txt lines (dtoverlay, dtparam, gpio= directives). Note correct path for variant.
149- ESP32: menuconfig/sdkconfig.defaults lines (if Arduino: note that most config is in code)
150
151### Initialization Code
152
153- RPi: provide both gpiozero and RPi.GPIO versions unless user specified one
154- ESP32: provide both Arduino and ESP-IDF versions unless user specified one
155- Always include: pin mode setup, pull-up/pull-down config, protocol init with correct pins, brief comments
156
157### Wiring Notes
158
159- Human-readable wiring instructions using physical pin numbers AND GPIO numbers
160- Include: pull-up resistor values for I2C/1-Wire, power rail connections, level shifter notes if mixing voltages, decoupling caps for sensitive devices
161
162### Warnings
163
164- Pin conflicts detected during validation
165- Strapping pin usage (ESP32)
166- Current budget concerns
167- UART/Bluetooth conflicts (RPi 3/4/Zero2W)
168- PWM/audio conflicts (RPi)
169- ADC2/WiFi conflicts (ESP32)
170- Deprecated library warnings (e.g., RPi.GPIO on Pi 5)
171
172### Alternatives
173
174- For every conflict that was auto-resolved, explain: original pin → replacement pin and why
175- If multiple valid assignments exist, briefly note the top alternative
176
177## 5 · Critical Rules
178
179### Universal
180
1811. Always present GPIO numbers prominently — never reference physical pin numbers only
1822. Never silently assign a reserved or restricted pin — always warn
1833. Check I2C device address collisions when multiple I2C devices share a bus
1844. Include pull-up/pull-down notes for every protocol that requires them
1855. Respect per-platform current limits and warn when cumulative draw approaches budget
1866. Warn about deprecated libraries (RPi.GPIO on Pi 5 has limited support; suggest gpiozero or lgpio)
1877. If the user's request exceeds available pins, say so and suggest multiplexing (I2C expander, SPI daisy-chain)
188
189### RPi-Specific
190
1911. Use BCM numbering by default. If user requests BOARD numbering, provide both.
1922. Never assign GPIO0 or GPIO1 — reserved for HAT EEPROM I2C
1933. On Pi 3/4/Zero 2W: UART0 (GPIO14/15) is linked to Bluetooth by default. Warn and explain dtoverlay=miniuart-bt or dtoverlay=disable-bt
1944. Prefer GPIO12/13 for hardware PWM (PWM0/PWM1). GPIO18 is PWM-capable but conflicts with PCM/audio.
1955. PWM on GPIO18 + audio output = conflict. Warn if both are needed.
1966. Total GPIO current budget: 50mA across all pins. Track and warn.
1977. SPI0 claims GPIO7–11 (CE1, CE0, MISO, MOSI, SCLK). Do not assign these for other use when SPI0 is active.
1988. Config.txt path: /boot/config.txt on Pi 3 and older, /boot/firmware/config.txt on Pi 4/5 with Bookworm+
199
200### ESP32-Specific
201
2021. Flash SPI pins (GPIO6–11) are never available. On WROVER modules, GPIO16–17 are also reserved (PSRAM).
2032. Strapping pins (GPIO0, 2, 5, 12, 15): warn on every use with the required boot state for each.
2043. GPIO12 (MTDI) gets an elevated warning: if pulled high at boot, flash voltage switches to 1.8V — can brick 3.3V flash modules. Advise efuse or boot-fix if user must use it.
2054. ADC2 (GPIO0, 2, 4, 12–15, 25–27) is unavailable when WiFi is active — this applies to the original ESP32 variant only, not S2/S3/C3/C6.
2065. GPIO34–39 are input-only: no internal pull-ups, no output mode. Assign only for input signals.
2076. For deep-sleep wake: use RTC GPIOs only (GPIO0–21, 25–27 on ESP32). Check per-variant RTC GPIO list.
2087. UART0 (GPIO1 TX, GPIO3 RX) is the default debug/programming port. Do not reassign without explicit user intent.
2098. Any output-capable GPIO can generate PWM via LEDC peripheral — no special pin selection needed.
2109. Maximum source current per pin: 40mA (recommended 20mA). Total chip limit varies by variant.
211
212## 6 · Script Interface
213
214### validate_pinmap.py
215
216Location: scripts/validate_pinmap.py
217
218CLI usage:
219
220```bash
221python scripts/validate_pinmap.py --format json [--verbose] < input.json
222python scripts/validate_pinmap.py --help
223```
224
225Input JSON schema:
226
227```json
228{
229 "platform": "rpi | esp32",
230 "variant": "rpi3 | rpi4 | rpi5 | rpi_zero2w | esp32 | esp32s2 | esp32s3 | esp32c3 | esp32c6",
231 "module": "WROOM | WROVER | null",
232 "wifi_enabled": true,
233 "pins": [
234 {
235 "gpio": 17,
236 "function": "I2C_SDA | I2C_SCL | SPI_MOSI | SPI_MISO | SPI_SCLK | SPI_CS | UART_TX | UART_RX | PWM | DIGITAL_IN | DIGITAL_OUT | ANALOG_IN | 1WIRE | CAN_TX | CAN_RX",
237 "protocol_bus": 0,
238 "device": "BME280",
239 "pull": "up | down | none",
240 "notes": ""
241 }
242 ]
243}
244```
245
246Output JSON schema:
247
248```json
249{
250 "valid": true,
251 "errors": [
252 {
253 "gpio": 6,
254 "code": "RESERVED_PIN | CONFLICT | INPUT_ONLY_AS_OUTPUT | STRAPPING_UNACKNOWLEDGED | ADC2_WIFI | CURRENT_EXCEEDED",
255 "message": "Human-readable error",
256 "severity": "error"
257 }
258 ],
259 "warnings": [
260 {
261 "gpio": 12,
262 "code": "STRAPPING_PIN | UART_BT_CONFLICT | PWM_AUDIO_CONFLICT | DEPRECATED_LIB | CURRENT_WARNING | BOOT_STATE",
263 "message": "Human-readable warning",
264 "severity": "warning"
265 }
266 ],
267 "summary": {
268 "total_pins": 8,
269 "errors": 0,
270 "warnings": 2,
271 "current_draw_ma": 32
272 }
273}
274```
275
276Exit codes: 0 = valid (warnings ok), 1 = errors found, 2 = invalid input
277
278### generate_config.py
279
280Location: scripts/generate_config.py
281
282CLI usage:
283
284```bash
285python scripts/generate_config.py --format json --framework arduino|espidf|gpiozero|rpigpio [--verbose] < input.json
286python scripts/generate_config.py --help
287```
288
289Input JSON schema: same as validate_pinmap.py input, plus:
290
291```json
292{
293 "platform": "rpi | esp32",
294 "variant": "rpi3 | rpi4 | rpi5 | rpi_zero2w | esp32 | esp32s2 | esp32s3 | esp32c3 | esp32c6",
295 "module": "WROOM | WROVER | null",
296 "wifi_enabled": true,
297 "pins": [],
298 "framework": "arduino | espidf | gpiozero | rpigpio"
299}
300```
301
302Output JSON schema:
303
304```json
305{
306 "config_lines": ["dtoverlay=i2c1", "dtparam=spi=on"],
307 "init_code": "# Full initialization code as a single string with newlines",
308 "wiring_notes": [
309 "Connect BME280 SDA to GPIO2 (physical pin 3). Add 4.7kΩ pull-up to 3.3V."
310 ],
311 "warnings": ["GPIO12 is a strapping pin — see boot state notes"],
312 "alternatives": [
313 {
314 "original_gpio": 12,
315 "alternative_gpio": 17,
316 "reason": "Avoids MTDI strapping pin risk"
317 }
318 ]
319}
320```
321
322Exit codes: 0 = success, 1 = generation error, 2 = invalid input
323
324## 7 · Requirements
325
326- Python 3.9+ (standard library only — no pip packages required)
327
328## 8 · Example
329
330**User request:** "Set up a weather station with BME280 temperature sensor and SSD1306 OLED display on Raspberry Pi 4"
331
332**Generated pinmap (excerpt):**
333
334```json
335{
336 "platform": "rpi",
337 "variant": "rpi4",
338 "pins": [
339 {"gpio": 2, "function": "I2C_SDA", "protocol_bus": 1, "device": "BME280+SSD1306", "pull": "external_up"},
340 {"gpio": 3, "function": "I2C_SCL", "protocol_bus": 1, "device": "BME280+SSD1306", "pull": "external_up"},
341 {"gpio": 17, "function": "DIGITAL_OUT", "device": "Status LED", "pull": "none"}
342 ]
343}
344```
345
346**Generated initialization code (gpiozero, excerpt):**
347
348```python
349from gpiozero import LED
350import smbus2
351
352bus = smbus2.SMBus(1) # I2C bus 1: SDA=GPIO2, SCL=GPIO3
353# BME280 at 0x76, SSD1306 at 0x3C — shared I2C bus, no conflict
354
355status_led = LED(17)
356```