diff --git a/zephcore/boards/esp32/lilygo_t3s3/Kconfig b/zephcore/boards/esp32/lilygo_t3s3/Kconfig new file mode 100644 index 0000000..1a4e6e4 --- /dev/null +++ b/zephcore/boards/esp32/lilygo_t3s3/Kconfig @@ -0,0 +1,5 @@ +# Extra heap for the SSD1306 128x64 CFB (UI pages) + ZephCore UI/BLE +# allocations on top of the esp32_common.conf platform heap. +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 4096 \ No newline at end of file diff --git a/zephcore/boards/esp32/lilygo_t3s3/Kconfig.lilygo_t3s3 b/zephcore/boards/esp32/lilygo_t3s3/Kconfig.lilygo_t3s3 new file mode 100644 index 0000000..67aefab --- /dev/null +++ b/zephcore/boards/esp32/lilygo_t3s3/Kconfig.lilygo_t3s3 @@ -0,0 +1,3 @@ +config BOARD_LILYGO_T3S3 + select SOC_ESP32S3_WROOM_N4R2 + select SOC_ESP32S3_PROCPU if BOARD_LILYGO_T3S3_ESP32S3_PROCPU \ No newline at end of file diff --git a/zephcore/boards/esp32/lilygo_t3s3/board.cmake b/zephcore/boards/esp32/lilygo_t3s3/board.cmake new file mode 100644 index 0000000..e1dd6ce --- /dev/null +++ b/zephcore/boards/esp32/lilygo_t3s3/board.cmake @@ -0,0 +1,7 @@ +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) \ No newline at end of file diff --git a/zephcore/boards/esp32/lilygo_t3s3/board.conf b/zephcore/boards/esp32/lilygo_t3s3/board.conf new file mode 100644 index 0000000..9c1ca3a --- /dev/null +++ b/zephcore/boards/esp32/lilygo_t3s3/board.conf @@ -0,0 +1,18 @@ +# LilyGo T3S3 — ESP32-S3-WROOM-1-N4R2, SX1262, SSD1306 OLED +# +# Hardware: +# SX1262 on SPI2 (DIO2 RF switch, 1.8V TCXO via DIO3) +# SSD1306 128x64 OLED on I2C0 +# User button on GPIO0, TX LED on GPIO37 +# VBAT ADC on GPIO1 +# Native USB Serial/JTAG console +# +# Include order: prj.conf → zephcore_common.conf → esp32_common.conf → board.conf + +# Board identification +CONFIG_ZEPHCORE_BOARD_NAME="LilyGo T3S3" +CONFIG_BT_DIS_MODEL_NUMBER_STR="LilyGo T3S3" + +# SX1262 — 22 dBm TX power (MeshCore variant default) +CONFIG_ZEPHCORE_DEFAULT_TX_POWER_DBM=22 +CONFIG_ZEPHCORE_MAX_TX_POWER_DBM=22 \ No newline at end of file diff --git a/zephcore/boards/esp32/lilygo_t3s3/board.overlay b/zephcore/boards/esp32/lilygo_t3s3/board.overlay new file mode 100644 index 0000000..881ceaf --- /dev/null +++ b/zephcore/boards/esp32/lilygo_t3s3/board.overlay @@ -0,0 +1,170 @@ +/* + * SPDX-License-Identifier: MIT + * LilyGo T3S3 — ZephCore overlay + * + * The board DTS defines the minimal SoC/bus layer (SPI2, I2C0, GPIO, USB + * serial, BLE, WiFi, flash partitions). This overlay adds the ZephCore + * peripheral wiring on top. + * + * Pin mapping (from Arduino MeshCore variants/lilygo_t3s3): + * LoRa SPI2: SCLK=GPIO5, MOSI=GPIO6, MISO=GPIO3, NSS=GPIO7 + * LoRa ctrl: RESET=GPIO8, BUSY=GPIO34, DIO1=GPIO33 + * DIO2 = antenna RF switch, DIO3 = 1.8V TCXO + * Display I2C0: SDA=GPIO18, SCL=GPIO17, RST=GPIO21 (SSD1306 @0x3C) + * Button: GPIO0 + * TX LED: GPIO37 + * VBAT ADC: GPIO1 = ADC unit 1 ch 0 (&adc0) + * + * GPIO bank note (ESP32-S3): GPIO0-31 are on &gpio0, GPIO32-47 on &gpio1. + * GPIO33 = &gpio1 pin 1, GPIO34 = &gpio1 pin 2, GPIO37 = &gpio1 pin 5. + */ + +#include +#include +#include + +/ { + aliases { + lora0 = &lora; + sw0 = &user_button; + lora-tx-led = &tx_led; + }; + + chosen { + zephyr,display = &ssd1306; + }; + + /* User button chain — same mapping as RAK4631 / WisMesh Pocket. */ + buttons: buttons { + compatible = "gpio-keys"; + + user_button: button_0 { + gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "User Button"; + zephyr,code = ; + }; + }; + + user_btn_longpress { + compatible = "zephyr,input-longpress"; + input = <&buttons>; + input-codes = ; + short-codes = ; + long-codes = ; + long-delay-ms = <1000>; + }; + + page_btn_multitap { + compatible = "zephcore,input-multi-tap"; + input-codes = ; + tap-codes = ; + tap-delay-ms = <400>; + }; + + /* TX activity LED — GPIO37, active-HIGH. Blinks on LoRa TX. */ + leds { + compatible = "gpio-leds"; + + tx_led: led_0 { + gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; /* GPIO37 = gpio1 pin 5 */ + label = "TX LED"; + }; + }; + + /* Battery ADC — ZephCore reads via zephyr,user { io-channels }. + * GPIO1 = ADC unit 1 ch 0 = &adc0 (label 0-indexed, unit 1-indexed). + * Multiplier: 1100 mV ref × 4 gain × 2:1 divider = 8800, matching + * MeshCore's 2 × analogReadMilliVolts. */ + zephyr,user { + io-channels = <&adc0 0>; + vbat-mv-multiplier = <8800>; + }; +}; + +/* SX1262 on SPI2 (pinctrl already set in board DTS). */ +&spi2 { + cs-gpios = <&gpio0 7 GPIO_ACTIVE_LOW>; /* NSS = GPIO7 */ + + lora: lora@0 { + compatible = "semtech,sx1262"; + reg = <0>; + spi-max-frequency = <8000000>; + + reset-gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; /* RESET = GPIO8 */ + busy-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; /* BUSY = GPIO34 = gpio1 pin 2 */ + dio1-gpios = <&gpio1 1 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; /* DIO1 = GPIO33 = gpio1 pin 1 */ + + /* DIO2 drives the antenna TX/RX switch (no rx/tx-enable GPIOs). */ + dio2-tx-enable; + + /* TCXO 1.8V via DIO3 — 5 ms matches Arduino (RadioLib ctrl timeout) */ + dio3-tcxo-voltage = ; + tcxo-power-startup-delay-ms = <5>; + + rx-boosted; + }; +}; + +/* SSD1306 128x64 OLED on I2C0 */ +&i2c0 { + ssd1306: ssd1306@3c { + compatible = "solomon,ssd1306"; + reg = <0x3c>; + width = <128>; + height = <64>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <63>; + segment-remap; + com-invdir; + inversion-on; + prechargep = <0x22>; + reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; /* RST_OLED = GPIO21 */ + }; + + #include "../../common/sensors-i2c.dtsi" +}; + +/* Battery ADC channel configuration on adc0 (ADC unit 1 -> GPIO1 = ch0). + * Without the channel node adc_channel_setup_dt() fails and + * getBattMilliVolts() returns 0. */ +&adc0 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + /* ADC_GAIN_1_4 = 12 dB ≈ Arduino's default 3.3V scale; + * 1/6 not supported by the esp32 driver → channel setup fails. */ + zephyr,gain = "ADC_GAIN_1_4"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; + +/* ADC unit 2 (label adc1) is unused on this board; keep it disabled. */ +&adc1 { + status = "disabled"; +}; + +/* + * Flash partitions live in partitions.overlay (this dir) so the identical map + * is fed to both the app and the MCUboot image — see that file and + * sysbuild/CMakeLists.txt. + */ + +/* LittleFS auto-mount — standard /lfs mount point */ +#include "../../common/filesystem.dtsi" + +/* USB OTG companion transport. The node is inert unless the build enables the + * USB device stack via boards/common/esp32s3_usb.conf. + * + * This board consoles over USB Serial/JTAG (board DTS), which shares D+/D- + * with USB OTG — so the console reroute to uart0 lives in the auto-paired + * boards/common/esp32s3_usb.overlay and applies only when that conf is passed. + * Do NOT include esp32s3_console_uart0.dtsi here: it would move the console + * onto GPIO43/44 in every build of this board. */ +#include "../../common/esp32s3_usb_otg.dtsi" \ No newline at end of file diff --git a/zephcore/boards/esp32/lilygo_t3s3/board.yml b/zephcore/boards/esp32/lilygo_t3s3/board.yml new file mode 100644 index 0000000..21090ff --- /dev/null +++ b/zephcore/boards/esp32/lilygo_t3s3/board.yml @@ -0,0 +1,6 @@ +board: + name: lilygo_t3s3 + full_name: LilyGo T3S3 + vendor: lilygo + socs: + - name: esp32s3 \ No newline at end of file diff --git a/zephcore/boards/esp32/lilygo_t3s3/lilygo_t3s3-pinctrl.dtsi b/zephcore/boards/esp32/lilygo_t3s3/lilygo_t3s3-pinctrl.dtsi new file mode 100644 index 0000000..9d11abf --- /dev/null +++ b/zephcore/boards/esp32/lilygo_t3s3/lilygo_t3s3-pinctrl.dtsi @@ -0,0 +1,42 @@ +/* + * SPDX-License-Identifier: MIT + * LilyGo T3S3 — Pin Control Definitions + * + * Pin mapping (from Arduino MeshCore variants/lilygo_t3s3): + * SPI2 LoRa: SCLK=GPIO5, MOSI=GPIO6, MISO=GPIO3, NSS=GPIO7 (GPIO CS) + * LoRa ctrl: RESET=GPIO8, BUSY=GPIO34, DIO1=GPIO33 (DIO2 = RF switch) + * I2C0: SDA=GPIO18, SCL=GPIO17 (SSD1306 OLED @0x3C, RST=GPIO21) + * Button: GPIO0 + * TX LED: GPIO37 + * VBAT ADC: GPIO1 + * Console: USB Serial/JTAG (native) + */ + +#include +#include +#include + +&pinctrl { + /* SPI2 — SX1262 LoRa (CS via cs-gpios, not pinctrl) */ + spim2_default: spim2_default { + group1 { + pinmux = , + ; + }; + group2 { + pinmux = ; + output-low; + }; + }; + + /* I2C0 — SSD1306 OLED + optional sensors */ + i2c0_default: i2c0_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; +}; \ No newline at end of file diff --git a/zephcore/boards/esp32/lilygo_t3s3/lilygo_t3s3_procpu.dts b/zephcore/boards/esp32/lilygo_t3s3/lilygo_t3s3_procpu.dts new file mode 100644 index 0000000..629b92a --- /dev/null +++ b/zephcore/boards/esp32/lilygo_t3s3/lilygo_t3s3_procpu.dts @@ -0,0 +1,81 @@ +/* + * SPDX-License-Identifier: MIT + * LilyGo T3S3 — ESP32-S3 (WROOM-1 N4R2), 4MB flash, 2MB QSPI PSRAM + * + * Hardware: + * MCU: ESP32-S3 (Xtensa LX7, dual-core) + * Module: ESP32-S3-WROOM-1-N4R2 (4MB flash, 2MB QSPI PSRAM) + * Radio: SX1262 on SPI2 (defined in board.overlay) + * Display: SSD1306 128x64 OLED on I2C0 (defined in board.overlay) + * Button: GPIO0 + * TX LED: GPIO37 + * VBAT: GPIO1 ADC + * Console: Native USB Serial/JTAG + * + * Peripheral wiring (radio, display, button, LED, battery) is intentionally + * kept in board.overlay — this DTS is the minimal SoC/bus layer. + */ + +/dts-v1/; + +#include +#include "lilygo_t3s3-pinctrl.dtsi" +#include + +/ { + model = "LilyGo T3S3"; + compatible = "lilygo,t3s3"; + + 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 { + uart-0 = &uart0; + i2c-0 = &i2c0; + watchdog0 = &wdt0; + }; +}; + +&usb_serial { + status = "okay"; +}; + +&i2c0 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&spi2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim2_default>; + pinctrl-names = "default"; +}; + +&gpio0 { status = "okay"; }; +&gpio1 { status = "okay"; }; + +&timer0 { status = "okay"; }; +&timer1 { status = "okay"; }; +&timer2 { status = "okay"; }; +&timer3 { status = "okay"; }; + +&wdt0 { status = "okay"; }; +&trng0 { status = "okay"; }; + +&esp32_bt_hci { + status = "okay"; +}; + +&wifi { + status = "okay"; +}; \ No newline at end of file diff --git a/zephcore/boards/esp32/lilygo_t3s3/lilygo_t3s3_procpu_defconfig b/zephcore/boards/esp32/lilygo_t3s3/lilygo_t3s3_procpu_defconfig new file mode 100644 index 0000000..a2d09e5 --- /dev/null +++ b/zephcore/boards/esp32/lilygo_t3s3/lilygo_t3s3_procpu_defconfig @@ -0,0 +1,12 @@ +# LilyGo T3S3 — minimal Zephyr defconfig (procpu) +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_GPIO=y +CONFIG_CLOCK_CONTROL=y +CONFIG_PINCTRL=y +CONFIG_SPI=y +CONFIG_I2C=y +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y +CONFIG_NVS=y \ No newline at end of file diff --git a/zephcore/boards/esp32/lilygo_t3s3/partitions.overlay b/zephcore/boards/esp32/lilygo_t3s3/partitions.overlay new file mode 100644 index 0000000..2960f4c --- /dev/null +++ b/zephcore/boards/esp32/lilygo_t3s3/partitions.overlay @@ -0,0 +1,53 @@ +/* + * Flash partition layout — SHARED by the app image and MCUboot. + * + * Fed to BOTH images (app via EXTRA_DTC_OVERLAY_FILE, MCUboot via + * mcuboot_EXTRA_DTC_OVERLAY_FILE in sysbuild/CMakeLists.txt) so their flash maps + * are identical — otherwise MCUboot stages/looks for the OTA image at a different + * address than the app writes it to and OTA silently reverts on reboot. + * + * slot0 starts at 0x10000 (right after the 64KB MCUboot region), matching the + * Arduino/ESP-IDF app offset (Mesh America "flash-update" compatible). sys_partition + * is reclaimed. Slots are equal size and slot1 ends exactly on the unchanged + * storage/lfs offsets, so a -merged reflash keeps identity/prefs/contacts/BLE-bonds. + * + * 4MB layout. + */ +/delete-node/ &sys_partition; +/delete-node/ &slot0_lpcore_partition; +/delete-node/ &slot1_lpcore_partition; +/delete-node/ &storage_partition; +/delete-node/ &scratch_partition; +/delete-node/ &coredump_partition; +/delete-node/ &slot0_partition; +/delete-node/ &slot1_partition; + +/ { + chosen { + zephyr,settings-partition = &storage_partition; + }; +}; + +&flash0 { + partitions { + /* App slots — equal size (swap-mode compatible), slot0 at 0x10000. */ + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x10000 0x1C6000>; + }; + slot1_partition: partition@1D6000 { + label = "image-1"; + reg = <0x1D6000 0x1C6000>; + }; + /* BLE bond NVS — offset unchanged so bonds survive the reflash. */ + storage_partition: partition@39C000 { + label = "storage"; + reg = <0x39C000 0x4000>; + }; + /* LittleFS (identity/prefs/contacts) — offset unchanged. */ + lfs_partition: partition@3A0000 { + label = "lfs"; + reg = <0x3A0000 0x60000>; + }; + }; +}; \ No newline at end of file diff --git a/zephcore/boards/supported_boards.md b/zephcore/boards/supported_boards.md index d3957db..48966f6 100644 --- a/zephcore/boards/supported_boards.md +++ b/zephcore/boards/supported_boards.md @@ -40,6 +40,7 @@ xiao_esp32c3 xiao_esp32c6/esp32c6/hpcore xiao_esp32s3/esp32s3/procpu lilygo_tlora_c6/esp32c6/hpcore +lilygo_t3s3/esp32s3/procpu station_g2/esp32s3/procpu heltec_wifi_lora32_v3/esp32s3/procpu heltec_wifi_lora32_v4/esp32s3/procpu