Merge branch 'feat/isp_dsi_example' into 'master'

example(isp): added isp af example

Closes IDF-9808

See merge request espressif/esp-idf!30469
This commit is contained in:
Armando (Dou Yiwen) 2024-05-17 15:17:35 +08:00
commit 895e6d5afc
22 changed files with 651 additions and 52 deletions

View File

@ -121,11 +121,11 @@ examples/peripherals/i2s/i2s_recorder:
examples/peripherals/isp/auto_focus: examples/peripherals/isp/auto_focus:
disable: disable:
- if: INCLUDE_DEFAULT == 1 - if: SOC_MIPI_CSI_SUPPORTED != 1 or SOC_MIPI_DSI_SUPPORTED != 1 or SOC_ISP_SUPPORTED != 1
temporary: true
reason: disable build temporarily # TODO: IDF-8895
depends_components: depends_components:
- esp_driver_isp - esp_driver_isp
- esp_driver_cam
- esp_lcd
examples/peripherals/jpeg/jpeg_decode: examples/peripherals/jpeg/jpeg_decode:
disable: disable:

View File

@ -17,7 +17,7 @@ The subsections below give only absolutely necessary information. For full steps
This example requires: This example requires:
- OV5647 camera sensor with VCM (Voice Coil Motor). The VCM used in this example is DW9714. - OV5647 camera sensor
- ILI9881C LCD screen - ILI9881C LCD screen
- ESP32P4 devkit - ESP32P4 devkit

View File

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

View File

@ -12,8 +12,20 @@ menu "Example Configuration"
help help
Example used LDO voltage, in mV Example used LDO voltage, in mV
choice EXAMPLE_MIPI_CSI_VRES choice EXAMPLE_MIPI_CSI_DISP_HRES
bool "Set MIPI CSI verticol resolution" 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 default EXAMPLE_MIPI_CSI_VRES_640
config EXAMPLE_MIPI_CSI_VRES_640 config EXAMPLE_MIPI_CSI_VRES_640
@ -22,4 +34,8 @@ menu "Example Configuration"
bool "1280" bool "1280"
endchoice 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 endmenu

View File

