Merge branch 'feat/csi_dsi_example_v5.3' into 'release/v5.3'

example: csi dsi example and isp af dsi example(v5.3)

See merge request espressif/esp-idf!30913
This commit is contained in:
morris 2024-05-20 11:12:30 +08:00
commit 19ab395364
28 changed files with 1199 additions and 16 deletions

View File

@ -300,6 +300,7 @@ static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_
bool need_yield = false;
BaseType_t high_task_woken = pdFALSE;
csi_controller_t *ctlr = (csi_controller_t *)user_data;
bool has_new_trans = false;
bool use_backup = false;
dw_gdma_block_transfer_config_t csi_dma_transfer_config = {};
@ -328,12 +329,14 @@ static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_
use_backup = true;
} else {
csi_dma_transfer_config.dst.addr = (uint32_t)(new_trans.buffer);
has_new_trans = true;
}
} else if (xQueueReceiveFromISR(ctlr->trans_que, &new_trans, &high_task_woken) == pdTRUE) {
if (!(new_trans.buffer) || new_trans.buflen < ctlr->fb_size_in_bytes) {
use_backup = true;
} else {
csi_dma_transfer_config.dst.addr = (uint32_t)(new_trans.buffer);
has_new_trans = true;
}
} else if (!ctlr->bk_buffer_dis) {
use_backup = true;
@ -344,7 +347,9 @@ static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_
new_trans.buflen = ctlr->fb_size_in_bytes;
ESP_EARLY_LOGD(TAG, "no new buffer or no long enough new buffer, use driver internal buffer");
csi_dma_transfer_config.dst.addr = (uint32_t)ctlr->backup_buffer;
} else {
}
if (!has_new_trans) {
assert(false && "no new buffer, and no driver internal buffer");
}

View File

@ -9,4 +9,5 @@ endif()
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${public_include}
PRIV_REQUIRES esp_driver_gpio
)

View File

@ -241,6 +241,10 @@ esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctrlr_t af_ctrlr, const
isp_ll_af_env_monitor_set_period(af_ctrlr->isp_proc->hal.hw, 0);
isp_ll_clear_intr(af_ctrlr->isp_proc->hal.hw, ISP_LL_EVENT_AF_ENV);
isp_ll_af_env_monitor_set_mode(af_ctrlr->isp_proc->hal.hw, ISP_LL_AF_ENV_MONITOR_MODE_ABS);
isp_ll_af_env_monitor_set_period(af_ctrlr->isp_proc->hal.hw, af_ctrlr->config.interval);
isp_ll_enable_intr(af_ctrlr->isp_proc->hal.hw, ISP_LL_EVENT_AF_ENV, true);
return ESP_OK;
}
@ -267,7 +271,7 @@ esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_ctrlr_t af_ctr
return ESP_OK;
}
esp_err_t esp_isp_af_env_detector_set_threshold(isp_af_ctrlr_t af_ctrlr, int definition_thresh, int luminance_thresh)
esp_err_t esp_isp_af_controller_set_env_detector_threshold(isp_af_ctrlr_t af_ctrlr, int definition_thresh, int luminance_thresh)
{
ESP_RETURN_ON_FALSE_ISR(af_ctrlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "detector isn't in enable state");

View File

@ -24,6 +24,13 @@ examples/peripherals/analog_comparator:
- esp_driver_gpio
- esp_driver_ana_cmpr
examples/peripherals/camera/camera_dsi:
disable:
- if: SOC_MIPI_CSI_SUPPORTED != 1 or SOC_MIPI_DSI_SUPPORTED != 1
depends_components:
- esp_lcd
- esp_driver_cam
examples/peripherals/dac:
disable:
- if: SOC_DAC_SUPPORTED != 1
@ -118,11 +125,11 @@ examples/peripherals/i2s/i2s_recorder:
examples/peripherals/isp/auto_focus:
disable:
- if: INCLUDE_DEFAULT == 1
temporary: true
reason: disable build temporarily # TODO: IDF-8895
- if: SOC_MIPI_CSI_SUPPORTED != 1 or SOC_MIPI_DSI_SUPPORTED != 1 or SOC_ISP_SUPPORTED != 1
depends_components:
- esp_driver_isp
- esp_driver_cam
- esp_lcd
examples/peripherals/jpeg/jpeg_decode:
disable:

View File

@ -0,0 +1,6 @@
# 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)
project(camera_dsi)

View File

@ -0,0 +1,139 @@
| Supported Targets | ESP32-P4 |
| ----------------- | -------- |
# Camera display via DSI example
## Overview
This example demonstrates how to use the esp_driver_cam component to capture camera sensor signals 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
This example requires:
- OV5647 camera sensor
- ILI9881C LCD screen
- ESP32P4 devkit
GND GND
┌────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────┐
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ ┌───────────────┴─────────────┴──────────────────┐ │
│ │ │ ┌──────────┴───────────┐
│ │ │ DSI DATA 1P │ │
│ │ ├───────────────────────────┤ │
┌───────────┴─────────┐ CSI DATA 1P │ │ │ │
│ ├──────────────────────┤ │ DSI DATA 1N │ │
│ │ │ ├───────────────────────────┤ │
│ │ CSI DATA 1N │ ESP32-P4 │ │ │
│ OV5647 ├──────────────────────┤ │ DSI CLK N │ ILI9881C │
│ │ │ ├───────────────────────────┤ │
│ │ CSI CLK N │ │ │ │
│ ├──────────────────────┤ │ DSI CLK P │ │
│ │ │ ├───────────────────────────┤ │
│ │ CSI CLK P │ │ │ │
│ ├──────────────────────┤ │ DSI DATA 0P │ │
│ │ │ ├───────────────────────────┤ │
│ │ CSI DATA 0P │ │ │ │
│ ├──────────────────────┤ │ DSI DATA 0N │ │
│ │ │ ├───────────────────────────┤ │
│ │ CSI DATA 0N │ │ │ │
│ ├──────────────────────┤ │ └──────────────────────┘
│ │ │ │
└───────┬──┬──────────┘ │ │
│ │ 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_OV5647 to y
```
### 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 (1085) main_task: Calling app_main()
I (1095) ili9881c: ID1: 0x98, ID2: 0x81, ID3: 0x5c
I (1125) gpio: GPIO[31]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
I (1125) gpio: GPIO[34]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
I (1295) ov5647: Detected Camera sensor PID=0x5647 with index 0
I (1305) cam_dsi: fmt[0].name:MIPI_2lane_24Minput_RAW8_800x1280_50fps
I (1305) cam_dsi: fmt[1].name:MIPI_2lane_24Minput_RAW8_800x640_50fps
I (1315) cam_dsi: fmt[2].name:MIPI_2lane_24Minput_RAW8_800x800_50fps
I (1355) cam_dsi: Format in use:MIPI_2lane_24Minput_RAW8_800x640_50fps
```
## 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 "camera_dsi_main.c"
INCLUDE_DIRS "."
REQUIRES esp_mm esp_driver_isp esp_driver_cam esp_driver_i2c esp_lcd dsi_init
)

