From 64ea32e88aab7d09ea7548935fa387c359588a4c Mon Sep 17 00:00:00 2001 From: Ian Wakely Date: Sun, 24 Nov 2024 20:31:10 -0500 Subject: [PATCH] boards: Adding Adafruit QT Py ESP32s3 support. This adds support for the ESP32s3 based Adafruit QT Py, as well as its PSRAM variant. Signed-off-by: Ian Wakely --- boards/adafruit/qt_py_esp32s3/Kconfig | 6 + .../Kconfig.adafruit_qt_py_esp32s3 | 9 + .../adafruit/qt_py_esp32s3/Kconfig.sysbuild | 10 + .../adafruit_qt_py_esp32s3-pinctrl.dtsi | 67 ++++ .../adafruit_qt_py_esp32s3_appcpu.dts | 30 ++ .../adafruit_qt_py_esp32s3_appcpu.yaml | 27 ++ .../adafruit_qt_py_esp32s3_appcpu_defconfig | 4 + ...dafruit_qt_py_esp32s3_appcpu_psram.overlay | 34 ++ .../adafruit_qt_py_esp32s3_appcpu_psram.yaml | 27 ++ .../adafruit_qt_py_esp32s3_procpu.dts | 149 +++++++++ .../adafruit_qt_py_esp32s3_procpu.yaml | 19 ++ .../adafruit_qt_py_esp32s3_procpu_defconfig | 7 + ...dafruit_qt_py_esp32s3_procpu_psram.overlay | 34 ++ .../adafruit_qt_py_esp32s3_procpu_psram.yaml | 19 ++ boards/adafruit/qt_py_esp32s3/board.cmake | 9 + boards/adafruit/qt_py_esp32s3/board.yml | 12 + .../doc/img/adafruit_qt_py_esp32s3.webp | Bin 0 -> 30372 bytes boards/adafruit/qt_py_esp32s3/doc/index.rst | 291 ++++++++++++++++++ boards/adafruit/qt_py_esp32s3/revision.cmake | 3 + .../qt_py_esp32s3/seeed_xiao_connector.dtsi | 30 ++ .../qt_py_esp32s3/support/openocd.cfg | 7 + 21 files changed, 794 insertions(+) create mode 100644 boards/adafruit/qt_py_esp32s3/Kconfig create mode 100644 boards/adafruit/qt_py_esp32s3/Kconfig.adafruit_qt_py_esp32s3 create mode 100644 boards/adafruit/qt_py_esp32s3/Kconfig.sysbuild create mode 100644 boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3-pinctrl.dtsi create mode 100644 boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu.dts create mode 100644 boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu.yaml create mode 100644 boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu_defconfig create mode 100644 boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu_psram.overlay create mode 100644 boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu_psram.yaml create mode 100644 boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu.dts create mode 100644 boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu.yaml create mode 100644 boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu_defconfig create mode 100644 boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu_psram.overlay create mode 100644 boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu_psram.yaml create mode 100644 boards/adafruit/qt_py_esp32s3/board.cmake create mode 100644 boards/adafruit/qt_py_esp32s3/board.yml create mode 100644 boards/adafruit/qt_py_esp32s3/doc/img/adafruit_qt_py_esp32s3.webp create mode 100644 boards/adafruit/qt_py_esp32s3/doc/index.rst create mode 100644 boards/adafruit/qt_py_esp32s3/revision.cmake create mode 100644 boards/adafruit/qt_py_esp32s3/seeed_xiao_connector.dtsi create mode 100644 boards/adafruit/qt_py_esp32s3/support/openocd.cfg diff --git a/boards/adafruit/qt_py_esp32s3/Kconfig b/boards/adafruit/qt_py_esp32s3/Kconfig new file mode 100644 index 00000000000000..eff63767823922 --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/Kconfig @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Ian Wakely + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 4096 if BOARD_ADAFRUIT_QT_PY_ESP32S3_ESP32S3_PROCPU + default 256 if BOARD_ADAFRUIT_QT_PY_ESP32S3_ESP32S3_APPCPU diff --git a/boards/adafruit/qt_py_esp32s3/Kconfig.adafruit_qt_py_esp32s3 b/boards/adafruit/qt_py_esp32s3/Kconfig.adafruit_qt_py_esp32s3 new file mode 100644 index 00000000000000..9d5e991b572c55 --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/Kconfig.adafruit_qt_py_esp32s3 @@ -0,0 +1,9 @@ +# Adafruit ESP32S3 board configuration + +# Copyright (c) 2024 Ian Wakely + +config BOARD_ADAFRUIT_QT_PY_ESP32S3 + select SOC_ESP32S3_WROOM_N8 if "$(BOARD_REVISION)" = "" + select SOC_ESP32S3_WROOM_N4R2 if "$(BOARD_REVISION)" = "psram" + select SOC_ESP32S3_PROCPU if BOARD_ADAFRUIT_QT_PY_ESP32S3_ESP32S3_PROCPU + select SOC_ESP32S3_APPCPU if BOARD_ADAFRUIT_QT_PY_ESP32S3_ESP32S3_APPCPU diff --git a/boards/adafruit/qt_py_esp32s3/Kconfig.sysbuild b/boards/adafruit/qt_py_esp32s3/Kconfig.sysbuild new file mode 100644 index 00000000000000..3a2d17ac5cfd06 --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/Kconfig.sysbuild @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +choice BOOTLOADER + default BOOTLOADER_MCUBOOT +endchoice + +choice BOOT_SIGNATURE_TYPE + default BOOT_SIGNATURE_TYPE_NONE +endchoice diff --git a/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3-pinctrl.dtsi b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3-pinctrl.dtsi new file mode 100644 index 00000000000000..8c59416d21bfbf --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3-pinctrl.dtsi @@ -0,0 +1,67 @@ +/* + * Copyright 2022 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + spim2_default: spim2_default { + group1 { + pinmux = , + ; + }; + group2 { + pinmux = ; + output-low; + }; + }; + + spim3_ws2812_led: spim3_ws2812_led { + group1 { + pinmux = ; + output-low; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + i2c1_default: i2c1_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + twai_default: twai_default { + group1 { + pinmux = , + ; + }; + }; +}; diff --git a/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu.dts b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu.dts new file mode 100644 index 00000000000000..876a6d78fc68f2 --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu.dts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Ian Wakely + */ + +/dts-v1/; + +#include +#include "adafruit_qt_py_esp32s3-pinctrl.dtsi" +#include + +/ { + model = "Adafruit QT Py ESP32S3 APPCPU"; + compatible = "espressif,esp32s3"; + + chosen { + zephyr,sram = &sram1; + zephyr,ipc_shm = &shm0; + zephyr,ipc = &ipm0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_appcpu_partition; + }; +}; + +&trng0 { + status = "okay"; +}; + +&ipm0 { + status = "okay"; +}; diff --git a/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu.yaml b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu.yaml new file mode 100644 index 00000000000000..70b5253574ce63 --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: adafruit_qt_py_esp32s3/esp32s3/appcpu +name: Adafruit QT Py ESP32S3 APPCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - uart +testing: + ignore_tags: + - net + - bluetooth + - flash + - cpp + - posix + - watchdog + - logging + - kernel + - pm + - gpio + - crypto + - eeprom + - heap + - cmsis_rtos + - jwt + - zdsp +vendor: adafruit diff --git a/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu_defconfig b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu_defconfig new file mode 100644 index 00000000000000..9abf2ff0430aba --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu_defconfig @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_CLOCK_CONTROL=y diff --git a/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu_psram.overlay b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu_psram.overlay new file mode 100644 index 00000000000000..ac1ec4af1b19cf --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu_psram.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Ian Wakely + */ + +/delete-node/ &flash0; + +/ { + model = "Adafruit QT Py ESP32S3 PSRAM APPCPU"; + + soc { + flash: flash-controller@60002000 { + compatible = "espressif,esp32-flash-controller"; + reg = <0x60002000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + /* 4MB flash */ + flash0: flash@0 { + compatible = "soc-nv-flash"; + erase-block-size = <4096>; + write-block-size = <4>; + reg = <0x0 DT_SIZE_M(4)>; + }; + }; + }; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(2)>; + status = "okay"; +}; + +#include diff --git a/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu_psram.yaml b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu_psram.yaml new file mode 100644 index 00000000000000..4d3dba70d68cab --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_appcpu_psram.yaml @@ -0,0 +1,27 @@ +identifier: adafruit_qt_py_esp32s3@psram/esp32s3/appcpu +name: Adafruit QT Py ESP32S3 PSRAM APPCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - uart +testing: + ignore_tags: + - net + - bluetooth + - flash + - cpp + - posix + - watchdog + - logging + - kernel + - pm + - gpio + - crypto + - eeprom + - heap + - cmsis_rtos + - jwt + - zdsp +vendor: adafruit diff --git a/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu.dts b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu.dts new file mode 100644 index 00000000000000..ac757645e5b575 --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu.dts @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2023 Seeed Studio inc. + * Copyright (c) 2024 Ian Wakely + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include +#include "adafruit_qt_py_esp32s3-pinctrl.dtsi" +#include "seeed_xiao_connector.dtsi" +#include + +/ { + model = "Adafruit QT Py ESP32S3 PROCPU"; + compatible = "seeed,xiao-esp32s3"; + + chosen { + zephyr,sram = &sram1; + zephyr,console = &usb_serial; + zephyr,shell-uart = &usb_serial; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,bt-hci = &esp32_bt_hci; + }; + + aliases { + i2c-0 = &i2c0; + watchdog0 = &wdt0; + led-strip = &led_strip; + sw0 = &button0; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "User button"; + zephyr,code = ; + }; + }; +}; + +&usb_serial { + status = "okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&i2c0 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&i2c1 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; +}; + +&trng0 { + status = "okay"; +}; + +&spi2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim2_default>; + pinctrl-names = "default"; +}; + +&spi3 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim3_ws2812_led>; + pinctrl-names = "default"; + + line-idle-low; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <6400000>; + + /* WS2812 */ + chain-length = <1>; + spi-cpha; + spi-one-frame = <0xf0>; /* 11110000: 625 ns high and 625 ns low */ + spi-zero-frame = <0xc0>; /* 11000000: 312.5 ns high and 937.5 ns low */ + color-mapping = ; + }; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; + + /* + * Unlike some of the other Adafruit boards, the neopixel on this board has + * its positive side hooked up to a GPIO pin rather than a positive voltage + * rail to save on power. This will enable the LED on board initialization. + */ + neopixel-power-enable { + gpio-hog; + gpios = <6 GPIO_ACTIVE_HIGH>; + output-high; + }; +}; + +&wdt0 { + status = "okay"; +}; + +&twai { + pinctrl-0 = <&twai_default>; + pinctrl-names = "default"; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&esp32_bt_hci { + status = "okay"; +}; diff --git a/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu.yaml b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu.yaml new file mode 100644 index 00000000000000..b3d1cd326ebd98 --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu.yaml @@ -0,0 +1,19 @@ +identifier: adafruit_qt_py_esp32s3/esp32s3/procpu +name: Adafruit QT Py ESP32S3 PROCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - uart + - i2c + - i2s + - spi + - can + - counter + - watchdog + - entropy + - pwm + - dma +vendor: adafruit diff --git a/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu_defconfig b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu_defconfig new file mode 100644 index 00000000000000..6539bd42e5947e --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu_defconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_GPIO=y diff --git a/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu_psram.overlay b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu_psram.overlay new file mode 100644 index 00000000000000..5ab0be63c3ffb3 --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu_psram.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Ian Wakely + */ + +/delete-node/ &flash0; + +/ { + model = "Adafruit QT Py ESP32S3 PSRAM PROCPU"; + + soc { + flash: flash-controller@60002000 { + compatible = "espressif,esp32-flash-controller"; + reg = <0x60002000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + /* 4MB flash */ + flash0: flash@0 { + compatible = "soc-nv-flash"; + erase-block-size = <4096>; + write-block-size = <4>; + reg = <0x0 DT_SIZE_M(4)>; + }; + }; + }; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(2)>; + status = "okay"; +}; + +#include diff --git a/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu_psram.yaml b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu_psram.yaml new file mode 100644 index 00000000000000..37e6a7f15d66fc --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/adafruit_qt_py_esp32s3_procpu_psram.yaml @@ -0,0 +1,19 @@ +identifier: adafruit_qt_py_esp32s3@psram/esp32s3/procpu +name: Adafruit QT Py ESP32S3 PSRAM PROCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - uart + - i2c + - i2s + - spi + - can + - counter + - watchdog + - entropy + - pwm + - dma +vendor: adafruit diff --git a/boards/adafruit/qt_py_esp32s3/board.cmake b/boards/adafruit/qt_py_esp32s3/board.cmake new file mode 100644 index 00000000000000..2f04d1fe8861ea --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/board.cmake @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(NOT "${OPENOCD}" MATCHES "^${ESPRESSIF_TOOLCHAIN_PATH}/.*") + set(OPENOCD OPENOCD-NOTFOUND) +endif() +find_program(OPENOCD openocd PATHS ${ESPRESSIF_TOOLCHAIN_PATH}/openocd-esp32/bin NO_DEFAULT_PATH) + +include(${ZEPHYR_BASE}/boards/common/esp32.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/adafruit/qt_py_esp32s3/board.yml b/boards/adafruit/qt_py_esp32s3/board.yml new file mode 100644 index 00000000000000..c9b26924f8c39f --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/board.yml @@ -0,0 +1,12 @@ +board: + name: adafruit_qt_py_esp32s3 + full_name: QT Py ESP32-S3 + vendor: adafruit + socs: + - name: esp32s3 + revision: + format: "custom" + default: "" + revisions: + - name: "" + - name: "psram" diff --git a/boards/adafruit/qt_py_esp32s3/doc/img/adafruit_qt_py_esp32s3.webp b/boards/adafruit/qt_py_esp32s3/doc/img/adafruit_qt_py_esp32s3.webp new file mode 100644 index 0000000000000000000000000000000000000000..43637d31a6fa4507e4503067ed69fdeb4457095b GIT binary patch literal 30372 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 literal 0 HcmV?d00001 diff --git a/boards/adafruit/qt_py_esp32s3/doc/index.rst b/boards/adafruit/qt_py_esp32s3/doc/index.rst new file mode 100644 index 00000000000000..1c1f6e04eeecae --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/doc/index.rst @@ -0,0 +1,291 @@ +.. zephyr:board:: adafruit_qt_py_esp32s3 + +Overview +******** + +An Adafruit based Xiao compatible board based on the ESP32-S3, which is great +for IoT projects and prototyping with new sensors. + +For more details see the `Adafruit QT Py ESP32S3`_ product page. + +Hardware +******** + +This board comes in 2 variants, both based on the ESP32-S3 with WiFi and BLE +support. The default variant supporting 8MB of flash with no PSRAM, while the +``psram`` variant supporting 4MB of flash with 2MB of PSRAM. Both boards have a +USB-C port for programming and debugging and is based on a standard XIAO 14 +pin pinout. + +In addition to the Xiao compatible pinout, it also has a RGB NeoPixel for +status and debugging, a reset button, and a button for entering the ROM +bootloader or user input. Like many other Adafruit boards, it has a +`SparkFun Qwiic`_-compatible `STEMMA QT`_ connector for the I2C bus so you +don't even need to solder. + +ESP32-S3 is a low-power MCU-based system on a chip (SoC) with integrated +2.4 GHz Wi-Fi and Bluetooth® Low Energy (Bluetooth LE). It consists of +high-performance dual-core microprocessor (Xtensa® 32-bit LX7), a low power +coprocessor, a Wi-Fi baseband, a Bluetooth LE baseband, RF module, and +numerous peripherals. + +Supported Features +================== + +Current Zephyr's Adafruit QT Py ESP32-S3 board supports the following features: + ++------------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++============+============+=====================================+ +| UART | on-chip | serial port | ++------------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++------------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++------------+------------+-------------------------------------+ +| USB-JTAG | on-chip | hardware interface | ++------------+------------+-------------------------------------+ +| SPI Master | on-chip | spi | ++------------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++------------+------------+-------------------------------------+ +| I2S | on-chip | i2s | ++------------+------------+-------------------------------------+ +| TWAI/CAN | on-chip | can | ++------------+------------+-------------------------------------+ +| ADC | on-chip | adc | ++------------+------------+-------------------------------------+ +| Timers | on-chip | counter | ++------------+------------+-------------------------------------+ +| Watchdog | on-chip | watchdog | ++------------+------------+-------------------------------------+ +| TRNG | on-chip | entropy | ++------------+------------+-------------------------------------+ +| LEDC | on-chip | pwm | ++------------+------------+-------------------------------------+ +| MCPWM | on-chip | pwm | ++------------+------------+-------------------------------------+ +| PCNT | on-chip | qdec | ++------------+------------+-------------------------------------+ +| GDMA | on-chip | dma | ++------------+------------+-------------------------------------+ +| Wi-Fi | on-chip | | ++------------+------------+-------------------------------------+ +| Bluetooth | on-chip | | ++------------+------------+-------------------------------------+ + +Prerequisites +------------- + +Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the +command below to retrieve those files. + +.. code-block:: console + + west blobs fetch hal_espressif + +.. note:: + + It is recommended running the command above after :file:`west update`. + +Building & Flashing +******************* + +Simple boot +=========== + +The board could be loaded using the single binary image, without 2nd stage +bootloader. It is the default option when building the application without +additional configuration. + +.. note:: + + Simple boot does not provide any security features nor OTA updates. + +MCUboot bootloader +================== + +User may choose to use MCUboot bootloader instead. In that case the bootloader +must be built (and flashed) at least once. + +There are two options to be used when building an application: + +1. Sysbuild +2. Manual build + +.. note:: + + User can select the MCUboot bootloader by adding the following line + to the board default configuration file. + + .. code:: cfg + + CONFIG_BOOTLOADER_MCUBOOT=y + +Sysbuild +======== + +The sysbuild makes possible to build and flash all necessary images needed to +bootstrap the board with the ESP32 SoC. + +To build the sample application using sysbuild use the command: + +.. zephyr-app-commands:: + :tool: west + :zephyr-app: samples/hello_world + :board: adafruit_qt_py_esp32s3 + :goals: build + :west-args: --sysbuild + :compact: + +By default, the ESP32 sysbuild creates bootloader (MCUboot) and application +images. But it can be configured to create other kind of images. + +Build directory structure created by sysbuild is different from traditional +Zephyr build. Output is structured by the domain subdirectories: + +.. code-block:: + + build/ + ├── hello_world + │ └── zephyr + │ ├── zephyr.elf + │ └── zephyr.bin + ├── mcuboot + │ └── zephyr + │ ├── zephyr.elf + │ └── zephyr.bin + └── domains.yaml + +.. note:: + + With ``--sysbuild`` option the bootloader will be re-build and re-flash + every time the pristine build is used. + +For more information about the system build please read the :ref:`sysbuild` documentation. + +Manual build +============ + +During the development cycle, it is intended to build & flash as quickly possible. +For that reason, images can be built one at a time using traditional build. + +The instructions following are relevant for both manual build and sysbuild. +The only difference is the structure of the build directory. + +.. note:: + + Remember that bootloader (MCUboot) needs to be flash at least once. + +Build and flash applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +.. tabs:: + + .. group-tab:: QT Py ESP32S3 + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adafruit_qt_py_esp32s3/esp32s3/procpu + :goals: build + + .. group-tab:: QT Py ESP32S3 with PSRAM + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adafruit_qt_py_esp32s3@psram/esp32s3/procpu + :goals: build + +The usual ``flash`` target will work with the ``adafruit_qt_py_esp32s3`` board +configuration. Here is an example for the :zephyr:code-sample:`hello_world` +application. + +.. tabs:: + + .. group-tab:: QT Py ESP32S3 + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adafruit_qt_py_esp32s3/esp32s3/procpu + :goals: flash + + .. group-tab:: QT Py ESP32S3 with PSRAM + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adafruit_qt_py_esp32s3@psram/esp32s3/procpu + :goals: flash + +Open the serial monitor using the following command: + +.. code-block:: shell + + west espressif monitor + +After the board has automatically reset and booted, you should see the following +message in the monitor: + +.. code-block:: console + + ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** + Hello World! adafruit_qt_py_esp32s3/esp32s3/procpu + +Debugging +********* + +ESP32-S3 support on OpenOCD is available at `OpenOCD ESP32`_. + +ESP32-S3 has a built-in JTAG circuitry and can be debugged without any +additional chip. Only an USB cable connected to the D+/D- pins is necessary. + +Further documentation can be obtained from the SoC vendor +in `JTAG debugging for ESP32-S3`_. + +Here is an example for building the :zephyr:code-sample:`hello_world` application. + +.. tabs:: + + .. group-tab:: QT Py ESP32S3 + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adafruit_qt_py_esp32s3/esp32s3/procpu + :goals: debug + + .. group-tab:: QT Py ESP32S3 with PSRAM + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adafruit_qt_py_esp32s3@psram/esp32s3/procpu + :goals: debug + +You can debug an application in the usual way. Here is an example for +the :zephyr:code-sample:`hello_world` application. + +.. tabs:: + + .. group-tab:: QT Py ESP32S3 + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adafruit_qt_py_esp32s3/esp32s3/procpu + :goals: debug + + .. group-tab:: QT Py ESP32S3 with PSRAM + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adafruit_qt_py_esp32s3@psram/esp32s3/procpu + :goals: debug + +References +********** + +.. target-notes:: + +.. _`Adafruit QT Py ESP32S3`: https://www.adafruit.com/product/5426 +.. _`Adafruit QT Py ESP32S3 - PSRAM`: https://www.adafruit.com/product/5700 +.. _`JTAG debugging for ESP32-S3`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ +.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases +.. _`SparkFun Qwiic`: https://www.sparkfun.com/qwiic +.. _`STEMMA QT`: https://learn.adafruit.com/introducing-adafruit-stemma-qt diff --git a/boards/adafruit/qt_py_esp32s3/revision.cmake b/boards/adafruit/qt_py_esp32s3/revision.cmake new file mode 100644 index 00000000000000..26aeb65f775eff --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/revision.cmake @@ -0,0 +1,3 @@ +if(DEFINED BOARD_REVISION AND NOT BOARD_REVISION STREQUAL "psram") + message(FATAL_ERROR "Invalid board revision, ${BOARD_REVISION}, valid revisions are: (for non-PSRAM version), psram") +endif() diff --git a/boards/adafruit/qt_py_esp32s3/seeed_xiao_connector.dtsi b/boards/adafruit/qt_py_esp32s3/seeed_xiao_connector.dtsi new file mode 100644 index 00000000000000..39880f7c942d8a --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/seeed_xiao_connector.dtsi @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Ian Wakely + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + xiao_d: connector { + compatible = "seeed,xiao-gpio"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 18 0>, /* D0 */ + <1 0 &gpio0 17 0>, /* D1 */ + <2 0 &gpio0 9 0>, /* D2 */ + <3 0 &gpio0 8 0>, /* D3 */ + <4 0 &gpio0 7 0>, /* D4 */ + <5 0 &gpio0 6 0>, /* D5 */ + <6 0 &gpio0 5 0>, /* D6 */ + <7 0 &gpio0 16 0>, /* D7 */ + <8 0 &gpio1 4 0>, /* D8 */ + <9 0 &gpio1 5 0>, /* D9 */ + <10 0 &gpio1 3 0>; /* D10 */ + }; +}; + +xiao_spi: &spi2 {}; +xiao_i2c: &i2c0 {}; +xiao_serial: &uart0 {}; +xiao_adc: &adc0 {}; diff --git a/boards/adafruit/qt_py_esp32s3/support/openocd.cfg b/boards/adafruit/qt_py_esp32s3/support/openocd.cfg new file mode 100644 index 00000000000000..2f740b4a36ab1f --- /dev/null +++ b/boards/adafruit/qt_py_esp32s3/support/openocd.cfg @@ -0,0 +1,7 @@ +set ESP_RTOS none +set ESP32_ONLYCPU 1 + +# Source the JTAG interface configuration file +source [find interface/esp_usb_jtag.cfg] +# Source the ESP32-S3 configuration file +source [find target/esp32s3.cfg]