diff --git a/ports/esp32/boards/sdkconfig.spiram_sx b/ports/esp32/boards/sdkconfig.spiram_sx
new file mode 100644
index 0000000000..18a0712cbf
--- /dev/null
+++ b/ports/esp32/boards/sdkconfig.spiram_sx
@@ -0,0 +1,11 @@
+# MicroPython on ESP32-S2 and ESP32-PAD1_subscript_3, ESP IDF configuration with SPIRAM support
+CONFIG_ESP32S2_SPIRAM_SUPPORT=y
+CONFIG_SPIRAM_TYPE_AUTO=y
+CONFIG_DEFAULT_PSRAM_CLK_IO=30
+CONFIG_DEFAULT_PSRAM_CS_IO=26
+CONFIG_SPIRAM_SPEED_80M=y
+CONFIG_SPIRAM=y
+CONFIG_SPIRAM_BOOT_INIT=y
+CONFIG_SPIRAM_IGNORE_NOTFOUND=y
+CONFIG_SPIRAM_USE_MEMMAP=y
+CONFIG_SPIRAM_MEMTEST=y
diff --git a/ports/esp32/machine_adc.c b/ports/esp32/machine_adc.c
index 4c19d5992b..739d47da50 100644
--- a/ports/esp32/machine_adc.c
+++ b/ports/esp32/machine_adc.c
@@ -43,6 +43,7 @@ typedef struct _madc_obj_t {
 } madc_obj_t;
 
 STATIC const madc_obj_t madc_obj[] = {
+    #if CONFIG_IDF_TARGET_ESP32
     {{&machine_adc_type}, GPIO_NUM_36, ADC1_CHANNEL_0},
     {{&machine_adc_type}, GPIO_NUM_37, ADC1_CHANNEL_1},
     {{&machine_adc_type}, GPIO_NUM_38, ADC1_CHANNEL_2},
@@ -51,6 +52,18 @@ STATIC const madc_obj_t madc_obj[] = {
     {{&machine_adc_type}, GPIO_NUM_33, ADC1_CHANNEL_5},
     {{&machine_adc_type}, GPIO_NUM_34, ADC1_CHANNEL_6},
     {{&machine_adc_type}, GPIO_NUM_35, ADC1_CHANNEL_7},
+    #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+    {{&machine_adc_type}, GPIO_NUM_1, ADC1_CHANNEL_0},
+    {{&machine_adc_type}, GPIO_NUM_2, ADC1_CHANNEL_1},
+    {{&machine_adc_type}, GPIO_NUM_3, ADC1_CHANNEL_2},
+    {{&machine_adc_type}, GPIO_NUM_4, ADC1_CHANNEL_3},
+    {{&machine_adc_type}, GPIO_NUM_5, ADC1_CHANNEL_4},
+    {{&machine_adc_type}, GPIO_NUM_6, ADC1_CHANNEL_5},
+    {{&machine_adc_type}, GPIO_NUM_7, ADC1_CHANNEL_6},
+    {{&machine_adc_type}, GPIO_NUM_8, ADC1_CHANNEL_7},
+    {{&machine_adc_type}, GPIO_NUM_9, ADC1_CHANNEL_8},
+    {{&machine_adc_type}, GPIO_NUM_10, ADC1_CHANNEL_9},
+    #endif
 };
 
 STATIC uint8_t adc_bit_width;
@@ -145,7 +158,7 @@ STATIC mp_obj_t madc_width(mp_obj_t cls_in, mp_obj_t width_in) {
         case ADC_WIDTH_12Bit:
             adc_bit_width = 12;
             break;
-        #elif CONFIG_IDF_TARGET_ESP32S2
+        #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
         case ADC_WIDTH_BIT_13:
             adc_bit_width = 13;
             break;
@@ -175,7 +188,7 @@ STATIC const mp_rom_map_elem_t madc_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_WIDTH_10BIT), MP_ROM_INT(ADC_WIDTH_10Bit) },
     { MP_ROM_QSTR(MP_QSTR_WIDTH_11BIT), MP_ROM_INT(ADC_WIDTH_11Bit) },
     { MP_ROM_QSTR(MP_QSTR_WIDTH_12BIT), MP_ROM_INT(ADC_WIDTH_12Bit) },
-    #elif CONFIG_IDF_TARGET_ESP32S2
+    #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
     { MP_ROM_QSTR(MP_QSTR_WIDTH_13BIT), MP_ROM_INT(ADC_WIDTH_BIT_13) },
     #endif
 };
diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c
index 8dbdd19849..bd623d0413 100644
--- a/ports/esp32/machine_pin.c
+++ b/ports/esp32/machine_pin.c
@@ -56,6 +56,8 @@ typedef struct _machine_pin_irq_obj_t {
 } machine_pin_irq_obj_t;
 
 STATIC const machine_pin_obj_t machine_pin_obj[] = {
+    #if CONFIG_IDF_TARGET_ESP32
+
     {{&machine_pin_type}, GPIO_NUM_0},
     {{&machine_pin_type}, GPIO_NUM_1},
     {{&machine_pin_type}, GPIO_NUM_2},
@@ -78,17 +80,10 @@ STATIC const machine_pin_obj_t machine_pin_obj[] = {
     {{&machine_pin_type}, GPIO_NUM_19},
     {{NULL}, -1},
     {{&machine_pin_type}, GPIO_NUM_21},
-    #if CONFIG_IDF_TARGET_ESP32
     {{&machine_pin_type}, GPIO_NUM_22},
     {{&machine_pin_type}, GPIO_NUM_23},
     {{NULL}, -1},
     {{&machine_pin_type}, GPIO_NUM_25},
-    #else
-    {{NULL}, -1},
-    {{NULL}, -1},
-    {{NULL}, -1},
-    {{NULL}, -1},
-    #endif
     {{&machine_pin_type}, GPIO_NUM_26},
     {{&machine_pin_type}, GPIO_NUM_27},
     {{NULL}, -1},
@@ -103,6 +98,63 @@ STATIC const machine_pin_obj_t machine_pin_obj[] = {
     {{&machine_pin_type}, GPIO_NUM_37},
     {{&machine_pin_type}, GPIO_NUM_38},
     {{&machine_pin_type}, GPIO_NUM_39},
+
+    #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+
+    {{&machine_pin_type}, GPIO_NUM_0},
+    {{&machine_pin_type}, GPIO_NUM_1},
+    {{&machine_pin_type}, GPIO_NUM_2},
+    {{&machine_pin_type}, GPIO_NUM_3},
+    {{&machine_pin_type}, GPIO_NUM_4},
+    {{&machine_pin_type}, GPIO_NUM_5},
+    {{&machine_pin_type}, GPIO_NUM_6},
+    {{&machine_pin_type}, GPIO_NUM_7},
+    {{&machine_pin_type}, GPIO_NUM_8},
+    {{&machine_pin_type}, GPIO_NUM_9},
+    {{&machine_pin_type}, GPIO_NUM_10},
+    {{&machine_pin_type}, GPIO_NUM_11},
+    {{&machine_pin_type}, GPIO_NUM_12},
+    {{&machine_pin_type}, GPIO_NUM_13},
+    {{&machine_pin_type}, GPIO_NUM_14},
+    {{&machine_pin_type}, GPIO_NUM_15},
+    {{&machine_pin_type}, GPIO_NUM_16},
+    {{&machine_pin_type}, GPIO_NUM_17},
+    {{&machine_pin_type}, GPIO_NUM_18},
+    #if CONFIG_USB_CDC_ENABLED
+    {{NULL}, -1}, // 19 is for native USB D-
+    {{NULL}, -1}, // 20 is for native USB D-
+    #else
+    {{&machine_pin_type}, GPIO_NUM_19},
+    {{&machine_pin_type}, GPIO_NUM_20},
+    #endif
+    {{&machine_pin_type}, GPIO_NUM_21},
+    {{NULL}, -1}, // 22 not a pin
+    {{NULL}, -1}, // 23 not a pin
+    {{NULL}, -1}, // 24 not a pin
+    {{NULL}, -1}, // 25 not a pin
+    {{NULL}, -1}, // 26 FLASH/PSRAM
+    {{NULL}, -1}, // 27 FLASH/PSRAM
+    {{NULL}, -1}, // 28 FLASH/PSRAM
+    {{NULL}, -1}, // 29 FLASH/PSRAM
+    {{NULL}, -1}, // 30 FLASH/PSRAM
+    {{NULL}, -1}, // 31 FLASH/PSRAM
+    {{NULL}, -1}, // 32 FLASH/PSRAM
+    {{&machine_pin_type}, GPIO_NUM_33},
+    {{&machine_pin_type}, GPIO_NUM_34},
+    {{&machine_pin_type}, GPIO_NUM_35},
+    {{&machine_pin_type}, GPIO_NUM_36},
+    {{&machine_pin_type}, GPIO_NUM_37},
+    {{&machine_pin_type}, GPIO_NUM_38},
+    {{&machine_pin_type}, GPIO_NUM_39}, // MTCLK
+    {{&machine_pin_type}, GPIO_NUM_40}, // MTDO
+    {{&machine_pin_type}, GPIO_NUM_41}, // MTDI
+    {{&machine_pin_type}, GPIO_NUM_42}, // MTMS
+    {{&machine_pin_type}, GPIO_NUM_43}, // U0TXD
+    {{&machine_pin_type}, GPIO_NUM_44}, // U0RXD
+    {{&machine_pin_type}, GPIO_NUM_45},
+    {{&machine_pin_type}, GPIO_NUM_46},
+
+    #endif
 };
 
 // forward declaration
@@ -399,6 +451,8 @@ const mp_obj_type_t machine_pin_type = {
 STATIC const mp_obj_type_t machine_pin_irq_type;
 
 STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = {
+    #if CONFIG_IDF_TARGET_ESP32
+
     {{&machine_pin_irq_type}, GPIO_NUM_0},
     {{&machine_pin_irq_type}, GPIO_NUM_1},
     {{&machine_pin_irq_type}, GPIO_NUM_2},
@@ -421,17 +475,10 @@ STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = {
     {{&machine_pin_irq_type}, GPIO_NUM_19},
     {{NULL}, -1},
     {{&machine_pin_irq_type}, GPIO_NUM_21},
-    #if CONFIG_IDF_TARGET_ESP32
     {{&machine_pin_irq_type}, GPIO_NUM_22},
     {{&machine_pin_irq_type}, GPIO_NUM_23},
     {{NULL}, -1},
     {{&machine_pin_irq_type}, GPIO_NUM_25},
-    #else
-    {{NULL}, -1},
-    {{NULL}, -1},
-    {{NULL}, -1},
-    {{NULL}, -1},
-    #endif
     {{&machine_pin_irq_type}, GPIO_NUM_26},
     {{&machine_pin_irq_type}, GPIO_NUM_27},
     {{NULL}, -1},
@@ -446,6 +493,62 @@ STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = {
     {{&machine_pin_irq_type}, GPIO_NUM_37},
     {{&machine_pin_irq_type}, GPIO_NUM_38},
     {{&machine_pin_irq_type}, GPIO_NUM_39},
+
+    #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+
+    {{&machine_pin_irq_type}, GPIO_NUM_0},
+    {{&machine_pin_irq_type}, GPIO_NUM_1},
+    {{&machine_pin_irq_type}, GPIO_NUM_2},
+    {{&machine_pin_irq_type}, GPIO_NUM_3},
+    {{&machine_pin_irq_type}, GPIO_NUM_4},
+    {{&machine_pin_irq_type}, GPIO_NUM_5},
+    {{&machine_pin_irq_type}, GPIO_NUM_6},
+    {{&machine_pin_irq_type}, GPIO_NUM_7},
+    {{&machine_pin_irq_type}, GPIO_NUM_8},
+    {{&machine_pin_irq_type}, GPIO_NUM_9},
+    {{&machine_pin_irq_type}, GPIO_NUM_10},
+    {{&machine_pin_irq_type}, GPIO_NUM_11},
+    {{&machine_pin_irq_type}, GPIO_NUM_12},
+    {{&machine_pin_irq_type}, GPIO_NUM_13},
+    {{&machine_pin_irq_type}, GPIO_NUM_14},
+    {{&machine_pin_irq_type}, GPIO_NUM_15},
+    {{&machine_pin_irq_type}, GPIO_NUM_16},
+    {{&machine_pin_irq_type}, GPIO_NUM_17},
+    {{&machine_pin_irq_type}, GPIO_NUM_18},
+    #if CONFIG_USB_CDC_ENABLED
+    {{NULL}, -1}, // 19 is for native USB D-
+    {{NULL}, -1}, // 20 is for native USB D-
+    #else
+    {{&machine_pin_irq_type}, GPIO_NUM_19},
+    {{&machine_pin_irq_type}, GPIO_NUM_20},
+    #endif
+    {{&machine_pin_irq_type}, GPIO_NUM_21},
+    {{NULL}, -1}, // 22 not a pin
+    {{NULL}, -1}, // 23 not a pin
+    {{NULL}, -1}, // 24 not a pin
+    {{NULL}, -1}, // 25 not a pin
+    {{NULL}, -1}, // 26 FLASH/PSRAM
+    {{NULL}, -1}, // 27 FLASH/PSRAM
+    {{NULL}, -1}, // 28 FLASH/PSRAM
+    {{NULL}, -1}, // 29 FLASH/PSRAM
+    {{NULL}, -1}, // 30 FLASH/PSRAM
+    {{NULL}, -1}, // 31 FLASH/PSRAM
+    {{NULL}, -1}, // 32 FLASH/PSRAM
+    {{&machine_pin_irq_type}, GPIO_NUM_33},
+    {{&machine_pin_irq_type}, GPIO_NUM_34},
+    {{&machine_pin_irq_type}, GPIO_NUM_35},
+    {{&machine_pin_irq_type}, GPIO_NUM_36},
+    {{&machine_pin_irq_type}, GPIO_NUM_37},
+    {{&machine_pin_irq_type}, GPIO_NUM_38},
+    {{&machine_pin_irq_type}, GPIO_NUM_39},
+    {{&machine_pin_irq_type}, GPIO_NUM_40},
+    {{&machine_pin_irq_type}, GPIO_NUM_41},
+    {{&machine_pin_irq_type}, GPIO_NUM_42},
+    {{&machine_pin_irq_type}, GPIO_NUM_43},
+    {{&machine_pin_irq_type}, GPIO_NUM_44},
+    {{&machine_pin_irq_type}, GPIO_NUM_45},
+
+    #endif
 };
 
 STATIC mp_obj_t machine_pin_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
diff --git a/ports/esp32/machine_touchpad.c b/ports/esp32/machine_touchpad.c
index 335157b154..168ac16d0e 100644
--- a/ports/esp32/machine_touchpad.c
+++ b/ports/esp32/machine_touchpad.c
@@ -31,7 +31,11 @@
 #if CONFIG_IDF_TARGET_ESP32
 
 #include "driver/gpio.h"
+#if CONFIG_IDF_TARGET_ESP32
 #include "driver/touch_pad.h"
+#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+#include "driver/touch_sensor.h"
+#endif
 
 typedef struct _mtp_obj_t {
     mp_obj_base_t base;
@@ -39,6 +43,7 @@ typedef struct _mtp_obj_t {
     touch_pad_t touchpad_id;
 } mtp_obj_t;
 
+#if CONFIG_IDF_TARGET_ESP32
 STATIC const mtp_obj_t touchpad_obj[] = {
     {{&machine_touchpad_type}, GPIO_NUM_4, TOUCH_PAD_NUM0},
     {{&machine_touchpad_type}, GPIO_NUM_0, TOUCH_PAD_NUM1},
@@ -51,6 +56,24 @@ STATIC const mtp_obj_t touchpad_obj[] = {
     {{&machine_touchpad_type}, GPIO_NUM_33, TOUCH_PAD_NUM8},
     {{&machine_touchpad_type}, GPIO_NUM_32, TOUCH_PAD_NUM9},
 };
+#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+STATIC const mtp_obj_t touchpad_obj[] = {
+    {{&machine_touchpad_type}, GPIO_NUM_1, TOUCH_PAD_NUM1},
+    {{&machine_touchpad_type}, GPIO_NUM_2, TOUCH_PAD_NUM2},
+    {{&machine_touchpad_type}, GPIO_NUM_3, TOUCH_PAD_NUM3},
+    {{&machine_touchpad_type}, GPIO_NUM_4, TOUCH_PAD_NUM4},
+    {{&machine_touchpad_type}, GPIO_NUM_5, TOUCH_PAD_NUM5},
+    {{&machine_touchpad_type}, GPIO_NUM_6, TOUCH_PAD_NUM6},
+    {{&machine_touchpad_type}, GPIO_NUM_7, TOUCH_PAD_NUM7},
+    {{&machine_touchpad_type}, GPIO_NUM_8, TOUCH_PAD_NUM8},
+    {{&machine_touchpad_type}, GPIO_NUM_9, TOUCH_PAD_NUM9},
+    {{&machine_touchpad_type}, GPIO_NUM_10, TOUCH_PAD_NUM10},
+    {{&machine_touchpad_type}, GPIO_NUM_11, TOUCH_PAD_NUM11},
+    {{&machine_touchpad_type}, GPIO_NUM_12, TOUCH_PAD_NUM12},
+    {{&machine_touchpad_type}, GPIO_NUM_13, TOUCH_PAD_NUM13},
+    {{&machine_touchpad_type}, GPIO_NUM_14, TOUCH_PAD_NUM14},
+};
+#endif
 
 STATIC mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
     const mp_obj_t *args) {
diff --git a/ports/esp32/main.c b/ports/esp32/main.c
index 7ca3d84140..ff6dd69574 100644
--- a/ports/esp32/main.c
+++ b/ports/esp32/main.c
@@ -42,6 +42,8 @@
 #include "esp32/spiram.h"
 #elif CONFIG_IDF_TARGET_ESP32S2
 #include "esp32s2/spiram.h"
+#elif CONFIG_IDF_TARGET_ESP32S3
+#include "esp32s3/spiram.h"
 #endif
 
 #include "py/stackctrl.h"
@@ -104,6 +106,18 @@ void mp_task(void *pvParameter) {
             mp_task_heap = malloc(mp_task_heap_size);
             break;
     }
+    #elif CONFIG_ESP32S2_SPIRAM_SUPPORT || CONFIG_ESP32S3_SPIRAM_SUPPORT
+    // Try to use the entire external SPIRAM directly for the heap
+    size_t mp_task_heap_size;
+    size_t esp_spiram_size = esp_spiram_get_size();
+    void *mp_task_heap = (void *)0x3ff80000 - esp_spiram_size;
+    if (esp_spiram_size > 0) {
+        mp_task_heap_size = esp_spiram_size;
+    } else {
+        // No SPIRAM, fallback to normal allocation
+        mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
+        mp_task_heap = malloc(mp_task_heap_size);
+    }
     #else
     // Allocate the uPy heap using malloc and get the largest available region
     size_t mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt
index 656045da90..1cc30b71ec 100644
--- a/ports/esp32/main/CMakeLists.txt
+++ b/ports/esp32/main/CMakeLists.txt
@@ -128,6 +128,9 @@ if(IDF_TARGET STREQUAL "esp32")
 elseif(IDF_TARGET STREQUAL "esp32s2")
     list(APPEND IDF_COMPONENTS esp32s2)
     list(APPEND IDF_COMPONENTS tinyusb)
+elseif(IDF_TARGET STREQUAL "esp32s3")
+    list(APPEND IDF_COMPONENTS esp32s3)
+    list(APPEND IDF_COMPONENTS tinyusb)
 endif()
 
 # Register the main IDF component.
diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c
index 2eb5cd2fee..bbe7fae033 100644
--- a/ports/esp32/modmachine.c
+++ b/ports/esp32/modmachine.c
@@ -42,6 +42,9 @@
 #elif CONFIG_IDF_TARGET_ESP32S2
 #include "esp32s2/rom/rtc.h"
 #include "esp32s2/clk.h"
+#elif CONFIG_IDF_TARGET_ESP32S3
+#include "esp32s3/rom/rtc.h"
+#include "esp32s3/clk.h"
 #endif
 
 #include "py/obj.h"
diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c
index cf668216df..a0bafb755e 100644
--- a/ports/esp32/mphalport.c
+++ b/ports/esp32/mphalport.c
@@ -32,7 +32,14 @@
 
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
+
+#if CONFIG_IDF_TARGET_ESP32
 #include "esp32/rom/uart.h"
+#elif CONFIG_IDF_TARGET_ESP32S2
+#include "esp32s2/rom/uart.h"
+#elif CONFIG_IDF_TARGET_ESP32S3
+#include "esp32s3/rom/uart.h"
+#endif
 
 #include "py/obj.h"
 #include "py/objstr.h"
diff --git a/ports/esp32/partitions-16MiB.csv b/ports/esp32/partitions-16MiB.csv
new file mode 100644
index 0000000000..5133185c78
--- /dev/null
+++ b/ports/esp32/partitions-16MiB.csv
@@ -0,0 +1,8 @@
+# Notes: the offset of the partition table itself is set in
+# $ESPIDF/components/partition_table/Kconfig.projbuild and the
+# offset of the factory/ota_0 partition is set in makeimg.py
+# Name,   Type, SubType, Offset,  Size, Flags
+nvs,      data, nvs,     0x9000,  0x6000,
+phy_init, data, phy,     0xf000,  0x1000,
+factory,  app,  factory, 0x10000, 0x180000,
+vfs,      data, fat,     0x200000, 0xD59F80,