Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions pio-scripts/enable_lto_s3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env python3
"""
Enable Link Time Optimization (LTO) for PlatformIO / Xtensa ESP32-S3 builds.

Simply adding -flto to build_flags is not sufficient: LTO also requires the
linker to receive -flto and the archiver/ranlib to be the GCC-LTO-aware
variants (gcc-ar / gcc-ranlib). This script wires all three up so that the
flag is consistently applied and the static-library archives are built in a
way that LTO can see through them.
"""
## This script was created with the help of an AI, reviewed by @troyhacks

Import("env")
import os
import shutil

def _find_tool(name, cc_dir):
"""Locate a toolchain binary: check cc_dir first, then PATH."""
if cc_dir:
for suffix in ("", ".exe"):
candidate = os.path.join(cc_dir, name + suffix)
if os.path.isfile(candidate):
return candidate
# Fall back to searching PATH
return shutil.which(name)

def enable_lto(env):
# -flto: LTO itself.
# -fipa-pta: interprocedural pointer analysis — requires whole-program IR, only useful with LTO.
# -ffunction-sections / -fdata-sections / -Wl,--gc-sections: linker dead-code elimination;
# far more effective with LTO because the linker has cross-TU visibility.
LTO_CCFLAGS = ["-flto", "-fipa-pta", "-ffunction-sections", "-fdata-sections"]
LTO_LDFLAGS = ["-flto", "-Wl,--gc-sections"]

for flaglist, new_flags in (("CCFLAGS", LTO_CCFLAGS),
("CXXFLAGS", LTO_CCFLAGS),
("LINKFLAGS", LTO_LDFLAGS)):
existing = env.get(flaglist, [])
to_add = [f for f in new_flags if f not in existing]
if to_add:
env.Append(**{flaglist: to_add})

# Swap ar / ranlib for the LTO-aware GCC wrappers so that static
# library archives carry IR that the linker can optimise across.
cc = str(env.get("CC", ""))
if cc:
toolchain_prefix = cc.replace("gcc", "").replace("g++", "")
# toolchain_prefix is something like "xtensa-esp32s3-elf-"
new_ar = toolchain_prefix + "gcc-ar"
new_ranlib = toolchain_prefix + "gcc-ranlib"

# Resolve CC to its real path so we can search the same directory
cc_resolved = shutil.which(cc) or cc
cc_dir = os.path.dirname(cc_resolved)

ar_path = _find_tool(new_ar, cc_dir)
if ar_path:
env.Replace(AR=ar_path)
print(f"enable_lto: AR -> {ar_path}")
else:
print(f"enable_lto: gcc-ar '{new_ar}' not found, keeping default AR")

ranlib_path = _find_tool(new_ranlib, cc_dir)
if ranlib_path:
env.Replace(RANLIB=ranlib_path)
print(f"enable_lto: RANLIB -> {ranlib_path}")
else:
print(f"enable_lto: gcc-ranlib '{new_ranlib}' not found, keeping default RANLIB")

print("enable_lto: -flto added to CCFLAGS / CXXFLAGS / LINKFLAGS")

enable_lto(env)
63 changes: 63 additions & 0 deletions usermods/M5Stack_CoreS3_Display/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# M5Stack Core S3 Display Usermod

Display usermod for the ILI9342C 320x240 TFT display on the M5Stack Core S3, using LovyanGFX.

## Pin Mapping (M5Stack Core S3)

| ESP32-S3 | ILI9342C | Description |
|----------|----------|-----------------|
| G37 | MOSI | SPI Data |
| G36 | SCLK | SPI Clock |
| G3 | CS | Chip Select |
| G35 | DC | Data/Command |

Reset is controlled via the AW9523B GPIO expander (P1_1). Backlight is powered via AXP2101 PMU (DLDO1).

## Building

In `platformio_override.ini` for your M5Stack Core S3 environment:

```build_flags =
-D USERMOD_M5STACK_CORE_S3_DISPLAY
;; For the M5Stack ModuleAudio:
-D SR_ENABLE_DEFAULT
-D SR_DMTYPE=6
-D I2S_SDPIN=13
-D I2S_WSPIN=6
-D I2S_CKPIN=0
-D MCLK_PIN=7
-D HW_SDA_PIN=12
-D HW_SCL_PIN=11

lib_deps =
https://github.com/lovyan03/LovyanGFX```

Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
## Features

- SSID and IP address in header bar
- 16-band graphic equalizer bars (differential drawing)
- Real audio reactive data when Audioreactive usermod is enabled
- Simulated bouncing bars when no audio data
- Rainbow color per bar (red → violet)
- Maximum of 100 FPS to match AudioReactive
- Minimum of 5 FPS so it updates even if you use unlimited FPS mode.

## Display Notes

- Uses LovyanGFX with `SPI3_HOST` (HSPI)
- Native landscape 320x240 resolution
- BGR color order, display inversion enabled
- Backlight always on (controlled by AXP2101 DLDO1)
Comment thread
coderabbitai[bot] marked this conversation as resolved.

## TroyHacks Recommended AudioReactive Settings

For the M5Stack Core S3 + ModuleAudio line-in:

- The ModuleAudio uses an ES8388
- Squelch & Gain at 1
- AGC is Normal
- MicLev is Freeze
- Mic Quality is Perfect
- FFT Window is Nutall (or whatever you prefer)
- Profile is Generic Line-In
- Limiter is Enabled, with a rise of 1 and a fall of 250 (to 500).
Loading
Loading