View this page on MeshCore Docs.
Station G3 and G2 compatibility audit
Source audit on 2026-10-18, starting from
1147c28b279f01443c9ec44c3b71cc767f11482e. A user reported that G2 firmware
works on a physical G3 while G3 firmware has problems. The comparison below
identifies differences in configuration and startup; it does not establish the
cause of that device's symptoms or claim a successful hardware retest.
Radio and peripheral pins
The G2 radio map matches G3 physical slot 1 exactly. G3's _r2 suffix refers
to physical socket 2, not motherboard revision 2. Current G3 firmware detects
the populated socket at boot and retains both legacy target names.
| Signal or build macro | G2 | G3 slot 1 | G3 slot 2 |
|---|---|---|---|
| SX1262 DIO1 / interrupt | 48 | 48 | 2 |
| SPI NSS / chip select | 11 | 11 | 43 |
| SX1262 reset | 21 | 21 | 44 |
| SX1262 BUSY | 47 | 47 | 1 |
| SPI SCK | 12 | 12 | 39 |
| SPI MISO | 14 | 14 | 41 |
| SPI MOSI | 13 | 13 | 40 |
| External LNA control | Not controlled by G2 firmware | 10, active low | 42, active low |
| PA PL1 control | Not controlled by G2 firmware | 9, shared; high selects higher level | 9, shared |
| I2C SDA / SCL | 5 / 6 | 5 / 6 | 5 / 6 |
| User button | 38 | 38 | 38 |
PIN_GPS_RX / PIN_GPS_TX |
15 / 7 | 15 / 7 | 15 / 7 |
The radio and FEM maps agree with the manufacturer's
ESP32-S3 pinout viewer
and its pin data, and the tracked
G2 recipe,
G3 recipes, and
runtime socket table.
The GPS macros name the peripheral's signals: the ESP32 startup calls
Serial1.setPins(PIN_GPS_TX, PIN_GPS_RX), giving MCU RX GPIO7 and TX GPIO15.
No incorrect radio map was established. Both base recipes select a 1.8 V
TCXO and disable the SX1262's internal boosted RX gain by default. The base TX
power is 7 dBm in both; their configured maximum chip-drive limits differ
(G2: 19 dBm; G3: 22 dBm). This audit does not change those power limits.
Ordinary-profile flash compatibility
Before this change, both board manifests declared QIO flash, but the G2 recipe
overrode it to DIO. Ordinary G3 profiles inherited QIO. The G3 board manifest
now selects DIO as well, following the known-working G2 startup policy.
All G3 role recipes, including the legacy _r2 targets, inherit that setting.
ESP32-S3 Full builds already force DIO through
the Full partition policy. This change
therefore corrects an ordinary-profile difference; it does not explain a
failure in an already verified DIO Full image. The PSRAM memory type remains
qio_opi. Flash capacity, partition layouts, USB configuration, and radio pin
assignments are unchanged.
Ordinary G2 firmware uses the legacy default.csv partition table, while G3
uses default_16MB.csv. Electrical compatibility does not make those layouts
interchangeable. When moving a node that currently runs a G2 image to a G3
image, check its installed layout and use the documented
partition migration if needed to retain
its identity and settings. This fix does not change either layout.
The two board manifests otherwise have matching build/upload settings; their board names and manufacturer-page URLs distinguish them. DIO is a compatibility choice here, not a claim that QIO caused the user's reported problem.
Bounded radio startup probe
The G3-only socket probe added in f765604cb8 imposed a 100 ms BUSY wait and
only three RC-standby attempts before rejecting a socket. G2 goes directly
through RadioLib's normal initialization, which permits a longer reset and
RC-standby settling interval. This is a separate, reproducible startup
compatibility gap, independent of the flash-mode difference.
The corrected probe shares one rollover-safe 1,000 ms deadline across reset, BUSY waits, and standby/version retries. It services cooperative USB while waiting. It retains identification-only operation, safe chip-select/reset cleanup, explicit socket overrides, and the existing fallback rules.
The native production-code fixture models both sockets and timer rollover. Elapsed times below are simulated fixture clocks, not physical measurements:
| Modeled condition | Previous probe | Corrected probe |
|---|---|---|
| BUSY remains high for 200 ms after reset | Rejected at 111 ms, no version-register reads | Detected at 202 ms, 16 bytes read |
| First five standby commands ignored | Rejected at 44 ms, 48 bytes read | Detected at 67 ms, 96 bytes read |
| BUSY never clears | Rejected early | Rejected at exactly 1,000 ms, no register reads |
| Socket absent | Rejected after three attempts | Rejected at exactly 1,000 ms |
| 800 ms BUSY followed by persistent command refusal | Rejected early | Rejected at exactly 1,000 ms total |
An immediately responsive chip still completes its probe in under 20 ms in the fixture. Negative controls restoring the old short BUSY budget or the three-attempt limit fail the delayed-startup regressions. These results prove the software tolerance gap; they do not prove it caused the user's hardware failure. No transmit or TCXO-setting override was introduced.
Physical socket commands in the normal infrastructure CLI
The follow-up audit also found that Repeater, Room, and Sensor infrastructure
commands consumed all get and set requests in the shared CLI. Their final
board-command hook was reached only for other verbs. Consequently, the G3's
normal get radio.slot and set radio.slot ... commands never reached the
board implementation. The separate pre-radio USB recovery console and KISS
binary commands called the board directly and were unaffected.
Unknown shared getters and setters now reach the board-command hook before returning an unknown-setting reply. Shared commands, including the guarded FEM setters, retain priority. Socket changes still save only the next-boot selection; they never switch the running radio or reboot behind the operator's back.
Receive-gain changes during transmission
The follow-up comparison from eb00b5370 found another G3-specific runtime
defect. G2 firmware leaves the external amplifier controls alone. G3's
setLNAEnable() reapplied receive mode unconditionally, so even repeating
set radio.fem.rxgain on during an active transmission enabled the LNA before
the transmit-completion hook. This was reachable through both the normal
infrastructure CLI and Companion gain setters.
The G3 FEM now tracks startup/sleep, receive, and transmit mode. A gain setter updates the requested receive preference while preserving the transmit bypass; the requested state is applied when receive mode resumes. Startup and terminal sleep also keep the LNA disabled until an explicit receive transition. PA-level changes retain their existing policy of applying at the start of the next transmission. The inactive socket's LNA is left disabled.
The unconditional receive-mode call came from the runtime FEM preference
implementation in
7509e51e3d,
Kevin Le, 2026-08-12. This finding concerns mode handling; the PA/LNA pin
assignments and polarities match the manufacturer documentation.
Complete saved-radio restoration in Room and Sensor roles
The same comparison found a shared role issue that can affect G3, G2, and other boards. Room and Sensor could clear their saved-radio retry flag after accepting the frequency/modulation tuple even when the subsequent saved TX-power command was rejected. Room also ignored rejection of its saved internal RX-gain command. An incoming packet or BUSY response during runtime restoration could therefore leave only part of the saved configuration applied.
Their saved-radio helper now reports success only after every applicable setting has been accepted. Rejection keeps the existing retry/backoff active, including restoration after a temporary radio setting expires. No preference layout, default setting, or Sensor RX-gain feature is added by this fix. This shared issue alone does not explain why G2 firmware works better on the user's G3.
Saved FEM and socket settings
G3 firmware actively drives its LNA and PA-level GPIOs. G2 firmware does not, so a saved FEM setting can have a visible effect only after switching to G3 firmware. Once the normal CLI has started, read these values before changing settings:
get radio.slot
get radio.fem.rxgain
get radio.fem.txgain
If startup reports Station G3 radio unavailable, the normal CLI has not
started. Press Enter and use the limited USB recovery commands instead:
!g3 help
!g3 get radio.slot
That recovery console accepts only socket selection, help, and reboot; the normal FEM getters are unavailable there.
radio.slot reports the saved selector, active socket, and detected sockets.
An explicit socket override does not silently fall back to another socket.
radio.fem.rxgain controls the external LNA and is distinct from
radio.rxgain, which controls the SX1262's internal boosted gain.
Preserve the saved values and jumper positions while diagnosing the device. The manufacturer documents GPIO control as effective with the corresponding LNA P/LNA S or PA PL1 jumper removed; PA PL2 selects the hardware power-level pair. Changing gain or jumpers is an operator choice, not an automatic part of this compatibility fix.
Git history and attribution
| Change | Introducing commit and author |
|---|---|
| Initial G2 support and board manifest | acac20dc89, Rastislav Vysoky, 2025-03-07 |
| G2 radio pin flags moved into the variant recipe | 7cb2e0863a, recrof, 2025-10-12 |
| Original G3 slot-1 map, PA9 and LNA10 | 75fb07fc2c, Chris / Cisien, 2026-05-09; merged in upstream PR #2515 |
| G2 DIO recipe override | 1a43123d2c, mikecarper, 2026-08-24 |
| G3 second-slot recipes and GPIO map | d8d72b7833, Adam Gessaman / agessaman, 2026-09-05 |
| Runtime socket discovery and shared pin binding | f765604cb8, mikecarper, 2026-10-15 |
git blame and the introducing diffs were checked, rather than attributing
copied pin values to the latest refactor. Original G3 support is present in
upstream dev; the second-slot recipes and
runtime discovery were added in this fork. The original G3 pull request reports
hardware testing by its author. That historical report does not qualify the
current firmware or the user's device.
Validation boundary
The host recipe regression resolves every tracked G3 environment, checks that
ordinary roles cannot override DIO, and verifies that qio_opi PSRAM remains
unchanged. It also executes the existing Full policy for canonical Repeater,
legacy _r2 Repeater, and Full Companion configurations. A deliberate nested
QIO override must fail that check.
| Check | Status |
|---|---|
| G3 recipe suite, including all 16 current role environments and the deliberate QIO override | PASS, 10 test methods |
| Existing ESP32 Full partition policy suite | PASS, 11 test methods |
| Native socket-detection suite, including 144 selection cases and 20 delayed/deadline cases | PASS, 6 test methods, ASan/UBSan |
| Combined socket detection/settings, boot recovery, radio pins, KISS slot and GPIO-hold suites | PASS, 36 test methods, including the 6 detection methods above |
Ordinary Repeater, legacy _r2 Repeater and KISS firmware builds |
PASS; all bootloader and application image headers verified as DIO |
| Canonical Full Companion package | PASS; 24 linked capability checks, internal RAM and application-slot checks passed; bootloader/application and merged-image headers verified as DIO |
| Follow-up G3 gain-mode tests through production CLI/Companion setters and GPIO helpers | PASS, 2 test methods; both sockets, failed saves and old-setter negative control |
| Follow-up Room/Sensor saved-radio startup and runtime restoration | PASS, 4 test methods; actual wrapper rejection, retry/backoff and temporary-radio expiry paths |
| Follow-up normal infrastructure socket-command routing | PASS, 7 test methods; real board/NVS dispatch, shared guards and old-dispatch negative controls |
| Combined follow-up native regression batch | PASS, 30 test methods with sanitizer coverage |
| Follow-up Repeater, Room, Sensor and ESP32-C6 Room firmware builds | PASS, all 4 environments |
| Follow-up canonical Full Companion package | PASS; 24 linked capability checks, internal RAM and application-slot checks passed |
| Follow-up hosted documentation link checks | PASS, 7 test methods |
| Physical G3 boot and RF receive/transmit | Not performed for this change |
No successful physical G3 boot, RF receive/transmit trial, or reproduction of the user's original problem is claimed by these host checks.