Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion docs/explanation/architecture/moonbase.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Dual-OTA spends half the app area on a second copy of the firmware that is idle

A 4 MB board has no choice, having room for one application and not two, and its app slot grows by a third in exchange. On a **16 MB** board the choice is deliberate rather than forced, and the freed 4 MB goes to the filesystem, 11 MB rather than 7.

Which boards use MoonBase is a per-variant decision recorded in `moondeck/build/build_esp32.py` rather than a property of flash size. Today the 4 MB classic, the S3-Zero and `esp32-16mb` use it, and it may become the default everywhere.
Which boards use MoonBase is a per-variant decision recorded in `moondeck/build/build_esp32.py` rather than a property of flash size; [the build system](../../reference/build-system.md) lists the variants that use it. It may become the default everywhere.

## The update cycle

Expand Down
6 changes: 6 additions & 0 deletions docs/reference/MIGRATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ For a device still on old firmware (no Backup button yet), the [installer page](

## v7.0.0

### The Adafruit MatrixPortal S3 has its own firmware, `esp32s3-n8r2`

**Action: *nothing*; to use the board's whole 8 MB, *install over USB* once with *Erase chip first* ticked.**

A MatrixPortal ran the `esp32s3-zero` image, which keeps working on it but uses 4 MB of its 8. The `esp32s3-n8r2` image has a 3 MB app slot and 4 MB of filesystem. Its partition table differs from the Zero's, which an update over the air never rewrites, so moving takes one install over USB, and the device comes back unprovisioned: take a backup first and restore it after.

### Network Send fills each universe with `channels_per_universe` channels exactly

**Action: on a Network Send driving fixtures whose channels do not divide 510 over Art-Net or E1.31, such as RGBW strips (4) or a 13-channel moving head, set `channels_per_universe` to a multiple of the fixture's channels, 508 or 507, where the receiver needs each fixture inside one universe. RGB, RGBWW and 6-channel fixtures need nothing.**
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/build-system.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ The Ethernet PHY and its pins are runtime settings. Each firmware carries the dr

## MoonBase and the partition layout

Some variants carry [MoonBase](../explanation/architecture/moonbase.md), the second boot image: `esp32`, `esp32-eth`, `esp32-wrover`, `esp32-pico`, `esp32-16mb`, `esp32s3-zero`, `esp32c3`, and `qemu`, which is emulated. On those, `flash_esp32.py` writes the whole layout in one pass: the app in the large `ota_0` slot, MoonBase in `factory`, and an otadata that boots the app. A network update writes the app and never the partition table, so a device on an older table adopts a new one only through a full serial flash. On the 4 MB classic that also moves the filesystem, and the device comes back unprovisioned.
Some variants carry [MoonBase](../explanation/architecture/moonbase.md), the second boot image: `esp32`, `esp32-eth`, `esp32-wrover`, `esp32-pico`, `esp32-16mb`, `esp32s3-zero`, `esp32s3-n8r2`, `esp32c3`, and `qemu`, which is emulated. On those, `flash_esp32.py` writes the whole layout in one pass: the app in the large `ota_0` slot, MoonBase in `factory`, and an otadata that boots the app. A network update writes the app and never the partition table, so a device on an older table adopts a new one only through a full serial flash. On the 4 MB classic that also moves the filesystem, and the device comes back unprovisioned.

## ESP-IDF version

Expand Down
1 change: 1 addition & 0 deletions docs/reference/hardware/firmware-variants.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Selected by `build_esp32.py --firmware <key>`, reported by `SystemModule.firmwar
| `esp32-eth` | classic | Ethernet only, WiFi excluded |
| `esp32-16mb` | classic, 16 MB flash | WiFi and Ethernet |
| `esp32s3-n16r8`, `esp32s3-n8r8` | S3 | WiFi and W5500 SPI Ethernet |
| `esp32s3-zero`, `esp32s3-n8r2` | S3 with quad PSRAM: 4 MB flash on the Zero, 8 MB on the N8R2 | WiFi only |
| `esp32s3-n32r16` | S3 WROOM-2 N32R16V: 32 MB octal flash, 16 MB octal PSRAM | WiFi and W5500 SPI Ethernet; GPIO35 to 37 belong to the octal flash and PSRAM |
| `esp32p4rev1-eth` | P4 rev 1 (Waveshare ESP32-P4-NANO, Waveshare ESP32-P4-ETH) | Ethernet only |
| `esp32p4rev1-eth-wifi` | P4 rev 1 | Ethernet, plus WiFi via the on-board ESP32-C6 over esp_hosted |
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/hardware/hub75-panels.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The chip needs an LCD_CAM or a Parlio block: an S3, a P4 or an S31. The classic
Three boards have published pin maps, which the `board` select fills in:

- **MoonHub75**, a Lilygo T7-S3 on a passive adapter. It also carries an INMP441 microphone socket on IO10/11/12, so an audio-reactive effect and a panel run together.
- **Adafruit MatrixPortal S3.** Three of its lines sit on GPIO 35 to 37, which the octal-PSRAM images hold, so it runs the `esp32s3-zero` image.
- **Adafruit MatrixPortal S3.** Three of its lines sit on GPIO 35 to 37, which the octal-PSRAM images hold, so it runs the `esp32s3-n8r2` image, built for its quad-PSRAM N8R2 part.
- **Waveshare ESP32-S3 RGB Matrix**, SKU 34422. The Waveshare ESP32-S3-Matrix is a different product, with an onboard 8x8 matrix and no HUB75 connector.

A published map hides the pin rows, since those lines are soldered; they stay bound and still drive the panel. The generic per-chip sets and Custom show them. A line on a pin the chip wires to flash or PSRAM is refused before init, with the line named. Free pins per chip: [GPIO usage](gpio-usage.md).
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# MoonBase on a classic ESP32 with 8 MB flash (the ESP32-PICO-V3-02's embedded part).
# Partition table for any 8 MB board WITH MoonBase (the classic ESP32-PICO-V3-02, the S3 N8R2).
#
# The same trade the 4 MB and 16 MB MoonBase tables make: dual-OTA spends half the app area on a
# second copy of the firmware that sits idle except during an update, where MoonBase is a small
Expand Down
1 change: 0 additions & 1 deletion esp32/sdkconfig.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ CONFIG_LOG_DEFAULT_LEVEL_INFO=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions/esp32dev.csv"
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"

# Task watchdog: PANIC on a wedged task so the device self-heals (reboot + backtrace) instead of hanging
# SILENTLY forever: a silent hang looks dead and needs a physical power-cycle, the worst failure mode
Expand Down
10 changes: 2 additions & 8 deletions esp32/sdkconfig.defaults.esp32-pico
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
# ESP32-PICO-V3-02: classic ESP32 (Xtensa LX6) in a SiP package with 8 MB flash and 2 MB PSRAM
# both EMBEDDED in the chip. The QuinLED Dig-Next-2 carries one.
# Append to sdkconfig.defaults + sdkconfig.defaults.eth (later fragment wins).
# Append to sdkconfig.defaults + sdkconfig.defaults.eth (later fragment wins); the 8 MB flash size
# and partition table come from the moonbase-8mb fragment.
#
# Its own variant rather than a reuse of `esp32` or `esp32-wrover` for two reasons: the flash is
# 8 MB where the classic base sets 4, and the PSRAM must be on (the base has none) — a 4 MB image
# on this part would waste half the flash, and the wrover image's 4 MB table would too.

# The 8 MB flash and its MoonBase partition table: a factory recovery image, ONE 3 MB app slot, and
# 4 MB of LittleFS. The 4 MB base table affords only 1856 KB slots and 256 KB of filesystem.
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
CONFIG_ESPTOOLPY_FLASHSIZE="8MB"
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions/esp32dev_8mb_moonbase.csv"

# PSRAM: 2 MB, embedded in the SiP. QUAD mode, and there is nothing to select — on classic-ESP32
# silicon CONFIG_SPIRAM=y IS quad (CONFIG_SPIRAM_MODE_OCT exists only on the S3), which is the same
# reason the WROVER fragment sets this one symbol and no mode.
Expand Down
4 changes: 1 addition & 3 deletions esp32/sdkconfig.defaults.esp32c3
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
# ESP32-C3: one RISC-V core at 160 MHz, 400 KB SRAM, no PSRAM, 4 MB flash, WiFi only.
# Append to sdkconfig.defaults (later fragment wins); the partition table comes from the moonbase-4mb fragment.
# Append to sdkconfig.defaults (later fragment wins); the flash size and partition table come from the moonbase-4mb fragment.

# 160 MHz is the C3's top speed, where the base fragment asks for the 240 of the other chips.
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y

CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y

# MoonLive native codegen needs an executable heap, which ESP-IDF offers only with memory protection off: the same configuration as the S3 images.
CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n
CONFIG_HEAP_HAS_EXEC_HEAP=y
25 changes: 25 additions & 0 deletions esp32/sdkconfig.defaults.esp32s3-quad
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# ESP32-S3 with QUAD PSRAM: the S3-Zero (N4R2) and the N8R2 (the Adafruit MatrixPortal S3 carries one).
# Append to sdkconfig.defaults (later fragment wins); the flash size and partition table come from the
# moonbase-4mb or moonbase-8mb fragment layered on top.
#
# The N8R8/N16R8 images set SPIRAM_MODE_OCT, and an octal-mode binary does not merely under-perform on
# quad hardware, it fails PSRAM init at boot. Quad also leaves GPIO 35 to 37 free, which the MatrixPortal
# routes to HUB75 lines.

# Quad I/O flash reads, as on the N16R8, where reading code over two lines (DIO, the IDF default) cost 16% of the tick.
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y

# PSRAM: 2 MB, QUAD mode.
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_QUAD=y
# At the 80 MHz the part is rated for rather than IDF's 40 MHz default.
CONFIG_SPIRAM_SPEED_80M=y

# MoonLive native codegen needs an executable heap (allocExec -> MALLOC_CAP_EXEC IRAM).
# MALLOC_CAP_EXEC is gated behind CONFIG_HEAP_HAS_EXEC_HEAP, which IDF disables whenever
# memory protection (PMP/PMS W^X) is on. A JIT fundamentally needs writable-then-executable
# memory, so disable memprot (which enables the exec heap). Same configuration as the other
# S3 images; safety for scripted code is the staged bounds/watchdog checks, not the
# hardware W^X wall.
CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n
CONFIG_HEAP_HAS_EXEC_HEAP=y
36 changes: 0 additions & 36 deletions esp32/sdkconfig.defaults.esp32s3-zero

This file was deleted.

3 changes: 3 additions & 0 deletions esp32/sdkconfig.defaults.moonbase-4mb
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# MoonBase on a 4 MB board: the factory recovery image and ONE 2496 KB app slot, where dual-OTA
# affords two 1856 KB slots. The flash size is set here because the table spans exactly that much.
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions/4mb_moonbase.csv"

# No SD card backend on a 4 MB image: its flash is better spent on everything else, so SD ships only where there is more.
Expand Down
4 changes: 4 additions & 0 deletions esp32/sdkconfig.defaults.moonbase-8mb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# MoonBase on an 8 MB board: the factory recovery image, ONE 3 MB app slot, and 4 MB of LittleFS.
# The flash size is set here because the table spans exactly that much.
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions/8mb_moonbase.csv"
19 changes: 17 additions & 2 deletions moondeck/build/build_esp32.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def check_idf_pin(idf_path: Path) -> None:
"esp32-pico": {
"chip": "esp32",
"fragments": ["sdkconfig.defaults", "sdkconfig.defaults.eth",
"sdkconfig.defaults.esp32-pico"],
"sdkconfig.defaults.esp32-pico", "sdkconfig.defaults.moonbase-8mb"],
"moonbase": True, # 8 MB: factory MoonBase + one app slot (see moonbase/)
"eth_only": False,
"description": "ESP32-PICO-V3-02 (classic ESP32 SiP: 8 MB embedded flash + 2 MB "
Expand Down Expand Up @@ -256,7 +256,7 @@ def check_idf_pin(idf_path: Path) -> None:
},
"esp32s3-zero": {
"chip": "esp32s3",
"fragments": ["sdkconfig.defaults", "sdkconfig.defaults.esp32s3-zero",
"fragments": ["sdkconfig.defaults", "sdkconfig.defaults.esp32s3-quad",
"sdkconfig.defaults.moonbase-4mb"],
"moonbase": True, # 4 MB: factory MoonBase + one big app slot (see moonbase/)
"eth_only": False,
Expand All @@ -271,6 +271,21 @@ def check_idf_pin(idf_path: Path) -> None:
# on a part that has 48 KB to spare.
"panel_cards": False,
},
"esp32s3-n8r2": {
"chip": "esp32s3",
"fragments": ["sdkconfig.defaults", "sdkconfig.defaults.esp32s3-quad",
"sdkconfig.defaults.moonbase-8mb"],
"moonbase": True, # 8 MB: factory MoonBase + one app slot (see moonbase/)
"eth_only": False,
"description": "ESP32-S3 (N8R2: 8 MB flash, 2 MB QUAD PSRAM) - WiFi only, no "
"Ethernet. Its own variant because the N8R8/N16R8 images set "
"SPIRAM_MODE_OCT, which fails PSRAM init on a quad part, and the "
"S3-Zero image uses half the flash (Adafruit MatrixPortal S3).",
"ships": True,
Comment thread
AnjinMeili marked this conversation as resolved.
Resolved
# No Ethernet fragment, as on the S3-Zero: the MatrixPortal breaks out no SPI header
# for a W5500.
"panel_cards": False,
},
"esp32c3": {
"chip": "esp32c3",
"fragments": ["sdkconfig.defaults", "sdkconfig.defaults.esp32c3",
Expand Down
77 changes: 77 additions & 0 deletions mooninstaller/deviceModels.json
Original file line number Diff line number Diff line change
Expand Up @@ -1830,6 +1830,83 @@
}
}
},
{
"name": "Adafruit MatrixPortal S3",
"chip": "ESP32-S3",
"firmwares": [
"esp32s3-n8r2"
],
"url": "https://www.adafruit.com/product/5778",
"supported": [
"LEDs",
"WiFi",
"Buttons",
"I2C"
],
"planned": [
"Accelerometer"
],
"state": {
"System": {
"deviceModel": "Adafruit MatrixPortal S3",
"I2cBus": {
"type": "I2cBusModule",
"sda": 16,
"scl": 17
}
},
"Layouts": {
"$patch": "replace",
"Grid": {
"type": "GridLayout",
"width": 64,
"height": 32
}
},
"Effects": {
"$patch": "replace",
"Layer": {
"type": "Layer"
}
},
"Drivers": {
"$patch": "replace",
"Hub75": {
"type": "Hub75Driver",
"board": "MatrixPortal S3",
"scanRate": "1/16"
}
},
"Services": {
"$patch": "replace",
"Buttons": {
"type": "ButtonService",
"buttons": [
{
"pin": 0,
"activeLow": true,
"target": "Control.switch1",
"kind": "toggle"
},
{
"pin": 6,
"activeLow": true,
"target": "Control.fader1",
"kind": "delta",
"value": 16
},
{
"pin": 7,
"activeLow": true,
"target": "Control.fader1",
"kind": "delta",
"value": -16
}
]
}
}
}
},
{
"name": "ESP32-C3 SuperMini",
"chip": "ESP32-C3",
Expand Down
8 changes: 8 additions & 0 deletions mooninstaller/firmwares.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@
"ships": true,
"description": "ESP32-S3-Zero (N4R2: 4 MB embedded flash, 2 MB embedded QUAD PSRAM) - WiFi only, no Ethernet. Its own variant because neither other S3 image can boot here: both assume 8/16 MB flash and set SPIRAM_MODE_OCT, and octal mode fails PSRAM init on this board's quad part. A thumbnail-sized board for small installations."
},
{
"name": "esp32s3-n8r2",
"platform": "esp32",
"chip": "esp32s3",
"eth_only": false,
"ships": true,
"description": "ESP32-S3 (N8R2: 8 MB flash, 2 MB QUAD PSRAM) - WiFi only, no Ethernet. Its own variant because the N8R8/N16R8 images set SPIRAM_MODE_OCT, which fails PSRAM init on a quad part, and the S3-Zero image uses half the flash (Adafruit MatrixPortal S3)."
},
{
"name": "esp32c3",
"platform": "esp32",
Expand Down
2 changes: 1 addition & 1 deletion test/unit/core/unit_PartitionTables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ uint32_t declaredFlashBytes(const std::string& file) {
{"esp32dev.csv", 4u * 1024 * 1024},
{"4mb_moonbase.csv", 4u * 1024 * 1024},
{"wled_4mb_1mb_fs.csv", 4u * 1024 * 1024},
{"esp32dev_8mb_moonbase.csv", 8u * 1024 * 1024},
{"8mb_moonbase.csv", 8u * 1024 * 1024},
{"esp32s3_n8r8.csv", 8u * 1024 * 1024},
{"ota_16mb.csv", 16u * 1024 * 1024},
{"ota_16mb_moonbase.csv", 16u * 1024 * 1024},
Expand Down
Loading