Skip to content

M5Stack Unit C6L: display support, dual-firmware OTA switching#1885

Open
TheRealHaoLiu wants to merge 9 commits intomeshcore-dev:devfrom
TheRealHaoLiu:main-m5stack-unit-c6l
Open

M5Stack Unit C6L: display support, dual-firmware OTA switching#1885
TheRealHaoLiu wants to merge 9 commits intomeshcore-dev:devfrom
TheRealHaoLiu:main-m5stack-unit-c6l

Conversation

@TheRealHaoLiu
Copy link

@TheRealHaoLiu TheRealHaoLiu commented Mar 1, 2026

Summary

Complete M5Stack Unit C6L support with correct hardware configuration, display, and dual-firmware OTA switching. This is a superset of #1884 — includes all the pin/IO expander fixes plus additional features.

Note: This PR includes all fixes from #1884. Merge one or the other, not both.

Hardware fixes (same as #1884)

  • Correct I2C pins, TCXO voltage, NeoPixel, USB CDC
  • Add PI4IO I2C GPIO expander support
  • Remove incorrect SX126X_RXEN

New features

  • SSD1306 64x48 SPI display driver: New SSD1306SPIDisplay class with fix for Adafruit library missing 64x48 COM pins configuration
  • Dual-firmware OTA switching: Hold BOOT button during power-on to switch between repeater and companion firmware stored in separate OTA partitions, with buzzer feedback
  • Repeater display UI: Boot screen, node name with marquee scrolling, radio parameters, I2C expander button wake
  • Companion display UI: Boot screen, BLE PIN display, node name with marquee scrolling, frequency, unread message count
  • USB companion radio: Added USB serial companion mode alongside BLE
  • File organization: Variant-specific UITasks in companion/ and repeater/ subdirectories

Code review fixes

  • Removed hardcoded US-only LoRa frequency overrides — inherit defaults from arduino_base like all other variants
  • Extracted MarqueeScroller struct into DisplayDriver.h to deduplicate scroll logic between companion and repeater UITasks
  • Fixed USB companion display incorrectly showing "Connected" — now shows "USB Ready"

Test plan

  • All four environments build (companion BLE, companion USB, repeater, room server)
  • Tested on actual M5Stack Unit C6L hardware
  • OTA partition switching works via BOOT button hold
  • Display renders correctly on 64x48 SSD1306 OLED
  • Marquee scrolling works for long node names
  • Button wakes display after auto-off
  • Both firmware identities preserved independently in SPIFFS
  • USB companion mode connects and works with companion app
  • BLE companion mode shows PIN correctly

🤖 Generated with Claude Code

@TheRealHaoLiu TheRealHaoLiu marked this pull request as draft March 1, 2026 03:26
@TheRealHaoLiu TheRealHaoLiu force-pushed the main-m5stack-unit-c6l branch 4 times, most recently from 7f42d19 to fe20d79 Compare March 1, 2026 03:57
@TheRealHaoLiu TheRealHaoLiu marked this pull request as ready for review March 1, 2026 04:02
Copy link

@wbijen wbijen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work getting the C6L fully functional with display, IO expander, and buzzer support. Left some review comments.

One thing: I think this should target dev rather than main.

return true;
}

void checkOTASwitch() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice feature — OTA partition switching makes good use of the 16MB flash and gives users a way to swap between repeater and companion without reflashing. That said, this feels like it could be its own PR since it's not C6L-specific — any dual-partition ESP32 board could benefit. Splitting it out would make it easier to review the hardware/display changes here independently, and let other variants adopt OTA switching too.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if its ok i will submit a PR to refactor this as a follow up

@TheRealHaoLiu TheRealHaoLiu changed the base branch from main to dev March 4, 2026 01:21
@TheRealHaoLiu TheRealHaoLiu force-pushed the main-m5stack-unit-c6l branch from 93d4511 to 06b75f3 Compare March 4, 2026 01:26
@TheRealHaoLiu
Copy link
Author

