diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 4b4d7286b..a47e14c3d 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -202,6 +202,11 @@ build_application_edge_agent: EXAMPLE_TARGET: esp32s3 EXAMPLE_BOARD_BRAND: "lceda-course-examples" + - IMAGE: ["espressif/idf:release-v5.5"] + EXAMPLE_BOARD: ["xiao_esp32s3_sense"] + EXAMPLE_TARGET: esp32s3 + EXAMPLE_BOARD_BRAND: "seeedstudio" + build_application_mcp_server_point: extends: - .build_examples_template diff --git a/application/edge_agent/boards/seeedstudio/xiao_esp32s3_sense/README.md b/application/edge_agent/boards/seeedstudio/xiao_esp32s3_sense/README.md new file mode 100644 index 000000000..0b5e64b83 --- /dev/null +++ b/application/edge_agent/boards/seeedstudio/xiao_esp32s3_sense/README.md @@ -0,0 +1,108 @@ +# Seeed Studio XIAO ESP32-S3 Sense + +## Hardware Overview + +| Feature | Specification | +|---------------|-----------------------------------------------------| +| Chip | ESP32-S3 (R8 module: 8 MB flash + 8 MB OPI PSRAM) | +| Flash | 8 MB QIO @ 80 MHz | +| PSRAM | Octal 80 MHz (wired to the OPI peripheral, no GPIO) | +| Camera | OV2640 over DVP 8-bit (XCLK 20 MHz, SCCB on GPIO39/40) | +| Microphone | On-board PDM mic on I2S0 (CLK=GPIO42, DATA=GPIO41) | +| microSD | On-board slot, SPI mode (CS=GPIO21, SCK=7, MISO=8, MOSI=9) | +| User LED | GPIO21 — **shared with SD card CS, see Notes** | +| Console | USB Serial/JTAG (internal USB PHY, on-board USB-C) | + +Upstream board page: [XIAO ESP32-S3 Sense](https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/) + +## GPIO Mapping + +| Function | GPIO | Notes | +|---------------------------|------|-----------------------------------------| +| I2C SDA (camera SCCB) | 40 | Shared with header D4 | +| I2C SCL (camera SCCB) | 39 | Shared with header D5 / MTCK | +| I2S PDM CLK (mic) | 42 | Shared with D11 / MTMS | +| I2S PDM DATA (mic) | 41 | Shared with D12 / MTDI | +| SPI SCK (SD) | 7 | Shared with header D8 | +| SPI MISO (SD) | 8 | Shared with header D9 | +| SPI MOSI (SD) | 9 | Shared with header D10 | +| SPI CS (SD) | 21 | **Shared with user LED** | +| Camera XCLK | 10 | 20 MHz, generated by LEDC | +| Camera PCLK | 13 | | +| Camera VSYNC | 38 | | +| Camera HREF/DE | 47 | | +| Camera D0..D7 | 15, 17, 18, 16, 14, 12, 11, 48 | Y2..Y9 mapping | + +Pin table source: [Sense MicroSD card wiki](https://wiki.seeedstudio.com/xiao_esp32s3_sense_filesystem/) and the Seeed Arduino `SD_Test` example (`SD.begin(21)`). + +## Important Notes + +### User LED and SD card share GPIO21 + +The XIAO ESP32-S3 Sense expansion board hardwires the SD card's CS line and the +on-board user LED to the same GPIO. They cannot be used at the same time. This +adaptation gives the SD card the pin (it is required for non-volatile storage of +sessions, memory, and router rules). If you need the LED instead, cut the J3 +solder jumper on the expansion board to disconnect the SD card slot, then drop +a `status_led` device into `board_devices.yaml` that points at GPIO21 with +`active_level: 0` (the LED is active-low). + +### JTAG over GPIO is unavailable + +GPIO39–42 carry camera SCCB (39/40) and the PDM microphone (41/42). The XIAO +does not break out JTAG pins, so the firmware console is forced to the +on-board USB-C via `CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y`. GPIO JTAG debugging +is not possible on this board. + +### SD card limits + +The Seeed wiki states maximum 32 GB and FAT32 only. SDXC cards (≥ 64 GB, +exFAT) will not be mounted even after reformatting. Use cards from 4 GB to +32 GB, class A1 or better, formatted with the +[official SD Card Formatter](https://www.sdcard.org/downloads/formatter/) — +Windows "quick format" alone is not sufficient for cards that previously +held a Linux filesystem. + +### Camera XCLK may affect SD reliability + +GPIO10 emits a 20 MHz XCLK for the OV2640 while the camera is open. On some +units this couples into the SD card's SPI lines and produces CRC errors +(`sdmmc_card_init failed (0x107)`) when both are active. If you see this +under load, either close the camera when reading the SD card or drop the +SD SPI `frequency` in `board_devices.yaml` to `1000000` (1 MHz). + +## Build & Flash + +```bash +cd application/edge_agent + +# Generate board-manager glue. Always rerun this after editing the YAML +# files under this directory, otherwise the stale generated C code under +# components/gen_bmgr_codes/ is compiled instead. +idf.py bmgr -c ./boards -b xiao_esp32s3_sense + +# Build and flash +idf.py build +idf.py -p /dev/ttyACM0 flash monitor # Windows: -p COM3 +``` + +The XIAO ESP32-S3 enters download mode automatically on most hosts; if the +flash hangs at "Connecting...", hold **BOOT**, tap **RESET**, release +**BOOT**, then retry. + +## Partition Table + +Uses `partitions_8MB.csv` (auto-selected from `CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y` +by `tools/cmake/flash_partition_defaults.cmake`). The 8 MB layout reserves a +read-only system FAT image and a writable data FAT image; the data root is +mounted on the SD card when present and falls back to the on-flash FAT +partition otherwise. + +## Files + +| File | Description | +|-------------------------------|----------------------------------------------------------| +| `board_info.yaml` | Board identity (chip, manufacturer, description) | +| `board_peripherals.yaml` | I2C0, I2S0 (PDM), SPI2 pin and bus configuration | +| `board_devices.yaml` | Camera, audio_adc, fs_sdcard device list | +| `sdkconfig.defaults.board` | Flash/PSRAM/console defaults + OV2640 + audio Kconfig | diff --git a/application/edge_agent/boards/seeedstudio/xiao_esp32s3_sense/board_devices.yaml b/application/edge_agent/boards/seeedstudio/xiao_esp32s3_sense/board_devices.yaml new file mode 100644 index 000000000..d5612f692 --- /dev/null +++ b/application/edge_agent/boards/seeedstudio/xiao_esp32s3_sense/board_devices.yaml @@ -0,0 +1,80 @@ +version: 1.0.0 +# Devices Configuration for Seeed Studio XIAO ESP32-S3 Sense +# +# Device summary: +# camera - OV2640 over DVP 8-bit (XCLK 20 MHz, JPEG 800x600@30FPS default) +# audio_adc - on-board PDM microphone (bare PDM, no codec IC) +# fs_sdcard - on-board microSD slot over SPI; mounts as CLAW_PATH_DATA root +# +# NOTE: the on-board user LED on GPIO21 is NOT exposed as a device here. +# The Sense expansion board hardwires the SD card's CS line to GPIO21, so +# the LED and the SD card physically cannot be used at the same time. SD +# storage is more useful for an edge-agent workload, so the LED is dropped. +# (See https://wiki.seeedstudio.com/xiao_esp32s3_sense_filesystem/ for the +# official pin table: CS = GPIO21, SCK = GPIO7, MISO = GPIO8, MOSI = GPIO9.) + +devices: + - name: camera + type: camera + sub_type: dvp + version: default + config: + dvp_config: + reset_io: -1 + pwdn_io: -1 + vsync_io: 38 + de_io: 47 + pclk_io: 13 + xclk_io: 10 + xclk_freq: 20000000 + data_width: CAM_CTLR_DATA_WIDTH_8 + data_io: + data_io_0: 15 + data_io_1: 17 + data_io_2: 18 + data_io_3: 16 + data_io_4: 14 + data_io_5: 12 + data_io_6: 11 + data_io_7: 48 + peripherals: + - name: i2c_master + frequency: 100000 + + - name: audio_adc + chip: internal + type: audio_codec + version: default + config: + adc_enabled: true + dac_enabled: false + adc_max_channel: 1 + adc_channel_mask: "1" + adc_init_gain: 0 + mclk_enabled: false + peripherals: + - name: i2s_audio_in + + - name: fs_sdcard + type: fs_fat + sub_type: spi + version: default + config: + vfs_config: + # esp_vfs_fat supports FAT12/16/32 only; the SD card MUST be FAT32, + # not exFAT. Cards that fail to mount should be re-formatted with + # the official SD Card Formatter, not silently wiped here. + format_if_mount_failed: false + max_files: 5 + sub_config: + # Seeed's official pin table (SD.begin(21) in the wiki example): + # CS = GPIO21, SCK = GPIO7, MISO = GPIO8, MOSI = GPIO9 + # GPIO21 is shared with the user LED on the XIAO; CS wins. + cs_gpio_num: 21 + # 10 MHz is a safe ceiling for the Sense expansion board's short SD + # card traces. If 0x107 (CRC) errors appear at boot, drop this to + # 1 MHz; the SDMMC driver still auto-negotiates to 400 kHz for the + # CMD0/ACMD41 init phase. + frequency: 10000000 + peripherals: + - name: spi_sdcard diff --git a/application/edge_agent/boards/seeedstudio/xiao_esp32s3_sense/board_info.yaml b/application/edge_agent/boards/seeedstudio/xiao_esp32s3_sense/board_info.yaml new file mode 100644 index 000000000..517283454 --- /dev/null +++ b/application/edge_agent/boards/seeedstudio/xiao_esp32s3_sense/board_info.yaml @@ -0,0 +1,5 @@ +board: xiao_esp32s3_sense +chip: esp32s3 +version: 1.0.0 +description: "Seeed Studio XIAO ESP32-S3 Sense (ESP32-S3R8, OV2640 camera, PDM mic, microSD, user LED)" +manufacturer: "Seeed Studio" diff --git a/application/edge_agent/boards/seeedstudio/xiao_esp32s3_sense/board_peripherals.yaml b/application/edge_agent/boards/seeedstudio/xiao_esp32s3_sense/board_peripherals.yaml new file mode 100644 index 000000000..8998b6ce9 --- /dev/null +++ b/application/edge_agent/boards/seeedstudio/xiao_esp32s3_sense/board_peripherals.yaml @@ -0,0 +1,53 @@ +version: 1.0.0 +# Peripherals Configuration for Seeed Studio XIAO ESP32-S3 Sense +# +# Bus allocation: +# I2C0 - camera SCCB (also used by XIAO header D4/D5 as I2C if needed later) +# SCL=GPIO39, SDA=GPIO40 +# I2S0 - PDM microphone (pdm-in) +# CLK=GPIO42 (shared with D11/MTMS), DATA=GPIO41 (shared with D12/MTDI) +# SPI2 - on-board microSD card slot +# CS=GPIO21 (shared with user LED; SD takes the pin), SCK=GPIO7, +# MOSI=GPIO9, MISO=GPIO8 +# +# The on-board user LED on GPIO21 is intentionally NOT registered as a +# peripheral: the Sense expansion board hardwires the SD card CS to the +# same pin, so the LED cannot be driven while the SD card is in use. + +peripherals: + - name: i2c_master + type: i2c + role: master + config: + port: 0 + pins: + sda: 40 + scl: 39 + + - name: i2s_audio_in + type: i2s + role: master + format: pdm-in + config: + port: 0 + sample_rate_hz: 16000 + clk_src: I2S_CLK_SRC_DEFAULT + data_bit_width: 16 + slot_bit_width: I2S_SLOT_BIT_WIDTH_AUTO + slot_mode: I2S_SLOT_MODE_MONO + slot_mask: I2S_PDM_SLOT_LEFT + data_fmt: I2S_PDM_DATA_FMT_PCM + pins: + clk: 42 + din: 41 + + - name: spi_sdcard + type: spi + role: master + config: + spi_bus_config: + spi_port: SPI2_HOST + sclk_io_num: 7 + mosi_io_num: 9 + miso_io_num: 8 + max_transfer_sz: 4096 diff --git a/application/edge_agent/boards/seeedstudio/xiao_esp32s3_sense/sdkconfig.defaults.board b/application/edge_agent/boards/seeedstudio/xiao_esp32s3_sense/sdkconfig.defaults.board new file mode 100644 index 000000000..17499fe95 --- /dev/null +++ b/application/edge_agent/boards/seeedstudio/xiao_esp32s3_sense/sdkconfig.defaults.board @@ -0,0 +1,55 @@ +# XIAO ESP32-S3 Sense (ESP32-S3R8): 8 MB QIO flash @ 80 MHz +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y +CONFIG_ESPTOOLPY_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y + +# 8 MB octal PSRAM @ 80 MHz. +# The R8 module's PSRAM is wired to the chip's OPI peripheral, so no GPIO +# conflicts with the camera/SD/mic/LED wiring above. +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y + +# PSRAM is mandatory here: esp_video places camera frame buffers in PSRAM +# (800x600 JPEG needs several hundred KB, which does not fit in internal SRAM +# once WiFi/LwIP, IM bindings, and the claw task tree are loaded). +# Put WiFi station / LwIP buffers in PSRAM to free ~50 KB of internal RAM. +CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y + +# FreeRTOS task stacks tagged CLAW_TASK_STACK_PREFER_PSRAM (claw_core, +# claw_memory, claw_event_router, cap_system, cap_scheduler, cap_im_*, +# cap_lua, ...) must be allowed to use external memory. OCT PSRAM keeps +# the stack accessible while flash cache is disabled, so leave the default y. +# Do NOT set CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM=n (CoreS3 disables it +# only because it ships with QUAD PSRAM, which cannot). +# +# Keep instruction/rodata fetch from PSRAM disabled: 8 MB flash is enough +# for firmware, and flash-backed execution is faster than PSRAM-backed. +# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set +# CONFIG_SPIRAM_RODATA is not set + +# USB: Serial/JTAG is the on-board USB-C console. +# GPIO39-42 are reassigned to camera SCCB (39/40) and PDM mic (41/42), +# so JTAG over GPIO is not available. The internal USB PHY is used instead. +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y +CONFIG_ESP_CONSOLE_SECONDARY_NONE=y + +# Camera: OV2640 over DVP 8-bit, 20 MHz XCLK. +# The Kconfig name is the actual default that menuconfig reports for +# esp_video's OV2640 driver on this chip: +# DVP 8-bit, 20 MHz XCLK, 640x480 @ 25 FPS, JPEG +# (The earlier 800x600 @ 30 FPS line was a guess; menuconfig does +# not actually expose that combination for the OV2640.) +CONFIG_ESP_BOARD_DEV_CAMERA_SUPPORT=y +CONFIG_ESP_VIDEO_ENABLE_DVP_VIDEO_DEVICE=y +CONFIG_CAMERA_OV2640=y +CONFIG_CAMERA_OV2640_AUTO_DETECT_DVP_INTERFACE_SENSOR=y +CONFIG_CAMERA_OV2640_DVP_JPEG_640X480_25FPS=y +CONFIG_CAMERA_OV2640_DVP_DEFAULT_FMT_JPEG_640X480_25FPS=y +CONFIG_APP_CLAW_LUA_MODULE_CAMERA=y + +# Audio: bare PDM microphone on I2S0 (no codec IC, internal/dummy ADC) +CONFIG_ESP_BOARD_PERIPH_I2S_SUPPORT=y +CONFIG_CODEC_DATA_ADC_SUPPORT=y +CONFIG_APP_CLAW_LUA_MODULE_AUDIO=y