View File

@ -0,0 +1,41 @@
menu "Example Configuration"
config EXAMPLE_USED_LDO_CHAN_ID
int "example used LDO channel ID"
default 3
help
Example used LDO channel ID, you may check datasheet to know more details.
config EXAMPLE_USED_LDO_VOLTAGE_MV
int "example used LDO voltage in mV"
default 2500
range 0 3300
help
Example used LDO voltage, in mV
choice EXAMPLE_MIPI_CSI_DISP_HRES
bool "Set MIPI CSI horizontal resolution"
default EXAMPLE_MIPI_CSI_HRES_800
config EXAMPLE_MIPI_CSI_HRES_800
bool "800"
endchoice
config EXAMPLE_MIPI_CSI_DISP_HRES
int
default 800 if EXAMPLE_MIPI_CSI_HRES_800
choice EXAMPLE_MIPI_CSI_DISP_VRES
bool "Set MIPI CSI vertical resolution"
default EXAMPLE_MIPI_CSI_VRES_640
config EXAMPLE_MIPI_CSI_VRES_640
bool "640"
config EXAMPLE_MIPI_CSI_VRES_1280
bool "1280"
endchoice
config EXAMPLE_MIPI_CSI_DISP_VRES
int
default 640 if EXAMPLE_MIPI_CSI_VRES_640
default 1280 if EXAMPLE_MIPI_CSI_VRES_1280
endmenu

View File

