Add Heltec WiFi LoRa 32 V4-R2 (ILI9341 2.8" touch display) variant - #11218
Add Heltec WiFi LoRa 32 V4-R2 (ILI9341 2.8" touch display) variant#11218MuddyPaws2 wants to merge 9 commits into
Conversation
…pping - Extend esp32s3_base instead of heltec_v4_base to avoid heltec_v4/variant.h shadowing the R2 header and causing TFTDisplay.cpp to compile incorrectly - LGFX_PIN_MISO=-1: GPIO26 is PSRAM CS on ESP32-S3, must not be used for SPI - LGFX_ROTATION=2, VIEW_320x240, DISPLAY_SIZE=320x240: working display orientation - Add HELTEC_V4_R2 to architecture.h hw model mapping (-> HELTEC_V4, model 110) - Add HELTEC_V4_R2 to NodeDB BT default-off list for MUI boards Note: lv_conf.h in meshtastic/device-ui also needs updating to guard LV_MEM_POOL_ALLOC with CONFIG_SPIRAM_USE_MALLOC detection (see separate PR).
|
|
1 similar comment
|
|
@MuddyPaws2, Welcome to Meshtastic!Thanks for opening your first pull request. We really appreciate it. We discuss work as a team in discord, please join us in the #firmware channel. Welcome to the team 😄 |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds Heltec V4 R2 support through ESP32-S3 pin and hardware definitions, PlatformIO build and display configuration, hardware-model mapping, and TFT-specific Bluetooth initialization handling. ChangesHeltec V4 R2 hardware support
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Adds a new ESP32-S3 hardware variant for Heltec WiFi LoRa 32 V4-R2, targeting MUI/device-ui with an external ILI9341 SPI display and FT6336 touch, and wires it into the existing ESP32 hardware-model and default-config logic.
Changes:
- Added a new
heltec_v4_r2variant (pins + PlatformIO environment + build flags) for ILI9341 + FT6336 (MUI). - Mapped
HELTEC_V4_R2to the existingmeshtastic_HardwareModel_HELTEC_V4vendor/model selection. - Included
HELTEC_V4_R2in the “TFT devices default BT off” list.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| variants/esp32s3/heltec_v4_r2/variant.h | New variant pin definitions for SX1262 + GPS + external SPI TFT + I2C touch. |
| variants/esp32s3/heltec_v4_r2/platformio.ini | New PlatformIO env/build flags for MUI + LGFX generic ILI9341 + FT5x06 touch config. |
| variants/esp32s3/heltec_v4_r2/pins_arduino.h | Arduino pin mapping header for the new variant directory. |
| src/platform/esp32/architecture.h | Adds HELTEC_V4_R2 hardware-model mapping to HELTEC_V4. |
| src/mesh/NodeDB.cpp | Adds HELTEC_V4_R2 to TFT targets that default Bluetooth to disabled. |
| ; Display SPI wiring (SPI3_HOST): | ||
| ; GPIO47 → SCK GPIO33 → MOSI GPIO26 → MISO | ||
| ; GPIO34 → LCD_CS GPIO21 → LCD_RS GPIO48 → LCD_RST GPIO35 → LED/BL |
| #define PIN_GPS_RESET (42) | ||
| #define GPS_RESET_MODE LOW | ||
| #define PIN_GPS_EN (34) | ||
| #define GPS_EN_ACTIVE LOW |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@variants/esp32s3/heltec_v4_r2/platformio.ini`:
- Around line 5-7: Update the display SPI wiring comment near the LGFX_PIN_MISO
configuration to remove GPIO26 as the display MISO connection, reflecting that
MISO is disabled and GPIO26 is reserved for PSRAM. Keep the remaining SCK, MOSI,
chip-select, control, reset, and backlight mappings unchanged.
In `@variants/esp32s3/heltec_v4_r2/variant.h`:
- Around line 61-62: Resolve the GPIO34 ownership conflict: in
variants/esp32s3/heltec_v4_r2/variant.h lines 61-62, assign PIN_GPS_EN to the
dedicated GNSS control pin or disable GPS power control if unavailable; in
variants/esp32s3/heltec_v4_r2/platformio.ini lines 84-86, assign LGFX_PIN_CS to
the display’s actual chip-select pin other than GPIO34.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 477634c3-41f5-4444-9db5-9e1aa3411bb9
📒 Files selected for processing (5)
src/mesh/NodeDB.cppsrc/platform/esp32/architecture.hvariants/esp32s3/heltec_v4_r2/pins_arduino.hvariants/esp32s3/heltec_v4_r2/platformio.inivariants/esp32s3/heltec_v4_r2/variant.h
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/mesh/NodeDB.cpp (3)
3109-3117: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftDo not report skipped profile writes as successful.
Clearing
SEGMENT_CONFIGorSEGMENT_CHANNELSwhile leavingsuccess == truecauses callers to believe the save succeeded, although the changes will be lost across reboot. Preserve a pending mask/retry path or return an explicit failure/deferred status.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/mesh/NodeDB.cpp` around lines 3109 - 3117, Update the event profile save logic around eventProfileStorageUnavailable so clearing SEGMENT_CONFIG or SEGMENT_CHANNELS also prevents the operation from reporting success. Preserve or introduce a pending-mask/retry path for those skipped segments, or propagate an explicit failure/deferred status through the surrounding save function instead of leaving success true.
2825-2827: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winTreat absent event files as a successful no-op.
disableLockdownToPlaintext()rejects an absentEVENT_*file becausemigrateFileToPlaintext()returnsfalsewhenFSCom.open()fails. Since the contract documents this helper as idempotent/successful for already-plaintext or non-encrypted files, normal builds without those event files should be allowed to continue instead of leaving the device in lockdown.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/mesh/NodeDB.cpp` around lines 2825 - 2827, Update the file-migration flow used by disableLockdownToPlaintext() so missing EVENT_* files are treated as successful no-ops rather than failures from migrateFileToPlaintext(). Preserve failure handling for other filesystem or migration errors, while retaining idempotent success for already-plaintext or non-encrypted files.
2847-2854: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftRecord and flush deferred radio-profile saves.
If
saveProto()is called forconfigFileName,channelFileName, orbackupFileNamebeforeconfigLoadComplete, it returnstruewithout writing. Store each pending radio-profile file/segment and flush it after config recovery succeeds, or make callers handle the deferred result; otherwise a save can appear successful while being dropped.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/mesh/NodeDB.cpp` around lines 2847 - 2854, Update the saveProto deferral path guarded by isRadioProfileFile and shouldDeferBootPersistence to retain each deferred configFileName, channelFileName, or backupFileName save, including its segment data, and flush those pending saves after config recovery succeeds. Alternatively, propagate the deferred result so callers retry, but do not report success while dropping the write; preserve immediate writes for non-deferred files.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/mesh/NodeDB.cpp`:
- Around line 3109-3117: Update the event profile save logic around
eventProfileStorageUnavailable so clearing SEGMENT_CONFIG or SEGMENT_CHANNELS
also prevents the operation from reporting success. Preserve or introduce a
pending-mask/retry path for those skipped segments, or propagate an explicit
failure/deferred status through the surrounding save function instead of leaving
success true.
- Around line 2825-2827: Update the file-migration flow used by
disableLockdownToPlaintext() so missing EVENT_* files are treated as successful
no-ops rather than failures from migrateFileToPlaintext(). Preserve failure
handling for other filesystem or migration errors, while retaining idempotent
success for already-plaintext or non-encrypted files.
- Around line 2847-2854: Update the saveProto deferral path guarded by
isRadioProfileFile and shouldDeferBootPersistence to retain each deferred
configFileName, channelFileName, or backupFileName save, including its segment
data, and flush those pending saves after config recovery succeeds.
Alternatively, propagate the deferred result so callers retry, but do not report
success while dropping the write; preserve immediate writes for non-deferred
files.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 5b42f5d5-207e-4999-8f9a-3d22d2945bdd
📒 Files selected for processing (1)
src/mesh/NodeDB.cpp
There was a problem hiding this comment.
Are you sure we need this additional target? There is already another Heltec V4 R2 target:
https://github.com/meshtastic/firmware/tree/develop/variants/esp32s3/heltec_v4
If there are slight changes I would prefer to do device variant detection at runtime and switch accordingly as we do with other devices. So the user can use the same firmware on whatever device variant.
Edit: ok I see there's another touch controller and different display which require a new target, though I think it could be put and merged into the existing variants/esp32s3/heltec_v4 directory.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.vscode/settings.json:
- Around line 13-14: Remove the committed "idf.currentSetup" setting from the
workspace settings so no concrete ESP-IDF installation path is shared. Leave
ESP-IDF setup to each contributor’s user or workspace-local configuration while
preserving the other settings.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 18650ed6-e567-405c-ab47-d247e448afb6
📒 Files selected for processing (3)
.vscode/settings.jsonvariants/esp32s3/heltec_v4_r2/platformio.inivariants/esp32s3/heltec_v4_r2/variant.h
🚧 Files skipped from review as they are similar to previous changes (2)
- variants/esp32s3/heltec_v4_r2/variant.h
- variants/esp32s3/heltec_v4_r2/platformio.ini
| }, | ||
| "idf.currentSetup": "C:\\esp\\v6.0.1\\esp-idf" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "git status:"
git status --short || true
echo
echo "tracked settings files:"
git ls-files | grep -E '(^|/)(settings|extensions)\.json$' || true
echo
echo ".vscode/settings.json if present:"
if [ -f .vscode/settings.json ]; then
nl -ba .vscode/settings.json | sed -n '1,80p'
else
echo "missing"
fi
echo
echo "search idf.currentSetup in repo:"
rg -n '"idf\.currentSetup"|idf\.currentSetup' . || trueRepository: meshtastic/firmware
Length of output: 338
🌐 Web query:
esp-idf vscode extension idf.currentSetup setting currentSetup documentation
💡 Result:
The idf.currentSetup setting in the ESP-IDF VS Code extension is a configuration identifier used to store and track the currently selected ESP-IDF installation [1][2]. Key details regarding this setting: * Function: It serves as a pointer to the specific ESP-IDF setup (path, tools, and environment configuration) being used for the current project or workspace folder [3][4]. When you select an ESP-IDF version using the command ESP-IDF: Select Current ESP-IDF Version, the extension saves this selection in idf.currentSetup to ensure the correct environment variables are applied to your project [3][5]. * Scope: The setting has a Resource scope [1][2], meaning it is intended to be stored in workspace settings (e.g., .vscode/settings.json) or as part of a workspace folder state [3]. * Management: Users typically do not edit this setting manually. Instead, it is managed automatically by the extension through the ESP-IDF: Select Current ESP-IDF Version command [3][5]. * Precedence: If you have manually configured ESP-IDF environment variables (such as IDF_PATH, IDF_TOOLS_PATH, or IDF_PYTHON_ENV_PATH) in your VS Code settings, the extension will prioritize those over the setup selected via idf.currentSetup [4]. To utilize the idf.currentSetup configuration, you should ensure that manual environment variable overrides are cleared [4]. For further details on configuring or troubleshooting your setup, you can refer to the official ESP-IDF Extension Settings documentation or the extension's installation guide [2][4].
Citations:
- 1: https://docs.espressif.com/projects/vscode-esp-idf-extension/en/latest/settings.html?highlight=baud+rate
- 2: https://docs.espressif.com/projects/vscode-esp-idf-extension/en/latest/settings.html
- 3: https://github.com/espressif/vscode-esp-idf-extension
- 4: https://docs.espressif.com/projects/vscode-esp-idf-extension/en/latest/installation.html
- 5: https://developer.espressif.com/blog/2026/05/esp-idf-vs-code-extension-v2-1-0/
🌐 Web query:
site:docs.espressif.com projects vs-code-esp-idf-extension currentSetup setting
💡 Result:
The idf.currentSetup setting in the ESP-IDF extension for Visual Studio Code is used to store the identifier for your current ESP-IDF installation configuration [1]. It is a resource-scoped setting [1]. When you use the command "ESP-IDF: Select Current ESP-IDF Version" from the VS Code Command Palette, the extension displays a list of available ESP-IDF setups [2]. Once you select a setup, the extension automatically updates idf.currentSetup with the path to the chosen ESP-IDF installation [2]. This selection ensures the extension correctly configures the required environment variables—such as IDF_PATH, IDF_TOOLS_PATH, and IDF_PYTHON_ENV_PATH—for that specific project [2]. Key considerations regarding this setting: - Manual vs. Automatic: While the extension handles this setting automatically when you use the "Select Current ESP-IDF Version" command, it acts as the primary reference for the extension to know which ESP-IDF environment to use [2]. - Priority: If you have manually defined ESP-IDF environment variables in your system or VS Code environment, the extension will prioritize those over the setup selected in idf.currentSetup [2]. To ensure the extension uses your selected idf.currentSetup, you should clear any manually set ESP-IDF environment variables [2]. - Storage: When a setup is selected, the extension configures environment variables and saves them as part of the workspace folder state [2].
Citations:
- 1: https://docs.espressif.com/projects/vscode-esp-idf-extension/en/latest/settings.html
- 2: https://docs.espressif.com/projects/vscode-esp-idf-extension/en/latest/installation.html
🏁 Script executed:
#!/bin/sh
set -u
echo "tracked settings files:"
git ls-files | grep -E '(^|/)(settings|extensions)\.json$' || true
echo
echo ".vscode/settings.json:"
cat -n .vscode/settings.json | sed -n '1,90p' || true
echo
echo "search idf.currentSetup in repo:"
grep -RIn '"idf\.currentSetup"' . || trueRepository: meshtastic/firmware
Length of output: 890
🌐 Web query:
GitHub esp-idf extension idf.currentSetup settings currentSetup extension current.setup
💡 Result:
The idf.currentSetup setting in the ESP-IDF VS Code extension is an identifier used to track the currently selected ESP-IDF installation [1][2]. It is primarily managed automatically by the extension rather than being manually configured by the user [3]. Key details regarding idf.currentSetup include: Purpose and Function: When you use the command ESP-IDF: Select Current ESP-IDF Version, the extension selects an ESP-IDF setup from your available installations [4][3]. This selected version is saved as the idf.currentSetup in your workspace state, allowing the extension to automatically configure the necessary environment variables (such as IDF_PATH, IDF_TOOLS_PATH, and Python paths) for that specific project [5][3]. Management: - Automatic Configuration: The value is set automatically when you switch versions via the command palette [3]. - Priority: If you have manually defined environment variables using idf.customExtraVars in your settings.json, the extension will prioritize those manual configurations over the idf.currentSetup selection [5][3]. To use an ESP-IDF setup selected via idf.currentSetup, you should ensure that conflicting environment variables in idf.customExtraVars are removed [5]. - Scope: The setting is scoped to the Resource (workspace folder) level [1][2]. Usage: If you need to change your active ESP-IDF version, you should use the VS Code Command Palette: 1. Open the Command Palette (Ctrl+Shift+P or Cmd+Shift+P). 2. Type and select ESP-IDF: Select Current ESP-IDF Version. 3. Choose the desired setup from the provided list [4][6]. You can verify the current configuration and ensure it is working correctly by running the ESP-IDF: Doctor Command from the Command Palette [4][7].
Citations:
- 1: https://docs.espressif.com/projects/vscode-esp-idf-extension/en/latest/settings.html?highlight=baud+rate
- 2: https://docs.espressif.com/projects/vscode-esp-idf-extension/en/latest/settings.html
- 3: https://developer.espressif.com/blog/2026/05/esp-idf-vs-code-extension-v2-1-0/
- 4: https://github.com/espressif/vscode-esp-idf-extension
- 5: https://docs.espressif.com/projects/vscode-esp-idf-extension/en/latest/installation.html
- 6: https://github.com/espressif/vscode-esp-idf-extension/?tab=readme-ov-file
- 7: https://github.com/espressif/vscode-esp-idf-extension/blob/master/README.md
Remove the concrete ESP-IDF path from .vscode/settings.json.
Line 14 pins every workspace to C:\esp\v6.0.1\esp-idf, leaving non-Windows or other-contributor setups without a valid ESP-IDF reference. Keep this as manual/user or workspace-local ESP-IDF state instead of committing a hard-coded setup path.
Proposed fix
"[powershell]": {
"editor.defaultFormatter": "ms-vscode.powershell"
- },
- "idf.currentSetup": "C:\\esp\\v6.0.1\\esp-idf"
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| }, | |
| "idf.currentSetup": "C:\\esp\\v6.0.1\\esp-idf" | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.vscode/settings.json around lines 13 - 14, Remove the committed
"idf.currentSetup" setting from the workspace settings so no concrete ESP-IDF
installation path is shared. Leave ESP-IDF setup to each contributor’s user or
workspace-local configuration while preserving the other settings.
Summary
Adds firmware support for the Heltec WiFi LoRa 32 V4-R2, an ESP32-S3 + SX1262 board that pairs the standard Heltec V4 LoRa hardware with an external 2.8" ILI9341V SPI display (240×320) and FT6336G capacitive touch controller (I2C), running MUI (meshtastic-device-ui).
Hardware
Pin assignments
Display SPI (SPI3_HOST): SCK=47, MOSI=33, MISO=NC, DC=21, CS=34, RST=48, BL=35
Touch I2C (Wire/port 0): SDA=4, SCL=3, RST=45
Changes
variants/esp32s3/heltec_v4_r2/— new variant directory (variant.h,platformio.ini,pins_arduino.h)src/platform/esp32/architecture.h— mapHELTEC_V4_R2→HW_VENDOR meshtastic_HardwareModel_HELTEC_V4(model 110)src/mesh/NodeDB.cpp— addHELTEC_V4_R2to the MUI BT default-off listKey notes
Base extends
esp32s3_base, notheltec_v4_base: inheritingheltec_v4_baseprepends-I variants/esp32s3/heltec_v4to the include path, causing the V4'svariant.hto shadow the R2 header and incorrectly compileTFTDisplay.cpp.LVGL PSRAM allocator: With
CONFIG_SPIRAM_USE_MALLOC=y,heap_caps_aligned_alloc(..., MALLOC_CAP_SPIRAM)returns NULL. A companion PR tomeshtastic/device-uiwill fixlv_conf.hto usemalloc()instead for this configuration.Attestations
Summary by CodeRabbit