Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
; Patternflow - PlatformIO build (Arduino core 2.x / IDF 4.4)
;
; WHY THIS EXISTS: the Arduino-IDE build on core 3.x (IDF 5.5) leaves ~15 KB of
; internal heap after services; the same source built here leaves ~98 KB. That
; generation occupies ~71 KB more internal RAM before the sketch even starts -
; the gap is already there at the first heap reading in setup(), before Wi-Fi is
; up, so it is not a network-buffer setting. Only ~15 KB of it is static (11 KB
; more code in IRAM, which shares physical SRAM with DRAM on the S3, plus ~3.5 KB
; of .data/.bss); the rest is heap taken during IDF startup.
;
; The headroom is what lets big .pfm modules load - a module's .text needs one
; contiguous internal executable block - and keeps the console alive with a heavy
; module resident. Measured 2026-08-18, same board: core3 15,320/7,668 vs core2
; 98,708/90,100 (free/largest after services), muybridge_35mm refused vs 48.5 fps.
;
; The build tool is incidental: PlatformIO's classic espressif32 platform pins
; core 2.0.17; the Arduino IDE here has 3.3.8. pioarduino would give core 3 under
; PlatformIO, and Boards Manager can install core 2 in the IDE. The variable is
; the core/IDF generation.
;
; WINDOWS + NON-ASCII REPO PATH: xtensa ld cannot open outputs under the Korean
; repo path. Build with the project copied to an ASCII path, or set
; PLATFORMIO_BUILD_DIR=C:/Users/<you>/pf-pio-build
; before `pio run`.
;
; ARDUINO_USB_CDC_ON_BOOT must stay 1: Improv-Serial (the browser flasher's
; Wi-Fi setup) listens on the native USB port via Serial. Setting it to 0 moves
; Serial to UART0 and silently breaks provisioning.
[platformio]
default_envs = firmware
src_dir = pio_src
include_dir = .
data_dir = data
[env:firmware]
platform = espressif32@7.0.1
board = esp32-s3-devkitc-1
framework = arduino
monitor_speed = 115200
board_build.mcu = esp32s3
board_build.f_cpu = 240000000L
board_build.f_flash = 80000000L
board_build.flash_mode = qio
board_build.arduino.memory_type = qio_opi
board_build.psram_type = opi
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
board_build.partitions = partitions/app3M_fat9M_16MB.csv
board_build.filesystem = fatfs
extra_scripts =
pre:toolchain/sync_ino_to_src.py
post:toolchain/copy_named_bin.py
build_unflags =
-std=gnu++11
-std=c++11
build_flags =
-std=gnu++17
-DBOARD_HAS_PSRAM
-DARDUINO_USB_MODE=1
-DARDUINO_USB_CDC_ON_BOOT=1
-I$PROJECT_DIR
-I$PROJECT_DIR/src
-I$PROJECT_DIR/abi
; NimBLE (features/ble): peripheral-only, one link, no bonding store, and
; the host's pools in PSRAM. Internal DRAM is what caps a loadable module,
; so every byte the host can take from PSRAM instead is a byte a pattern
; keeps. Unused in a build without the feature - gc-sections drops it.
-DCONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED
-DCONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED
-DCONFIG_BT_NIMBLE_MAX_CONNECTIONS=1
-DCONFIG_BT_NIMBLE_MAX_BONDS=1
-DCONFIG_BT_NIMBLE_MAX_CCCDS=4
-DCONFIG_BT_NIMBLE_NVS_PERSIST=0
-DCONFIG_BT_NIMBLE_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL=1
; Vendored HUB75 (src/hub75) has blitRGB888; ignore the Library Manager clone.
lib_ignore =
HUB75
WebServer
lib_ldf_mode = deep+
; Named, not discovered. The dependency finder works by scanning includes, and
; a feature now reaches the tree through `features_local.h` behind a
; `__has_include` that LDF cannot evaluate — so the audio edition compiled its
; websocket server against a library LDF had decided was unused, and failed on
; the include. Which features a build carries must not decide which libraries
; exist: unused ones cost link time and nothing in the image, because
; --gc-sections drops them.
lib_deps =
lib/WebSockets
HTTPClient
WiFiClientSecure
h2zero/NimBLE-Arduino@^2.5.1
lathoub/AppleMIDI@^3.5.0
build_src_filter =
+<*>
+<../src/hub75/*.cpp>
+<../src/hub75/platforms/esp32/*.cpp>
+<../src/hub75/platforms/esp32s3/*.cpp>
+<../src/pubsubclient/*.cpp>
+<../src/webserver/*.cpp>
+<../src/webserver/detail/*.cpp>
; Optional:
; upload_port = COM5
; monitor_port = COM5
; Two 64×64 HUB75 modules daisy-chained (ESP → panel A IN, A OUT → panel B IN).
; Same source as `firmware`; logical canvas stays 128×64 so the 128×64
; pattern pack and Director/Sequences behaviour match. Output:
; .pio/build/firmware64x2/firmware64x2.bin
[env:firmware64x2]
extends = env:firmware
build_flags =
${env:firmware.build_flags}
-DPANEL_GEOMETRY=PANEL_GEOM_64x64_CHAIN2
-DPF_IMPROV_FW_SUFFIX=\"-64x2\"
; ── MIDI edition: the DevKit's USB port as a MIDI device ──────────────────
; Same source, one flag: ARDUINO_USB_MODE=0. The S3 has one USB PHY and two
; owners for it - the fixed USB-Serial/JTAG every other build uses for
; flashing, Improv and the log, and the USB-OTG controller that can be any
; device class. A MIDI device needs OTG, and the Arduino core decides at
; compile time which of the two owns `Serial`, so the choice is an env, not
; a bundle setting; features/midi's USB transport compiles in only here.
; With ARDUINO_USB_MODE=0 the OTG stack presents CDC (still `Serial`: Improv
; and the log survive) plus MIDI; the product string is what Windows names
; the MIDI port after; the ROM's download mode is untouched, so the browser
; flasher flashes this image like any other. What a person notices: after a
; flash or a reset the port comes back as a different USB device (a
; composite), so a flasher session may need one reconnect. Built by
; `bundles/build.sh midi`, which reads this env's name from bundles/midi/env.
; The board's own extra_flags carry ARDUINO_USB_MODE=1, hence the unflag.
; Output: .pio/build/firmware_midi/firmware_midi.bin
[env:firmware_midi]
extends = env:firmware
build_unflags =
${env:firmware.build_unflags}
-DARDUINO_USB_MODE=1
build_flags =
${env:firmware.build_flags}
-DARDUINO_USB_MODE=0
-DUSB_PRODUCT=\"Patternflow\"
-DUSB_MANUFACTURER=\"Patternflow\"
e5b871ed5This file is pinned to the selected release. Download the original to open it in your design tool.