@ -0,0 +1,212 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.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_lcd_ili9881c.h"
#include "esp_ldo_regulator.h"
#include "esp_cache.h"
#include "driver/i2c_master.h"
#include "driver/isp.h"
#include "esp_cam_ctlr_csi.h"
#include "esp_cam_ctlr.h"
#include "esp_sccb_intf.h"
#include "esp_sccb_i2c.h"
#include "esp_cam_sensor.h"
#include "ov5647.h"
#include "example_dsi_init.h"
#include "example_config.h"
static const char *TAG = "cam_dsi";
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);
void app_main(void)
{
esp_err_t ret = ESP_FAIL;
esp_lcd_panel_handle_t ili9881c_ctrl_panel = 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));
/**
* @background
* Sensor use RAW8
* ISP convert to RGB565
*/
//---------------DSI Init------------------//
example_dsi_resource_alloc(&ili9881c_ctrl_panel, &mipi_dpi_panel, &frame_buffer);
//---------------Necessary variable config------------------//
frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * EXAMPLE_MIPI_DSI_IMAGE_VSIZE * EXAMPLE_RGB565_BITS_PER_PIXEL / 8;
ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES: %d, EXAMPLE_MIPI_DSI_IMAGE_VSIZE: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, EXAMPLE_MIPI_DSI_IMAGE_VSIZE, 8);
ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size);
ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer);
esp_cam_ctlr_trans_t new_trans = {
.buffer = frame_buffer,
.buflen = frame_buffer_size,
};
//---------------I2C Init------------------//
i2c_master_bus_config_t i2c_bus_conf = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.sda_io_num = EXAMPLE_MIPI_SCCB_SDA_IO,
.scl_io_num = EXAMPLE_MIPI_SCCB_SCL_IO,
.i2c_port = I2C_NUM_0,
.flags.enable_internal_pullup = true,
};
i2c_master_bus_handle_t bus_handle = NULL;
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_conf, &bus_handle));
//---------------SCCB Init------------------//
esp_sccb_io_handle_t ov5647_io_handle = NULL;
sccb_i2c_config_t i2c_config = {
.scl_speed_hz = EXAMPLE_MIPI_SCCB_FREQ,
.device_address = EXAMPLE_OV5647_DEV_ADDR,
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
};
ESP_ERROR_CHECK(sccb_new_i2c_io(bus_handle, &i2c_config, &ov5647_io_handle));
//---------------CSI Init------------------//
esp_cam_ctlr_csi_config_t csi_config = {
.ctlr_id = 0,
.h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES,
.v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES,
.lane_bit_rate_mbps = EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS,
.input_data_color_type = MIPI_CSI_COLOR_RAW8,
.output_data_color_type = MIPI_CSI_COLOR_RGB565,
.data_lane_num = 2,
.byte_swap_en = false,
.queue_items = 1,
};
esp_cam_ctlr_handle_t cam_handle = NULL;
ret = esp_cam_new_csi_ctlr(&csi_config, &cam_handle);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "csi init fail[%d]", ret);
return;
}
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, &new_trans) != ESP_OK) {
ESP_LOGE(TAG, "ops register fail");
return;
}
ESP_ERROR_CHECK(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 = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES,
.v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES,
};
ESP_ERROR_CHECK(esp_isp_new_processor(&isp_config, &isp_proc));
ESP_ERROR_CHECK(esp_isp_enable(isp_proc));
//---------------DSI Panel Init------------------//
example_dsi_ili9881c_panel_init(ili9881c_ctrl_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);
if (esp_cam_ctlr_start(cam_handle) != ESP_OK) {
ESP_LOGE(TAG, "Driver start fail");
return;
}
esp_cam_sensor_config_t cam_config = {
.sccb_handle = ov5647_io_handle,
.reset_pin = -1,
.pwdn_pin = -1,
.xclk_pin = -1,
.sensor_port = ESP_CAM_SENSOR_MIPI_CSI,
};
esp_cam_sensor_device_t *cam = ov5647_detect(&cam_config);
if (!cam) {
ESP_LOGE(TAG, "failed to detect 5647");
return;
}
esp_cam_sensor_format_array_t cam_fmt_array = {0};
esp_cam_sensor_query_format(cam, &cam_fmt_array);
const esp_cam_sensor_format_t *parray = cam_fmt_array.format_array;
for (int i = 0; i < cam_fmt_array.count; i++) {
ESP_LOGI(TAG, "fmt[%d].name:%s", i, parray[i].name);
}
esp_cam_sensor_format_t *cam_cur_fmt = NULL;
for (int i = 0; i < cam_fmt_array.count; i++) {
#if CONFIG_EXAMPLE_MIPI_CSI_VRES_640
if (!strcmp(parray[i].name, "MIPI_2lane_24Minput_RAW8_800x640_50fps")) {
cam_cur_fmt = (esp_cam_sensor_format_t *) & (parray[i].name);
}
#else
if (!strcmp(parray[i].name, "MIPI_2lane_24Minput_RAW8_800x1280_50fps")) {
cam_cur_fmt = (esp_cam_sensor_format_t *) & (parray[i].name);
}
#endif
}
ret = esp_cam_sensor_set_format(cam, (const esp_cam_sensor_format_t *) cam_cur_fmt);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Format set fail");
} else {
ESP_LOGI(TAG, "Format in use:%s", cam_cur_fmt->name);
}
int enable_flag = 1;
// Set sensor output stream
ret = esp_cam_sensor_ioctl(cam, ESP_CAM_SENSOR_IOC_S_STREAM, &enable_flag);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Start stream fail");
}
example_dpi_panel_init(mipi_dpi_panel);
while (1) {
ESP_ERROR_CHECK(esp_cam_ctlr_receive(cam_handle, &new_trans, ESP_CAM_CTLR_MAX_DELAY));
}
}
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 new_trans = *(esp_cam_ctlr_trans_t *)user_data;
trans->buffer = new_trans.buffer;
trans->buflen = new_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,23 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#define EXAMPLE_RGB565_BITS_PER_PIXEL 16
#define EXAMPLE_MIPI_SCCB_FREQ (100000)
#define EXAMPLE_MIPI_SCCB_SCL_IO (8)
#define EXAMPLE_MIPI_SCCB_SDA_IO (7)
#define EXAMPLE_MIPI_IDI_CLOCK_RATE (50000000)
#define EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS 200 //line_rate = pclk * 4
#define EXAMPLE_OV5647_DEV_ADDR 0x36
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,7 @@
dependencies:
espressif/esp_cam_sensor: "^0.2.2"
espressif/esp_lcd_ili9881c: "*"
idf:
version: ">=5.3.0"
dsi_init:
path: ${IDF_PATH}/examples/peripherals/camera/components/dsi_init

View File

@ -0,0 +1,10 @@
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32p4
@pytest.mark.generic
def test_camera_dsi(dut: Dut) -> None:
dut.expect_exact('Calling app_main()')

View File

@ -0,0 +1,4 @@
CONFIG_SPIRAM=y
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
CONFIG_SPIRAM_SPEED_200M=y
CONFIG_CAMERA_OV5647=y

View File

@ -0,0 +1,4 @@
idf_component_register(SRCS "example_dsi_init.c"
INCLUDE_DIRS "."
REQUIRES esp_lcd
)

View File

