diff --git a/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_43/partitions.csv b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_43/partitions.csv index f3a1f39..0229d7c 100644 --- a/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_43/partitions.csv +++ b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_43/partitions.csv @@ -1,6 +1,7 @@ # Name, Type, SubType, Offset, Size, Flags # The LilyGO T-Embed S3 and the Waveshare ESP32-S3-LCD-4.3 carry images built -# from this table. factory stays at 0x380000 and vfs at 0x3a0000: a build that +# from this table, and so does the Waveshare ESP32-S3-Touch-LCD-7 (its board +# directory uses this one). factory stays at 0x380000 and vfs at 0x3a0000: a build that # moved them left one board hanging in fs_corrupted() before USB came up and # formatted over the other one's filesystem (cmods#30). 8MB flash. diff --git a/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/board.json b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/board.json new file mode 100644 index 0000000..73fb5f1 --- /dev/null +++ b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/board.json @@ -0,0 +1,32 @@ +{ + "deploy": [ + "../deploy.md" + ], + "deploy_options": { + "flash_offset": "0" + }, + "docs": "", + "features": [ + "BLE", + "External Flash", + "External RAM", + "WiFi" + ], + "images": [ + "generic_s3.jpg" + ], + "mcu": "esp32s3", + "product": "Waveshare ESP32-S3-Touch-LCD-7", + "thumbnail": "", + "url": "https://www.waveshare.com/esp32-s3-touch-lcd-7.htm", + "vendor": "Waveshare", + "variants": { + "SPIRAM_OCT": "Support for Octal-SPIRAM" + }, + "old_variants": { + "FLASH_4M": [ + "4MiB flash", + "Use the standard variant instead." + ] + } +} diff --git a/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/board.md b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/board.md new file mode 100644 index 0000000..4fc5a22 --- /dev/null +++ b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/board.md @@ -0,0 +1,9 @@ +Waveshare ESP32-S3-Touch-LCD-7: an ESP32-S3 with octal PSRAM driving an +800x480 RGB panel, with Wi-Fi and often a USB host running beside it. Use the +SPIRAM_OCT variant. + +It is the 4.3" board's configuration (same chip, memory and partition table: +`../WAVESHARE_ESP32_S3_TOUCH_43/sdkconfig.board`) plus `sdkconfig.lcd7`, +which protects internal DMA RAM and the Wi-Fi link from the panel; see the +comments there. Its `board_config.py` should pass `bounce_rows=10` and a +14 MHz pixel clock (PyDevices/pydevices#96). diff --git a/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/manifest.py b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/manifest.py new file mode 100644 index 0000000..5b663ee --- /dev/null +++ b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/manifest.py @@ -0,0 +1,4 @@ +# What this board carries when no FROZEN_MANIFEST is given: everything. Pass +# FROZEN_MANIFEST=../../../micropython-pydevices/manifests/.py for a +# smaller set. +include("../../../manifests/kitchen-sink.py") diff --git a/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/mpconfigboard.cmake b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/mpconfigboard.cmake new file mode 100644 index 0000000..20f0620 --- /dev/null +++ b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/mpconfigboard.cmake @@ -0,0 +1,26 @@ +# Waveshare ESP32-S3-Touch-LCD-7: an 8 MB-table ESP32-S3 with octal PSRAM. +# The stock ESP32_GENERIC_S3 board, unchanged; what this board adds is in +# mpconfigvariant_SPIRAM_OCT.cmake beside it. +include(${CMAKE_CURRENT_SOURCE_DIR}/boards/ESP32_GENERIC_S3/mpconfigboard.cmake) + +# Two things upstream's esp32 port does with FROZEN_MANIFEST that this file +# straightens out, in the place upstream gives a board to do it: +# +# 1. A FROZEN_MANIFEST given relative to the port directory (how every other +# port takes it) reaches makemanifest relative to the BUILD directory, +# because the Makefile hands it to idf.py unchanged. Absolutize it against +# the port directory, in both the variable and the copy the port took of +# it before including this file, so the same spelling works everywhere. +# 2. With no FROZEN_MANIFEST at all, the port falls back to its own +# boards/manifest.py, not this board's -- a board that wants its own +# default says so here, which is upstream's own idiom. +# idf.py caches -D values: to return to this board's default after building +# with a preset, start from a clean build directory. +if(MICROPY_USER_FROZEN_MANIFEST) + if(NOT IS_ABSOLUTE "${MICROPY_USER_FROZEN_MANIFEST}") + get_filename_component(MICROPY_USER_FROZEN_MANIFEST "${MICROPY_USER_FROZEN_MANIFEST}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + set(MICROPY_FROZEN_MANIFEST "${MICROPY_USER_FROZEN_MANIFEST}") + endif() +else() + set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) +endif() diff --git a/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/mpconfigboard.h b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/mpconfigboard.h new file mode 100644 index 0000000..9c2d0e3 --- /dev/null +++ b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/mpconfigboard.h @@ -0,0 +1,17 @@ +// The stock ESP32_GENERIC_S3 header, unchanged. +#include "boards/ESP32_GENERIC_S3/mpconfigboard.h" + +// usbif: extend TinyUSB's device configuration (descriptor + class config are +// provided by the usbif external C module). Guarded by __has_include so the +// board still builds when usbif is not in the preset: the header is on the +// include path only because usbif's micropython.cmake contributes that +// directory, so this is exactly an "is the module in this build" test. MSC is +// inside the guard too -- the class is useless without usbif, which supplies +// the block callbacks and chooses what the drive holds from Python at runtime. +// Moved here from cmods' board-header patch, 2026-09-23. +#if defined(__has_include) +#if __has_include("usbif_tusb_ext.h") +#define MICROPY_HW_USB_EXT_TUSB_CONFIG "usbif_tusb_ext.h" +#define MICROPY_HW_USB_MSC (1) +#endif +#endif diff --git a/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/mpconfigvariant_SPIRAM_OCT.cmake b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/mpconfigvariant_SPIRAM_OCT.cmake new file mode 100644 index 0000000..d139f16 --- /dev/null +++ b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/mpconfigvariant_SPIRAM_OCT.cmake @@ -0,0 +1,9 @@ +# The stock SPIRAM_OCT variant, then the 4.3" board's sdkconfig fragment (the +# partition table and everything the two boards share), then this board's +# own. The appends come LAST, in that order: kconfgen takes the last +# assignment in SDKCONFIG_DEFAULTS, so a fragment listed before the port's own +# is silently overridden (cmods#29), and sdkconfig.lcd7 must win over the +# shared values it changes. +include(${CMAKE_CURRENT_SOURCE_DIR}/boards/ESP32_GENERIC_S3/mpconfigvariant_SPIRAM_OCT.cmake) +list(APPEND SDKCONFIG_DEFAULTS ${CMAKE_CURRENT_LIST_DIR}/../WAVESHARE_ESP32_S3_TOUCH_43/sdkconfig.board) +list(APPEND SDKCONFIG_DEFAULTS ${CMAKE_CURRENT_LIST_DIR}/sdkconfig.lcd7) diff --git a/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/sdkconfig.lcd7 b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/sdkconfig.lcd7 new file mode 100644 index 0000000..1f8b196 --- /dev/null +++ b/boards/esp32/WAVESHARE_ESP32_S3_TOUCH_LCD_7/sdkconfig.lcd7 @@ -0,0 +1,28 @@ +# Waveshare ESP32-S3-Touch-LCD-7, on top of the 4.3" board's sdkconfig.board. +# Measured 2026-09-25 with spotapi's remote on the panel and earful streaming +# Spotify into a USB sound card hosted on the native port (earful +# docs/lcd-7.md). +# +# Internal DMA-capable RAM is what runs out first on this board: the panel's +# bounce buffers, the Wi-Fi driver, hardware AES and the USB host all need +# it. With the shared settings the DMA region sat at 24 bytes free, then +# esp-aes failed to allocate and Wi-Fi dropped. +# +# Every malloc() under this size went to internal RAM first (the port's +# default is 8 KB); code that needs internal or DMA memory asks for it +# explicitly and still gets it. +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=512 +# Unread socket data holds Wi-Fi RX buffers, which are internal DMA RAM: cap +# how many exist and how much a socket may have in flight. Audio at 160 kbps +# and Web API replies need far less than the shared 32 KB window. +CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=24 +CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=6 +CONFIG_ESP_WIFI_RX_BA_WIN=8 +CONFIG_LWIP_TCP_WND_DEFAULT=16384 +CONFIG_LWIP_TCP_RECVMBOX_SIZE=16 + +# 1 ms tick. At 100 Hz, MicroPython's sleep_ms() under one tick falls through +# to mp_hal_delay_us() and busy-waits with the GIL held: appdev's 10 ms loop +# kept the UI thread 54 % busy while idle and starved every other Python +# thread, and 2-5 ms native waits rounded down to zero ticks. +CONFIG_FREERTOS_HZ=1000