From 5f582fdc2805dfda71e9960d39060c265c5c2a6a Mon Sep 17 00:00:00 2001 From: gaoxu Date: Wed, 21 May 2025 11:43:10 +0800 Subject: [PATCH 1/5] fix(cam): decrease i2c sccb frequency for camera --- .../sensor_init/include/example_sensor_init_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/peripherals/camera/common_components/sensor_init/include/example_sensor_init_config.h b/examples/peripherals/camera/common_components/sensor_init/include/example_sensor_init_config.h index dd3acc4720..1aa6a81dc0 100644 --- a/examples/peripherals/camera/common_components/sensor_init/include/example_sensor_init_config.h +++ b/examples/peripherals/camera/common_components/sensor_init/include/example_sensor_init_config.h @@ -10,7 +10,7 @@ extern "C" { #endif -#define EXAMPLE_CAM_SCCB_FREQ (100000) +#define EXAMPLE_CAM_SCCB_FREQ (10 * 1000) #ifdef __cplusplus } From 449abbab768db0af4e39083049de43f7006bb3da Mon Sep 17 00:00:00 2001 From: gaoxu Date: Wed, 21 May 2025 11:43:44 +0800 Subject: [PATCH 2/5] fix(cam): fix dvp can not get cam_buffer --- .../esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c index 5e53b9bab4..eaddf9a94a 100644 --- a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c +++ b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c @@ -146,8 +146,11 @@ static IRAM_ATTR esp_err_t esp_cam_ctlr_dvp_start_trans(esp_cam_ctlr_dvp_cam_t * ESP_RETURN_ON_ERROR_ISR(esp_cam_ctlr_dvp_dma_stop(&ctlr->dma), TAG, "failed to stop DMA"); } - if (ctlr->cbs.on_get_new_trans && ctlr->cbs.on_get_new_trans(&(ctlr->base), &trans, ctlr->cbs_user_data)) { - buffer_ready = true; + if (ctlr->cbs.on_get_new_trans) { + ctlr->cbs.on_get_new_trans(&(ctlr->base), &trans, ctlr->cbs_user_data); + if (trans.buffer) { + buffer_ready = true; + } } else if (!ctlr->bk_buffer_dis) { trans.buffer = ctlr->backup_buffer; trans.buflen = ctlr->fb_size_in_bytes; @@ -740,13 +743,14 @@ esp_err_t esp_cam_new_dvp_ctlr(const esp_cam_ctlr_dvp_config_t *config, esp_cam_ .port = config->ctlr_id, .byte_swap_en = config->byte_swap_en, }; - cam_hal_init(&ctlr->hal, &cam_hal_config); if (!config->pin_dont_init) { ESP_GOTO_ON_ERROR(esp_cam_ctlr_dvp_init(config->ctlr_id, config->clk_src, config->pin), fail5, TAG, "failed to initialize clock and GPIO"); } + cam_hal_init(&ctlr->hal, &cam_hal_config); + ctlr->ctlr_id = config->ctlr_id; ctlr->fb_size_in_bytes = fb_size_in_bytes; ctlr->dvp_fsm = ESP_CAM_CTLR_DVP_CAM_FSM_INIT; From 2a13a36589942106dfa89bd57d3acebab2643101 Mon Sep 17 00:00:00 2001 From: gaoxu Date: Mon, 2 Jun 2025 12:51:32 +0800 Subject: [PATCH 3/5] feat(cam): add esp32p4 dvp example --- examples/peripherals/.build-test-rules.yml | 7 + .../peripherals/camera/dvp_dsi/CMakeLists.txt | 8 + examples/peripherals/camera/dvp_dsi/README.md | 156 +++++++++++++++ .../camera/dvp_dsi/main/CMakeLists.txt | 4 + .../camera/dvp_dsi/main/Kconfig.projbuild | 45 +++++ .../camera/dvp_dsi/main/dvp_dsi_main.c | 184 ++++++++++++++++++ .../camera/dvp_dsi/main/example_config.h | 57 ++++++ .../camera/dvp_dsi/main/idf_component.yml | 7 + .../camera/dvp_dsi/pytest_dvp_dsi.py | 11 ++ .../camera/dvp_dsi/sdkconfig.defaults | 1 + .../camera/dvp_dsi/sdkconfig.defaults.esp32p4 | 4 + 11 files changed, 484 insertions(+) create mode 100644 examples/peripherals/camera/dvp_dsi/CMakeLists.txt create mode 100644 examples/peripherals/camera/dvp_dsi/README.md create mode 100644 examples/peripherals/camera/dvp_dsi/main/CMakeLists.txt create mode 100644 examples/peripherals/camera/dvp_dsi/main/Kconfig.projbuild create mode 100644 examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c create mode 100644 examples/peripherals/camera/dvp_dsi/main/example_config.h create mode 100644 examples/peripherals/camera/dvp_dsi/main/idf_component.yml create mode 100644 examples/peripherals/camera/dvp_dsi/pytest_dvp_dsi.py create mode 100644 examples/peripherals/camera/dvp_dsi/sdkconfig.defaults create mode 100644 examples/peripherals/camera/dvp_dsi/sdkconfig.defaults.esp32p4 diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 95a61b9d6c..4540c93bb3 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -44,6 +44,13 @@ examples/peripherals/bitscrambler: depends_components: - esp_driver_bitscrambler +examples/peripherals/camera/dvp_dsi: + disable: + - if: SOC_LCDCAM_CAM_SUPPORTED != 1 or SOC_MIPI_DSI_SUPPORTED != 1 + depends_components: + - esp_lcd + - esp_driver_cam + examples/peripherals/camera/dvp_isp_dsi: disable: - if: SOC_ISP_DVP_SUPPORTED != 1 or SOC_MIPI_DSI_SUPPORTED != 1 diff --git a/examples/peripherals/camera/dvp_dsi/CMakeLists.txt b/examples/peripherals/camera/dvp_dsi/CMakeLists.txt new file mode 100644 index 0000000000..df4e6c3652 --- /dev/null +++ b/examples/peripherals/camera/dvp_dsi/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(dvp_dsi) diff --git a/examples/peripherals/camera/dvp_dsi/README.md b/examples/peripherals/camera/dvp_dsi/README.md new file mode 100644 index 0000000000..f6408ca4f2 --- /dev/null +++ b/examples/peripherals/camera/dvp_dsi/README.md @@ -0,0 +1,156 @@ +| Supported Targets | ESP32-P4 | +| ----------------- | -------- | + + +# DVP Camera display via DSI example + +## Overview + +This example demonstrates how to use the esp_driver_cam component to capture DVP camera sensor signals and display it via DSI interface. This example will auto-detect camera sensors via [ESP camera sensor driver](https://components.espressif.com/components/espressif/esp_cam_sensor) and capture camera sensor signals via DVP interface and display it via DSI interface. + +## Usage + +The subsections below give only absolutely necessary information. For full steps to configure ESP-IDF and use it to build and run projects, see [ESP-IDF Getting Started](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html#get-started). + + +### Hardware Required + +- OV2640 camera sensor, or other camera sensors with DVP port that can output RGB565 format color data +- EK79007 LCD screen +- ESP32P4 devkit + +**Note:** For EK79007 you will need to connect following pins: +- 5V - 5V +- GND - GND +- RST_LCD - 3V3 + +You can also connect camera sensors and LCD screens from other vendors to the ESP chip, you can find corresponding camera or LCD drivers from [ESP Component Registry](https://components.espressif.com), or design your own customized drivers. + + + GND GND + ┌────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────┐ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ ┌───────────────┴─────────────┴──────────────────┐ │ + │ │ │ ┌──────────┴───────────┐ + │ │ │ DSI DATA 1P │ │ + │ │ ├───────────────────────────┤ │ + ┌───────────┴─────────┐ │ │ │ │ + │ │ │ │ DSI DATA 1N │ │ + │ │ │ ├───────────────────────────┤ │ + │ │ XCLK │ ESP32-P4 │ │ │ + │ DVP Camera ├──────────────────────┤ │ DSI CLK N │ LCD Screen │ + │ │ │ ├───────────────────────────┤ │ + │ │ D0~7 │ │ │ │ + │ ├──────────────────────┤ │ DSI CLK P │ │ + │ │ │ ├───────────────────────────┤ │ + │ │ PCLK │ │ │ │ + │ ├──────────────────────┤ │ DSI DATA 0P │ │ + │ │ │ ├───────────────────────────┤ │ + │ │ VSYNC │ │ │ │ + │ ├──────────────────────┤ │ DSI DATA 0N │ │ + │ │ │ ├───────────────────────────┤ │ + │ │ DE (HREF) │ │ │ │ + │ ├──────────────────────┤ │ └──────────────────────┘ + │ │ │ │ + └───────┬──┬──────────┘ │ │ + │ │ I2C SCL │ │ + │ └─────────────────────────────────┤ │ + │ I2C SDA │ │ + └────────────────────────────────────┤ │ + └────────────────────────────────────────────────┘ + + +### Set Chip Target + +First of all, your target must be supported by both: + +- **By your ESP-IDF version**: For the full list of supported targets, run: + ``` + idf.py --list-targets + ``` +- **By this example**: For the full list of supported targets, refer to the supported targets table at the top of this README. + +After you make sure that your target is supported, go to your example project directory and [set the chip target](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/tools/idf-py.html#select-the-target-chip-set-target): + +``` +idf.py set-target +``` + +For example, to set esp32-P4 as the chip target, run: + +``` +idf.py set-target esp32p4 +``` + + +### Configure the Project + +For information about Kconfig options, see [Project Configuration](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/kconfig.html) > _Name of relevant section(s)_. + +To conveniently check or modify Kconfig options for this example in a project configuration menu, run: + +``` +idf.py menuconfig +``` + +``` +Set CONFIG_CAMERA_OV2640 to y +``` + +Remember to select the LCD screen model and set corresponding correct horizontal/vertical resolution in ``menuconfig`` > ``Example DSI Configuration``. + +Available options for the camera sensor output horizontal/vertical resolution can be seen in ``menuconfig`` > ``Example Configuration``. + + +### Build and Flash + +Execute the following command to build the project, flash it to your development board, and run the monitor tool to view the serial output: + +``` +idf.py build flash monitor +``` + +This command can be reduced to `idf.py flash monitor`. + +If the above command fails, check the log on the serial monitor which usually provides information on the possible cause of the issue. + +To exit the serial monitor, use `Ctrl` + `]`. + + +## Example Output + +If you see the following console output, your example should be running correctly: + +``` +I (1481) main_task: Calling app_main() +I (1481) ek79007: version: 1.0.2 +I (1701) ov2640: Detected Camera sensor PID=0x26 +I (1701) sensor_init: fmt[0].name:DVP_8bit_20Minput_RGB565_640x480_6fps +I (1701) sensor_init: fmt[1].name:DVP_8bit_20Minput_YUV422_640x480_6fps +I (1711) sensor_init: fmt[2].name:DVP_8bit_20Minput_JPEG_640x480_25fps +I (1711) sensor_init: fmt[3].name:DVP_8bit_20Minput_RGB565_240x240_25fps +I (1721) sensor_init: fmt[4].name:DVP_8bit_20Minput_YUV422_240x240_25fps +I (1721) sensor_init: fmt[5].name:DVP_8bit_20Minput_JPEG_320x240_50fps +I (1731) sensor_init: fmt[6].name:DVP_8bit_20Minput_JPEG_1280x720_12fps +I (1741) sensor_init: fmt[7].name:DVP_8bit_20Minput_JPEG_1600x1200_12fps +I (1741) sensor_init: fmt[8].name:DVP_8bit_20Minput_RAW8_800x640_30fps +I (1751) sensor_init: fmt[9].name:DVP_8bit_20Minput_RAW8_800x640_15fps +I (1761) sensor_init: fmt[10].name:DVP_8bit_20Minput_RAW8_800x800_15fps +I (1761) sensor_init: fmt[11].name:DVP_8bit_20Minput_RAW8_1024x600_15fps +I (8291) sensor_init: Format in use:DVP_8bit_20Minput_RGB565_640x480_6fps + +``` + + +## Reference + +- Link to the ESP-IDF feature's API reference, for example [ESP-IDF: Camera Controller Driver](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/camera_driver.html) +- [ESP-IDF Getting Started](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html#get-started) +- [Project Configuration](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/kconfig.html) (Kconfig Options) diff --git a/examples/peripherals/camera/dvp_dsi/main/CMakeLists.txt b/examples/peripherals/camera/dvp_dsi/main/CMakeLists.txt new file mode 100644 index 0000000000..300b506de9 --- /dev/null +++ b/examples/peripherals/camera/dvp_dsi/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "dvp_dsi_main.c" + INCLUDE_DIRS "." + REQUIRES esp_mm esp_driver_cam esp_driver_i2c dsi_init sensor_init + ) diff --git a/examples/peripherals/camera/dvp_dsi/main/Kconfig.projbuild b/examples/peripherals/camera/dvp_dsi/main/Kconfig.projbuild new file mode 100644 index 0000000000..c0057383a3 --- /dev/null +++ b/examples/peripherals/camera/dvp_dsi/main/Kconfig.projbuild @@ -0,0 +1,45 @@ +menu "Example Configuration" + config EXAMPLE_USED_LDO_CHAN_ID + int "Occupied channel ID of the LDO to power on the MIPI DSI PHY" + default 3 + help + Example used LDO channel ID, you may check datasheet to know more details. + + config EXAMPLE_USED_LDO_VOLTAGE_MV + int "Occupied LDO voltage in mV" + default 2500 + range 0 3300 + help + Example used LDO voltage, in mV + + choice EXAMPLE_CAM_HRES + bool "Set camera horizontal resolution" + default EXAMPLE_CAM_HRES_640 + + config EXAMPLE_CAM_HRES_640 + bool "640" + config EXAMPLE_CAM_HRES_240 + bool "240" + endchoice + + config EXAMPLE_CAM_HRES + int + default 640 if EXAMPLE_CAM_HRES_640 + default 240 if EXAMPLE_CAM_HRES_240 + + choice EXAMPLE_CAM_VRES + bool "Set camera vertical resolution" + default EXAMPLE_CAM_VRES_480 if EXAMPLE_CAM_HRES_640 + default EXAMPLE_CAM_VRES_240 if EXAMPLE_CAM_HRES_240 + + config EXAMPLE_CAM_VRES_480 + bool "480" + config EXAMPLE_CAM_VRES_240 + bool "240" + endchoice + + config EXAMPLE_CAM_VRES + int + default 480 if EXAMPLE_CAM_VRES_480 + default 240 if EXAMPLE_CAM_VRES_240 +endmenu diff --git a/examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c b/examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c new file mode 100644 index 0000000000..2cc372ac5c --- /dev/null +++ b/examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c @@ -0,0 +1,184 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "sdkconfig.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "esp_lcd_mipi_dsi.h" +#include "esp_lcd_panel_ops.h" +#include "esp_ldo_regulator.h" +#include "esp_cache.h" +#include "driver/i2c_master.h" +#include "esp_cam_ctlr.h" +#include "esp_cam_ctlr_dvp.h" +#include "example_dsi_init.h" +#include "example_dsi_init_config.h" +#include "example_sensor_init.h" +#include "example_config.h" + +static const char *TAG = "dvp_dsi"; + +typedef struct { + esp_lcd_panel_handle_t panel_hdl; + void *cam_buf; +} display_update_param_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); + +static bool example_display_update_ready(esp_lcd_panel_handle_t panel, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx) +{ + display_update_param_t *param = (display_update_param_t *)user_ctx; + esp_lcd_panel_draw_bitmap(param->panel_hdl, 0, 0, CONFIG_EXAMPLE_CAM_HRES, CONFIG_EXAMPLE_CAM_VRES, param->cam_buf); + return false; +} + +void app_main(void) +{ + esp_err_t ret = ESP_FAIL; + esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL; + esp_lcd_panel_io_handle_t mipi_dbi_io = NULL; + esp_lcd_panel_handle_t mipi_dpi_panel = NULL; + void *frame_buffer = NULL; + size_t frame_buffer_size = 0; + + //mipi ldo + esp_ldo_channel_handle_t ldo_mipi_phy = NULL; + esp_ldo_channel_config_t ldo_mipi_phy_config = { + .chan_id = CONFIG_EXAMPLE_USED_LDO_CHAN_ID, + .voltage_mv = CONFIG_EXAMPLE_USED_LDO_VOLTAGE_MV, + }; + ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy)); + + //---------------DSI Init------------------// + example_dsi_resource_alloc(&mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &frame_buffer); + + //---------------Necessary variable config------------------// + frame_buffer_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + + ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES: %d, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, EXAMPLE_RGB565_BITS_PER_PIXEL); + ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size); + ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer); + + size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + void *cam_buffer = heap_caps_calloc(1, cam_buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM); + if (!cam_buffer) { + ESP_LOGE(TAG, "no mem for cam_buffer"); + return; + } + esp_cam_ctlr_trans_t cam_trans = { + .buffer = cam_buffer, + .buflen = cam_buffer_size, + }; + + //----------CAM Controller Init------------// + esp_cam_ctlr_handle_t cam_handle = NULL; + esp_cam_ctlr_dvp_pin_config_t pin_cfg = { + .data_width = EXAMPLE_DVP_CAM_DATA_WIDTH, + .data_io = { + EXAMPLE_DVP_CAM_D0_IO, + EXAMPLE_DVP_CAM_D1_IO, + EXAMPLE_DVP_CAM_D2_IO, + EXAMPLE_DVP_CAM_D3_IO, + EXAMPLE_DVP_CAM_D4_IO, + EXAMPLE_DVP_CAM_D5_IO, + EXAMPLE_DVP_CAM_D6_IO, + EXAMPLE_DVP_CAM_D7_IO, + }, + .vsync_io = EXAMPLE_DVP_CAM_VSYNC_IO, + .de_io = EXAMPLE_DVP_CAM_DE_IO, + .pclk_io = EXAMPLE_DVP_CAM_PCLK_IO, + .xclk_io = EXAMPLE_DVP_CAM_XCLK_IO, // Set XCLK pin to generate XCLK signal + }; + + esp_cam_ctlr_dvp_config_t dvp_config = { + .ctlr_id = 0, + .clk_src = CAM_CLK_SRC_DEFAULT, + .h_res = CONFIG_EXAMPLE_CAM_HRES, + .v_res = CONFIG_EXAMPLE_CAM_VRES, + .input_data_color_type = CAM_CTLR_COLOR_RGB565, + .dma_burst_size = 128, + .pin_dont_init = false, + .pin = &pin_cfg, + .bk_buffer_dis = 1, + }; + + ret = esp_cam_new_dvp_ctlr(&dvp_config, &cam_handle); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "dvp init fail[%d]", ret); + return; + } + + //--------Camera Sensor and SCCB Init-----------// + example_sensor_config_t cam_sensor_config = { + .i2c_port_num = I2C_NUM_0, + .i2c_sda_io_num = EXAMPLE_DVP_CAM_SCCB_SDA_IO, + .i2c_scl_io_num = EXAMPLE_DVP_CAM_SCCB_SCL_IO, + .port = ESP_CAM_SENSOR_DVP, + .format_name = EXAMPLE_CAM_FORMAT, + }; + example_sensor_handle_t sensor_handle = { + .sccb_handle = NULL, + .i2c_bus_handle = NULL, + }; + example_sensor_init(&cam_sensor_config, &sensor_handle); + + esp_cam_ctlr_evt_cbs_t cbs = { + .on_get_new_trans = s_camera_get_new_vb, + .on_trans_finished = s_camera_get_finished_trans, + }; + if (esp_cam_ctlr_register_event_callbacks(cam_handle, &cbs, &cam_trans) != ESP_OK) { + ESP_LOGE(TAG, "ops register fail"); + return; + } + + ESP_ERROR_CHECK(esp_cam_ctlr_enable(cam_handle)); + + //---------------DPI Reset------------------// + example_dpi_panel_reset(mipi_dpi_panel); + + //init to all white + memset(frame_buffer, 0xFF, frame_buffer_size); + esp_cache_msync((void *)frame_buffer, frame_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + + example_dpi_panel_init(mipi_dpi_panel); + + if (esp_cam_ctlr_start(cam_handle) != ESP_OK) { + ESP_LOGE(TAG, "Driver start fail"); + return; + } + + // Register DPI panel event callback for display update ready notification + display_update_param_t display_update_param = { + .panel_hdl = mipi_dpi_panel, + .cam_buf = cam_buffer, + }; + esp_lcd_dpi_panel_event_callbacks_t dpi_cbs = { + .on_color_trans_done = example_display_update_ready, + }; + ESP_ERROR_CHECK(esp_lcd_dpi_panel_register_event_callbacks(mipi_dpi_panel, &dpi_cbs, &display_update_param)); + esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, CONFIG_EXAMPLE_CAM_HRES, CONFIG_EXAMPLE_CAM_VRES, cam_buffer); + + while (1) { + vTaskDelay(100 / portTICK_PERIOD_MS); + } +} + +static bool s_camera_get_new_vb(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data) +{ + esp_cam_ctlr_trans_t cam_trans = *(esp_cam_ctlr_trans_t *)user_data; + trans->buffer = cam_trans.buffer; + trans->buflen = cam_trans.buflen; + return false; +} + +static bool s_camera_get_finished_trans(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data) +{ + return false; +} diff --git a/examples/peripherals/camera/dvp_dsi/main/example_config.h b/examples/peripherals/camera/dvp_dsi/main/example_config.h new file mode 100644 index 0000000000..b297650636 --- /dev/null +++ b/examples/peripherals/camera/dvp_dsi/main/example_config.h @@ -0,0 +1,57 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define EXAMPLE_RGB565_BITS_PER_PIXEL (16) + +#define EXAMPLE_DVP_CAM_SCCB_SCL_IO (33) +#define EXAMPLE_DVP_CAM_SCCB_SDA_IO (32) + +#define EXAMPLE_DVP_CAM_XCLK_FREQ_HZ (20000000) + +#define EXAMPLE_DVP_CAM_DATA_WIDTH (8) +#define EXAMPLE_DVP_CAM_D0_IO (53) +#define EXAMPLE_DVP_CAM_D1_IO (54) +#define EXAMPLE_DVP_CAM_D2_IO (26) +#define EXAMPLE_DVP_CAM_D3_IO (1) +#define EXAMPLE_DVP_CAM_D4_IO (0) +#define EXAMPLE_DVP_CAM_D5_IO (45) +#define EXAMPLE_DVP_CAM_D6_IO (46) +#define EXAMPLE_DVP_CAM_D7_IO (47) +#define EXAMPLE_DVP_CAM_XCLK_IO (20) +#define EXAMPLE_DVP_CAM_PCLK_IO (21) +#define EXAMPLE_DVP_CAM_DE_IO (22) +#define EXAMPLE_DVP_CAM_VSYNC_IO (23) +#define EXAMPLE_DVP_CAM_HSYNC_IO (-1) + +#if CONFIG_EXAMPLE_CAM_HRES_640 + +#if CONFIG_EXAMPLE_CAM_VRES_480 +#define EXAMPLE_CAM_FORMAT "DVP_8bit_20Minput_RGB565_640x480_6fps" +#endif + +#elif CONFIG_EXAMPLE_CAM_HRES_240 + +#if CONFIG_EXAMPLE_CAM_VRES_240 +#define EXAMPLE_CAM_FORMAT "DVP_8bit_20Minput_RGB565_240x240_25fps" +#endif + +#endif + +#ifndef EXAMPLE_CAM_FORMAT +#error "Unsupported camera format! Please adjust EXAMPLE_CAM_HRES and EXAMPLE_CAM_VRES in menuconfig" +#endif + +#ifdef __cplusplus +} +#endif diff --git a/examples/peripherals/camera/dvp_dsi/main/idf_component.yml b/examples/peripherals/camera/dvp_dsi/main/idf_component.yml new file mode 100644 index 0000000000..5aeb9ac3f5 --- /dev/null +++ b/examples/peripherals/camera/dvp_dsi/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + idf: + version: ">=5.3.0" + dsi_init: + path: ${IDF_PATH}/examples/peripherals/camera/common_components/dsi_init + sensor_init: + path: ${IDF_PATH}/examples/peripherals/camera/common_components/sensor_init diff --git a/examples/peripherals/camera/dvp_dsi/pytest_dvp_dsi.py b/examples/peripherals/camera/dvp_dsi/pytest_dvp_dsi.py new file mode 100644 index 0000000000..4a5ee1803c --- /dev/null +++ b/examples/peripherals/camera/dvp_dsi/pytest_dvp_dsi.py @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2025 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 + + +@pytest.mark.generic +@idf_parametrize('target', ['esp32p4'], indirect=['target']) +def test_dvp_dsi(dut: Dut) -> None: + dut.expect_exact('Calling app_main()') diff --git a/examples/peripherals/camera/dvp_dsi/sdkconfig.defaults b/examples/peripherals/camera/dvp_dsi/sdkconfig.defaults new file mode 100644 index 0000000000..dc0f8f7a83 --- /dev/null +++ b/examples/peripherals/camera/dvp_dsi/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_CAMERA_OV2640=y diff --git a/examples/peripherals/camera/dvp_dsi/sdkconfig.defaults.esp32p4 b/examples/peripherals/camera/dvp_dsi/sdkconfig.defaults.esp32p4 new file mode 100644 index 0000000000..49f03baabb --- /dev/null +++ b/examples/peripherals/camera/dvp_dsi/sdkconfig.defaults.esp32p4 @@ -0,0 +1,4 @@ +CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_SPIRAM=y +CONFIG_SPIRAM_SPEED_200M=y +CONFIG_EXAMPLE_MIPI_DSI_DISP_USE_DMA2D=y From 1533cab12bf13564149745e8fd407302a20aebcf Mon Sep 17 00:00:00 2001 From: gaoxu Date: Mon, 2 Jun 2025 14:56:00 +0800 Subject: [PATCH 4/5] fix(cam): fix dvp do not generate clock --- .../dvp/include/esp_cam_ctlr_dvp.h | 2 + .../dvp/src/esp_cam_ctlr_dvp_cam.c | 10 +++ .../test_apps/dvp/main/test_dvp_driver.c | 89 ++++++++++++++++++- .../camera/dvp_dsi/main/dvp_dsi_main.c | 2 +- 4 files changed, 101 insertions(+), 2 deletions(-) diff --git a/components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h b/components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h index 01cd362a90..032ab47a21 100644 --- a/components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h +++ b/components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h @@ -43,10 +43,12 @@ typedef struct esp_cam_ctlr_dvp_config { uint32_t bk_buffer_dis : 1; /*!< Disable backup buffer */ uint32_t pin_dont_init : 1; /*!< Don't initialize DVP pins if users have called "esp_cam_ctlr_dvp_init" before */ uint32_t pic_format_jpeg : 1; /*!< Input picture format is JPEG, if set this flag and "input_data_color_type" will be ignored */ + uint32_t external_xtal : 1; /*!< Using external XTAL, if set, xclk_io and dvp output clock will be ignored */ }; /*!< Boolean Flags */ uint32_t dma_burst_size; /*!< DVP DMA burst transmission block size, set to 0 means to disable the data burst, other value must be power of 2, e.g., 4/8/16/32/64/128 */ + uint32_t xclk_freq; /*!< DVP output clock frequency in HZ, only valid if `external_xtal` is set to true */ const esp_cam_ctlr_dvp_pin_config_t *pin; /*!< DVP pin configuration, this will be ignored by "esp_cam_new_dvp_ctlr" if "pin_dont_init" is set */ } esp_cam_ctlr_dvp_config_t; diff --git a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c index eaddf9a94a..26cdb6a0e2 100644 --- a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c +++ b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c @@ -707,6 +707,9 @@ esp_err_t esp_cam_new_dvp_ctlr(const esp_cam_ctlr_dvp_config_t *config, esp_cam_ ESP_RETURN_ON_FALSE(config && ret_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: config or ret_handle is null"); ESP_RETURN_ON_FALSE(config->ctlr_id < CAP_DVP_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid argument: ctlr_id >= %d", CAP_DVP_PERIPH_NUM); ESP_RETURN_ON_FALSE(config->pin_dont_init || config->pin, ESP_ERR_INVALID_ARG, TAG, "invalid argument: pin_dont_init is unset and pin is null"); + ESP_RETURN_ON_FALSE(config->external_xtal || config->pin_dont_init || config->pin->xclk_io != GPIO_NUM_NC, ESP_ERR_INVALID_ARG, TAG, "invalid argument: xclk_io is not set"); + ESP_RETURN_ON_FALSE(config->external_xtal || config->xclk_freq, ESP_ERR_INVALID_ARG, TAG, "invalid argument: xclk_freq is not set"); + ESP_RETURN_ON_ERROR(esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &alignment_size), TAG, "failed to get cache alignment"); ESP_RETURN_ON_ERROR(esp_cam_ctlr_dvp_cam_get_frame_size(config, &fb_size_in_bytes), TAG, "invalid argument: input frame pixel format is not supported"); ESP_RETURN_ON_ERROR(dvp_shared_ctrl_claim_io_signals(), TAG, "failed to claim io signals"); @@ -745,10 +748,17 @@ esp_err_t esp_cam_new_dvp_ctlr(const esp_cam_ctlr_dvp_config_t *config, esp_cam_ }; if (!config->pin_dont_init) { + // Initialzie DVP clock and GPIO internally ESP_GOTO_ON_ERROR(esp_cam_ctlr_dvp_init(config->ctlr_id, config->clk_src, config->pin), fail5, TAG, "failed to initialize clock and GPIO"); } + if (!config->external_xtal) { + // Generate DVP xtal clock internally + ESP_GOTO_ON_ERROR(esp_cam_ctlr_dvp_output_clock(config->ctlr_id, config->clk_src, config->xclk_freq), + fail5, TAG, "failed to generate xtal clock"); + } + cam_hal_init(&ctlr->hal, &cam_hal_config); ctlr->ctlr_id = config->ctlr_id; diff --git a/components/esp_driver_cam/test_apps/dvp/main/test_dvp_driver.c b/components/esp_driver_cam/test_apps/dvp/main/test_dvp_driver.c index 4f6b7041e8..ec99cc5202 100644 --- a/components/esp_driver_cam/test_apps/dvp/main/test_dvp_driver.c +++ b/components/esp_driver_cam/test_apps/dvp/main/test_dvp_driver.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 */ @@ -20,6 +20,7 @@ TEST_CASE("TEST DVP driver allocation", "[DVP]") .dma_burst_size = 128, .byte_swap_en = false, .pin_dont_init = true, + .external_xtal = true, }; esp_cam_ctlr_handle_t handle = NULL; TEST_ESP_OK(esp_cam_new_dvp_ctlr(&dvp_config, &handle)); @@ -45,6 +46,7 @@ TEST_CASE("TEST DVP driver allocation with JPEG input", "[DVP]") .byte_swap_en = false, .pin_dont_init = true, .pic_format_jpeg = true, + .external_xtal = true, }; esp_cam_ctlr_handle_t handle = NULL; TEST_ESP_OK(esp_cam_new_dvp_ctlr(&dvp_config, &handle)); @@ -71,6 +73,7 @@ TEST_CASE("TEST DVP driver no backup buffer usage", "[DVP]") .byte_swap_en = false, .bk_buffer_dis = true, .pin_dont_init = true, + .external_xtal = true, }; esp_cam_ctlr_handle_t handle = NULL; TEST_ESP_OK(esp_cam_new_dvp_ctlr(&dvp_config, &handle)); @@ -84,3 +87,87 @@ TEST_CASE("TEST DVP driver no backup buffer usage", "[DVP]") TEST_ASSERT_EQUAL((dvp_config.h_res * dvp_config.v_res * 2), bk_buffer_len); // out type RGB565 using 2 byte / pixel TEST_ESP_OK(esp_cam_ctlr_del(handle)); } + +TEST_CASE("TEST DVP driver intern/extern init", "[DVP]") +{ + esp_cam_ctlr_dvp_config_t dvp_config = { + .ctlr_id = 0, + .clk_src = CAM_CLK_SRC_DEFAULT, + .h_res = 800, + .v_res = 640, + .input_data_color_type = CAM_CTLR_COLOR_RGB565, + .dma_burst_size = 128, + .byte_swap_en = false, + .external_xtal = true, + }; + esp_cam_ctlr_handle_t handle = NULL; + + //Init externally, do not check pin + dvp_config.pin_dont_init = true; + TEST_ESP_OK(esp_cam_new_dvp_ctlr(&dvp_config, &handle)); + TEST_ESP_OK(esp_cam_ctlr_del(handle)); + + //Init internally but not set pin + dvp_config.pin_dont_init = false; + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_cam_new_dvp_ctlr(&dvp_config, &handle)); + + //Init internally and set pin + esp_cam_ctlr_dvp_pin_config_t pin_cfg = { + .data_width = 8, + }; + dvp_config.pin = &pin_cfg; + TEST_ESP_OK(esp_cam_new_dvp_ctlr(&dvp_config, &handle)); + TEST_ESP_OK(esp_cam_ctlr_del(handle)); +} + +TEST_CASE("TEST DVP driver intern/extern generate xclk", "[DVP]") +{ + esp_cam_ctlr_dvp_config_t dvp_config = { + .ctlr_id = 0, + .clk_src = CAM_CLK_SRC_DEFAULT, + .h_res = 800, + .v_res = 640, + .input_data_color_type = CAM_CTLR_COLOR_RGB565, + .dma_burst_size = 128, + .byte_swap_en = false, + .external_xtal = true, + }; + esp_cam_ctlr_handle_t handle = NULL; + + //Init externally, generate xclk externally, check nothing + dvp_config.pin_dont_init = true; + dvp_config.external_xtal = true; + TEST_ESP_OK(esp_cam_new_dvp_ctlr(&dvp_config, &handle)); + TEST_ESP_OK(esp_cam_ctlr_del(handle)); + + //Init externally, generate xclk internally, do not check pin, check xclk_freq + dvp_config.pin_dont_init = true; + dvp_config.external_xtal = false; + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_cam_new_dvp_ctlr(&dvp_config, &handle)); + dvp_config.xclk_freq = 20000000; + TEST_ESP_OK(esp_cam_new_dvp_ctlr(&dvp_config, &handle)); + TEST_ESP_OK(esp_cam_ctlr_del(handle)); + + esp_cam_ctlr_dvp_pin_config_t pin_cfg = { + .data_width = 8, + .xclk_io = GPIO_NUM_NC, + }; + + //Init internally, generate xclk externally, check nothing + dvp_config.pin = &pin_cfg; + dvp_config.pin_dont_init = false; + dvp_config.external_xtal = true; + TEST_ESP_OK(esp_cam_new_dvp_ctlr(&dvp_config, &handle)); + TEST_ESP_OK(esp_cam_ctlr_del(handle)); + + //Init internally, generate xclk internally, check xclk_io and xclk_freq + dvp_config.pin = &pin_cfg; + dvp_config.pin_dont_init = false; + dvp_config.external_xtal = false; + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_cam_new_dvp_ctlr(&dvp_config, &handle)); + + pin_cfg.xclk_io = 20; + dvp_config.pin = &pin_cfg; + TEST_ESP_OK(esp_cam_new_dvp_ctlr(&dvp_config, &handle)); + TEST_ESP_OK(esp_cam_ctlr_del(handle)); +} diff --git a/examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c b/examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c index 2cc372ac5c..5e5f6d4053 100644 --- a/examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c +++ b/examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c @@ -104,9 +104,9 @@ void app_main(void) .v_res = CONFIG_EXAMPLE_CAM_VRES, .input_data_color_type = CAM_CTLR_COLOR_RGB565, .dma_burst_size = 128, - .pin_dont_init = false, .pin = &pin_cfg, .bk_buffer_dis = 1, + .xclk_freq = EXAMPLE_DVP_CAM_XCLK_FREQ_HZ, }; ret = esp_cam_new_dvp_ctlr(&dvp_config, &cam_handle); From b173783d921698db7375201e952955acb1bb3a59 Mon Sep 17 00:00:00 2001 From: gaoxu Date: Mon, 2 Jun 2025 15:57:50 +0800 Subject: [PATCH 5/5] docs(camera): add lcd_cam dvp driver docs for camera --- .../peripherals/camera_driver.rst | 55 ++++++++++++++++++- .../peripherals/camera_driver.rst | 55 ++++++++++++++++++- 2 files changed, 106 insertions(+), 4 deletions(-) diff --git a/docs/en/api-reference/peripherals/camera_driver.rst b/docs/en/api-reference/peripherals/camera_driver.rst index adc47fd05e..3d34c21cef 100644 --- a/docs/en/api-reference/peripherals/camera_driver.rst +++ b/docs/en/api-reference/peripherals/camera_driver.rst @@ -10,8 +10,9 @@ Introduction .. list:: - : SOC_MIPI_CSI_SUPPORTED : - MIPI Camera Serial Interface (CSI) - : SOC_ISP_DVP_SUPPORTED : - ISP Digital Video Port (ISP DVP) + : SOC_MIPI_CSI_SUPPORTED : - MIPI Camera Serial Interface (MIPI CSI) + : SOC_ISP_DVP_SUPPORTED : - Digital Video Port through ISP module (ISP DVP) + : SOC_LCDCAM_CAM_SUPPORTED : - Digital Video Port through LCD_CAM module(LCD_CAM DVP) The camera controller driver is designed for this hardware peripheral. @@ -38,6 +39,14 @@ Resource Allocation Install Camera Controller Driver ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Camera controller driver can be implemented in one of following ways: + +.. list:: + + : SOC_MIPI_CSI_SUPPORTED : - :cpp:func:`esp_cam_new_csi_ctlr` + : SOC_ISP_DVP_SUPPORTED : - :cpp:func:`esp_cam_new_isp_dvp_ctlr` + : SOC_LCDCAM_CAM_SUPPORTED : - :cpp:func:`esp_cam_new_lcd_cam_ctlr` + .. only:: SOC_MIPI_CSI_SUPPORTED A camera controller driver can be implemented by the CSI peripheral, which requires the configuration that specified by :cpp:type:`esp_cam_ctlr_csi_config_t`. @@ -95,6 +104,48 @@ Install Camera Controller Driver }; ESP_ERROR_CHECK(esp_cam_new_isp_dvp_ctlr(isp_proc, &dvp_ctlr_config, &cam_handle)); +.. only:: SOC_LCDCAM_CAM_SUPPORTED + + A camera controller driver can be implemented by the DVP port of LCD_CAM, which requires the configuration that specified by :cpp:type:`esp_cam_ctlr_dvp_config_t`. + + :cpp:member:`esp_cam_ctlr_dvp_config_t::exexternal_xtal`: set this to use externally generated xclk, otherwise the camera driver will generate it internally. + + If :cpp:type:`esp_cam_ctlr_lcd_cam_cfg_t` is specified, users can call :cpp:func:`esp_cam_new_lcd_cam_ctlr` to allocate and initialize a DVP camera controller handle. This function will return an DVP camera controller handle if it runs correctly. You can take following code as reference. + + .. code:: c + + esp_cam_ctlr_handle_t cam_handle = NULL; + esp_cam_ctlr_dvp_pin_config_t pin_cfg = { + .data_width = EXAMPLE_DVP_CAM_DATA_WIDTH, + .data_io = { + EXAMPLE_DVP_CAM_D0_IO, + EXAMPLE_DVP_CAM_D1_IO, + EXAMPLE_DVP_CAM_D2_IO, + EXAMPLE_DVP_CAM_D3_IO, + EXAMPLE_DVP_CAM_D4_IO, + EXAMPLE_DVP_CAM_D5_IO, + EXAMPLE_DVP_CAM_D6_IO, + EXAMPLE_DVP_CAM_D7_IO, + }, + .vsync_io = EXAMPLE_DVP_CAM_VSYNC_IO, + .de_io = EXAMPLE_DVP_CAM_DE_IO, + .pclk_io = EXAMPLE_DVP_CAM_PCLK_IO, + .xclk_io = EXAMPLE_DVP_CAM_XCLK_IO, // Set XCLK pin to generate XCLK signal + }; + esp_cam_ctlr_dvp_config_t dvp_config = { + .ctlr_id = 0, + .clk_src = CAM_CLK_SRC_DEFAULT, + .h_res = CONFIG_EXAMPLE_CAM_HRES, + .v_res = CONFIG_EXAMPLE_CAM_VRES, + .input_data_color_type = CAM_CTLR_COLOR_RGB565, + .dma_burst_size = 128, + .pin = &pin_cfg, + .bk_buffer_dis = 1, + .xclk_freq = EXAMPLE_DVP_CAM_XCLK_FREQ_HZ, + }; + + ESP_ERROR_CHECK(esp_cam_new_dvp_ctlr(&dvp_config, &cam_handle)); + Uninstall Camera Controller Driver ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/zh_CN/api-reference/peripherals/camera_driver.rst b/docs/zh_CN/api-reference/peripherals/camera_driver.rst index 4ac1866073..82484235fe 100644 --- a/docs/zh_CN/api-reference/peripherals/camera_driver.rst +++ b/docs/zh_CN/api-reference/peripherals/camera_driver.rst @@ -10,8 +10,9 @@ .. list:: - : SOC_MIPI_CSI_SUPPORTED : - MIPI 摄像头串行接口 (CSI) - : SOC_ISP_DVP_SUPPORTED : - ISP 数字视频端口 (ISP DVP) + : SOC_MIPI_CSI_SUPPORTED : - MIPI 摄像头串行接口 (MIPI CSI) + : SOC_ISP_DVP_SUPPORTED : - ISP的DVP端口 (ISP DVP) + : SOC_LCDCAM_CAM_SUPPORTED : - LCD_CAM的DVP端口 (LCD_CAM DVP) 摄像头控制器驱动程序是为上述硬件外设而设计的。 @@ -38,6 +39,14 @@ 安装摄像头控制器驱动程序 ~~~~~~~~~~~~~~~~~~~~~~~~ +摄像头控制器驱动程序可以通过以下方式之一安装: + +.. list:: + + : SOC_MIPI_CSI_SUPPORTED : - :cpp:func:`esp_cam_new_csi_ctlr` + : SOC_ISP_DVP_SUPPORTED : - :cpp:func:`esp_cam_new_isp_dvp_ctlr` + : SOC_LCDCAM_CAM_SUPPORTED : - :cpp:func:`esp_cam_new_lcd_cam_ctlr` + .. only:: SOC_MIPI_CSI_SUPPORTED 摄像头控制器驱动程序可以通过 CSI 外设实现,需要应用 :cpp:type:`esp_cam_ctlr_csi_config_t` 指定的配置。 @@ -95,6 +104,48 @@ }; ESP_ERROR_CHECK(esp_cam_new_isp_dvp_ctlr(isp_proc, &dvp_ctlr_config, &cam_handle)); +.. only:: SOC_LCDCAM_CAM_SUPPORTED + + 摄像头控制器驱动程序可以通过 LCD_CAM外设实现,需要应用 :cpp:type:`esp_cam_ctlr_dvp_config_t` 和 :cpp:type:`esp_cam_ctlr_dvp_pin_config_t` 指定的配置。 + + :cpp:member:`esp_cam_ctlr_dvp_config_t::exexternal_xtal`:使用外部生成的 xclk,或者使用驱动内部内部生成的 xclk。 + + 如果指定了 :cpp:type:`esp_cam_ctlr_dvp_config_t` 中的配置,就可以调用 :cpp:func:`esp_cam_new_dvp_ctlr` 来分配和初始化 DVP 摄像头控制器句柄。如果函数运行正确,将返回一个 DVP 摄像头控制器句柄。请参考以下代码。 + + .. code:: c + + esp_cam_ctlr_handle_t cam_handle = NULL; + esp_cam_ctlr_dvp_pin_config_t pin_cfg = { + .data_width = EXAMPLE_DVP_CAM_DATA_WIDTH, + .data_io = { + EXAMPLE_DVP_CAM_D0_IO, + EXAMPLE_DVP_CAM_D1_IO, + EXAMPLE_DVP_CAM_D2_IO, + EXAMPLE_DVP_CAM_D3_IO, + EXAMPLE_DVP_CAM_D4_IO, + EXAMPLE_DVP_CAM_D5_IO, + EXAMPLE_DVP_CAM_D6_IO, + EXAMPLE_DVP_CAM_D7_IO, + }, + .vsync_io = EXAMPLE_DVP_CAM_VSYNC_IO, + .de_io = EXAMPLE_DVP_CAM_DE_IO, + .pclk_io = EXAMPLE_DVP_CAM_PCLK_IO, + .xclk_io = EXAMPLE_DVP_CAM_XCLK_IO, // Set XCLK pin to generate XCLK signal + }; + esp_cam_ctlr_dvp_config_t dvp_config = { + .ctlr_id = 0, + .clk_src = CAM_CLK_SRC_DEFAULT, + .h_res = CONFIG_EXAMPLE_CAM_HRES, + .v_res = CONFIG_EXAMPLE_CAM_VRES, + .input_data_color_type = CAM_CTLR_COLOR_RGB565, + .dma_burst_size = 128, + .pin = &pin_cfg, + .bk_buffer_dis = 1, + .xclk_freq = EXAMPLE_DVP_CAM_XCLK_FREQ_HZ, + }; + + ESP_ERROR_CHECK(esp_cam_new_dvp_ctlr(&dvp_config, &cam_handle)); + 卸载摄像头控制器驱动程序 ~~~~~~~~~~~~~~~~~~~~~~~~