@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include "esp_log.h"
#include "esp_lcd_mipi_dsi.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_ili9881c.h"
#include "example_dsi_init.h"
void example_dsi_resource_alloc(esp_lcd_panel_handle_t *ili9881c_ctrl_panel, esp_lcd_panel_handle_t *mipi_dpi_panel, void **frame_buffer)
{
esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL;
esp_lcd_panel_io_handle_t mipi_dbi_io = NULL;
//---------------DSI resource allocation------------------//
esp_lcd_dsi_bus_config_t bus_config = {
.bus_id = 0,
.num_data_lanes = 2,
.phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT,
.lane_bit_rate_mbps = 1000, // 1000 Mbps
};
ESP_ERROR_CHECK(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus));
esp_lcd_dbi_io_config_t dbi_config = {
.virtual_channel = 0,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
};
ESP_ERROR_CHECK(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &mipi_dbi_io));
esp_lcd_panel_dev_config_t lcd_dev_config = {
.bits_per_pixel = 16,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.reset_gpio_num = -1,
};
ESP_ERROR_CHECK(esp_lcd_new_panel_ili9881c(mipi_dbi_io, &lcd_dev_config, ili9881c_ctrl_panel));
esp_lcd_dpi_panel_config_t dpi_config = {
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
.dpi_clock_freq_mhz = 80,
.virtual_channel = 0,
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
.video_timing = {
.h_size = EXAMPLE_MIPI_DSI_IMAGE_HSIZE,
.v_size = EXAMPLE_MIPI_DSI_IMAGE_VSIZE,
.hsync_back_porch = EXAMPLE_MIPI_DSI_IMAGE_HBP,
.hsync_pulse_width = EXAMPLE_MIPI_DSI_IMAGE_HSYNC,
.hsync_front_porch = EXAMPLE_MIPI_DSI_IMAGE_HFP,
.vsync_back_porch = EXAMPLE_MIPI_DSI_IMAGE_VBP,
.vsync_pulse_width = EXAMPLE_MIPI_DSI_IMAGE_VSYNC,
.vsync_front_porch = EXAMPLE_MIPI_DSI_IMAGE_VFP,
},
};
ESP_ERROR_CHECK(esp_lcd_new_panel_dpi(mipi_dsi_bus, &dpi_config, mipi_dpi_panel));
ESP_ERROR_CHECK(esp_lcd_dpi_panel_get_frame_buffer(*mipi_dpi_panel, 1, frame_buffer));
}
void example_dsi_ili9881c_panel_init(esp_lcd_panel_handle_t ili9881c_ctrl_panel)
{
//---------------DSI Panel Init------------------//
ESP_ERROR_CHECK(esp_lcd_panel_reset(ili9881c_ctrl_panel));
ESP_ERROR_CHECK(esp_lcd_panel_init(ili9881c_ctrl_panel));
// turn on display
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(ili9881c_ctrl_panel, true));
}
void example_dpi_panel_init(esp_lcd_panel_handle_t mipi_dpi_panel)
{
//---------------DPI Panel Init------------------//
ESP_ERROR_CHECK(esp_lcd_panel_init(mipi_dpi_panel));
}

View File

@ -0,0 +1,47 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#define EXAMPLE_MIPI_DSI_IMAGE_HSIZE 800
#define EXAMPLE_MIPI_DSI_IMAGE_VSIZE 1280
#define EXAMPLE_MIPI_DSI_IMAGE_HSYNC 40
#define EXAMPLE_MIPI_DSI_IMAGE_HBP 140
#define EXAMPLE_MIPI_DSI_IMAGE_HFP 40
#define EXAMPLE_MIPI_DSI_IMAGE_VSYNC 4
#define EXAMPLE_MIPI_DSI_IMAGE_VBP 16
#define EXAMPLE_MIPI_DSI_IMAGE_VFP 16
/**
* @brief DSI init function
*
* @param[out] ili9881c_ctrl_panel ILI9881C panel handle
* @param[out] mipi_dpi_panel MIPI DPI panel handle
* @param[out] frame_buffer frame buffer
*/
void example_dsi_resource_alloc(esp_lcd_panel_handle_t *ili9881c_ctrl_panel, esp_lcd_panel_handle_t *mipi_dpi_panel, void **frame_buffer);
/**
* @brief DSI ILI9881C panel init function
*
* @param[in] ili9881c_ctrl_panel ILI9881C panel handle
*/
void example_dsi_ili9881c_panel_init(esp_lcd_panel_handle_t ili9881c_ctrl_panel);
/**
* @brief DPI panel init function
*
* @param[in] mipi_dpi_panel MIPI DPI panel handle
*/
void example_dpi_panel_init(esp_lcd_panel_handle_t mipi_dpi_panel);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,4 @@
dependencies:
espressif/esp_lcd_ili9881c: "^0.2.0"
idf:
version: ">=5.3.0"

View File

@ -0,0 +1,6 @@
# 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)
project(isp_af_dsi)

View File

