diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7e0e7274..2f03b94b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,6 +2,44 @@
cmake_minimum_required(VERSION 3.20.0)
+#
+# Zephyr build system imposes to have a fixed folder structure for the target-specific
+# files, that is [...]/boards/ARCH/BOARDNAME because it infers the target
+# architecture by looking at the name of the parent folder of the board folder.
+#
+# This does not make sense, because:
+# 1) The folder with the target-specific files should be put anywhere, given that
+# the project using Zephyr may have its own conventions.
+# 2) Inferring the target architecture only from the folder tree is an idiocy.
+#
+# So: to make Zephyr play happily in his sandpit without complaints, we create a
+# board_root subfolder inside the build one and we copy the board-specific config
+# files there from our platform/targets tree creating the necessary folder tree.
+#
+# NOTE: the board-specific CMakeLists.txt files have to use the ${OPENRTX_ROOT}
+# variable as the base path. E.g. ${OPENRTX_ROOT}/platform/drivers/somedriver.c
+#
+if (${BOARD} STREQUAL "ttwrplus")
+ set(ARCH xtensa)
+ set(CONF_FILE ${CMAKE_CURRENT_LIST_DIR}/platform/mcu/ESP32S3/zephyr.conf)
+endif()
+
+#
+# Create the board_root folder and the proper folder tree for the targets
+#
+execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory
+ ${CMAKE_CURRENT_LIST_DIR}/platform/targets/${BOARD}
+ ${CMAKE_CURRENT_LIST_DIR}/build/board_root/boards/${ARCH}/${BOARD})
+
+#
+# Set the BOARD_ROOT and OPENRTX_ROOT variables
+#
+set(BOARD_ROOT ${CMAKE_CURRENT_LIST_DIR}/build/board_root)
+set(OPENRTX_ROOT ${CMAKE_CURRENT_LIST_DIR})
+
+#
+# Finally, set up the project
+#
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(openrtx)
diff --git a/platform/targets/ttwrplus/CMakeLists.txt b/platform/targets/ttwrplus/CMakeLists.txt
new file mode 100644
index 00000000..fa06db34
--- /dev/null
+++ b/platform/targets/ttwrplus/CMakeLists.txt
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+#
+# CMake configuration file for the T-TWR Plus OpenRTX target
+#
+cmake_minimum_required(VERSION 3.20.0)
+
+target_sources(app
+ PRIVATE
+ ${OPENRTX_ROOT}/platform/mcu/ESP32S3/drivers/delays.c
+
+ ${OPENRTX_ROOT}/platform/targets/ttwrplus/platform.c
+
+ ${OPENRTX_ROOT}/platform/drivers/stubs/audio_stub.c
+ ${OPENRTX_ROOT}/platform/drivers/stubs/cps_io_stub.c
+ ${OPENRTX_ROOT}/platform/drivers/stubs/display_stub.c
+ ${OPENRTX_ROOT}/platform/drivers/stubs/keyboard_stub.c
+ ${OPENRTX_ROOT}/platform/drivers/stubs/nvmem_stub.c
+ ${OPENRTX_ROOT}/platform/drivers/stubs/radio_stub.c
+)
+
+target_include_directories(app
+ PRIVATE
+ ${OPENRTX_ROOT}/platform/targets/ttwrplus
+)
+
+target_compile_definitions(app PRIVATE PLATFORM_TTWRPLUS)
diff --git a/platform/targets/ttwrplus/Kconfig.board b/platform/targets/ttwrplus/Kconfig.board
new file mode 100644
index 00000000..1a2cc075
--- /dev/null
+++ b/platform/targets/ttwrplus/Kconfig.board
@@ -0,0 +1,7 @@
+# LilyGo T-TWR Plus board configuration
+
+# SPDX-License-Identifier: Apache-2.0
+
+config BOARD_TTWRPLUS
+ bool "LilyGo T-TWR Plus Board"
+ depends on SOC_ESP32S3
diff --git a/platform/targets/ttwrplus/Kconfig.defconfig b/platform/targets/ttwrplus/Kconfig.defconfig
new file mode 100644
index 00000000..d4069cbb
--- /dev/null
+++ b/platform/targets/ttwrplus/Kconfig.defconfig
@@ -0,0 +1,19 @@
+# LilyGo T-TWR Plus board configuration
+
+# SPDX-License-Identifier: Apache-2.0
+
+config BOARD
+ default "ttwrplus"
+ depends on BOARD_TTWRPLUS
+
+config ENTROPY_GENERATOR
+ default y
+
+config HEAP_MEM_POOL_SIZE
+ default 98304 if WIFI
+ default 40960 if BT
+ default 4096
+
+choice BT_HCI_BUS_TYPE
+ default BT_ESP32 if BT
+endchoice
diff --git a/platform/targets/ttwrplus/Kconfig.sysbuild b/platform/targets/ttwrplus/Kconfig.sysbuild
new file mode 100644
index 00000000..2a92f43f
--- /dev/null
+++ b/platform/targets/ttwrplus/Kconfig.sysbuild
@@ -0,0 +1,9 @@
+# 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/platform/targets/ttwrplus/board.cmake b/platform/targets/ttwrplus/board.cmake
new file mode 100644
index 00000000..2f04d1fe
--- /dev/null
+++ b/platform/targets/ttwrplus/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/platform/targets/ttwrplus/hwconfig.h b/platform/targets/ttwrplus/hwconfig.h
new file mode 100644
index 00000000..0fd7622d
--- /dev/null
+++ b/platform/targets/ttwrplus/hwconfig.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ * Copyright (C) 2023 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Silvano Seva IU2KWO *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#ifndef HWCONFIG_H
+#define HWCONFIG_H
+
+#include
+
+/*
+ * Display properties are encoded in the devicetree
+ */
+#define DISPLAY DT_CHOSEN(zephyr_display)
+#define SCREEN_WIDTH DT_PROP(DISPLAY, width)
+#define SCREEN_HEIGHT DT_PROP(DISPLAY, height)
+#define PIX_FMT_BW
+
+/* TODO: battery type */
+#define BAT_NONE
+
+#endif /* HWCONFIG_H */
diff --git a/platform/targets/ttwrplus/platform.c b/platform/targets/ttwrplus/platform.c
new file mode 100644
index 00000000..efc98794
--- /dev/null
+++ b/platform/targets/ttwrplus/platform.c
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * Copyright (C) 2023 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Silvano Seva IU2KWO *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#include
+#include
+
+static const hwInfo_t hwInfo =
+{
+ .uhf_maxFreq = 430,
+ .uhf_minFreq = 440,
+ .uhf_band = 1,
+ .name = "ttwrplus"
+};
+
+
+void platform_init()
+{
+}
+
+void platform_terminate()
+{
+}
+
+uint16_t platform_getVbat()
+{
+ return 0;
+}
+
+uint8_t platform_getMicLevel()
+{
+ return 0;
+}
+
+uint8_t platform_getVolumeLevel()
+{
+ return 0;
+}
+
+int8_t platform_getChSelector()
+{
+ return 0;
+}
+
+bool platform_getPttStatus()
+{
+ return false;
+}
+
+bool platform_pwrButtonStatus()
+{
+ return true;
+}
+
+void platform_ledOn(led_t led)
+{
+ (void) led;
+}
+
+void platform_ledOff(led_t led)
+{
+ (void) led;
+}
+
+void platform_beepStart(uint16_t freq)
+{
+ (void) freq;
+}
+
+void platform_beepStop()
+{
+}
+
+const hwInfo_t *platform_getHwInfo()
+{
+ return &hwInfo;
+}
+
diff --git a/platform/targets/ttwrplus/support/openocd.cfg b/platform/targets/ttwrplus/support/openocd.cfg
new file mode 100644
index 00000000..2f740b4a
--- /dev/null
+++ b/platform/targets/ttwrplus/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]
diff --git a/platform/targets/ttwrplus/ttwrplus.dts b/platform/targets/ttwrplus/ttwrplus.dts
new file mode 100644
index 00000000..eb7f7268
--- /dev/null
+++ b/platform/targets/ttwrplus/ttwrplus.dts
@@ -0,0 +1,175 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/dts-v1/;
+
+#include
+#include
+#include
+#include
+#include
+
+/ {
+ model = "ttwrplus";
+ compatible = "espressif,esp32s3";
+
+ aliases {
+ i2c-0 = &i2c0;
+ watchdog0 = &wdt0;
+ };
+
+ chosen {
+ zephyr,sram = &sram0;
+ zephyr,console = &usb_serial;
+ zephyr,shell-uart = &usb_serial;
+ zephyr,flash = &flash0;
+ zephyr,display = &ssd1306;
+ };
+
+ aliases {
+ radio = &uart0;
+ };
+
+ buttons {
+ compatible = "gpio-keys";
+
+ sw_boot: button_0 {
+ gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+ label = "BOOT Button";
+ };
+
+ sw_user: button_1 {
+ gpios = <&gpio0 3 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
+ label = "USER Button";
+ };
+ };
+};
+
+&cpu0 {
+ clock-frequency = ;
+};
+
+&cpu1 {
+ clock-frequency = ;
+};
+
+&usb_serial {
+ status = "okay";
+};
+
+&uart0 {
+ status = "okay";
+ current-speed = <9600>;
+ pinctrl-0 = <&uart0_default>;
+ pinctrl-names = "default";
+};
+
+&i2c0 {
+ status = "okay";
+ clock-frequency = ;
+ pinctrl-0 = <&i2c0_default>;
+ pinctrl-names = "default";
+
+ ssd1306: ssd1306@3c {
+ compatible = "solomon,ssd1306fb";
+ reg = <0x3c>;
+
+ width = <128>;
+ height = <64>;
+
+ segment-offset = <2>;
+ page-offset = <0>;
+ display-offset = <0>;
+ multiplex-ratio = <63>;
+ prechargep = <0x22>;
+
+ segment-remap;
+ com-invdir;
+ };
+};
+
+&timer0 {
+ status = "disabled";
+};
+
+&timer1 {
+ status = "disabled";
+};
+
+&timer2 {
+ status = "disabled";
+};
+
+&timer3 {
+ status = "disabled";
+};
+
+&wdt0 {
+ status = "okay";
+};
+
+&trng0 {
+ status = "okay";
+};
+
+&pinctrl {
+ uart0_default: uart0_default {
+ group1 {
+ pinmux = ;
+ output-high;
+ };
+ group2 {
+ pinmux = ;
+ bias-pull-up;
+ };
+ };
+
+ i2c0_default: i2c0_default {
+ group1 {
+ pinmux = ,
+ ;
+ bias-pull-up;
+ drive-open-drain;
+ output-high;
+ };
+ };
+};
+
+&flash0 {
+ status = "okay";
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /* Reserve 64kB for the bootloader */
+ boot_partition: partition@0 {
+ label = "mcuboot";
+ reg = <0x00000000 0x00010000>;
+ read-only;
+ };
+
+ /* Reserve 1024kB for the application in slot 0 */
+ slot0_partition: partition@10000 {
+ label = "image-0";
+ reg = <0x00010000 0x00100000>;
+ };
+
+ /* Reserve 1024kB for the application in slot 1 */
+ slot1_partition: partition@110000 {
+ label = "image-1";
+ reg = <0x00110000 0x00100000>;
+ };
+
+ /* Reserve 256kB for the scratch partition */
+ scratch_partition: partition@210000 {
+ label = "image-scratch";
+ reg = <0x00210000 0x00040000>;
+ };
+
+ storage_partition: partition@250000 {
+ label = "storage";
+ reg = <0x00250000 0x00006000>;
+ };
+ };
+};
diff --git a/platform/targets/ttwrplus/ttwrplus.yaml b/platform/targets/ttwrplus/ttwrplus.yaml
new file mode 100644
index 00000000..fa3dbb89
--- /dev/null
+++ b/platform/targets/ttwrplus/ttwrplus.yaml
@@ -0,0 +1,20 @@
+identifier: ttwrplus
+name: LilyGO T-TWR Plus
+type: mcu
+arch: xtensa
+toolchain:
+ - zephyr
+supported:
+ - gpio
+ - uart
+ - i2c
+ - spi
+ - counter
+ - watchdog
+ - entropy
+ - pwm
+ - dma
+testing:
+ ignore_tags:
+ - net
+ - bluetooth
diff --git a/platform/targets/ttwrplus/ttwrplus_defconfig b/platform/targets/ttwrplus/ttwrplus_defconfig
new file mode 100644
index 00000000..3d84c30b
--- /dev/null
+++ b/platform/targets/ttwrplus/ttwrplus_defconfig
@@ -0,0 +1,3 @@
+CONFIG_DISPLAY=y
+CONFIG_SSD1306=y
+CONFIG_SSD1306_SH1106_COMPATIBLE=y