feat(cam): add esp32p4 dvp example

This commit is contained in:
gaoxu
2025-06-02 12:51:32 +08:00
parent 449abbab76
commit 2a13a36589
11 changed files with 484 additions and 0 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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 <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)

View File

@@ -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
)

View File

@@ -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

View File

@@ -0,0 +1,184 @@
/*
* 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_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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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()')

View File

@@ -0,0 +1 @@
CONFIG_CAMERA_OV2640=y

View File

@@ -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