@ -0,0 +1,141 @@
| Supported Targets | ESP32-P4 |
| ----------------- | -------- |
# Camera display via DSI example
## Overview
This example demonstrates how to use the ISP (image signal processor) to work with esp_driver_cam component. This example will capture camera sensor signals via CSI interface and display it via DSI interface. This example also enables the ISP AF (auto-focus) feature.
## 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
This example requires:
- OV5647 camera sensor with VCM (Voice Coil Motor). The VCM used in this example is DW9714.
- ILI9881C LCD screen
- ESP32P4 devkit
GND GND
┌────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────┐
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ ┌───────────────┴─────────────┴──────────────────┐ │
│ │ │ ┌──────────┴───────────┐
│ │ │ DSI DATA 1P │ │
│ │ ├───────────────────────────┤ │
┌───────────┴─────────┐ CSI DATA 1P │ │ │ │
│ ├──────────────────────┤ │ DSI DATA 1N │ │
│ │ │ ├───────────────────────────┤ │
│ │ CSI DATA 1N │ ESP32-P4 │ │ │
│ OV5647 ├──────────────────────┤ │ DSI CLK N │ ILI9881C │
│ │ │ ├───────────────────────────┤ │
│ │ CSI CLK N │ │ │ │
│ ├──────────────────────┤ │ DSI CLK P │ │
│ │ │ ├───────────────────────────┤ │
│ │ CSI CLK P │ │ │ │
│ ├──────────────────────┤ │ DSI DATA 0P │ │
│ │ │ ├───────────────────────────┤ │
│ │ CSI DATA 0P │ │ │ │
│ ├──────────────────────┤ │ DSI DATA 0N │ │
│ │ │ ├───────────────────────────┤ │
│ │ CSI DATA 0N │ │ │ │
│ ├──────────────────────┤ │ └──────────────────────┘
│ │ │ │
└───────┬──┬──────────┘ │ │
│ │ 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_OV5647 to y
```
### 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 (1085) main_task: Calling app_main()
I (1095) ili9881c: ID1: 0x98, ID2: 0x81, ID3: 0x5c
I (1125) gpio: GPIO[31]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
I (1125) gpio: GPIO[34]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
I (1295) ov5647: Detected Camera sensor PID=0x5647 with index 0
I (1305) cam_dsi: fmt[0].name:MIPI_2lane_24Minput_RAW8_800x1280_50fps
I (1305) cam_dsi: fmt[1].name:MIPI_2lane_24Minput_RAW8_800x640_50fps
I (1315) cam_dsi: fmt[2].name:MIPI_2lane_24Minput_RAW8_800x800_50fps
I (1355) cam_dsi: Format in use:MIPI_2lane_24Minput_RAW8_800x640_50fps
```
You will also see the screen auto-focus when the screen image changes.
## Reference
- Link to the ESP-IDF camera controller driver API reference, [ESP-IDF: Camera Controller Driver](https://docs.espressif.com/projects/esp-idf/en/latest/esp32p4/api-reference/peripherals/camera_driver.html)
- Link to the ESP-IDF ISP driver API reference, [ESP-IDF: Image Signal Processor](https://docs.espressif.com/projects/esp-idf/en/latest/esp32p4/api-reference/peripherals/isp.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

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -33,8 +33,9 @@ typedef struct {
* @brief Sensor driver API to set sensor focus value
*
* @param[in] focus_val Camera sensor focus value
* @param[in] arg User arg
*/
esp_err_t (*af_sensor_set_focus)(int focus_val);
esp_err_t (*af_sensor_set_focus)(int focus_val, void *arg);
} isp_af_sa_scheme_sensor_drv_t;
@ -72,13 +73,14 @@ esp_err_t isp_af_delete_sa_scheme(isp_af_scheme_handle_t scheme);
* @param[in] scheme AF scheme handle
* @param[in] sensor_drv Sensor driver, see `isp_af_sa_scheme_sensor_drv_t`
* @param[in] info Sensor info
* @param[in] arg User arg
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid
* - ESP_ERR_INVALID_STATE Invalid state
*/
esp_err_t isp_af_sa_scheme_register_sensor_driver(isp_af_scheme_handle_t scheme, const isp_af_sa_scheme_sensor_drv_t *sensor_drv, const isp_af_sa_scheme_sensor_info_t *info);
esp_err_t isp_af_sa_scheme_register_sensor_driver(isp_af_scheme_handle_t scheme, const isp_af_sa_scheme_sensor_drv_t *sensor_drv, const isp_af_sa_scheme_sensor_info_t *info, void *arg);
#ifdef __cplusplus
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -29,6 +29,7 @@ typedef struct {
isp_af_sa_scheme_sensor_info_t sensor_info;
isp_af_sa_scheme_sensor_drv_t sensor_drv;
void *arg;
} af_scheme_context_t;
/* ------------------------ Interface Functions --------------------------- */
@ -78,7 +79,7 @@ esp_err_t isp_af_delete_sa_scheme(isp_af_scheme_handle_t scheme)
return ESP_OK;
}
esp_err_t isp_af_sa_scheme_register_sensor_driver(isp_af_scheme_handle_t scheme, const isp_af_sa_scheme_sensor_drv_t *sensor_drv, const isp_af_sa_scheme_sensor_info_t *info)
esp_err_t isp_af_sa_scheme_register_sensor_driver(isp_af_scheme_handle_t scheme, const isp_af_sa_scheme_sensor_drv_t *sensor_drv, const isp_af_sa_scheme_sensor_info_t *info, void *arg)
{
ESP_RETURN_ON_FALSE(scheme, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer");
ESP_RETURN_ON_FALSE(scheme->ctx, ESP_ERR_INVALID_STATE, TAG, "no scheme created yet");
@ -86,6 +87,7 @@ esp_err_t isp_af_sa_scheme_register_sensor_driver(isp_af_scheme_handle_t scheme,
af_scheme_context_t *ctx = scheme->ctx;
ctx->sensor_drv.af_sensor_set_focus = sensor_drv->af_sensor_set_focus;
ctx->sensor_info.focus_val_max = info->focus_val_max;
ctx->arg = arg;
return ESP_OK;
}
@ -117,7 +119,7 @@ static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_lu
isp_af_result_t result = {};
ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(0), TAG, "sensor set focus val fail");
ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(0, ctx->arg), TAG, "sensor set focus val fail");
ESP_LOGV(TAG, "//----------- af start ----------//");
@ -128,7 +130,7 @@ static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_lu
for (int x = 0; x <= ctx->first_approx_cycles; x++) {
af_current = af_current_base + x * ctx->first_step_val;
ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(af_current), TAG, "sensor set focus val fail");
ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(af_current, ctx->arg), TAG, "sensor set focus val fail");
ESP_RETURN_ON_ERROR(esp_isp_af_controller_get_oneshot_result(ctx->af_ctlr, &result), TAG, "get AF result fail");
af_sum = result.definition[0] + result.definition[1] + result.definition[2];
if (af_sum > af_sum_max) {
@ -136,7 +138,7 @@ static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_lu
af_current_best = af_current;
}
ESP_LOGV(TAG, "af_sum: %"PRId32", af_current: %"PRId32".%"PRId32, af_sum, (int)af_current, (int)((int)(af_current * 1000) % 1000));
ESP_LOGV(TAG, "af_sum: %d, af_current: %d.%d", af_sum, (int)af_current, (int)((int)(af_current * 1000) % 1000));
}
// second search
@ -154,7 +156,7 @@ static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_lu
af_current = 0;
}
ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(af_current), TAG, "sensor set focus val fail");
ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(af_current, ctx->arg), TAG, "sensor set focus val fail");
ESP_RETURN_ON_ERROR(esp_isp_af_controller_get_oneshot_result(ctx->af_ctlr, &result), TAG, "get AF result fail");
af_sum = result.definition[0] + result.definition[1] + result.definition[2];
if (af_sum > af_sum_max) {
@ -167,7 +169,7 @@ static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_lu
// af done
ESP_LOGV(TAG, "//----------- af done ----------//");
ESP_LOGV(TAG, "af_sum_max: %d, af_current_best: %d.%d", af_sum_max, (int)af_current_best, (int)((int)(af_current_best * 1000) % 1000));
ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(af_current_best), TAG, "sensor set focus val fail");
ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(af_current_best, ctx->arg), TAG, "sensor set focus val fail");
// update env threshold
ESP_LOGV(TAG, "//------- update env threshold -------//");

