From 2a26e830e2ac5b91907497e7aff42f46188622a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Fesser?= Date: Mon, 6 Jul 2026 19:26:17 +0200 Subject: [PATCH 1/2] Fix Heltec V4 Vext polarity (OLED never powered) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The V4's Vext rail switch is a PMOS: GPIO36 LOW turns the rail ON. The DTS drove it ACTIVE_HIGH, leaving the OLED (and its I2C pull-ups) unpowered — the rail floats at ~1.6V and SSD1306 init always fails with -ETIMEDOUT. Verified on hardware with a multimeter: GPIO36 high = 1.6V on Vext, GPIO36 low = 3.3V, display works. This matches what the working Arduino MeshCore firmware actually does with the pin, despite its PIN_VEXT_EN_ACTIVE=HIGH define: RefCountedDigitalPin::begin() initialises the pin to its *inactive* level (LOW), and the V4 OLED build constructs the display with a NULL periph_power (variants/heltec_v4/target.cpp) so nothing ever claims it HIGH. GPIO36 is therefore driven LOW continuously under Arduino — the exact state this fix reproduces via an ACTIVE_LOW boot-on regulator. --- .../heltec_wifi_lora32_v4_procpu.dts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/zephcore/boards/esp32/heltec_wifi_lora32_v4/heltec_wifi_lora32_v4_procpu.dts b/zephcore/boards/esp32/heltec_wifi_lora32_v4/heltec_wifi_lora32_v4_procpu.dts index 2d67431..96a1b71 100644 --- a/zephcore/boards/esp32/heltec_wifi_lora32_v4/heltec_wifi_lora32_v4_procpu.dts +++ b/zephcore/boards/esp32/heltec_wifi_lora32_v4/heltec_wifi_lora32_v4_procpu.dts @@ -8,7 +8,7 @@ * OLED: SSD1306 128x64 on I2C0 * Button: GPIO0 * LED: GPIO35 (PWM via LEDC0) - * Vext: GPIO36 active-HIGH (powers OLED and sensors) + * Vext: GPIO36 active-LOW PMOS rail switch (powers OLED and sensors) * BatADC: GPIO1 (ADC1 ch0), enable GPIO37 active-LOW * * V4.2 (this file) — GC1109 PA, TX_EN on GPIO46. @@ -20,7 +20,7 @@ * GPIO7 = VFEM_Ctrl LDO power (active-HIGH, always-on) * GPIO2 = GC1109 CSD (chip enable, active-HIGH) * GPIO46 = GC1109 CPS (TX mode select, active-HIGH) - * - Vext control is active-HIGH (was active-LOW on V3) + * - Vext rail switch is active-LOW (PMOS; GPIO36 low = rail on) * - DIO2 used as RF switch alongside external FEM TX control * * LoRa SPI2: SCLK=9, MOSI=10, MISO=11, NSS=8 @@ -85,13 +85,16 @@ full-ohms = <(100000 + 390000)>; }; - /* Vext — powers OLED and external peripherals (active-HIGH on GPIO36). - * regulator-fixed + SSD1306 vin-supply: powers rail at boot without relying on - * power-domains (CONFIG_PM_DEVICE is disabled in prj.conf). */ + /* Vext rail switch — PMOS, ACTIVE LOW (GPIO36 low = rail ON). + * Powers the OLED (incl. its I2C pull-ups) and the expansion header. + * Verified on hardware: GPIO36 driven high leaves the rail floating + * (~1.6 V) and the OLED unpowered; driven low gives a clean 3.3 V. + * regulator-boot-on + always-on: the rail comes up at regulator init, + * well before the SSD1306 driver init. */ vext_enable: vext-enable { compatible = "regulator-fixed"; regulator-name = "vext"; - enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; /* GPIO36 = gpio1 pin 4 */ + enable-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; /* GPIO36 = gpio1 pin 4 */ regulator-boot-on; regulator-always-on; }; From c4fb9c0638ce43100ee150757945e690a4a5eb29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Fesser?= Date: Mon, 6 Jul 2026 19:26:17 +0200 Subject: [PATCH 2/2] Fix TX wait thread stack overflow on Xtensa (boot freeze) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TX_WAIT_THREAD_STACK_SIZE was 1024 bytes, shared by every radio adapter. On Xtensa (all ESP32/S3 boards) the windowed ABI needs ~3x the stack of Cortex-M for the same code — Zephyr's own Kconfig defaults reflect this (IDLE_STACK_SIZE: 1024 if XTENSA vs 320 ARM). Measured peak usage on Heltec V4 (immediate-mode logging, full TX cycle including startReceive/lora_config): 1252 bytes — already past the old 1024 limit. The overflow corrupts the exception frame and parks CPU0 in _DoubleExceptionVector (LoadProhibited @0x2c), a silent total freeze at boot. Confirmed via the S3 built-in USB-JTAG: current thread at crash = lora_tx_wait. 2048 gives ~39% headroom over the measured worst case. --- zephcore/adapters/radio/radio_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zephcore/adapters/radio/radio_common.h b/zephcore/adapters/radio/radio_common.h index fa04cc0..5b02489 100644 --- a/zephcore/adapters/radio/radio_common.h +++ b/zephcore/adapters/radio/radio_common.h @@ -24,7 +24,7 @@ #define RX_RING_SIZE 8 /* ~2 KB; buffers burst arrivals at SF7/BW500 */ /* --- TX wait thread --- */ -#define TX_WAIT_THREAD_STACK_SIZE 1024 +#define TX_WAIT_THREAD_STACK_SIZE 2048 #define TX_WAIT_THREAD_PRIORITY 10 /* preemptible, below main thread */ #define TX_TIMEOUT_MS 5000 /* hard timeout for TX completion signal */