From cba81af196811ceb1a51f990dd71e239450bc8d0 Mon Sep 17 00:00:00 2001 From: liquidraver <504870+liquidraver@users.noreply.github.com> Date: Thu, 16 Apr 2026 13:40:30 +0200 Subject: [PATCH] heltec v3/v4 oled&button changes --- .../esp32/heltec_wifi_lora32_v3/board.overlay | 260 +++++++++--------- .../esp32/heltec_wifi_lora32_v4/board.overlay | 20 +- .../heltec_wifi_lora32_v4_procpu.dts | 17 +- .../heltec_wifi_lora32_v43/board.overlay | 20 +- .../heltec_wifi_lora32_v43_procpu.dts | 15 +- zephcore/helpers/ui/ui_task.c | 20 +- 6 files changed, 171 insertions(+), 181 deletions(-) diff --git a/zephcore/boards/esp32/heltec_wifi_lora32_v3/board.overlay b/zephcore/boards/esp32/heltec_wifi_lora32_v3/board.overlay index bf6cc74..f93ab7d 100644 --- a/zephcore/boards/esp32/heltec_wifi_lora32_v3/board.overlay +++ b/zephcore/boards/esp32/heltec_wifi_lora32_v3/board.overlay @@ -1,126 +1,134 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Heltec WiFi LoRa 32 V3 — ZephCore overlay - * - * The upstream Zephyr DTS already defines SX1262, SSD1306 OLED, button, - * LED, battery ADC, Vext/ADC control, I2C0, SPI2, BLE, and WiFi. - * This overlay adds ZephCore-specific integration on top. - * - * LoRa SPI2 pins: SCLK=9, MOSI=10, MISO=11, NSS=8 - * LoRa control: DIO1=14, BUSY=13, RESET=12 - * Display I2C0: SDA=17, SCL=18 (SSD1306 @ 0x3C) - * Battery ADC: GPIO1 (ADC1 ch0), enable GPIO37, divider 100K/390K - * Vext: GPIO36 (active-LOW, powers OLED) - * Button: GPIO0 - * LED: GPIO35 - */ - -#include - -/ { - chosen { - /* Keep console/shell on UART0 for stable host logging on V3 */ - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - }; - - /* Add label to upstream buttons node (defined without one) */ - buttons: buttons { - }; - - /* Battery ADC — ZephCore reads via zephyr,user { io-channels } - * Upstream vbatt node uses voltage-divider compatible which ZephCore - * doesn't use. Multiplier: 3300mV full-scale * 5.42x = 17886. - * (5.42x is Arduino's empirical divider factor for V3/V4.) */ - zephyr,user { - io-channels = <&adc1 0>; - vbat-mv-multiplier = <17886>; - }; - - /* Battery ADC enable — GPIO37 (gpio1 pin 5) must be driven to read. - * Upstream has adc_ctrl power-domain-gpio; ZephCore expects a - * regulator-fixed named vbat_enable. */ - vbat_enable: vbat-enable { - compatible = "regulator-fixed"; - regulator-name = "vbat-enable"; - enable-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; - }; - - /* ---- Button input filter chain ---- - * Upstream button emits INPUT_KEY_0. Split into: - * short press → KEY_A (consumed by multi-tap) - * long press (1s) → KEY_POWER (deep sleep) */ - user_btn_longpress { - compatible = "zephyr,input-longpress"; - input = <&buttons>; - input-codes = ; - short-codes = ; - long-codes = ; - long-delay-ms = <1000>; - }; - - /* Multi-tap decodes short presses: - * 1 tap (400ms wait) → KEY_1 = page next - * 2 taps (400ms wait) → KEY_B = flood advert - * 3 taps (400ms wait) → KEY_D = buzzer mute toggle - * 4 taps (immediate) → KEY_C = GPS on/off */ - user_btn_multitap { - compatible = "zephcore,input-multi-tap"; - /* No 'input' phandle — listen to ALL devices. - * KEY_A is emitted by the longpress pseudo-device, - * not by &buttons, so we must not filter by device. */ - input-codes = ; - tap-codes = ; - tap-delay-ms = <400>; - }; -}; - -/* Enable native USB serial for console/CLI */ -&usb_serial { - status = "okay"; -}; - -/* Add RX boosted mode and DIO1 pull-down to LoRa radio. - * Upstream omits rx-boosted and has no pull-down on DIO1. */ -&lora0 { - dio1-gpios = <&gpio0 14 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; - rx-boosted; -}; - -/* Reduce CPU clock from 240 MHz to 160 MHz — saves power, HAL minimum */ -&cpu0 { - clock-frequency = ; -}; - -&cpu1 { - clock-frequency = ; -}; - -/* I2C sensors — auto-detected at runtime */ -&i2c0 { - #include "../../common/sensors-i2c.dtsi" -}; - -/* - * Flash partitions — reclaim unused space from 8MB layout. - * Delete lpcore slots, storage, scratch, and coredump partitions. - * Repurpose 0x7A0000 - 0x800000 (384KB) for LittleFS. - */ -/delete-node/ &slot0_lpcore_partition; -/delete-node/ &slot1_lpcore_partition; -/delete-node/ &storage_partition; -/delete-node/ &scratch_partition; -/delete-node/ &coredump_partition; - -&flash0 { - partitions { - /* LittleFS 384KB for DataStore + file-based BLE settings */ - lfs_partition: partition@7a0000 { - label = "lfs"; - reg = <0x7A0000 0x60000>; - }; - }; -}; - -/* LittleFS auto-mount — standard /lfs mount point */ -#include "../../common/filesystem.dtsi" +/* + * SPDX-License-Identifier: Apache-2.0 + * Heltec WiFi LoRa 32 V3 — ZephCore overlay + * + * The upstream Zephyr DTS already defines SX1262, SSD1306 OLED, button, + * LED, battery ADC, Vext/ADC control, I2C0, SPI2, BLE, and WiFi. + * This overlay adds ZephCore-specific integration on top. + * + * LoRa SPI2 pins: SCLK=9, MOSI=10, MISO=11, NSS=8 + * LoRa control: DIO1=14, BUSY=13, RESET=12 + * Display I2C0: SDA=17, SCL=18 (SSD1306 @ 0x3C) + * Battery ADC: GPIO1 (ADC1 ch0), enable GPIO37, divider 100K/390K + * Vext: GPIO36 (active-LOW, powers OLED) — regulator + vin-supply in overlay + * Button: GPIO0 + * LED: GPIO35 + */ + +#include + +/ { + chosen { + /* Keep console/shell on UART0 for stable host logging on V3 */ + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; + + /* Add label to upstream buttons node (defined without one) */ + buttons: buttons { + }; + + /* Battery ADC — ZephCore reads via zephyr,user { io-channels } + * Upstream vbatt node uses voltage-divider compatible which ZephCore + * doesn't use. Multiplier: 3300mV full-scale * 5.42x = 17886. + * (5.42x is Arduino's empirical divider factor for V3/V4.) */ + zephyr,user { + io-channels = <&adc1 0>; + vbat-mv-multiplier = <17886>; + }; + + /* Battery ADC enable — GPIO37 (gpio1 pin 5) must be driven to read. + * Upstream has adc_ctrl power-domain-gpio; ZephCore expects a + * regulator-fixed named vbat_enable. */ + vbat_enable: vbat-enable { + compatible = "regulator-fixed"; + regulator-name = "vbat-enable"; + enable-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; + }; + + /* Vext — GPIO36, active-LOW enables rail (matches Arduino periph_power / MeshCore + * PIN_VEXT_EN). Replaces upstream vext_ctrl power-domain so SSD1306 init works with + * CONFIG_PM_DEVICE=n. */ + vext_enable: vext-enable { + compatible = "regulator-fixed"; + regulator-name = "vext"; + enable-gpios = <&gpio1 4 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + regulator-boot-on; + regulator-always-on; + }; + + /* Button chain — same mapping as RAK4631 / WisMesh Pocket (rak4631/board.overlay). */ + user_btn_longpress { + compatible = "zephyr,input-longpress"; + input = <&buttons>; + input-codes = ; + short-codes = ; + long-codes = ; + long-delay-ms = <1000>; + }; + + page_btn_multitap { + compatible = "zephcore,input-multi-tap"; + input-codes = ; + tap-codes = ; + tap-delay-ms = <400>; + }; +}; + +/* Enable native USB serial for console/CLI */ +&usb_serial { + status = "okay"; +}; + +/* Add RX boosted mode and DIO1 pull-down to LoRa radio. + * Upstream omits rx-boosted and has no pull-down on DIO1. */ +&lora0 { + dio1-gpios = <&gpio0 14 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; + rx-boosted; +}; + +/* Reduce CPU clock from 240 MHz to 160 MHz — saves power, HAL minimum */ +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +/* I2C sensors — auto-detected at runtime */ +&i2c0 { + #include "../../common/sensors-i2c.dtsi" + + ssd1306_128x64: display-controller@3c { + /delete-property/ power-domains; + vin-supply = <&vext_enable>; + }; +}; + +/* + * Flash partitions — reclaim unused space from 8MB layout. + * Delete lpcore slots, storage, scratch, and coredump partitions. + * Repurpose 0x7A0000 - 0x800000 (384KB) for LittleFS. + */ +/delete-node/ &slot0_lpcore_partition; +/delete-node/ &slot1_lpcore_partition; +/delete-node/ &storage_partition; +/delete-node/ &scratch_partition; +/delete-node/ &coredump_partition; + +&flash0 { + partitions { + /* LittleFS 384KB for DataStore + file-based BLE settings */ + lfs_partition: partition@7a0000 { + label = "lfs"; + reg = <0x7A0000 0x60000>; + }; + }; +}; + +/* LittleFS auto-mount — standard /lfs mount point */ +#include "../../common/filesystem.dtsi" + +/* After SSD1306 no longer references vext_ctrl, remove upstream power-domain node. */ +/delete-node/ &vext_ctrl; diff --git a/zephcore/boards/esp32/heltec_wifi_lora32_v4/board.overlay b/zephcore/boards/esp32/heltec_wifi_lora32_v4/board.overlay index 38871d8..f51dc54 100644 --- a/zephcore/boards/esp32/heltec_wifi_lora32_v4/board.overlay +++ b/zephcore/boards/esp32/heltec_wifi_lora32_v4/board.overlay @@ -3,7 +3,7 @@ * Heltec WiFi LoRa 32 V4 — ZephCore overlay * * The DTS already defines: SX1262 (lora0), SSD1306 OLED, button, LED, PWM, - * vext_ctrl, adc_ctrl, fem_power, I2C0, SPI2, BLE, WiFi. + * vext_enable, adc_ctrl, fem_power, I2C0, SPI2, BLE, WiFi. * This overlay adds ZephCore-specific integration on top. * * LoRa SPI2: SCLK=9, MOSI=10, MISO=11, NSS=8 @@ -43,30 +43,20 @@ enable-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; /* GPIO37 = gpio1 pin 5 */ }; - /* ---- Button input filter chain ---- - * Button emits INPUT_KEY_0. Split into: - * short press → KEY_A (consumed by multi-tap) - * long press (1 s) → KEY_POWER (deep sleep) */ + /* Button chain — same mapping as RAK4631 / WisMesh Pocket (rak4631/board.overlay). */ user_btn_longpress { compatible = "zephyr,input-longpress"; input = <&buttons>; input-codes = ; short-codes = ; - long-codes = ; + long-codes = ; long-delay-ms = <1000>; }; - /* Multi-tap decodes short presses: - * 1 tap (400 ms wait) → KEY_1 = page next - * 2 taps (400 ms wait) → KEY_B = flood advert - * 3 taps (400 ms wait) → KEY_D = buzzer mute toggle - * 4 taps (immediate) → KEY_C = GPS on/off */ - user_btn_multitap { + page_btn_multitap { compatible = "zephcore,input-multi-tap"; - /* No 'input' phandle — listen to ALL devices. - * KEY_A is emitted by the longpress pseudo-device. */ input-codes = ; - tap-codes = ; + tap-codes = ; tap-delay-ms = <400>; }; }; 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 f000835..b0bd45c 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 @@ -85,14 +85,15 @@ full-ohms = <(100000 + 390000)>; }; - /* Vext — powers OLED and external peripherals. - * V4 DIFFERENCE: active-HIGH (GPIO36 HIGH = power on). - * V3 was active-LOW on the same GPIO. */ - vext_ctrl: vext_ctrl { - compatible = "power-domain-gpio"; + /* 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_enable: vext-enable { + compatible = "regulator-fixed"; + regulator-name = "vext"; enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; /* GPIO36 = gpio1 pin 4 */ - #power-domain-cells = <0>; - label = "Vext Control"; + regulator-boot-on; + regulator-always-on; }; /* ADC enable — GPIO37 (gpio1 pin 5) must be driven HIGH to read battery. @@ -186,7 +187,7 @@ inversion-on; prechargep = <0x22>; reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; /* RST_OLED = GPIO21 */ - power-domains = <&vext_ctrl>; + vin-supply = <&vext_enable>; }; }; diff --git a/zephcore/boards/esp32/heltec_wifi_lora32_v43/board.overlay b/zephcore/boards/esp32/heltec_wifi_lora32_v43/board.overlay index 5852e0d..6e42ee2 100644 --- a/zephcore/boards/esp32/heltec_wifi_lora32_v43/board.overlay +++ b/zephcore/boards/esp32/heltec_wifi_lora32_v43/board.overlay @@ -3,7 +3,7 @@ * Heltec WiFi LoRa 32 V4.3 — ZephCore overlay * * The DTS already defines: SX1262 (lora0), SSD1306 OLED, button, LED, PWM, - * vext_ctrl, adc_ctrl, fem_power, I2C0, SPI2, BLE, WiFi. + * vext_enable, adc_ctrl, fem_power, I2C0, SPI2, BLE, WiFi. * This overlay adds ZephCore-specific integration on top. * * LoRa SPI2: SCLK=9, MOSI=10, MISO=11, NSS=8 @@ -43,30 +43,20 @@ enable-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; /* GPIO37 = gpio1 pin 5 */ }; - /* ---- Button input filter chain ---- - * Button emits INPUT_KEY_0. Split into: - * short press → KEY_A (consumed by multi-tap) - * long press (1 s) → KEY_POWER (deep sleep) */ + /* Button chain — same mapping as RAK4631 / WisMesh Pocket (rak4631/board.overlay). */ user_btn_longpress { compatible = "zephyr,input-longpress"; input = <&buttons>; input-codes = ; short-codes = ; - long-codes = ; + long-codes = ; long-delay-ms = <1000>; }; - /* Multi-tap decodes short presses: - * 1 tap (400 ms wait) → KEY_1 = page next - * 2 taps (400 ms wait) → KEY_B = flood advert - * 3 taps (400 ms wait) → KEY_D = buzzer mute toggle - * 4 taps (immediate) → KEY_C = GPS on/off */ - user_btn_multitap { + page_btn_multitap { compatible = "zephcore,input-multi-tap"; - /* No 'input' phandle — listen to ALL devices. - * KEY_A is emitted by the longpress pseudo-device. */ input-codes = ; - tap-codes = ; + tap-codes = ; tap-delay-ms = <400>; }; }; diff --git a/zephcore/boards/esp32/heltec_wifi_lora32_v43/heltec_wifi_lora32_v43_procpu.dts b/zephcore/boards/esp32/heltec_wifi_lora32_v43/heltec_wifi_lora32_v43_procpu.dts index 1fcb772..c8a36ed 100644 --- a/zephcore/boards/esp32/heltec_wifi_lora32_v43/heltec_wifi_lora32_v43_procpu.dts +++ b/zephcore/boards/esp32/heltec_wifi_lora32_v43/heltec_wifi_lora32_v43_procpu.dts @@ -84,12 +84,15 @@ full-ohms = <(100000 + 390000)>; }; - /* Vext — powers OLED and external peripherals (active-HIGH, same as V4.2) */ - vext_ctrl: vext_ctrl { - compatible = "power-domain-gpio"; + /* 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_enable: vext-enable { + compatible = "regulator-fixed"; + regulator-name = "vext"; enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; /* GPIO36 = gpio1 pin 4 */ - #power-domain-cells = <0>; - label = "Vext Control"; + regulator-boot-on; + regulator-always-on; }; /* ADC enable — GPIO37 (gpio1 pin 5) must be driven HIGH to read battery */ @@ -182,7 +185,7 @@ inversion-on; prechargep = <0x22>; reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; /* RST_OLED = GPIO21 */ - power-domains = <&vext_ctrl>; + vin-supply = <&vext_enable>; }; }; diff --git a/zephcore/helpers/ui/ui_task.c b/zephcore/helpers/ui/ui_task.c index 1258238..10077ba 100644 --- a/zephcore/helpers/ui/ui_task.c +++ b/zephcore/helpers/ui/ui_task.c @@ -8,14 +8,14 @@ * * Input flow (after longpress + multi-tap filter chain): * KEY_1 → action_page_next() (1 tap, 400ms delayed) - * KEY_B → action_flood_advert() (2 taps, 400ms delayed) - * KEY_D → action_buzzer_toggle() (3 taps, 400ms delayed) + * KEY_LEFT → action_page_prev() (2 taps — RAK4631 / Pocket / Heltec V3–V4.3) + * KEY_B → action_flood_advert() (2 taps on extended multitap overlays) + * KEY_D → action_buzzer_toggle() (3 taps) * KEY_C → action_gps_toggle() (4 taps, immediate) * KEY_G → GPS switch on/off (hardware toggle, ThinkNode M1) - * KEY_POWER → action_deep_sleep() (long press ≥1s) - * KEY_RIGHT → action_page_next() (joystick, Wio Tracker) - * KEY_LEFT → action_page_prev() (joystick, Wio Tracker) - * KEY_ENTER → action_page_enter() (joystick center, Wio Tracker) + * KEY_POWER / KEY_F → action_deep_sleep() (long press — boards that emit these) + * KEY_ENTER → action_page_enter() (long press — Pocket / Heltec; joystick center Wio) + * KEY_RIGHT → action_page_next() (joystick, Wio Tracker) * * Notification flow: * LoRa RX → CompanionMesh → ui_notify(UI_EVENT_CONTACT_MSG) @@ -753,11 +753,9 @@ static void ui_input_cb(struct input_event *evt, void *user_data) /* Map input key codes to UI actions. * - * KEY_1: 1 tap (from multi-tap, 400ms delayed) - * KEY_B: 2 taps (from multi-tap, 400ms delayed) - * KEY_D: 3 taps (from multi-tap, 400ms delayed) - * KEY_C: 4 taps (from multi-tap, immediate — max count) - * KEY_POWER: long press (from longpress filter, ≥1s) + * RAK4631 / WisMesh Pocket / Heltec V3–V4.3: 1 tap KEY_1, 2 taps KEY_LEFT; + * long press KEY_ENTER (page enter). Other boards: up to 4–5 tap codes + * (KEY_B/D/C/E) and KEY_POWER or KEY_F long → deep sleep. * KEY_RIGHT/LEFT/ENTER/UP/DOWN: joystick (Wio Tracker) * * NOTE: KEY_A (raw short-press from longpress filter) is NOT handled