View File

@ -0,0 +1,4 @@
idf_component_register(SRCS "isp_af_dsi_main.c"
INCLUDE_DIRS "."
REQUIRES esp_mm esp_driver_isp esp_driver_cam esp_driver_i2c esp_lcd dsi_init
)

View File

@ -0,0 +1,41 @@
menu "Example Configuration"
config EXAMPLE_USED_LDO_CHAN_ID
int "example used LDO channel ID"
default 3
help
Example used LDO channel ID, you may check datasheet to know more details.
config EXAMPLE_USED_LDO_VOLTAGE_MV
int "example used LDO voltage in mV"
default 2500
range 0 3300
help
Example used LDO voltage, in mV
choice EXAMPLE_MIPI_CSI_DISP_HRES
bool "Set MIPI CSI horizontal resolution"
default EXAMPLE_MIPI_CSI_HRES_800
config EXAMPLE_MIPI_CSI_HRES_800
bool "800"
endchoice
config EXAMPLE_MIPI_CSI_DISP_HRES
int
default 800 if EXAMPLE_MIPI_CSI_HRES_800
choice EXAMPLE_MIPI_CSI_DISP_VRES
bool "Set MIPI CSI vertical resolution"
default EXAMPLE_MIPI_CSI_VRES_640
config EXAMPLE_MIPI_CSI_VRES_640
bool "640"
config EXAMPLE_MIPI_CSI_VRES_1280
bool "1280"
endchoice
config EXAMPLE_MIPI_CSI_DISP_VRES
int
default 640 if EXAMPLE_MIPI_CSI_VRES_640
default 1280 if EXAMPLE_MIPI_CSI_VRES_1280
endmenu

View File

@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#define EXAMPLE_RGB565_BITS_PER_PIXEL 16
#define EXAMPLE_MIPI_SCCB_FREQ (100000)
#define EXAMPLE_MIPI_SCCB_SCL_IO (8)
#define EXAMPLE_MIPI_SCCB_SDA_IO (7)
#define EXAMPLE_MIPI_IDI_CLOCK_RATE (50000000)
#define EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS 200 //line_rate = pclk * 4
#define EXAMPLE_OV5647_DEV_ADDR 0x36
#define EXAMPLE_DW9714_DEV_ADDR 0xC
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,9 @@
dependencies:
espressif/esp_cam_sensor: "^0.2.2"
espressif/esp_lcd_ili9881c: "*"
idf:
version: ">=5.3.0"
isp_af_schemes:
path: ${IDF_PATH}/examples/peripherals/isp/auto_focus/components/isp_af_schemes
dsi_init:
path: ${IDF_PATH}/examples/peripherals/camera/components/dsi_init

View File

