diff --git a/components/esp_driver_cam/test_apps/csi/main/CMakeLists.txt b/components/esp_driver_cam/test_apps/csi/main/CMakeLists.txt index feae732ba4..9714f7e10b 100644 --- a/components/esp_driver_cam/test_apps/csi/main/CMakeLists.txt +++ b/components/esp_driver_cam/test_apps/csi/main/CMakeLists.txt @@ -4,10 +4,15 @@ if(CONFIG_SOC_MIPI_CSI_SUPPORTED) list(APPEND srcs "test_csi_driver.c") endif() +if(CONFIG_CAMERA_OV5647) + list(APPEND srcs "test_csi_ov5647.c") +endif() + set(priv_requires unity esp_driver_cam esp_psram + sensor_init ) idf_component_register(SRCS ${srcs} diff --git a/components/esp_driver_cam/test_apps/csi/main/idf_component.yml b/components/esp_driver_cam/test_apps/csi/main/idf_component.yml new file mode 100644 index 0000000000..06820194d6 --- /dev/null +++ b/components/esp_driver_cam/test_apps/csi/main/idf_component.yml @@ -0,0 +1,4 @@ +dependencies: + espressif/esp_cam_sensor: ">=0.5.*" + sensor_init: + path: ${IDF_PATH}/examples/peripherals/camera/common_components/sensor_init diff --git a/components/esp_driver_cam/test_apps/csi/main/test_app_main.c b/components/esp_driver_cam/test_apps/csi/main/test_app_main.c index a47ab1a130..d31e0aa8e6 100644 --- a/components/esp_driver_cam/test_apps/csi/main/test_app_main.c +++ b/components/esp_driver_cam/test_apps/csi/main/test_app_main.c @@ -9,7 +9,7 @@ #include "esp_heap_caps.h" #include "sdkconfig.h" -#define TEST_MEMORY_LEAK_THRESHOLD (400) +#define TEST_MEMORY_LEAK_THRESHOLD (500) void setUp(void) { diff --git a/components/esp_driver_cam/test_apps/csi/main/test_csi_ov5647.c b/components/esp_driver_cam/test_apps/csi/main/test_csi_ov5647.c new file mode 100644 index 0000000000..19b62682c6 --- /dev/null +++ b/components/esp_driver_cam/test_apps/csi/main/test_csi_ov5647.c @@ -0,0 +1,147 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "unity.h" +#include "esp_cam_ctlr_csi.h" +#include "esp_cam_ctlr.h" +#include "esp_ldo_regulator.h" +#include "sdkconfig.h" +#include "driver/isp.h" +#include "example_sensor_init.h" +#include "esp_private/esp_cache_private.h" + +#define TEST_USED_LDO_CHAN_ID 3 +#define TEST_USED_LDO_VOLTAGE_MV 2500 + +#define TEST_RGB565_BITS_PER_PIXEL 16 +#define TEST_MIPI_CSI_LANE_BITRATE_MBPS 200 + +#define TEST_MIPI_CSI_CAM_SCCB_SCL_IO 8 +#define TEST_MIPI_CSI_CAM_SCCB_SDA_IO 7 + +#define TEST_MIPI_DSI_DISP_HRES 800 +#define TEST_MIPI_DSI_DISP_VRES 1280 +#define TEST_MIPI_CSI_DISP_HRES 800 +#define TEST_MIPI_CSI_DISP_VRES 640 + +#define TEST_CAM_FORMAT "MIPI_2lane_24Minput_RAW8_800x640_50fps" + +static int new_buffer_count = 0; +static int trans_finished_count = 0; + +static bool IRAM_ATTR camera_get_new_buffer(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data) +{ + esp_cam_ctlr_trans_t *new_trans = (esp_cam_ctlr_trans_t *)user_data; + trans->buffer = new_trans->buffer; + trans->buflen = new_trans->buflen; + new_buffer_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) +{ + trans_finished_count++; + return false; +} + +TEST_CASE("TEST esp_cam on ov5647", "[csi][camera][ov5647]") +{ + size_t frame_buffer_size = TEST_MIPI_CSI_DISP_HRES * + TEST_MIPI_DSI_DISP_VRES * + TEST_RGB565_BITS_PER_PIXEL / 8; + + //mipi ldo + esp_ldo_channel_handle_t ldo_mipi_phy = NULL; + esp_ldo_channel_config_t ldo_config = { + .chan_id = TEST_USED_LDO_CHAN_ID, + .voltage_mv = TEST_USED_LDO_VOLTAGE_MV, + }; + TEST_ESP_OK(esp_ldo_acquire_channel(&ldo_config, &ldo_mipi_phy)); + + size_t frame_buffer_alignment = 0; + TEST_ESP_OK(esp_cache_get_alignment(0, &frame_buffer_alignment)); + void *frame_buffer = heap_caps_aligned_calloc(frame_buffer_alignment, 1, frame_buffer_size, + MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + + esp_cam_ctlr_trans_t trans_data = { + .buffer = frame_buffer, + .buflen = frame_buffer_size, + }; + + //--------Camera Sensor and SCCB Init-----------// + 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_MIPI_CSI_CAM_SCCB_SDA_IO, + .i2c_scl_io_num = TEST_MIPI_CSI_CAM_SCCB_SCL_IO, + .port = ESP_CAM_SENSOR_MIPI_CSI, + .format_name = TEST_CAM_FORMAT, + }; + example_sensor_init(&sensor_config, &sensor_handle); + + //---------------CSI Init------------------// + esp_cam_ctlr_csi_config_t csi_config = { + .ctlr_id = 0, + .h_res = TEST_MIPI_CSI_DISP_HRES, + .v_res = TEST_MIPI_CSI_DISP_VRES, + .lane_bit_rate_mbps = TEST_MIPI_CSI_LANE_BITRATE_MBPS, + .input_data_color_type = CAM_CTLR_COLOR_RAW8, + .output_data_color_type = CAM_CTLR_COLOR_RGB565, + .data_lane_num = 2, + .byte_swap_en = false, + .queue_items = 1, + }; + esp_cam_ctlr_handle_t cam_handle = NULL; + TEST_ESP_OK(esp_cam_new_csi_ctlr(&csi_config, &cam_handle)); + + 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)); + + //---------------ISP Init------------------// + isp_proc_handle_t isp_proc = NULL; + esp_isp_processor_cfg_t isp_config = { + .clk_hz = 80 * 1000 * 1000, + .input_data_source = ISP_INPUT_DATA_SOURCE_CSI, + .input_data_color_type = ISP_COLOR_RAW8, + .output_data_color_type = ISP_COLOR_RGB565, + .has_line_start_packet = false, + .has_line_end_packet = false, + .h_res = TEST_MIPI_CSI_DISP_HRES, + .v_res = TEST_MIPI_CSI_DISP_VRES, + }; + TEST_ESP_OK(esp_isp_new_processor(&isp_config, &isp_proc)); + + TEST_ESP_OK(esp_isp_enable(isp_proc)); + TEST_ESP_OK(esp_cam_ctlr_start(cam_handle)); + TEST_ESP_OK(esp_cam_ctlr_receive(cam_handle, &trans_data, ESP_CAM_CTLR_MAX_DELAY)); + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ESP_OK(esp_cam_ctlr_stop(cam_handle)); + + TEST_ASSERT_GREATER_THAN(2, new_buffer_count); + TEST_ASSERT_GREATER_THAN(2, trans_finished_count); + + TEST_ESP_OK(esp_cam_ctlr_disable(cam_handle)); + TEST_ESP_OK(esp_cam_ctlr_del(cam_handle)); + + TEST_ESP_OK(esp_isp_disable(isp_proc)); + TEST_ESP_OK(esp_isp_del_processor(isp_proc)); + + TEST_ESP_OK(esp_ldo_release_channel(ldo_mipi_phy)); + + example_sensor_deinit(sensor_handle); + + heap_caps_free(frame_buffer); +} diff --git a/components/esp_driver_cam/test_apps/csi/pytest_csi.py b/components/esp_driver_cam/test_apps/csi/pytest_csi.py index 3be2c9557f..51d788d67d 100644 --- a/components/esp_driver_cam/test_apps/csi/pytest_csi.py +++ b/components/esp_driver_cam/test_apps/csi/pytest_csi.py @@ -6,6 +6,26 @@ from pytest_embedded_idf.utils import idf_parametrize @pytest.mark.generic +@pytest.mark.parametrize( + 'config', + ['cache_safe', 'release'], + indirect=True, +) @idf_parametrize('target', ['esp32p4'], indirect=['target']) -def test_csi(dut: Dut) -> None: +def test_csi_driver(case_tester) -> None: # type: ignore + for case in case_tester.test_menu: + if 'TEST esp_cam on ov5647' in case.name: + continue + case_tester.run_normal_case(case=case, reset=True) + + +@pytest.mark.camera +@pytest.mark.ov5647 +@pytest.mark.parametrize( + 'config', + ['cache_safe', 'release'], + indirect=True, +) +@idf_parametrize('target', ['esp32p4'], indirect=['target']) +def test_csi_camera(dut: Dut) -> None: dut.run_all_single_board_cases() diff --git a/components/esp_driver_cam/test_apps/csi/sdkconfig.ci.release b/components/esp_driver_cam/test_apps/csi/sdkconfig.ci.release new file mode 100644 index 0000000000..3cff15d49e --- /dev/null +++ b/components/esp_driver_cam/test_apps/csi/sdkconfig.ci.release @@ -0,0 +1,3 @@ +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/components/esp_driver_cam/test_apps/csi/sdkconfig.defaults.esp32p4 b/components/esp_driver_cam/test_apps/csi/sdkconfig.defaults.esp32p4 index 1f374c18ed..ca90c75b74 100644 --- a/components/esp_driver_cam/test_apps/csi/sdkconfig.defaults.esp32p4 +++ b/components/esp_driver_cam/test_apps/csi/sdkconfig.defaults.esp32p4 @@ -3,3 +3,5 @@ CONFIG_IDF_TARGET="esp32p4" CONFIG_SPIRAM=y CONFIG_IDF_EXPERIMENTAL_FEATURES=y CONFIG_SPIRAM_SPEED_200M=y + +CONFIG_CAMERA_OV5647=y diff --git a/examples/peripherals/camera/common_components/sensor_init/example_sensor_init.c b/examples/peripherals/camera/common_components/sensor_init/example_sensor_init.c index 671c92e399..c5a0688d65 100644 --- a/examples/peripherals/camera/common_components/sensor_init/example_sensor_init.c +++ b/examples/peripherals/camera/common_components/sensor_init/example_sensor_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,7 +19,7 @@ static const char *TAG = "sensor_init"; -void example_sensor_init(example_sensor_config_t *sensor_config, i2c_master_bus_handle_t *out_i2c_bus_handle) +void example_sensor_init(example_sensor_config_t *sensor_config, example_sensor_handle_t *out_sensor_handle) { esp_err_t ret = ESP_FAIL; @@ -99,6 +99,12 @@ void example_sensor_init(example_sensor_config_t *sensor_config, i2c_master_bus_ ESP_LOGE(TAG, "Start stream fail"); } ESP_ERROR_CHECK(ret); - - *out_i2c_bus_handle = i2c_bus_handle; + out_sensor_handle->i2c_bus_handle = i2c_bus_handle; + out_sensor_handle->sccb_handle = cam_config.sccb_handle; +} + +void example_sensor_deinit(example_sensor_handle_t sensor_handle) +{ + ESP_ERROR_CHECK(esp_sccb_del_i2c_io(sensor_handle.sccb_handle)); + ESP_ERROR_CHECK(i2c_del_master_bus(sensor_handle.i2c_bus_handle)); } diff --git a/examples/peripherals/camera/common_components/sensor_init/include/example_sensor_init.h b/examples/peripherals/camera/common_components/sensor_init/include/example_sensor_init.h index 866cb3dd95..745a99caa3 100644 --- a/examples/peripherals/camera/common_components/sensor_init/include/example_sensor_init.h +++ b/examples/peripherals/camera/common_components/sensor_init/include/example_sensor_init.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,14 @@ extern "C" { #endif +/** + * @brief Handle of SCCB interface and sensor + */ +typedef struct { + esp_sccb_io_handle_t sccb_handle; /*!< SCCB io handle that created by `sccb_new_i2c_io` */ + i2c_master_bus_handle_t i2c_bus_handle; /*!< I2C bus handle that created by `i2c_new_master_bus` */ +} example_sensor_handle_t; + /** * @brief Configuration of SCCB interface and sensor */ @@ -28,9 +36,16 @@ typedef struct { * @brief SCCB Interface and Sensor Init * * @param[in] sensor_config Camera sensor configuration - * @param[out] out_i2c_bus_handle I2C bus handle + * @param[out] out_sensor_handle Camera sensor handle */ -void example_sensor_init(example_sensor_config_t *sensor_config, i2c_master_bus_handle_t *out_i2c_bus_handle); +void example_sensor_init(example_sensor_config_t *sensor_config, example_sensor_handle_t *out_sensor_handle); + +/** + * @brief SCCB Interface and Sensor Deinit + * + * @param[in] out_sensor_handle Camera sensor handle + */ +void example_sensor_deinit(example_sensor_handle_t sensor_handle); #ifdef __cplusplus } diff --git a/examples/peripherals/camera/dvp_isp_dsi/main/dvp_isp_dsi_main.c b/examples/peripherals/camera/dvp_isp_dsi/main/dvp_isp_dsi_main.c index 3527eb2fbe..6b56a12233 100644 --- a/examples/peripherals/camera/dvp_isp_dsi/main/dvp_isp_dsi_main.c +++ b/examples/peripherals/camera/dvp_isp_dsi/main/dvp_isp_dsi_main.c @@ -119,8 +119,11 @@ void app_main(void) .port = ESP_CAM_SENSOR_DVP, .format_name = EXAMPLE_CAM_FORMAT, }; - i2c_master_bus_handle_t i2c_bus_handle = NULL; - example_sensor_init(&cam_sensor_config, &i2c_bus_handle); + example_sensor_handle_t sensor_handle = { + .sccb_handle = NULL, + .i2c_bus_handle = NULL, + }; + example_sensor_init(&cam_sensor_config, &sensor_handle); //---------------ISP Init------------------// isp_proc_handle_t isp_proc = NULL; diff --git a/examples/peripherals/camera/mipi_isp_dsi/main/mipi_isp_dsi_main.c b/examples/peripherals/camera/mipi_isp_dsi/main/mipi_isp_dsi_main.c index 34ef7368e0..d7f3645da6 100644 --- a/examples/peripherals/camera/mipi_isp_dsi/main/mipi_isp_dsi_main.c +++ b/examples/peripherals/camera/mipi_isp_dsi/main/mipi_isp_dsi_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -66,7 +66,10 @@ void app_main(void) }; //--------Camera Sensor and SCCB Init-----------// - i2c_master_bus_handle_t i2c_bus_handle = NULL; + example_sensor_handle_t sensor_handle = { + .sccb_handle = NULL, + .i2c_bus_handle = NULL, + }; example_sensor_config_t cam_sensor_config = { .i2c_port_num = I2C_NUM_0, .i2c_sda_io_num = EXAMPLE_MIPI_CSI_CAM_SCCB_SDA_IO, @@ -74,7 +77,7 @@ void app_main(void) .port = ESP_CAM_SENSOR_MIPI_CSI, .format_name = EXAMPLE_CAM_FORMAT, }; - example_sensor_init(&cam_sensor_config, &i2c_bus_handle); + example_sensor_init(&cam_sensor_config, &sensor_handle); //---------------CSI Init------------------// esp_cam_ctlr_csi_config_t csi_config = { diff --git a/examples/peripherals/isp/multi_pipelines/main/isp_dsi_main.c b/examples/peripherals/isp/multi_pipelines/main/isp_dsi_main.c index 67d1a3d857..018f522d61 100644 --- a/examples/peripherals/isp/multi_pipelines/main/isp_dsi_main.c +++ b/examples/peripherals/isp/multi_pipelines/main/isp_dsi_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -223,7 +223,10 @@ void app_main(void) }; //--------Camera Sensor and SCCB Init-----------// - i2c_master_bus_handle_t i2c_bus_handle = NULL; + example_sensor_handle_t sensor_handle = { + .sccb_handle = NULL, + .i2c_bus_handle = NULL, + }; example_sensor_config_t cam_sensor_config = { .i2c_port_num = I2C_NUM_0, .i2c_sda_io_num = EXAMPLE_MIPI_CSI_CAM_SCCB_SDA_IO, @@ -231,7 +234,7 @@ void app_main(void) .port = ESP_CAM_SENSOR_MIPI_CSI, .format_name = EXAMPLE_CAM_FORMAT, }; - example_sensor_init(&cam_sensor_config, &i2c_bus_handle); + example_sensor_init(&cam_sensor_config, &sensor_handle); //---------------VCM SCCB Init------------------// esp_sccb_io_handle_t dw9714_io_handle = NULL; @@ -240,7 +243,7 @@ void app_main(void) .device_address = EXAMPLE_DW9714_DEV_ADDR, .dev_addr_length = I2C_ADDR_BIT_LEN_7, }; - ESP_ERROR_CHECK(sccb_new_i2c_io(i2c_bus_handle, &i2c_config, &dw9714_io_handle)); + ESP_ERROR_CHECK(sccb_new_i2c_io(sensor_handle.i2c_bus_handle, &i2c_config, &dw9714_io_handle)); //---------------CSI Init------------------// esp_cam_ctlr_csi_config_t csi_config = { diff --git a/tools/ci/idf_pytest/constants.py b/tools/ci/idf_pytest/constants.py index af12e7d59f..17994e1240 100644 --- a/tools/ci/idf_pytest/constants.py +++ b/tools/ci/idf_pytest/constants.py @@ -126,6 +126,8 @@ ENV_MARKERS = { 'flash_4mb': 'C2 runners with 4 MB flash', 'jtag_re_enable': 'Runner to re-enable jtag which is softly disabled by burning bit SOFT_DIS_JTAG on eFuse', 'es8311': 'Development board that carries es8311 codec', + 'camera': 'Runner with camera', + 'ov5647': 'Runner with camera ov5647', # multi-dut markers 'multi_dut_modbus_rs485': 'a pair of runners connected by RS485 bus', 'ieee802154': 'ieee802154 related tests should run on ieee802154 runners.',