@ -55,9 +55,9 @@ void app_main(void)
example_dsi_resource_alloc(&ili9881c_ctrl_panel, &mipi_dpi_panel, &frame_buffer); example_dsi_resource_alloc(&ili9881c_ctrl_panel, &mipi_dpi_panel, &frame_buffer);
//---------------Necessary variable config------------------// //---------------Necessary variable config------------------//
frame_buffer_size = EXAMPLE_MIPI_CSI_DISP_HSIZE * EXAMPLE_MIPI_DSI_IMAGE_VSIZE * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * EXAMPLE_MIPI_DSI_IMAGE_VSIZE * EXAMPLE_RGB565_BITS_PER_PIXEL / 8;
ESP_LOGD(TAG, "EXAMPLE_MIPI_CSI_DISP_HSIZE: %d, EXAMPLE_MIPI_DSI_IMAGE_VSIZE: %d, bits per pixel: %d", EXAMPLE_MIPI_CSI_DISP_HSIZE, EXAMPLE_MIPI_DSI_IMAGE_VSIZE, 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_size: %zu", frame_buffer_size);
ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer); ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer);
@ -89,12 +89,8 @@ void app_main(void)
//---------------CSI Init------------------// //---------------CSI Init------------------//
esp_cam_ctlr_csi_config_t csi_config = { esp_cam_ctlr_csi_config_t csi_config = {
.ctlr_id = 0, .ctlr_id = 0,
.h_res = EXAMPLE_MIPI_CSI_DISP_HSIZE, .h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES,
#if CONFIG_EXAMPLE_MIPI_CSI_VRES_640 .v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES,
.v_res = EXAMPLE_MIPI_CSI_DISP_VSIZE_640P,
#else
.v_res = EXAMPLE_MIPI_CSI_DISP_VSIZE_1280P,
#endif
.lane_bit_rate_mbps = EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS, .lane_bit_rate_mbps = EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS,
.input_data_color_type = MIPI_CSI_COLOR_RAW8, .input_data_color_type = MIPI_CSI_COLOR_RAW8,
.output_data_color_type = MIPI_CSI_COLOR_RGB565, .output_data_color_type = MIPI_CSI_COLOR_RGB565,
@ -129,12 +125,8 @@ void app_main(void)
.output_data_color_type = ISP_COLOR_RGB565, .output_data_color_type = ISP_COLOR_RGB565,
.has_line_start_packet = false, .has_line_start_packet = false,
.has_line_end_packet = false, .has_line_end_packet = false,
.h_res = EXAMPLE_MIPI_CSI_DISP_HSIZE, .h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES,
#if CONFIG_EXAMPLE_MIPI_CSI_VRES_640 .v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES,
.v_res = EXAMPLE_MIPI_CSI_DISP_VSIZE_640P,
#else
.v_res = EXAMPLE_MIPI_CSI_DISP_VSIZE_1280P,
#endif
}; };
ESP_ERROR_CHECK(esp_isp_new_processor(&isp_config, &isp_proc)); ESP_ERROR_CHECK(esp_isp_new_processor(&isp_config, &isp_proc));
ESP_ERROR_CHECK(esp_isp_enable(isp_proc)); ESP_ERROR_CHECK(esp_isp_enable(isp_proc));
@ -174,7 +166,6 @@ void app_main(void)
esp_cam_sensor_format_t *cam_cur_fmt = NULL; esp_cam_sensor_format_t *cam_cur_fmt = NULL;
for (int i = 0; i < cam_fmt_array.count; i++) { for (int i = 0; i < cam_fmt_array.count; i++) {
#if CONFIG_EXAMPLE_MIPI_CSI_VRES_640 #if CONFIG_EXAMPLE_MIPI_CSI_VRES_640
if (!strcmp(parray[i].name, "MIPI_2lane_24Minput_RAW8_800x640_50fps")) { if (!strcmp(parray[i].name, "MIPI_2lane_24Minput_RAW8_800x640_50fps")) {
cam_cur_fmt = (esp_cam_sensor_format_t *) & (parray[i].name); cam_cur_fmt = (esp_cam_sensor_format_t *) & (parray[i].name);

View File

@ -12,24 +12,11 @@ extern "C" {
#define EXAMPLE_RGB565_BITS_PER_PIXEL 16 #define EXAMPLE_RGB565_BITS_PER_PIXEL 16
#define EXAMPLE_MIPI_SCCB_FREQ (100000) #define EXAMPLE_MIPI_SCCB_FREQ (100000)
#define EXAMPLE_MIPI_SCCB_SCL_IO (34) #define EXAMPLE_MIPI_SCCB_SCL_IO (8)
#define EXAMPLE_MIPI_SCCB_SDA_IO (31) #define EXAMPLE_MIPI_SCCB_SDA_IO (7)
#define EXAMPLE_MIPI_CSI_DISP_HSIZE 800
#define EXAMPLE_MIPI_CSI_DISP_VSIZE_640P 640
#define EXAMPLE_MIPI_CSI_DISP_VSIZE_1280P 1280
#define EXAMPLE_MIPI_CSI_640P 1
#define EXAMPLE_MIPI_IDI_CLOCK_RATE (50000000) #define EXAMPLE_MIPI_IDI_CLOCK_RATE (50000000)
#define EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS 200 //line_rate = pclk * 4 #define EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS 200 //line_rate = pclk * 4
#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
#define EXAMPLE_OV5647_DEV_ADDR 0x36 #define EXAMPLE_OV5647_DEV_ADDR 0x36
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -3,3 +3,5 @@ dependencies:
espressif/esp_lcd_ili9881c: "*" espressif/esp_lcd_ili9881c: "*"
idf: idf:
version: ">=5.3.0" version: ">=5.3.0"
dsi_init:
path: ${IDF_PATH}/examples/peripherals/camera/components/dsi_init

View File

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

View File

@ -6,14 +6,10 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "esp_log.h" #include "esp_log.h"
#include "esp_heap_caps.h"
#include "esp_lcd_mipi_dsi.h" #include "esp_lcd_mipi_dsi.h"
#include "esp_lcd_panel_ops.h" #include "esp_lcd_panel_ops.h"
#include "esp_lcd_ili9881c.h" #include "esp_lcd_ili9881c.h"
#include "esp_ldo_regulator.h"
#include "esp_cache.h"
#include "example_dsi_init.h" #include "example_dsi_init.h"
#include "example_config.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) void example_dsi_resource_alloc(esp_lcd_panel_handle_t *ili9881c_ctrl_panel, esp_lcd_panel_handle_t *mipi_dpi_panel, void **frame_buffer)
{ {

View File

@ -10,6 +10,15 @@
extern "C" { extern "C" {
#endif #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 * @brief DSI init function
* *

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 * 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 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -33,8 +33,9 @@ typedef struct {
* @brief Sensor driver API to set sensor focus value * @brief Sensor driver API to set sensor focus value
* *
* @param[in] focus_val Camera 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; } 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] scheme AF scheme handle
* @param[in] sensor_drv Sensor driver, see `isp_af_sa_scheme_sensor_drv_t` * @param[in] sensor_drv Sensor driver, see `isp_af_sa_scheme_sensor_drv_t`
* @param[in] info Sensor info * @param[in] info Sensor info
* @param[in] arg User arg
* *
* @return * @return
* - ESP_OK On success * - ESP_OK On success
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid
* - ESP_ERR_INVALID_STATE Invalid state * - 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 #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 * 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_info_t sensor_info;
isp_af_sa_scheme_sensor_drv_t sensor_drv; isp_af_sa_scheme_sensor_drv_t sensor_drv;
void *arg;
} af_scheme_context_t; } af_scheme_context_t;
/* ------------------------ Interface Functions --------------------------- */ /* ------------------------ Interface Functions --------------------------- */
@ -78,7 +79,7 @@ esp_err_t isp_af_delete_sa_scheme(isp_af_scheme_handle_t scheme)
return ESP_OK; 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, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer");
ESP_RETURN_ON_FALSE(scheme->ctx, ESP_ERR_INVALID_STATE, TAG, "no scheme created yet"); 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; af_scheme_context_t *ctx = scheme->ctx;
ctx->sensor_drv.af_sensor_set_focus = sensor_drv->af_sensor_set_focus; ctx->sensor_drv.af_sensor_set_focus = sensor_drv->af_sensor_set_focus;
ctx->sensor_info.focus_val_max = info->focus_val_max; ctx->sensor_info.focus_val_max = info->focus_val_max;
ctx->arg = arg;
return ESP_OK; 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 = {}; 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 ----------//"); 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++) { for (int x = 0; x <= ctx->first_approx_cycles; x++) {
af_current = af_current_base + x * ctx->first_step_val; 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"); 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]; af_sum = result.definition[0] + result.definition[1] + result.definition[2];
if (af_sum > af_sum_max) { if (af_sum > af_sum_max) {
@ -154,7 +156,7 @@ static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_lu
af_current = 0; 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"); 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]; af_sum = result.definition[0] + result.definition[1] + result.definition[2];
if (af_sum > af_sum_max) { 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 // af done
ESP_LOGV(TAG, "//----------- 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_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 // update env threshold
ESP_LOGV(TAG, "//------- 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