Add M5Stack FIRE board port (ESP32-classic, ILI9342C, no touch) - #146
Open
Sompong6103 wants to merge 4 commits into
Open
Add M5Stack FIRE board port (ESP32-classic, ILI9342C, no touch)#146Sompong6103 wants to merge 4 commits into
Sompong6103 wants to merge 4 commits into
Conversation
The splash<->usage screen toggle was driven only by a touchscreen tap (global_click_cb on LV_EVENT_CLICKED). Boards with no touch panel had no way to leave the splash at all — the PWR button only cycled animations, so the device sat on the splash forever even with data flowing. Add a `has_touch` field to BoardCaps and route the PWR button to ui_toggle_splash() (previously dead code) on touchless boards, giving them the splash<->usage navigation the tap provides elsewhere. Animations still auto-rotate (~20s) and follow the usage-rate group, so manual cycling isn't lost. Every existing board is a touch board and is set has_touch = true. No behavior change on touch boards. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gjg2WZ5FuhRRivQCL3sQm1
First ESP32-classic port (all others are S3/C6) and the first touch-less board. 320x240 ILI9342C TFT over 4-wire SPI, three front buttons in place of touch, IP5306 power-bank IC for battery, MPU6886 IMU (populated, unused). - display.cpp: Arduino_ILI9342 @ 40 MHz, ips=true, rotation 2 (upright with the front buttons along the bottom edge). LEDC-PWM backlight. - touch.cpp: permanent no-op (no touch panel); the has_touch=false cap makes the middle button (B) the splash<->usage toggle. - input.cpp: BtnA (GPIO39) -> HID Space, BtnC (GPIO37) -> HID Shift+Tab, on the input-only GPIOs (external pull-ups, plain INPUT). - power.cpp: IP5306 over I2C for battery (coarse 25/50/75/100% gauge) and charging; middle button (GPIO38) is the PWR-role button. No software power-off (the IP5306's side button handles hardware power). - sound.cpp: no-op (speaker is a DAC path, not the I2S/ES8311 chime engine). The m5stack-fire board JSON supplies the classic-ESP32 MCU, PSRAM (+ rev1 cache workaround), 16 MB flash and partitions, so the env stays minimal. No ARDUINO_USB_CDC_ON_BOOT: classic ESP32 has no native USB — Serial (and the screenshot command) run over UART0 through the CH9102 bridge, which also means upload is at 460800 (921600 is flaky on that bridge). Verified on hardware: display, orientation, IP5306 battery/charging, BLE data service end-to-end (live usage from the daemon), and button navigation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gjg2WZ5FuhRRivQCL3sQm1
The M5Stack FIRE is ESP32-classic over a CH9102 UART bridge, so it enumerates as /dev/cu.usbserial-* (or /dev/cu.wchusbserial*), not the /dev/cu.usbmodem* that the native-USB S3/C6 boards expose. Auto-detect only globbed usbmodem*, so `./flash-mac.sh m5stack_fire` failed to find the port. Make port detection board-aware and point at the CH34x/CH9102 driver in the not-found message. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PZgpe4j1XPLai2KY9PZTky
There was a problem hiding this comment.
Pull request overview
Adds a new firmware board port for the M5Stack FIRE (ESP32-classic, ILI9342C SPI TFT, no touch) and extends the existing board capability model so shared UI/navigation works on touchless targets.
Changes:
- Introduces a
BoardCaps.has_touchcapability and updates shared button handling to allow splash ↔ usage navigation without touch. - Adds
firmware/src/boards/m5stack_fire/implementing the HAL (display, input, power, etc.) for the M5Stack FIRE. - Updates PlatformIO env, flashing helper, and porting/docs to reflect support for ESP32-classic + non-touch boards.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| flash-mac.sh | Auto-detects UART-bridge serial devices for m5stack_fire vs native USB-JTAG for S3/C6 boards. |
| firmware/src/main.cpp | Routes PWR short-press differently for touchless boards via BoardCaps.has_touch. |
| firmware/src/hal/board_caps.h | Adds has_touch to runtime capabilities used by shared code. |
| firmware/src/boards/waveshare_lcd_154/caps.cpp | Sets has_touch = true for existing board. |
| firmware/src/boards/waveshare_amoled_216/caps.cpp | Sets has_touch = true for existing board. |
| firmware/src/boards/waveshare_amoled_216_c6/caps.cpp | Sets has_touch = true for existing board. |
| firmware/src/boards/waveshare_amoled_206/caps.cpp | Sets has_touch = true for existing board. |
| firmware/src/boards/waveshare_amoled_18/caps.cpp | Sets has_touch = true for existing board. |
| firmware/src/boards/waveshare_amoled_18_c6/caps.cpp | Sets has_touch = true for existing board. |
| firmware/src/boards/template/caps.cpp | Updates template to include has_touch guidance for new ports. |
| firmware/src/boards/m5stack_fire/touch.cpp | Implements a permanent no-op touch HAL for a non-touch device. |
| firmware/src/boards/m5stack_fire/sound.cpp | No-op sound HAL for the FIRE’s DAC speaker path (not I2S/ES8311). |
| firmware/src/boards/m5stack_fire/power.cpp | Implements IP5306 battery/charge + synthesized PWR button edges. |
| firmware/src/boards/m5stack_fire/input.cpp | Implements A/C front buttons on input-only GPIOs (active LOW). |
| firmware/src/boards/m5stack_fire/imu.cpp | No-op IMU HAL (fixed orientation). |
| firmware/src/boards/m5stack_fire/display.cpp | Implements ILI9342C SPI TFT + LEDC PWM backlight. |
| firmware/src/boards/m5stack_fire/caps.cpp | Declares FIRE runtime capabilities (size/buttons/battery/touch=false). |
| firmware/src/boards/m5stack_fire/board.h | Defines pin map and capability flags for the M5Stack FIRE. |
| firmware/src/boards/m5stack_fire/board_init.cpp | Initializes I2C bus for IP5306/MPU6886. |
| firmware/platformio.ini | Adds [env:m5stack_fire] and dependencies/build flags for the new target. |
| docs/porting/adding-a-board.md | Updates porting assumptions: broader ESP32 family + SPI TFT + optional touch. |
| CLAUDE.md | Updates project context/docs to include the new FIRE port and ESP32-classic support. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - `boards/waveshare_amoled_18_c6/` — Waveshare ESP32-C6-Touch-AMOLED-1.8 (368×448 portrait, SH8601, FT3168 touch, TCA9554 expander). Build env: `waveshare_amoled_18_c6`. Same panel as the S3 1.8 but on the C6 SoC. All subsystems (display, touch, BOOT + PWR buttons, battery, BLE) verified on hardware. | ||
| - `boards/waveshare_amoled_206/` — Waveshare ESP32-S3-Touch-AMOLED-2.06 (CO5300, 410×502 watch form factor, FT3168 touch, no IO expander, 32 MB flash, PCF85063 RTC, ES8311 codec). Build env: `waveshare_amoled_206`. Display, touch, battery, IMU init, and BLE verified on hardware; the ES8311 chime path is not wired up (`sound.cpp` no-ops). | ||
| - `boards/waveshare_lcd_154/` — Waveshare ESP32-S3-Touch-LCD-1.54 (ST7789, 240×240 square, CST816T touch @ 0x15). Build env: `waveshare_lcd_154`. **The first non-AMOLED port**: a plain 4-wire SPI TFT, not QSPI, and the panel has no brightness command — backlight is LEDC PWM on `LCD_BL`. **No PMU**: battery is an ADC divider on GPIO1 and `BAT_EN` (GPIO2) is a power-hold line that must be driven HIGH early in `board_init()` or the board browns out on battery. Three buttons (BOOT + GPIO5 + a PWR-role GPIO4); ES8311 chime wired up; QMI8658 populated but unused (fixed orientation, no rotation). | ||
| - `boards/m5stack_fire/` — M5Stack FIRE (ILI9342C, 320×240 landscape SPI TFT, **no touch**, IP5306 PMU, MPU6886 unused). Build env: `m5stack_fire`. **The first ESP32-classic port and the first touch-less board**: navigation is the three front buttons (A=GPIO39 left→Space, C=GPIO37 right→Shift+Tab, B=GPIO38 middle→PWR-role: cycle screens/brightness + hold-to-pair). Battery/charging come from the **IP5306** power-bank IC over I2C (coarse 25/50/75/100 % gauge, feeds the four-state icon); hardware power on/off is the IP5306's own red side button, so no software power-off. Speaker is a DAC path, not the I2S/ES8311 chime engine, so `sound.cpp` no-ops. Classic ESP32 has **no native USB** — Serial (and the `screenshot` command) run over UART0 through the on-board CH9102 bridge, which appears as `/dev/cu.usbserial-*` (macOS) / `/dev/ttyUSB*` (Linux), *not* `usbmodem*`. The `m5stack-fire` board JSON supplies PSRAM (+ the rev1 cache workaround), 16 MB flash and the 16 MB partitions, so the env stays minimal. 240px-tall → lands on the existing "small" (240×240) UI breakpoint; the extra 80px of width is unused headroom a future landscape breakpoint could claim. |
| // so input.cpp uses plain INPUT (not INPUT_PULLUP). | ||
| // A (left) → primary, HID Space (voice-mode PTT) | ||
| // C (right) → secondary, HID Shift+Tab (mode toggle) | ||
| // B (middle) → PWR-role, cycle screens / brightness / hold-to-pair |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add M5Stack FIRE board port (ESP32-classic, ILI9342C, no touch)
Summary
Adds a seventh board port: the M5Stack FIRE. It's the first ESP32-classic target (all existing ports are S3 or C6) and the first touch-less board, so it exercises two paths the HAL hadn't before.
Verified end-to-end on hardware: display + orientation, IP5306 battery/charging, the BLE data service showing live usage from the daemon (session 6% / weekly 50%), and button navigation.

What's in it
New board (
firmware/src/boards/m5stack_fire/)display.cpp—Arduino_ILI9342(mainline GFX ≥1.6.4) over 4-wire SPI @ 40 MHz,ips=true, rotation 2 (upright with the front buttons along the bottom edge). LEDC-PWM backlight, same as the LCD-1.54.touch.cpp— permanent no-op; there is no touch panel.input.cpp— front buttons A (GPIO39) → HID Space, C (GPIO37) → HID Shift+Tab, on the input-only GPIOs (external pull-ups, plainINPUT).power.cpp— IP5306 over I2C for battery (coarse 25/50/75/100 % gauge → the four-state icon) and charging; middle button B (GPIO38) is the PWR-role button. No software power-off — the IP5306's side button handles hardware power.imu.cpp/sound.cpp— MPU6886 unused (fixed orientation); speaker is a DAC path, not the I2S/ES8311 chime engine, so sound no-ops (same posture as the 2.06 / C6 ports).Touch-less navigation (
has_touchcapability)global_click_cbonLV_EVENT_CLICKED), so a board with no touch panel could never leave the splash — it sat there forever even with data flowing.has_touchfield toBoardCapsand routes the PWR button toui_toggle_splash()(previously dead code) on touch-less boards. Animations still auto-rotate (~20 s) and follow the usage-rate group, so manual cycling isn't lost.has_touch = true; no behavior change on them.Env + docs
[env:m5stack_fire]inplatformio.ini. Them5stack-fireboard JSON already supplies the classic-ESP32 MCU, PSRAM (+ rev1 cache workaround), 16 MB flash and partitions, so the env stays minimal.ARDUINO_USB_CDC_ON_BOOT: classic ESP32 has no native USB — Serial (and thescreenshotcommand) run over UART0 through the on-board CH9102 bridge, which enumerates as/dev/cu.usbserial-*//dev/ttyUSB*(notusbmodem*), and upload runs at 460800 (921600 is flaky on that bridge).CLAUDE.md+docs/porting/adding-a-board.mdupdated: the port disproves the old "S3-only / QSPI-AMOLED-only / touch-required" assumptions.Build / flash
./flash-mac.sh m5stack_fire # auto-detects or pio run -d firmware -e m5stack_fire pio run -d firmware -e m5stack_fire -t upload --upload-port /dev/cu.usbserial-XXXXNotes for reviewers / follow-ups
has_touchchange touches every board'scaps.cpp(one line each) — that's the intended blast radius of adding a capability field, not scope creep.power.cpp; the bolt reads correctly on this unit but the masks are worth a second look on other IP5306 revisions.Commits
feat: add has_touch cap so touchless boards navigate splash via PWRfeat: add M5Stack FIRE board portEach commit builds on its own.
🤖 Generated with Claude Code