feat(cam): support dvp cam on ESP32-S31

This commit is contained in:
gaoxu
2026-05-14 17:09:49 +08:00
parent 7ff718a988
commit 4e3751b32e
52 changed files with 1040 additions and 786 deletions
@@ -1,2 +1,2 @@
| Supported Targets | ESP32-P4 | ESP32-S3 |
| ----------------- | -------- | -------- |
| Supported Targets | ESP32-P4 | ESP32-S3 | ESP32-S31 |
| ----------------- | -------- | -------- | --------- |
@@ -3,8 +3,8 @@ set(srcs "test_app_main.c")
if(CONFIG_SOC_LCDCAM_CAM_SUPPORTED)
list(APPEND srcs "test_dvp_driver.c")
endif()
if(CONFIG_IDF_TARGET_ESP32S3)
list(APPEND srcs "test_dvp_s3eye.c")
if(CONFIG_CAMERA_OV2640 AND CONFIG_SOC_LCDCAM_CAM_SUPPORTED)
list(APPEND srcs "test_dvp_ov2640.c")
endif()
set(priv_requires
@@ -14,6 +14,10 @@ set(priv_requires
esp_driver_ledc
)
if(CONFIG_CAMERA_OV2640 AND CONFIG_SOC_LCDCAM_CAM_SUPPORTED)
list(APPEND priv_requires sensor_init)
endif()
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS "."
PRIV_REQUIRES ${priv_requires}
@@ -0,0 +1,130 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "unity.h"
#include "driver/i2c_master.h"
#include "esp_attr.h"
#include "esp_heap_caps.h"
#include "esp_cam_ctlr.h"
#include "esp_cam_ctlr_dvp.h"
#include "example_sensor_init.h"
#include "test_dvp_ov2640_board.h"
static int s_new_trans_count;
static int s_trans_finished_count;
static bool IRAM_ATTR camera_get_new_buffer(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data)
{
(void)handle;
esp_cam_ctlr_trans_t *new_trans = (esp_cam_ctlr_trans_t *)user_data;
trans->buffer = new_trans->buffer;
trans->buflen = new_trans->buflen;
s_new_trans_count++;
return false;
}
static bool IRAM_ATTR camera_trans_finished(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data)
{
(void)handle;
(void)trans;
(void)user_data;
s_trans_finished_count++;
return false;
}
TEST_CASE("TEST esp_cam DVP on ov2640", "[dvp][camera][ov2640]")
{
s_new_trans_count = 0;
s_trans_finished_count = 0;
esp_cam_ctlr_dvp_pin_config_t pin_cfg = {
.data_width = TEST_DVP_CAM_DATA_WIDTH,
.data_io = {
TEST_DVP_CAM_D0_IO,
TEST_DVP_CAM_D1_IO,
TEST_DVP_CAM_D2_IO,
TEST_DVP_CAM_D3_IO,
TEST_DVP_CAM_D4_IO,
TEST_DVP_CAM_D5_IO,
TEST_DVP_CAM_D6_IO,
TEST_DVP_CAM_D7_IO,
},
.vsync_io = TEST_DVP_CAM_VSYNC_IO,
.de_io = TEST_DVP_CAM_DE_IO,
.pclk_io = TEST_DVP_CAM_PCLK_IO,
.xclk_io = TEST_DVP_CAM_XCLK_IO,
};
esp_cam_ctlr_dvp_config_t dvp_config = {
.ctlr_id = 0,
.clk_src = CAM_CLK_SRC_DEFAULT,
.h_res = TEST_DVP_CAM_FRAME_WIDTH,
.v_res = TEST_DVP_CAM_FRAME_HEIGHT,
.input_data_color_type = TEST_DVP_CAM_INPUT_COLOR_TYPE,
.output_data_color_type = TEST_DVP_CAM_OUTPUT_COLOR_TYPE,
.dma_burst_size = 64,
.pin = &pin_cfg,
.bk_buffer_dis = 1,
.xclk_freq = TEST_DVP_CAM_XCLK_FREQ_HZ,
.cam_data_width = TEST_DVP_CAM_DATA_WIDTH,
.byte_swap_en = false,
.bit_swap_en = false,
};
esp_cam_ctlr_handle_t cam_handle = NULL;
TEST_ESP_OK(esp_cam_new_dvp_ctlr(&dvp_config, &cam_handle));
size_t frame_buffer_size = TEST_DVP_CAM_FRAME_SIZE_BYTES;
void *frame_buffer = esp_cam_ctlr_alloc_buffer(cam_handle, frame_buffer_size, TEST_DVP_CAM_BUF_ALLOC_CAPS);
TEST_ASSERT_NOT_NULL(frame_buffer);
esp_cam_ctlr_trans_t trans_data = {
.buffer = frame_buffer,
.buflen = frame_buffer_size,
};
example_sensor_handle_t sensor_handle = {
.sccb_handle = NULL,
.i2c_bus_handle = NULL,
};
example_sensor_config_t sensor_config = {
.i2c_port_num = I2C_NUM_0,
.i2c_sda_io_num = TEST_DVP_CAM_SCCB_SDA_IO,
.i2c_scl_io_num = TEST_DVP_CAM_SCCB_SCL_IO,
.reset_pin = TEST_DVP_CAM_RESET_IO,
.pwdn_pin = TEST_DVP_CAM_PWDN_IO,
.xclk_pin = TEST_DVP_CAM_XCLK_IO,
.port = ESP_CAM_SENSOR_DVP,
.format_name = TEST_DVP_CAM_FORMAT_NAME,
};
example_sensor_init(&sensor_config, &sensor_handle);
if (sensor_handle.sccb_handle == NULL || sensor_handle.i2c_bus_handle == NULL) {
TEST_ESP_OK(esp_cam_ctlr_del(cam_handle));
heap_caps_free(frame_buffer);
TEST_FAIL_MESSAGE("failed to detect or initialize ov2640 sensor");
}
esp_cam_ctlr_evt_cbs_t cbs = {
.on_get_new_trans = camera_get_new_buffer,
.on_trans_finished = camera_trans_finished,
};
TEST_ESP_OK(esp_cam_ctlr_register_event_callbacks(cam_handle, &cbs, &trans_data));
TEST_ESP_OK(esp_cam_ctlr_enable(cam_handle));
TEST_ESP_OK(esp_cam_ctlr_start(cam_handle));
vTaskDelay(pdMS_TO_TICKS(1000));
TEST_ESP_OK(esp_cam_ctlr_stop(cam_handle));
// Roughly one transfer per frame is expected for the selected OV2640 format.
TEST_ASSERT_GREATER_OR_EQUAL(TEST_DVP_CAM_EXPECTED_NEW_TRANS_MIN, s_new_trans_count);
TEST_ASSERT_GREATER_OR_EQUAL(TEST_DVP_CAM_EXPECTED_FINISHED_MIN, s_trans_finished_count);
TEST_ESP_OK(esp_cam_ctlr_disable(cam_handle));
TEST_ESP_OK(esp_cam_ctlr_del(cam_handle));
example_sensor_deinit(sensor_handle);
heap_caps_free(frame_buffer);
}
@@ -0,0 +1,134 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#include "hal/cam_ctlr_types.h"
#include "esp_heap_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
#define TEST_DVP_CAM_FRAME_BITS_PER_PIXEL 16
#define TEST_DVP_CAM_EXPECTED_NEW_TRANS_MIN 6
#define TEST_DVP_CAM_EXPECTED_FINISHED_MIN 5
#define TEST_DVP_CAM_XCLK_FREQ_HZ 20000000
#define TEST_DVP_CAM_DATA_WIDTH 8
#if CONFIG_IDF_TARGET_ESP32S3
#define TEST_DVP_CAM_FRAME_WIDTH 640
#define TEST_DVP_CAM_FRAME_HEIGHT 480
#define TEST_DVP_CAM_FORMAT_NAME "DVP_8bit_20Minput_YUV422_YUYV_640x480_6fps"
#define TEST_DVP_CAM_INPUT_COLOR_TYPE CAM_CTLR_COLOR_YUV422_YUYV
#define TEST_DVP_CAM_OUTPUT_COLOR_TYPE CAM_CTLR_COLOR_YUV422_YUYV
#define TEST_DVP_CAM_PWDN_IO (-1)
#define TEST_DVP_CAM_RESET_IO (-1)
#define TEST_DVP_CAM_SCCB_SCL_IO 5
#define TEST_DVP_CAM_SCCB_SDA_IO 4
#define TEST_DVP_CAM_D0_IO 11
#define TEST_DVP_CAM_D1_IO 9
#define TEST_DVP_CAM_D2_IO 8
#define TEST_DVP_CAM_D3_IO 10
#define TEST_DVP_CAM_D4_IO 12
#define TEST_DVP_CAM_D5_IO 18
#define TEST_DVP_CAM_D6_IO 17
#define TEST_DVP_CAM_D7_IO 16
#define TEST_DVP_CAM_XCLK_IO 15
#define TEST_DVP_CAM_PCLK_IO 13
#define TEST_DVP_CAM_DE_IO 7
#define TEST_DVP_CAM_VSYNC_IO 6
#elif CONFIG_IDF_TARGET_ESP32P4
#define TEST_DVP_CAM_FRAME_WIDTH 640
#define TEST_DVP_CAM_FRAME_HEIGHT 480
#define TEST_DVP_CAM_FORMAT_NAME "DVP_8bit_20Minput_YUV422_UYVY_640x480_6fps"
#define TEST_DVP_CAM_INPUT_COLOR_TYPE CAM_CTLR_COLOR_YUV422_UYVY
#define TEST_DVP_CAM_OUTPUT_COLOR_TYPE CAM_CTLR_COLOR_YUV422_UYVY
#define TEST_DVP_CAM_PWDN_IO (-1)
#define TEST_DVP_CAM_RESET_IO (-1)
#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3
#define TEST_DVP_CAM_SCCB_SCL_IO 8
#define TEST_DVP_CAM_SCCB_SDA_IO 7
#define TEST_DVP_CAM_D0_IO 2
#define TEST_DVP_CAM_D1_IO 32
#define TEST_DVP_CAM_D2_IO 33
#define TEST_DVP_CAM_D3_IO 23
#define TEST_DVP_CAM_D4_IO 3
#define TEST_DVP_CAM_D5_IO 6
#define TEST_DVP_CAM_D6_IO 5
#define TEST_DVP_CAM_D7_IO 21
#define TEST_DVP_CAM_XCLK_IO 20
#define TEST_DVP_CAM_PCLK_IO 4
#define TEST_DVP_CAM_DE_IO 22
#define TEST_DVP_CAM_VSYNC_IO 37
#else
#define TEST_DVP_CAM_SCCB_SCL_IO 33
#define TEST_DVP_CAM_SCCB_SDA_IO 32
#define TEST_DVP_CAM_D0_IO 53
#define TEST_DVP_CAM_D1_IO 54
#define TEST_DVP_CAM_D2_IO 26
#define TEST_DVP_CAM_D3_IO 1
#define TEST_DVP_CAM_D4_IO 0
#define TEST_DVP_CAM_D5_IO 45
#define TEST_DVP_CAM_D6_IO 46
#define TEST_DVP_CAM_D7_IO 47
#define TEST_DVP_CAM_XCLK_IO 20
#define TEST_DVP_CAM_PCLK_IO 21
#define TEST_DVP_CAM_DE_IO 22
#define TEST_DVP_CAM_VSYNC_IO 23
#endif
#elif CONFIG_IDF_TARGET_ESP32S31
#define TEST_DVP_CAM_FRAME_WIDTH 640
#define TEST_DVP_CAM_FRAME_HEIGHT 480
#define TEST_DVP_CAM_FORMAT_NAME "DVP_8bit_20Minput_YUV422_YUYV_640x480_6fps"
#define TEST_DVP_CAM_INPUT_COLOR_TYPE CAM_CTLR_COLOR_YUV422_YUYV
#define TEST_DVP_CAM_OUTPUT_COLOR_TYPE CAM_CTLR_COLOR_YUV422_YUYV
#define TEST_DVP_CAM_PWDN_IO 61
#define TEST_DVP_CAM_RESET_IO 60
#define TEST_DVP_CAM_SCCB_SCL_IO 1
#define TEST_DVP_CAM_SCCB_SDA_IO 0
#define TEST_DVP_CAM_D0_IO 46
#define TEST_DVP_CAM_D1_IO 47
#define TEST_DVP_CAM_D2_IO 48
#define TEST_DVP_CAM_D3_IO 49
#define TEST_DVP_CAM_D4_IO 50
#define TEST_DVP_CAM_D5_IO 51
#define TEST_DVP_CAM_D6_IO 52
#define TEST_DVP_CAM_D7_IO 53
#define TEST_DVP_CAM_XCLK_IO 55
#define TEST_DVP_CAM_PCLK_IO 54
#define TEST_DVP_CAM_DE_IO 57
#define TEST_DVP_CAM_VSYNC_IO 56
#endif
#define TEST_DVP_CAM_FRAME_SIZE_BYTES \
(TEST_DVP_CAM_FRAME_WIDTH * TEST_DVP_CAM_FRAME_HEIGHT * TEST_DVP_CAM_FRAME_BITS_PER_PIXEL / 8)
#if CONFIG_SPIRAM
#define TEST_DVP_CAM_BUF_ALLOC_CAPS (MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA)
#else
#define TEST_DVP_CAM_BUF_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
#endif
#ifdef __cplusplus
}
#endif
@@ -1,166 +0,0 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "esp_cache.h"
#include "driver/i2c_master.h"
#include "esp_cam_ctlr.h"
#include "esp_cam_ctlr_dvp.h"
#include "driver/ledc.h"
#include "example_sensor_init.h"
#include "unity.h"
//----------CAM Config------------//
#define TEST_RGB565_BITS_PER_PIXEL 16
#define TEST_DVP_CAM_SCCB_SCL_IO (5)
#define TEST_DVP_CAM_SCCB_SDA_IO (4)
#define TEST_DVP_CAM_XCLK_FREQ_HZ (20000000)
#define TEST_DVP_CAM_DATA_WIDTH (8)
#define TEST_DVP_CAM_D0_IO (11)
#define TEST_DVP_CAM_D1_IO (9)
#define TEST_DVP_CAM_D2_IO (8)
#define TEST_DVP_CAM_D3_IO (10)
#define TEST_DVP_CAM_D4_IO (12)
#define TEST_DVP_CAM_D5_IO (18)
#define TEST_DVP_CAM_D6_IO (17)
#define TEST_DVP_CAM_D7_IO (16)
#define TEST_DVP_CAM_XCLK_IO (15)
#define TEST_DVP_CAM_PCLK_IO (13)
#define TEST_DVP_CAM_DE_IO (7)
#define TEST_DVP_CAM_VSYNC_IO (6)
#define TEST_DVP_CAM_HSYNC_IO (-1)
#define TEST_DVP_CAM_BUF_ALLOC_CAPS (MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA)
#define TEST_DVP_CAM_H_RES 240
#define TEST_DVP_CAM_V_RES 240
#define TEST_CAM_FORMAT "DVP_8bit_20Minput_RGB565_240x240_25fps"
#define BUFFER_SIZE (TEST_DVP_CAM_H_RES * TEST_DVP_CAM_V_RES * TEST_RGB565_BITS_PER_PIXEL / 8)
typedef struct {
// esp_lcd_panel_handle_t panel_hdl;
esp_cam_ctlr_trans_t cam_trans;
} example_cam_context_t;
static bool s_camera_get_new_vb(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data);
static bool s_camera_get_finished_trans(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data);
int count_new_vb = 0;
int count_finished_trans = 0;
TEST_CASE("TEST DVP camera on esp32s3_eye", "[dvp][camera][esp32s3_eye]")
{
//----------CAM Controller Init------------//
esp_cam_ctlr_handle_t cam_handle = NULL;
esp_cam_ctlr_dvp_pin_config_t pin_cfg = {
.data_width = TEST_DVP_CAM_DATA_WIDTH,
.data_io = {
TEST_DVP_CAM_D0_IO,
TEST_DVP_CAM_D1_IO,
TEST_DVP_CAM_D2_IO,
TEST_DVP_CAM_D3_IO,
TEST_DVP_CAM_D4_IO,
TEST_DVP_CAM_D5_IO,
TEST_DVP_CAM_D6_IO,
TEST_DVP_CAM_D7_IO,
},
.vsync_io = TEST_DVP_CAM_VSYNC_IO,
.de_io = TEST_DVP_CAM_DE_IO,
.pclk_io = TEST_DVP_CAM_PCLK_IO,
.xclk_io = TEST_DVP_CAM_XCLK_IO,
};
esp_cam_ctlr_dvp_config_t dvp_config = {
.ctlr_id = 0,
.clk_src = CAM_CLK_SRC_DEFAULT,
.h_res = TEST_DVP_CAM_H_RES,
.v_res = TEST_DVP_CAM_V_RES,
.input_data_color_type = CAM_CTLR_COLOR_RGB565,
.output_data_color_type = CAM_CTLR_COLOR_RGB565,
.dma_burst_size = 64,
.pin = &pin_cfg,
.bk_buffer_dis = 1,
.xclk_freq = TEST_DVP_CAM_XCLK_FREQ_HZ,
};
TEST_ESP_OK(esp_cam_new_dvp_ctlr(&dvp_config, &cam_handle));
//--------Allocate Camera Buffer----------//
size_t cam_buffer_size = TEST_DVP_CAM_H_RES * TEST_DVP_CAM_V_RES * TEST_RGB565_BITS_PER_PIXEL / 8;
void *cam_buffer = NULL;
cam_buffer = esp_cam_ctlr_alloc_buffer(cam_handle, cam_buffer_size, TEST_DVP_CAM_BUF_ALLOC_CAPS);
//--------Camera Sensor and SCCB Init-----------//
example_sensor_config_t cam_sensor_config = {
.i2c_port_num = I2C_NUM_0,
.i2c_sda_io_num = TEST_DVP_CAM_SCCB_SDA_IO,
.i2c_scl_io_num = TEST_DVP_CAM_SCCB_SCL_IO,
.port = ESP_CAM_SENSOR_DVP,
.format_name = TEST_CAM_FORMAT,
};
example_sensor_handle_t sensor_handle = {
.sccb_handle = NULL,
.i2c_bus_handle = NULL,
};
example_sensor_init(&cam_sensor_config, &sensor_handle);
//--------Register Camera Callbacks----------//
example_cam_context_t cam_ctx = {
// .panel_hdl = lcd_panel_hdl,
.cam_trans = {
.buffer = cam_buffer,
.buflen = cam_buffer_size,
}
};
esp_cam_ctlr_evt_cbs_t cbs = {
.on_get_new_trans = s_camera_get_new_vb,
.on_trans_finished = s_camera_get_finished_trans,
};
TEST_ESP_OK(esp_cam_ctlr_register_event_callbacks(cam_handle, &cbs, &cam_ctx));
TEST_ESP_OK(esp_cam_ctlr_enable(cam_handle));
TEST_ESP_OK(esp_cam_ctlr_start(cam_handle));
vTaskDelay(1000 / portTICK_PERIOD_MS);
//For this format"DVP_8bit_20Minput_RGB565_240x240_25fps", the FPS is 25
TEST_ASSERT_GREATER_OR_EQUAL(25, count_new_vb);
TEST_ASSERT_GREATER_OR_EQUAL(24, count_finished_trans);
TEST_ESP_OK(esp_cam_ctlr_stop(cam_handle));
TEST_ESP_OK(esp_cam_ctlr_disable(cam_handle));
TEST_ESP_OK(esp_cam_ctlr_del(cam_handle));
example_sensor_deinit(sensor_handle);
heap_caps_free(cam_buffer);
}
static bool s_camera_get_new_vb(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data)
{
example_cam_context_t *ctx = (example_cam_context_t *)user_data;
*trans = ctx->cam_trans;
count_new_vb++;
return false;
}
static bool s_camera_get_finished_trans(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data)
{
count_finished_trans++;
return false;
}
@@ -1,41 +1,34 @@
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize
def _skip_board_specific_cases(case_tester) -> None: # type: ignore
for case in case_tester.test_menu:
if 'TEST esp_cam DVP on ov2640' in case.name:
continue
case_tester.run_normal_case(case=case, reset=True)
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
['cache_safe', 'release', 'pm_enable'],
indirect=True,
)
@idf_parametrize('target', ['esp32p4'], indirect=['target'])
def test_dvp(dut: Dut) -> None:
dut.run_all_single_board_cases()
@pytest.mark.octal_psram
@pytest.mark.parametrize(
'config',
['cache_safe', 'release', 'pm_enable'],
indirect=True,
)
@idf_parametrize('target', ['esp32s3'], indirect=['target'])
def test_dvp_driver(case_tester) -> None: # type: ignore
for case in case_tester.test_menu:
if 'TEST DVP camera on esp32s3_eye' in case.name:
continue
case_tester.run_normal_case(case=case, reset=True)
@idf_parametrize('target', ['esp32p4', 'esp32s31'], indirect=['target'])
def test_dvp(case_tester) -> None: # type: ignore
_skip_board_specific_cases(case_tester)
@pytest.mark.esp32s3_eye
@pytest.mark.parametrize(
'config',
['esp32s3_eye'],
['cache_safe', 'release', 'pm_enable', 'esp32s3_ov2640'],
indirect=True,
)
@idf_parametrize('target', ['esp32s3'], indirect=['target'])
def test_dvp_s3eye(dut: Dut) -> None:
def test_dvp_esp32s3(dut: Dut) -> None:
dut.run_all_single_board_cases()
@@ -0,0 +1,6 @@
CONFIG_IDF_TARGET="esp32p4"
CONFIG_SPIRAM=y
CONFIG_SPIRAM_SPEED_200M=y
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
CONFIG_CAMERA_OV2640=y
@@ -0,0 +1,5 @@
CONFIG_IDF_TARGET="esp32s31"
CONFIG_SPIRAM=y
CONFIG_SPIRAM_SPEED_250M=y
CONFIG_CAMERA_OV2640=y
@@ -1,7 +0,0 @@
CONFIG_IDF_TARGET="esp32s3"
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
CONFIG_CAMERA_OV2640=y
@@ -0,0 +1 @@
CONFIG_CAMERA_OV2640=y
@@ -1,4 +1,6 @@
CONFIG_IDF_TARGET="esp32s3"
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_OCT=y
@@ -0,0 +1,4 @@
CONFIG_IDF_TARGET="esp32s31"
CONFIG_SPIRAM=y
CONFIG_SPIRAM_SPEED_250M=y