Great work getting the C6L fully functional with display, IO expander, and buzzer support. Left some review comments.

One thing: I think this should target dev rather than main.

rebased against dev

TheRealHaoLiu and others added 3 commits March 3, 2026 20:29
Add companion_radio_ble build for M5Stack Unit C6L (ESP32-C6 with SX1262).

Features:
- PI4IO I/O expander support for LoRa RF control (LNA, RF switch, reset)
- Button input via I/O expander
- Buzzer support
- US/Canada frequency preset (910.525 MHz, SF7, BW62.5, CR5)
- BLE companion radio interface

Hardware pins:
- SPI: SCLK=20, MISO=22, MOSI=21, NSS=23
- LoRa: DIO1=7, BUSY=19, reset via I/O expander
- I2C: SDA=10, SCL=8
- NeoPixel TX LED: GPIO2
- Buzzer: GPIO11

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add SSD1306SPIDisplay driver with lazy initialization for SPI bus sharing
- Add minimal UITask for 64x48 display showing PIN, node name, frequency
- Share SPI bus between LoRa radio and display with spi_initialized flag
- Support display auto-off after 30 seconds and button wake

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rename companion_radio_ble env to follow naming conventions
- Add m5stack_unit_c6l_repeater with packet logging
- Add m5stack_unit_c6l_room_server with packet logging
- All environments use matching LoRa settings (910.525MHz, SF7, BW62.5)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@TheRealHaoLiu TheRealHaoLiu force-pushed the main-m5stack-unit-c6l branch from 06b75f3 to 0adb940 Compare March 4, 2026 01:29
TheRealHaoLiu and others added 5 commits March 3, 2026 21:19
…Unit C6L

- Add OTA partition switching via BOOT button hold during startup,
  allowing switching between repeater and companion firmware without
  reflashing. Buzzer feedback indicates switch or error.
- Fix SSD1306 64x48 display garbled output by setting correct COM pins
  configuration (0x12) after Adafruit library init, which lacks a 64x48
  case. Disable text wrap to prevent long text from overflowing.
- Fix ESP32-C6 BLE build by adding missing esp_mac.h include for
  esp_efuse_mac_get_default().
- Add display support to repeater build with C6L-specific UITask
  featuring boot screen, marquee scrolling for long node names,
  and I2C expander button wake.
- Add boot screen to companion UITask showing MeshCore version and
  mode, with marquee scrolling and unread message count.
- Reorganize variant UITask files into companion/ and repeater/
  subdirectories for consistency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix strdup memory leak in repeater UITask: use stack buffer instead
- Remove redundant _display null check in companion UITask (already
  guarded at top of loop())
- Remove redundant build_src_filter exclusions in companion, repeater,
  and room_server envs (base config already handles them)
- Remove repeater UITask.h copy: include original header directly via
  relative path instead of maintaining a duplicate
- Remove unused -I flag for repeater subdirectory
- Delete upstream UnitC6LBoard.h/cpp (replaced by M5StackUnitC6LBoard)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Inherit LORA_FREQ/SF/BW/CR defaults from arduino_base like all other
variants. These are only first-boot defaults anyway; saved NodePrefs
take priority on subsequent boots.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a reusable MarqueeScroller struct alongside DisplayDriver and
refactors both companion and repeater UITask to use it, eliminating
duplicated marquee logic with inconsistent state storage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@TheRealHaoLiu TheRealHaoLiu force-pushed the main-m5stack-unit-c6l branch from 0adb940 to 973d8c1 Compare March 4, 2026 02:19
ArduinoSerialInterface::isConnected() always returns true, so USB
mode permanently showed "Connected". Use BLE_PIN_CODE ifdef to show
BLE PIN/connected status in BLE mode and "USB Ready" in USB mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@TheRealHaoLiu TheRealHaoLiu requested a review from wbijen March 4, 2026 02:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants