From 24ca4602b1f31acd9696f96f92f9890d87eac5cd Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sat, 6 Dec 2025 12:42:05 -0600 Subject: [PATCH 1/7] roughed in support for esp32-h2 via Waveshare dev board --- arch/esp32/esp32h2.ini | 47 +++++++++++++++++++ src/modules/ExternalNotificationModule.h | 3 +- src/modules/SerialModule.cpp | 8 ++-- src/platform/esp32/main-esp32.cpp | 11 +++-- src/sleep.cpp | 6 ++- .../esp32h2/waveshare-esp32-h2/platformio.ini | 11 +++++ variants/esp32h2/waveshare-esp32-h2/variant.h | 8 ++++ 7 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 arch/esp32/esp32h2.ini create mode 100644 variants/esp32h2/waveshare-esp32-h2/platformio.ini create mode 100644 variants/esp32h2/waveshare-esp32-h2/variant.h diff --git a/arch/esp32/esp32h2.ini b/arch/esp32/esp32h2.ini new file mode 100644 index 00000000000..ca325c321c5 --- /dev/null +++ b/arch/esp32/esp32h2.ini @@ -0,0 +1,47 @@ +[esp32h2_base] +extends = esp32_base +platform = + # Do not renovate until we have switched to pioarduino tagged builds + https://github.com/Jason2866/platform-espressif32/archive/39475a7213fa3a52b0c2048d1a31c215fc85fcf8.zip +build_flags = + ${arduino_base.build_flags} + -Wall + -Wextra + -Isrc/platform/esp32 + -std=c++11 + -DESP_OPENSSL_SUPPRESS_LEGACY_WARNING + -DSERIAL_BUFFER_SIZE=4096 + -DLIBPAX_ARDUINO + -DLIBPAX_WIFI + -DLIBPAX_BLE + -DMESHTASTIC_EXCLUDE_WEBSERVER + ;-DDEBUG_HEAP + ; TEMP + -DHAS_BLUETOOTH=0 + -DMESHTASTIC_EXCLUDE_PAXCOUNTER + -DMESHTASTIC_EXCLUDE_BLUETOOTH + +lib_deps = + ${arduino_base.lib_deps} + ${networking_base.lib_deps} + ${environmental_base.lib_deps} + ${environmental_extra.lib_deps} + ${radiolib_base.lib_deps} + # renovate: datasource=custom.pio depName=XPowersLib packageName=lewisxhe/library/XPowersLib + lewisxhe/XPowersLib@0.3.1 + # renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master + https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip + # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto + rweather/Crypto@0.4.0 + +build_src_filter = + ${esp32_base.build_src_filter} - + +monitor_speed = 460800 +monitor_filters = esp32_h2_exception_decoder + +lib_ignore = + NonBlockingRTTTL + NimBLE-Arduino + libpax + diff --git a/src/modules/ExternalNotificationModule.h b/src/modules/ExternalNotificationModule.h index f667f7be900..7961dc21e02 100644 --- a/src/modules/ExternalNotificationModule.h +++ b/src/modules/ExternalNotificationModule.h @@ -5,7 +5,8 @@ #include "configuration.h" #include "input/InputBroker.h" -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !defined(CONFIG_IDF_TARGET_ESP32C6) && \ + !defined(CONFIG_IDF_TARGET_ESP32H2) #include #else // Noop class for portduino. diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index 719e342b1a2..279c4175b2e 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -71,7 +71,7 @@ SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial api_type = TYPE_SERIAL; } static Print *serialPrint = &Serial; -#elif defined(CONFIG_IDF_TARGET_ESP32C6) || defined(RAK3172) || defined(EBYTE_E77_MBL) +#elif defined(CONFIG_IDF_TARGET_ESP32C6) || defined(RAK3172) || defined(EBYTE_E77_MBL) || defined(CONFIG_IDF_TARGET_ESP32H2) SerialModule::SerialModule() : StreamAPI(&Serial1), concurrency::OSThread("Serial") { api_type = TYPE_SERIAL; @@ -175,7 +175,7 @@ int32_t SerialModule::runOnce() // Give it a chance to flush out 💩 delay(10); } -#if defined(CONFIG_IDF_TARGET_ESP32C6) +#if defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) if (moduleConfig.serial.rxd && moduleConfig.serial.txd) { Serial1.setRxBufferSize(RX_BUFFER); Serial1.begin(baud, SERIAL_8N1, moduleConfig.serial.rxd, moduleConfig.serial.txd); @@ -277,7 +277,7 @@ int32_t SerialModule::runOnce() } #endif else { -#if defined(CONFIG_IDF_TARGET_ESP32C6) +#if defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) while (Serial1.available()) { serialPayloadSize = Serial1.readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN); #else @@ -538,7 +538,7 @@ void SerialModule::processWXSerial() { #if !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(CONFIG_IDF_TARGET_ESP32C6) && \ !defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && \ - !defined(ARCH_STM32WL) && !defined(MUZI_BASE) + !defined(ARCH_STM32WL) && !defined(MUZI_BASE) && !defined(CONFIG_IDF_TARGET_ESP32H2) static unsigned int lastAveraged = 0; static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded. static double dir_sum_sin = 0; diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index 760964119c2..54cf0dec050 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -169,6 +169,8 @@ void esp32Setup() // #define APP_WATCHDOG_SECS 45 #define APP_WATCHDOG_SECS 90 +// esp_task_wdt_init returns an unknown error, so skip it on ESP32H2 +#ifndef CONFIG_IDF_TARGET_ESP32H2 #ifdef CONFIG_IDF_TARGET_ESP32C6 esp_task_wdt_config_t *wdt_config = (esp_task_wdt_config_t *)malloc(sizeof(esp_task_wdt_config_t)); wdt_config->timeout_ms = APP_WATCHDOG_SECS * 1000; @@ -181,7 +183,7 @@ void esp32Setup() #endif res = esp_task_wdt_add(NULL); assert(res == ESP_OK); - +#endif #if HAS_32768HZ enableSlowCLK(); #endif @@ -223,9 +225,10 @@ void cpuDeepSleep(uint32_t msecToWake) 13, #endif 34, 35, 37}; - +#ifndef CONFIG_IDF_TARGET_ESP32H2 for (int i = 0; i < sizeof(rtcGpios); i++) rtc_gpio_isolate((gpio_num_t)rtcGpios[i]); +#endif #endif // FIXME, disable internal rtc pullups/pulldowns on the non isolated pins. for inputs that we aren't using @@ -258,10 +261,10 @@ void cpuDeepSleep(uint32_t msecToWake) #endif // #end ESP32S3_WAKE_TYPE #endif - +#ifdef ESP_PD_DOMAIN_RTC_PERIPH // We want RTC peripherals to stay on esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - +#endif esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs esp_deep_sleep_start(); // TBD mA sleep current (battery) } diff --git a/src/sleep.cpp b/src/sleep.cpp index 756582c74ba..9370b1f4476 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -388,10 +388,10 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r uint64_t sleepUsec = sleepMsec * 1000LL; // NOTE! ESP docs say we must disable bluetooth and wifi before light sleep - +#ifdef ESP_PD_DOMAIN_RTC_PERIPH // We want RTC peripherals to stay on esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - +#endif #if defined(BUTTON_PIN) && defined(BUTTON_NEED_PULLUP) gpio_pullup_en((gpio_num_t)BUTTON_PIN); #endif @@ -523,6 +523,8 @@ void enableModemSleep() esp32_config.max_freq_mhz = CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ; #elif CONFIG_IDF_TARGET_ESP32C6 esp32_config.max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ; +#elif CONFIG_IDF_TARGET_ESP32H2 + esp32_config.max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ; #elif CONFIG_IDF_TARGET_ESP32C3 esp32_config.max_freq_mhz = CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ; #else diff --git a/variants/esp32h2/waveshare-esp32-h2/platformio.ini b/variants/esp32h2/waveshare-esp32-h2/platformio.ini new file mode 100644 index 00000000000..10f7ae53eff --- /dev/null +++ b/variants/esp32h2/waveshare-esp32-h2/platformio.ini @@ -0,0 +1,11 @@ +[env:waveshare-esp32h2] +extends = esp32h2_base +board = esp32-h2-devkitm-1 +board_build.f_flash = 16000000L +board_level = pr +build_flags = + ${esp32h2_base.build_flags} + -I variants/esp32h2/waveshare-esp32-h2 + -DARDUINO_USB_CDC_ON_BOOT=1 + -DARDUINO_USB_MODE=1 + -DHAS_WIFI=0 diff --git a/variants/esp32h2/waveshare-esp32-h2/variant.h b/variants/esp32h2/waveshare-esp32-h2/variant.h new file mode 100644 index 00000000000..806d648fd03 --- /dev/null +++ b/variants/esp32h2/waveshare-esp32-h2/variant.h @@ -0,0 +1,8 @@ + +#define HAS_SCREEN 0 +#define HAS_WIFI 0 + +#define LORA_SCK 4 +#define LORA_MISO 3 +#define LORA_MOSI 2 +#define LORA_CS 1 \ No newline at end of file From f0b72a4b4b17a2c9abdae1bd13793298f94793d5 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Mon, 8 Dec 2025 16:49:01 -0600 Subject: [PATCH 2/7] Move the esp32-h2 .ini --- {arch/esp32 => variants/esp32h2}/esp32h2.ini | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {arch/esp32 => variants/esp32h2}/esp32h2.ini (100%) diff --git a/arch/esp32/esp32h2.ini b/variants/esp32h2/esp32h2.ini similarity index 100% rename from arch/esp32/esp32h2.ini rename to variants/esp32h2/esp32h2.ini From fea10ccecd35ba0d5da84aa5347497f545a9d4e0 Mon Sep 17 00:00:00 2001 From: vidplace7 Date: Sat, 6 Jun 2026 22:13:43 -0400 Subject: [PATCH 3/7] Cleanup for pioarduino --- variants/esp32h2/esp32h2.ini | 46 +++++-------------- .../esp32h2/waveshare-esp32-h2/platformio.ini | 3 +- variants/esp32h2/waveshare-esp32-h2/variant.h | 3 +- 3 files changed, 13 insertions(+), 39 deletions(-) diff --git a/variants/esp32h2/esp32h2.ini b/variants/esp32h2/esp32h2.ini index ca325c321c5..5579f718169 100644 --- a/variants/esp32h2/esp32h2.ini +++ b/variants/esp32h2/esp32h2.ini @@ -1,38 +1,14 @@ [esp32h2_base] extends = esp32_base -platform = - # Do not renovate until we have switched to pioarduino tagged builds - https://github.com/Jason2866/platform-espressif32/archive/39475a7213fa3a52b0c2048d1a31c215fc85fcf8.zip -build_flags = - ${arduino_base.build_flags} - -Wall - -Wextra - -Isrc/platform/esp32 - -std=c++11 - -DESP_OPENSSL_SUPPRESS_LEGACY_WARNING - -DSERIAL_BUFFER_SIZE=4096 - -DLIBPAX_ARDUINO - -DLIBPAX_WIFI - -DLIBPAX_BLE - -DMESHTASTIC_EXCLUDE_WEBSERVER - ;-DDEBUG_HEAP - ; TEMP - -DHAS_BLUETOOTH=0 - -DMESHTASTIC_EXCLUDE_PAXCOUNTER - -DMESHTASTIC_EXCLUDE_BLUETOOTH +custom_esp32_kind = esp32h2 -lib_deps = - ${arduino_base.lib_deps} - ${networking_base.lib_deps} - ${environmental_base.lib_deps} - ${environmental_extra.lib_deps} - ${radiolib_base.lib_deps} - # renovate: datasource=custom.pio depName=XPowersLib packageName=lewisxhe/library/XPowersLib - lewisxhe/XPowersLib@0.3.1 - # renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master - https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip - # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto - rweather/Crypto@0.4.0 +build_flags = + ${esp32_base.build_flags} + -DHAS_WIFI=0 + -DMESHTASTIC_EXCLUDE_WIFI=1 ; TODO + -DMESHTASTIC_EXCLUDE_MQTT=1 + -DMESHTASTIC_EXCLUDE_PAXCOUNTER=1 + -DMESHTASTIC_EXCLUDE_WEBSERVER=1 build_src_filter = ${esp32_base.build_src_filter} - @@ -41,7 +17,7 @@ monitor_speed = 460800 monitor_filters = esp32_h2_exception_decoder lib_ignore = - NonBlockingRTTTL - NimBLE-Arduino + ${esp32_common.lib_ignore} libpax - + esp32_idf5_https_server + esp_http_server diff --git a/variants/esp32h2/waveshare-esp32-h2/platformio.ini b/variants/esp32h2/waveshare-esp32-h2/platformio.ini index 10f7ae53eff..f29383ec674 100644 --- a/variants/esp32h2/waveshare-esp32-h2/platformio.ini +++ b/variants/esp32h2/waveshare-esp32-h2/platformio.ini @@ -3,9 +3,8 @@ extends = esp32h2_base board = esp32-h2-devkitm-1 board_build.f_flash = 16000000L board_level = pr -build_flags = +build_flags = ${esp32h2_base.build_flags} -I variants/esp32h2/waveshare-esp32-h2 -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MODE=1 - -DHAS_WIFI=0 diff --git a/variants/esp32h2/waveshare-esp32-h2/variant.h b/variants/esp32h2/waveshare-esp32-h2/variant.h index 3c16b7a1a83..34110c4e0af 100644 --- a/variants/esp32h2/waveshare-esp32-h2/variant.h +++ b/variants/esp32h2/waveshare-esp32-h2/variant.h @@ -1,10 +1,9 @@ #define HAS_SCREEN 0 -#define HAS_WIFI 0 #define SERIAL_PRINT_PORT 1 #define LORA_SCK 4 #define LORA_MISO 3 #define LORA_MOSI 2 -#define LORA_CS 1 \ No newline at end of file +#define LORA_CS 1 From a853053a72a9eaa2760b7240959ee7af05321b90 Mon Sep 17 00:00:00 2001 From: vidplace7 Date: Sun, 7 Jun 2026 14:08:52 -0400 Subject: [PATCH 4/7] Inherit from esp32_common --- src/platform/esp32/main-esp32.cpp | 1 + src/sleep.cpp | 2 ++ variants/esp32h2/esp32h2.ini | 8 ++++---- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index e883d4fd77d..8cf070905bc 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -280,6 +280,7 @@ void cpuDeepSleep(uint32_t msecToWake) // We want RTC peripherals to stay on esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); #endif + esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs esp_deep_sleep_start(); // TBD mA sleep current (battery) } diff --git a/src/sleep.cpp b/src/sleep.cpp index 4ecc1e4042e..3f16e2fd6a8 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -410,10 +410,12 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r uint64_t sleepUsec = sleepMsec * 1000LL; // NOTE! ESP docs say we must disable bluetooth and wifi before light sleep + #if SOC_PM_SUPPORT_RTC_PERIPH_PD // We want RTC peripherals to stay on esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); #endif + #if defined(BUTTON_PIN) && defined(BUTTON_NEED_PULLUP) gpio_pullup_en((gpio_num_t)BUTTON_PIN); #endif diff --git a/variants/esp32h2/esp32h2.ini b/variants/esp32h2/esp32h2.ini index 5579f718169..0e5b2e42af0 100644 --- a/variants/esp32h2/esp32h2.ini +++ b/variants/esp32h2/esp32h2.ini @@ -1,17 +1,17 @@ [esp32h2_base] -extends = esp32_base +extends = esp32_common custom_esp32_kind = esp32h2 build_flags = - ${esp32_base.build_flags} + ${esp32_common.build_flags} -DHAS_WIFI=0 -DMESHTASTIC_EXCLUDE_WIFI=1 ; TODO -DMESHTASTIC_EXCLUDE_MQTT=1 -DMESHTASTIC_EXCLUDE_PAXCOUNTER=1 -DMESHTASTIC_EXCLUDE_WEBSERVER=1 -build_src_filter = - ${esp32_base.build_src_filter} - +build_src_filter = + ${esp32_common.build_src_filter} - monitor_speed = 460800 monitor_filters = esp32_h2_exception_decoder From 73af50a0f6a56b5019c04f036aa1150a8431d99c Mon Sep 17 00:00:00 2001 From: vidplace7 Date: Sun, 7 Jun 2026 14:16:08 -0400 Subject: [PATCH 5/7] ESP32H2 doesn't support UDP_MULTICAST --- variants/esp32h2/esp32h2.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/variants/esp32h2/esp32h2.ini b/variants/esp32h2/esp32h2.ini index 0e5b2e42af0..045790600e1 100644 --- a/variants/esp32h2/esp32h2.ini +++ b/variants/esp32h2/esp32h2.ini @@ -10,6 +10,9 @@ build_flags = -DMESHTASTIC_EXCLUDE_PAXCOUNTER=1 -DMESHTASTIC_EXCLUDE_WEBSERVER=1 +build_unflags= + -DHAS_UDP_MULTICAST=1 + build_src_filter = ${esp32_common.build_src_filter} - From 68f1c88cbf4a2aa981bbd21c944d365c4dab0cb2 Mon Sep 17 00:00:00 2001 From: vidplace7 Date: Sun, 7 Jun 2026 14:19:11 -0400 Subject: [PATCH 6/7] Set board_level to extra (for now) CI builds will fail until additional esp32h2 plumbing is set up. --- variants/esp32h2/waveshare-esp32-h2/platformio.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/variants/esp32h2/waveshare-esp32-h2/platformio.ini b/variants/esp32h2/waveshare-esp32-h2/platformio.ini index f29383ec674..413bfd72db6 100644 --- a/variants/esp32h2/waveshare-esp32-h2/platformio.ini +++ b/variants/esp32h2/waveshare-esp32-h2/platformio.ini @@ -2,7 +2,9 @@ extends = esp32h2_base board = esp32-h2-devkitm-1 board_build.f_flash = 16000000L -board_level = pr +; Set this back to 'pr' once the CI plumbing is in place. +; board_level = pr +board_level = extra build_flags = ${esp32h2_base.build_flags} -I variants/esp32h2/waveshare-esp32-h2 From 54aa53aba4f60df5d8780b8b7ad68f4553891b1b Mon Sep 17 00:00:00 2001 From: vidplace7 Date: Sun, 7 Jun 2026 14:23:39 -0400 Subject: [PATCH 7/7] trunk fmt --- src/modules/SerialModule.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index 8ce879aa28f..d7320bf122f 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -540,8 +540,7 @@ ParsedLine parseLine(const char *line) */ void SerialModule::processWXSerial() { -#if SERIAL_PRINT_PORT != 0 && !defined(ARCH_STM32WL) && !defined(CONFIG_IDF_TARGET_ESP32C6) && \ - !defined(CONFIG_IDF_TARGET_ESP32H2) +#if SERIAL_PRINT_PORT != 0 && !defined(ARCH_STM32WL) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) static unsigned int lastAveraged = 0; static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded. static double dir_sum_sin = 0;