@ -0,0 +1,357 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "esp_log.h"
#include "esp_heap_caps.h"
#include "esp_lcd_mipi_dsi.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_ili9881c.h"
#include "esp_ldo_regulator.h"
#include "esp_cache.h"
#include "driver/i2c_master.h"
#include "driver/isp.h"
#include "isp_af_scheme_sa.h"
#include "esp_cam_ctlr_csi.h"
#include "esp_cam_ctlr.h"
#include "esp_sccb_intf.h"
#include "esp_sccb_i2c.h"
#include "esp_cam_sensor.h"
#include "ov5647.h"
#include "example_dsi_init.h"
#include "example_config.h"
static const char *TAG = "isp_dsi";
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);
typedef union {
struct {
uint16_t s : 4;
uint16_t d : 10;
uint16_t flag : 1;
uint16_t pd : 1;
};
struct {
uint16_t byte2 : 8;
uint16_t byte1 : 8;
};
uint16_t val;
} dw9714_reg_t;
static bool IRAM_ATTR s_env_change_cb(isp_af_ctrlr_t af_ctrlr, const esp_isp_af_env_detector_evt_data_t *edata, void *user_data)
{
BaseType_t mustYield = pdFALSE;
TaskHandle_t task_handle = (TaskHandle_t)user_data;
vTaskNotifyGiveFromISR(task_handle, &mustYield);
return (mustYield == pdTRUE);
}
static esp_err_t s_sensor_set_focus_val(int focus_val, void *arg)
{
esp_sccb_io_handle_t dw9714_io_handle = arg;
dw9714_reg_t reg = {0};
reg.d = (uint16_t)((focus_val / 120.0) * 1023.0);
uint8_t data[2] = {0};
data[0] = reg.byte1;
data[1] = reg.byte2;
uint16_t reg_addr = (data[0] << 8) + (data[1]);
uint8_t reg_val = 0;
esp_err_t ret = esp_sccb_transmit_reg_a16v8(dw9714_io_handle, reg_addr, reg_val);
if (ret != ESP_OK) {
printf("dw9714 esp_sccb_transmit_reg_a16v8 failed\n");
return ret;
}
return ESP_OK;
}
static void af_task(void *arg)
{
TaskHandle_t task_handle = xTaskGetCurrentTaskHandle();
typedef struct af_task_param_t {
isp_proc_handle_t isp_proc;
esp_sccb_io_handle_t dw9714_io_handle;
} af_task_param_t;
af_task_param_t af_task_param = *(af_task_param_t *)arg;
/**
* AF window, windows for ISP hardware to record the
* - lunimance
* - definition
* of the current windows
*/
esp_isp_af_config_t af_config = {
.window = {
[0] = {
.top_left_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) - 100,
.bottom_right_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) + 99,
.top_left_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) - 100,
.bottom_right_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) + 99,
},
[1] = {
.top_left_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) - 100,
.bottom_right_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) + 99,
.top_left_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) - 100,
.bottom_right_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) + 99,
},
[2] = {
.top_left_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) - 100,
.bottom_right_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) + 99,
.top_left_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) - 100,
.bottom_right_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) + 99,
},
},
.edge_thresh = 128,
};
isp_af_ctrlr_t af_ctrlr = NULL;
ESP_ERROR_CHECK(esp_isp_new_af_controller(af_task_param.isp_proc, &af_config, &af_ctrlr));
esp_isp_af_env_config_t env_config = {
.interval = 10,
};
ESP_ERROR_CHECK(esp_isp_af_controller_set_env_detector(af_ctrlr, &env_config));
esp_isp_af_env_detector_evt_cbs_t cbs = {
.on_env_change = s_env_change_cb,
};
ESP_ERROR_CHECK(esp_isp_af_env_detector_register_event_callbacks(af_ctrlr, &cbs, task_handle));
isp_af_sa_scheme_config_t af_scheme_config = {
.first_step_val = 12,
.first_approx_cycles = 10,
.second_step_val = 2,
.second_approx_cycles = 10,
};
isp_af_scheme_handle_t af_scheme = NULL;
ESP_ERROR_CHECK(isp_af_create_sa_scheme(af_ctrlr, &af_scheme_config, &af_scheme));
isp_af_sa_scheme_sensor_drv_t sensor_driver = {
.af_sensor_set_focus = s_sensor_set_focus_val,
};
isp_af_sa_scheme_sensor_info_t sensor_info = {
.focus_val_max = 120,
};
ESP_ERROR_CHECK(isp_af_sa_scheme_register_sensor_driver(af_scheme, &sensor_driver, &sensor_info, af_task_param.dw9714_io_handle));
int definition_thresh = 0;
int luminance_thresh = 0;
ESP_ERROR_CHECK(esp_isp_af_controller_enable(af_ctrlr));
while (1) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
ESP_ERROR_CHECK(isp_af_process(af_scheme, &definition_thresh, &luminance_thresh));
ESP_ERROR_CHECK(esp_isp_af_controller_set_env_detector_threshold(af_ctrlr, definition_thresh, luminance_thresh));
}
}
void app_main(void)
{
esp_err_t ret = ESP_FAIL;
esp_lcd_panel_handle_t ili9881c_ctrl_panel = 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));
/**
* @background
* Sensor use RAW8
* ISP convert to RGB565
*/
//---------------DSI Init------------------//
example_dsi_resource_alloc(&ili9881c_ctrl_panel, &mipi_dpi_panel, &frame_buffer);
//---------------Necessary variable config------------------//
frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * EXAMPLE_MIPI_DSI_IMAGE_VSIZE * EXAMPLE_RGB565_BITS_PER_PIXEL / 8;
ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES: %d, EXAMPLE_MIPI_DSI_IMAGE_VSIZE: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, EXAMPLE_MIPI_DSI_IMAGE_VSIZE, 8);
ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size);
ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer);
esp_cam_ctlr_trans_t new_trans = {
.buffer = frame_buffer,
.buflen = frame_buffer_size,
};
//---------------I2C Init------------------//
i2c_master_bus_config_t i2c_bus_conf = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.sda_io_num = EXAMPLE_MIPI_SCCB_SDA_IO,
.scl_io_num = EXAMPLE_MIPI_SCCB_SCL_IO,
.i2c_port = I2C_NUM_0,
.flags.enable_internal_pullup = true,
};
i2c_master_bus_handle_t bus_handle = NULL;
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_conf, &bus_handle));
//---------------SCCB Init------------------//
esp_sccb_io_handle_t ov5647_io_handle = NULL;
sccb_i2c_config_t i2c_config = {
.scl_speed_hz = EXAMPLE_MIPI_SCCB_FREQ,
.device_address = EXAMPLE_OV5647_DEV_ADDR,
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
};
ESP_ERROR_CHECK(sccb_new_i2c_io(bus_handle, &i2c_config, &ov5647_io_handle));
esp_sccb_io_handle_t dw9714_io_handle = NULL;
i2c_config.device_address = EXAMPLE_DW9714_DEV_ADDR;
ESP_ERROR_CHECK(sccb_new_i2c_io(bus_handle, &i2c_config, &dw9714_io_handle));
//---------------CSI Init------------------//
esp_cam_ctlr_csi_config_t csi_config = {
.ctlr_id = 0,
.h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES,
.v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES,
.lane_bit_rate_mbps = EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS,
.input_data_color_type = MIPI_CSI_COLOR_RAW8,
.output_data_color_type = MIPI_CSI_COLOR_RGB565,
.data_lane_num = 2,
.byte_swap_en = false,
.queue_items = 1,
};
esp_cam_ctlr_handle_t handle = NULL;
ret = esp_cam_new_csi_ctlr(&csi_config, &handle);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "csi init fail[%d]", ret);
return;
}
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(handle, &cbs, &new_trans) != ESP_OK) {
ESP_LOGE(TAG, "ops register fail");
return;
}
ESP_ERROR_CHECK(esp_cam_ctlr_enable(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 = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES,
.v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES,
};
ESP_ERROR_CHECK(esp_isp_new_processor(&isp_config, &isp_proc));
ESP_ERROR_CHECK(esp_isp_enable(isp_proc));
typedef struct af_task_param_t {
isp_proc_handle_t isp_proc;
esp_sccb_io_handle_t dw9714_io_handle;
} af_task_param_t;
af_task_param_t af_task_param = {
.isp_proc = isp_proc,
.dw9714_io_handle = dw9714_io_handle,
};
xTaskCreatePinnedToCore(af_task, "af_task", 8192, &af_task_param, 5, NULL, 0);
//---------------DSI Panel Init------------------//
example_dsi_ili9881c_panel_init(ili9881c_ctrl_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);
if (esp_cam_ctlr_start(handle) != ESP_OK) {
ESP_LOGE(TAG, "Driver start fail");
return;
}
esp_cam_sensor_config_t cam_config = {
.sccb_handle = ov5647_io_handle,
.reset_pin = -1,
.pwdn_pin = -1,
.xclk_pin = -1,
.sensor_port = ESP_CAM_SENSOR_MIPI_CSI,
};
esp_cam_sensor_device_t *cam = ov5647_detect(&cam_config);
if (!cam) {
ESP_LOGE(TAG, "failed to detect 5647");
return;
}
esp_cam_sensor_format_array_t cam_fmt_array = {0};
esp_cam_sensor_query_format(cam, &cam_fmt_array);
const esp_cam_sensor_format_t *parray = cam_fmt_array.format_array;
for (int i = 0; i < cam_fmt_array.count; i++) {
ESP_LOGI(TAG, "fmt[%d].name:%s", i, parray[i].name);
}
esp_cam_sensor_format_t *cam_cur_fmt = NULL;
for (int i = 0; i < cam_fmt_array.count; i++) {
#if CONFIG_EXAMPLE_MIPI_CSI_VRES_640
if (!strcmp(parray[i].name, "MIPI_2lane_24Minput_RAW8_800x640_50fps")) {
cam_cur_fmt = (esp_cam_sensor_format_t *) & (parray[i].name);
break;
}
#else
if (!strcmp(parray[i].name, "MIPI_2lane_24Minput_RAW8_800x1280_50fps")) {
cam_cur_fmt = (esp_cam_sensor_format_t *) & (parray[i].name);
break;
}
#endif
}
ret = esp_cam_sensor_set_format(cam, (const esp_cam_sensor_format_t *) cam_cur_fmt);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Format set fail");
} else {
ESP_LOGI(TAG, "Format in use:%s", cam_cur_fmt->name);
}
int enable_flag = 1;
// Set sensor output stream
ret = esp_cam_sensor_ioctl(cam, ESP_CAM_SENSOR_IOC_S_STREAM, &enable_flag);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Start stream fail");
}
example_dpi_panel_init(mipi_dpi_panel);
while (1) {
ESP_ERROR_CHECK(esp_cam_ctlr_receive(handle, &new_trans, ESP_CAM_CTLR_MAX_DELAY));
}
}
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 new_trans = *(esp_cam_ctlr_trans_t *)user_data;
trans->buffer = new_trans.buffer;
trans->buflen = new_trans.buflen;
return false;
}
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,4 @@
CONFIG_SPIRAM=y
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
CONFIG_SPIRAM_SPEED_200M=y
CONFIG_CAMERA_OV5647=y