From 70d2ed5ee8299f4144a28cf8c214208cc93aa37a Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 15 May 2024 18:53:04 +0800 Subject: [PATCH] feat(isp): added isp dvp driver --- components/esp_driver_cam/CMakeLists.txt | 26 +- components/esp_driver_cam/Kconfig | 20 +- .../csi/include/esp_cam_ctlr_csi.h | 9 +- .../esp_driver_cam/csi/src/esp_cam_ctlr_csi.c | 7 +- components/esp_driver_cam/dvp_share_ctrl.c | 36 ++ components/esp_driver_cam/dvp_share_ctrl.h | 28 + .../include/esp_cam_ctlr_types.h | 5 + .../isp_dvp/include/esp_cam_ctlr_isp_dvp.h | 59 ++ .../isp_dvp/src/esp_cam_ctlr_isp_dvp.c | 568 ++++++++++++++++++ .../test_apps/csi/main/test_csi_driver.c | 8 +- .../test_apps/isp_dvp/sdkconfig.defaults | 6 + components/esp_driver_isp/CMakeLists.txt | 13 +- .../esp_driver_isp/include/driver/isp_af.h | 22 +- .../esp_driver_isp/include/driver/isp_types.h | 2 +- .../esp_private/isp_private.h} | 27 +- components/esp_driver_isp/src/isp_af.c | 32 +- components/esp_driver_isp/src/isp_bf.c | 2 +- components/esp_driver_isp/src/isp_core.c | 9 +- .../test_apps/isp/main/CMakeLists.txt | 1 + .../test_apps/isp/main/test_isp_driver.c | 45 +- .../test_apps/isp/sdkconfig.defaults | 3 + .../port/esp32p4/esp_clk_tree.c | 2 +- components/hal/esp32p4/include/hal/isp_ll.h | 131 ++++ components/hal/include/hal/cam_ctlr_types.h | 42 ++ components/hal/include/hal/isp_types.h | 9 + components/hal/include/hal/mipi_csi_types.h | 15 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 12 + components/soc/esp32p4/include/soc/soc_caps.h | 3 + components/soc/esp32p4/isp_periph.c | 26 + components/soc/include/soc/isp_periph.h | 8 + .../peripherals/camera_driver.rst | 8 +- docs/en/api-reference/peripherals/isp.rst | 8 +- .../components/dsi_init/CMakeLists.txt | 2 +- .../components/dsi_init/Kconfig.projbuild | 25 + .../components/dsi_init/example_dsi_init.c | 5 +- .../components/dsi_init/idf_component.yml | 2 +- .../dsi_init/include}/example_dsi_init.h | 13 +- .../include/example_dsi_init_config.h | 22 + .../camera/camera_dsi/main/CMakeLists.txt | 2 +- .../camera/camera_dsi/main/camera_dsi_main.c | 9 +- .../camera/camera_dsi/main/idf_component.yml | 2 +- .../isp_af_schemes/include/isp_af_scheme_sa.h | 2 +- .../isp_af_schemes/src/isp_af_scheme_sa.c | 4 +- .../isp/auto_focus/main/idf_component.yml | 2 +- .../isp/auto_focus/main/isp_af_dsi_main.c | 13 +- 45 files changed, 1172 insertions(+), 123 deletions(-) create mode 100644 components/esp_driver_cam/dvp_share_ctrl.c create mode 100644 components/esp_driver_cam/dvp_share_ctrl.h create mode 100644 components/esp_driver_cam/isp_dvp/include/esp_cam_ctlr_isp_dvp.h create mode 100644 components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c create mode 100644 components/esp_driver_cam/test_apps/isp_dvp/sdkconfig.defaults rename components/esp_driver_isp/{src/isp_internal.h => include/esp_private/isp_private.h} (70%) create mode 100644 components/hal/include/hal/cam_ctlr_types.h rename examples/peripherals/camera/{ => camera_dsi}/components/dsi_init/CMakeLists.txt (71%) create mode 100644 examples/peripherals/camera/camera_dsi/components/dsi_init/Kconfig.projbuild rename examples/peripherals/camera/{ => camera_dsi}/components/dsi_init/example_dsi_init.c (94%) rename examples/peripherals/camera/{ => camera_dsi}/components/dsi_init/idf_component.yml (53%) rename examples/peripherals/camera/{components/dsi_init => camera_dsi/components/dsi_init/include}/example_dsi_init.h (68%) create mode 100644 examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init_config.h diff --git a/components/esp_driver_cam/CMakeLists.txt b/components/esp_driver_cam/CMakeLists.txt index 86f16af2a9..17ac846f64 100644 --- a/components/esp_driver_cam/CMakeLists.txt +++ b/components/esp_driver_cam/CMakeLists.txt @@ -1,21 +1,29 @@ idf_build_get_property(target IDF_TARGET) -set(srcs "esp_cam_ctlr.c") +set(srcs "esp_cam_ctlr.c" "dvp_share_ctrl.c") -set(include "include" "interface") +set(includes "include" "interface") + +set(requires "esp_driver_isp") + +set(priv_requires "esp_driver_gpio") if(CONFIG_SOC_MIPI_CSI_SUPPORTED) list(APPEND srcs "csi/src/esp_cam_ctlr_csi.c") - list(APPEND include "csi/include") + list(APPEND includes "csi/include") endif() -if(${target} STREQUAL "linux") - set(priv_requires "") -else() - set(priv_requires esp_mm) +if(CONFIG_SOC_ISP_DVP_SUPPORTED) + list(APPEND srcs "isp_dvp/src/esp_cam_ctlr_isp_dvp.c") + list(APPEND includes "isp_dvp/include") +endif() + +if(NOT ${target} STREQUAL "linux") + list(APPEND requires esp_mm) endif() idf_component_register(SRCS ${srcs} - INCLUDE_DIRS ${include} - PRIV_REQUIRES "${priv_requires}" + INCLUDE_DIRS ${includes} + REQUIRES ${requires} + PRIV_REQUIRES ${priv_requires} ) diff --git a/components/esp_driver_cam/Kconfig b/components/esp_driver_cam/Kconfig index f7b3ceaa6b..771fd0e6ab 100644 --- a/components/esp_driver_cam/Kconfig +++ b/components/esp_driver_cam/Kconfig @@ -1,11 +1,27 @@ -menu "ESP Camera Controller Configurations" +menu "ESP-Driver:Camera Controller Configurations" + depends on SOC_MIPI_CSI_SUPPORTED - config MIPI_CSI_ISR_IRAM_SAFE + config CAM_CTLR_MIPI_CSI_ISR_IRAM_SAFE bool "CSI ISR IRAM-Safe" default n + select DW_GDMA_ISR_IRAM_SAFE + select DW_GDMA_CTRL_FUNC_IN_IRAM + select DW_GDMA_SETTER_FUNC_IN_IRAM + select DW_GDMA_GETTER_FUNC_IN_IRAM help Ensure the CSI driver ISR is IRAM-Safe. When enabled, the ISR handler will be available when the cache is disabled. + config CAM_CTLR_ISP_DVP_ISR_IRAM_SAFE + bool "ISP_DVP ISR IRAM-Safe" + default n + select DW_GDMA_ISR_IRAM_SAFE + select DW_GDMA_CTRL_FUNC_IN_IRAM + select DW_GDMA_SETTER_FUNC_IN_IRAM + select DW_GDMA_GETTER_FUNC_IN_IRAM + help + Ensure the ISP_DVP driver ISR is IRAM-Safe. When enabled, the ISR handler + will be available when the cache is disabled. + endmenu # ESP Camera Controller Configurations diff --git a/components/esp_driver_cam/csi/include/esp_cam_ctlr_csi.h b/components/esp_driver_cam/csi/include/esp_cam_ctlr_csi.h index fa63b5fc04..18eed2e00c 100644 --- a/components/esp_driver_cam/csi/include/esp_cam_ctlr_csi.h +++ b/components/esp_driver_cam/csi/include/esp_cam_ctlr_csi.h @@ -15,11 +15,6 @@ extern "C" { #endif -/** - * @brief ESP CAM controller max timeout value - */ -#define ESP_CAM_CTLR_MAX_DELAY UINT32_MAX - /** * @brief ESP CAM CSI controller configurations */ @@ -30,8 +25,8 @@ typedef struct { uint32_t v_res; ///< Input vertical resolution, i.e. the number of lines in a frame uint8_t data_lane_num; ///< Data lane num int lane_bit_rate_mbps; ///< Lane bit rate in Mbps - mipi_csi_color_t input_data_color_type; ///< Input color type - mipi_csi_color_t output_data_color_type; ///< Output color type + cam_ctlr_color_t input_data_color_type; ///< Input color type + cam_ctlr_color_t output_data_color_type; ///< Output color type int queue_items; ///< Queue items struct { uint32_t byte_swap_en : 1; ///< Enable byte swap diff --git a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c index e43474fd08..20b11ac0d1 100644 --- a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c +++ b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c @@ -24,7 +24,7 @@ #include "esp_private/esp_cache_private.h" #include "esp_cache.h" -#if CONFIG_MIPI_CSI_ISR_IRAM_SAFE +#if CONFIG_CAM_CTLR_MIPI_CSI_ISR_IRAM_SAFE #define CSI_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #else #define CSI_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT @@ -66,7 +66,6 @@ static esp_err_t s_csi_claim_controller(csi_controller_t *controller) mipi_csi_ll_enable_host_bus_clock(i, 1); mipi_csi_ll_reset_host_clock(i); } - _lock_release(&s_platform.mutex); break; } } @@ -295,7 +294,7 @@ static esp_err_t s_csi_ctlr_get_buffer_length(esp_cam_ctlr_handle_t handle, size return ESP_OK; } -static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_gdma_trans_done_event_data_t *event_data, void *user_data) +IRAM_ATTR static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_gdma_trans_done_event_data_t *event_data, void *user_data) { bool need_yield = false; BaseType_t high_task_woken = pdFALSE; @@ -374,7 +373,7 @@ esp_err_t s_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam csi_controller_t *ctlr = __containerof(handle, csi_controller_t, base); ESP_RETURN_ON_FALSE(ctlr->csi_fsm == CSI_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "driver starts already, not allow cbs register"); -#if CONFIG_MIPI_CSI_ISR_IRAM_SAFE +#if CONFIG_CAM_CTLR_MIPI_CSI_ISR_IRAM_SAFE if (cbs->on_get_new_trans) { ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_get_new_trans), ESP_ERR_INVALID_ARG, TAG, "on_get_new_trans callback not in IRAM"); } diff --git a/components/esp_driver_cam/dvp_share_ctrl.c b/components/esp_driver_cam/dvp_share_ctrl.c new file mode 100644 index 0000000000..60d080e6d4 --- /dev/null +++ b/components/esp_driver_cam/dvp_share_ctrl.c @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "esp_log.h" +#include "esp_err.h" +#include "freertos/FreeRTOS.h" + +bool dvp_signal_used; +static portMUX_TYPE s_spinlock = portMUX_INITIALIZER_UNLOCKED; + +esp_err_t dvp_shared_ctrl_claim_io_signals(void) +{ + esp_err_t ret = ESP_ERR_NOT_FOUND; + portENTER_CRITICAL(&s_spinlock); + if (!dvp_signal_used) { + dvp_signal_used = true; + ret = ESP_OK; + } + portEXIT_CRITICAL(&s_spinlock); + + return ret; +} + +esp_err_t dvp_shared_ctrl_declaim_io_signals(void) +{ + portENTER_CRITICAL(&s_spinlock); + dvp_signal_used = false; + portEXIT_CRITICAL(&s_spinlock); + + return ESP_OK; +} diff --git a/components/esp_driver_cam/dvp_share_ctrl.h b/components/esp_driver_cam/dvp_share_ctrl.h new file mode 100644 index 0000000000..3f321fc7eb --- /dev/null +++ b/components/esp_driver_cam/dvp_share_ctrl.h @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Claim DVP IO signal usage + */ +esp_err_t dvp_shared_ctrl_claim_io_signals(void); + +/** + * @brief Declaim DVP IO signal usage + */ +esp_err_t dvp_shared_ctrl_declaim_io_signals(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_cam/include/esp_cam_ctlr_types.h b/components/esp_driver_cam/include/esp_cam_ctlr_types.h index c215d21996..5dae1bc5db 100644 --- a/components/esp_driver_cam/include/esp_cam_ctlr_types.h +++ b/components/esp_driver_cam/include/esp_cam_ctlr_types.h @@ -14,6 +14,11 @@ extern "C" { #endif +/** + * @brief ESP CAM controller max timeout value + */ +#define ESP_CAM_CTLR_MAX_DELAY UINT32_MAX + /** * @brief ESP CAM controller handle */ diff --git a/components/esp_driver_cam/isp_dvp/include/esp_cam_ctlr_isp_dvp.h b/components/esp_driver_cam/isp_dvp/include/esp_cam_ctlr_isp_dvp.h new file mode 100644 index 0000000000..a0cbbc9ca7 --- /dev/null +++ b/components/esp_driver_cam/isp_dvp/include/esp_cam_ctlr_isp_dvp.h @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include +#include "esp_err.h" +#include "driver/isp_types.h" +#include "hal/cam_ctlr_types.h" +#include "esp_cam_ctlr_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief ESP CAM ISP DVP controller configurations + */ +typedef struct { + cam_ctlr_data_width_t data_width; ///< Number of data lines + int data_io[ISP_DVP_DATA_SIG_NUM]; ///< ISP DVP data-in IO numbers + int pclk_io; ///< ISP DVP pclk IO numbers + int hsync_io; ///< ISP DVP hsync IO numbers + int vsync_io; ///< ISP DVP vsync IO numbers + int de_io; ///< ISP DVP de IO numbers + struct { + uint32_t pclk_invert: 1; ///< The pclk is inverted + uint32_t hsync_invert: 1; ///< The hsync signal is inverted + uint32_t vsync_invert: 1; ///< The vsync signal is inverted + uint32_t de_invert: 1; ///< The de signal is inverted + } io_flags; ///< ISP DVP IO flags + int queue_items; ///< Queue items + struct { + uint32_t byte_swap_en : 1; ///< Enable byte swap + uint32_t bk_buffer_dis : 1; ///< Disable backup buffer + }; +} esp_cam_ctlr_isp_dvp_cfg_t; + +/** + * @brief New ESP CAM ISP DVP controller + * + * @param[in] ctlr_config ISP DVP controller configurations + * @param[out] ret_handle Returned ESP CAM controller handle + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_NO_MEM: Out of memory + * - ESP_ERR_NOT_SUPPORTED: Currently not support modes or types + * - ESP_ERR_NOT_FOUND: ISP DVP is registered already + */ +esp_err_t esp_cam_new_isp_dvp_ctlr(isp_proc_handle_t isp_proc, const esp_cam_ctlr_isp_dvp_cfg_t *ctlr_config, esp_cam_ctlr_handle_t *ret_handle); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c b/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c new file mode 100644 index 0000000000..852b35aba1 --- /dev/null +++ b/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c @@ -0,0 +1,568 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "freertos/FreeRTOS.h" +#include "freertos/idf_additions.h" +#include "driver/isp_types.h" +#include "driver/gpio.h" +#include "hal/isp_hal.h" +#include "hal/gpio_hal.h" +#include "hal/isp_ll.h" +#include "hal/mipi_csi_brg_ll.h" +#include "hal/mipi_csi_ll.h" +#include "hal/color_hal.h" +#include "esp_private/periph_ctrl.h" +#include "esp_private/isp_private.h" +#include "esp_private/esp_cache_private.h" +#include "esp_private/mipi_csi_share_hw_ctrl.h" +#include "esp_private/dw_gdma.h" +#include "esp_cam_ctlr_types.h" +#include "esp_cam_ctlr_interface.h" +#include "esp_cache.h" +#include "esp_cam_ctlr_isp_dvp.h" +#include "../../dvp_share_ctrl.h" + +#if CONFIG_CAM_CTLR_ISP_DVP_ISR_IRAM_SAFE +#define ISP_DVP_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) +#else +#define ISP_DVP_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT +#endif + +typedef struct isp_dvp_controller_t { + int id; //dvp id + isp_fsm_t fsm; //finite state machine + portMUX_TYPE spinlock; //spinlock + isp_processor_t *isp_proc; //isp processor + int in_bpp; //input data type, bit per pixel + int out_bpp; //output data type, bit per pixel + size_t fb_size_in_bytes; //Frame buffer size, in bytes + esp_cam_ctlr_trans_t trans; //Saved done transaction to be given out to callers + void *backup_buffer; //backup buffer to make csi bridge can work to avoid wrong state + bool bk_buffer_exposed; //status of if back_buffer is exposed to users + bool bk_buffer_dis; //allow to not malloc backup_buffer + QueueHandle_t trans_que; //transaction queue + esp_cam_ctlr_evt_cbs_t cbs; //user callbacks + void *cbs_user_data; //callback userdata + dw_gdma_channel_handle_t dma_chan; //dwgdma channel handle + size_t dvp_transfer_size; //csi transfer size for dwgdma + bool isr_installed; //is isr installed + esp_cam_ctlr_t base; +} isp_dvp_controller_t; + +typedef struct isp_dvp_ctx_t { + _lock_t mutex; + isp_dvp_controller_t *dvp_ctlr[SOC_ISP_DVP_CTLR_NUMS]; +} isp_dvp_ctx_t; + +static const char *TAG = "ISP_DVP"; +static isp_dvp_ctx_t s_ctx; + +static esp_err_t s_isp_io_init(isp_dvp_controller_t *dvp_ctlr, const esp_cam_ctlr_isp_dvp_cfg_t *ctlr_config); +static esp_err_t s_isp_claim_dvp_controller(isp_proc_handle_t isp_proc, isp_dvp_controller_t *dvp_ctlr); +static esp_err_t s_isp_declaim_dvp_controller(isp_dvp_controller_t *dvp_ctlr); +static esp_err_t s_isp_del_dvp_controller(esp_cam_ctlr_handle_t handle); +static esp_err_t s_isp_dvp_get_frame_buffer(esp_cam_ctlr_handle_t handle, uint32_t fb_num, const void **fb0, ...); +static esp_err_t s_isp_dvp_get_frame_buffer_length(esp_cam_ctlr_handle_t handle, size_t *ret_fb_len); +static esp_err_t s_isp_dvp_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_data); +static esp_err_t s_isp_dvp_enable(esp_cam_ctlr_handle_t handle); +static esp_err_t s_isp_dvp_disable(esp_cam_ctlr_handle_t handle); +static esp_err_t s_isp_dvp_start(esp_cam_ctlr_handle_t handle); +static esp_err_t s_isp_dvp_stop(esp_cam_ctlr_handle_t handle); +static esp_err_t s_isp_dvp_receive(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, uint32_t timeout_ms); +static bool s_dvp_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_gdma_trans_done_event_data_t *event_data, void *user_data); + +esp_err_t esp_cam_new_isp_dvp_ctlr(isp_proc_handle_t isp_proc, const esp_cam_ctlr_isp_dvp_cfg_t *ctlr_config, esp_cam_ctlr_handle_t *ret_handle) +{ + esp_err_t ret = ESP_FAIL; + ESP_RETURN_ON_FALSE(isp_proc && ctlr_config && ret_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + + isp_dvp_controller_t *dvp_ctlr = heap_caps_calloc(1, sizeof(isp_dvp_controller_t), ISP_DVP_MEM_ALLOC_CAPS); + ESP_RETURN_ON_FALSE(dvp_ctlr, ESP_ERR_NO_MEM, TAG, "no mem for isp dvp controller"); + + dvp_ctlr->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; + dvp_ctlr->isp_proc = isp_proc; + +#if SOC_ISP_SHARE_CSI_BRG + ESP_GOTO_ON_ERROR(mipi_csi_brg_claim(MIPI_CSI_BRG_USER_ISP_DVP, &isp_proc->csi_brg_id), err, TAG, "csi bridge is in use already"); +#endif + //claim an DVP controller + ESP_GOTO_ON_ERROR(s_isp_claim_dvp_controller(isp_proc, dvp_ctlr), err, TAG, "no available controller"); + ESP_GOTO_ON_ERROR(dvp_shared_ctrl_claim_io_signals(), err, TAG, "failed to claim io signals"); + ESP_GOTO_ON_ERROR(s_isp_io_init(dvp_ctlr, ctlr_config), err, TAG, "io init fail"); + + dvp_ctlr->trans_que = xQueueCreateWithCaps(ctlr_config->queue_items, sizeof(esp_cam_ctlr_trans_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ESP_GOTO_ON_FALSE(dvp_ctlr->trans_que, ESP_ERR_NO_MEM, err, TAG, "no memory for transaction queue"); + //in color type + int in_bits_per_pixel = color_hal_pixel_format_get_bit_depth(isp_proc->in_color_format); + dvp_ctlr->in_bpp = in_bits_per_pixel; + ESP_LOGD(TAG, "dvp_ctlr->in_bpp: 0d %d", dvp_ctlr->in_bpp); + + //out color type + int out_bits_per_pixel = color_hal_pixel_format_get_bit_depth(isp_proc->out_color_format); + dvp_ctlr->out_bpp = out_bits_per_pixel; + ESP_LOGD(TAG, "dvp_ctlr->out_bpp: 0d %d", dvp_ctlr->out_bpp); + + // Note: Width * Height * BitsPerPixel must be divisible by 8 + int fb_size_in_bits = isp_proc->v_res * isp_proc->h_res * out_bits_per_pixel; + ESP_GOTO_ON_FALSE((fb_size_in_bits % 8 == 0), ESP_ERR_INVALID_ARG, err, TAG, "framesize not 8bit aligned"); + dvp_ctlr->fb_size_in_bytes = fb_size_in_bits / 8; + ESP_LOGD(TAG, "dvp_ctlr->fb_size_in_bytes=%d", dvp_ctlr->fb_size_in_bytes); + + dvp_ctlr->bk_buffer_dis = ctlr_config->bk_buffer_dis; + if (!dvp_ctlr->bk_buffer_dis) { + size_t dma_alignment = 4; + size_t cache_alignment = 1; + ESP_GOTO_ON_ERROR(esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &cache_alignment), err, TAG, "failed to get cache alignment"); + size_t alignment = MAX(cache_alignment, dma_alignment); + ESP_LOGD(TAG, "alignment: 0x%x\n", alignment); + + dvp_ctlr->backup_buffer = heap_caps_aligned_alloc(alignment, dvp_ctlr->fb_size_in_bytes, MALLOC_CAP_SPIRAM); + ESP_GOTO_ON_FALSE(dvp_ctlr->backup_buffer, ESP_ERR_NO_MEM, err, TAG, "no mem for backup buffer"); + ESP_LOGD(TAG, "dvp_ctlr->backup_buffer: %p\n", dvp_ctlr->backup_buffer); + esp_cache_msync((void *)(dvp_ctlr->backup_buffer), dvp_ctlr->fb_size_in_bytes, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + } + + bool valid_format = isp_ll_dvp_set_data_type(isp_proc->hal.hw, isp_proc->in_color_format); + ESP_GOTO_ON_FALSE(valid_format, ESP_ERR_INVALID_ARG, err, TAG, "invalid dvp color space config"); + if (ctlr_config->io_flags.pclk_invert) { + isp_ll_cam_enable_pclk_invert(isp_proc->hal.hw, true); + } + if (ctlr_config->io_flags.hsync_invert) { + isp_ll_cam_enable_hsync_invert(isp_proc->hal.hw, true); + } + if (ctlr_config->io_flags.vsync_invert) { + isp_ll_cam_enable_vsync_invert(isp_proc->hal.hw, true); + } + if (ctlr_config->io_flags.de_invert) { + isp_ll_cam_enable_de_invert(isp_proc->hal.hw, true); + } + isp_ll_dvp_cam_reset(isp_proc->hal.hw); + + // configure DW_GDMA for ISP DVP + dw_gdma_channel_alloc_config_t dvp_dma_alloc_config = { + .src = { + .block_transfer_type = DW_GDMA_BLOCK_TRANSFER_CONTIGUOUS, +#if SOC_ISP_SHARE_CSI_BRG + .role = DW_GDMA_ROLE_PERIPH_CSI, //CSI bridge +#endif + .handshake_type = DW_GDMA_HANDSHAKE_HW, + .num_outstanding_requests = 5, + .status_fetch_addr = MIPI_CSI_BRG_MEM_BASE, + }, + .dst = { + .block_transfer_type = DW_GDMA_BLOCK_TRANSFER_CONTIGUOUS, + .role = DW_GDMA_ROLE_MEM, + .handshake_type = DW_GDMA_HANDSHAKE_HW, + .num_outstanding_requests = 5, + }, + .flow_controller = DW_GDMA_FLOW_CTRL_SRC, + .chan_priority = 1, + }; + ESP_ERROR_CHECK(dw_gdma_new_channel(&dvp_dma_alloc_config, &dvp_ctlr->dma_chan)); + + size_t dvp_transfer_size = isp_proc->h_res * isp_proc->v_res * dvp_ctlr->in_bpp / 64; + dvp_ctlr->dvp_transfer_size = dvp_transfer_size; + ESP_LOGD(TAG, "dvp_transfer_size: 0d %d", dvp_transfer_size); + + dvp_ctlr->fsm = ISP_FSM_INIT; + isp_proc->csi_brg_hw = MIPI_CSI_BRG_LL_GET_HW(isp_proc->csi_brg_id); + mipi_csi_brg_ll_set_intput_data_h_pixel_num(isp_proc->csi_brg_hw, isp_proc->h_res); + mipi_csi_brg_ll_set_intput_data_v_row_num(isp_proc->csi_brg_hw, isp_proc->v_res); + mipi_csi_brg_ll_set_burst_len(isp_proc->csi_brg_hw, 512); + + esp_cam_ctlr_t *cam_ctlr = &(dvp_ctlr->base); + cam_ctlr->del = s_isp_del_dvp_controller; + cam_ctlr->enable = s_isp_dvp_enable; + cam_ctlr->start = s_isp_dvp_start; + cam_ctlr->stop = s_isp_dvp_stop; + cam_ctlr->disable = s_isp_dvp_disable; + cam_ctlr->receive = s_isp_dvp_receive; + cam_ctlr->register_event_callbacks = s_isp_dvp_register_event_callbacks; + cam_ctlr->get_internal_buffer = s_isp_dvp_get_frame_buffer; + cam_ctlr->get_buffer_len = s_isp_dvp_get_frame_buffer_length; + *ret_handle = cam_ctlr; + + return ESP_OK; + +err: + if (dvp_ctlr) { + s_isp_del_dvp_controller(&(dvp_ctlr->base)); + } + + return ret; +} + +esp_err_t s_isp_del_dvp_controller(esp_cam_ctlr_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + + ESP_RETURN_ON_FALSE(dvp_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state"); + if (dvp_ctlr->dma_chan) { + ESP_RETURN_ON_ERROR(dw_gdma_del_channel(dvp_ctlr->dma_chan), TAG, "failed to delete dwgdma channel"); + } +#if SOC_ISP_SHARE_CSI_BRG + ESP_RETURN_ON_ERROR(mipi_csi_brg_declaim(dvp_ctlr->isp_proc->csi_brg_id), TAG, "declaim csi bridge fail"); +#endif + ESP_RETURN_ON_ERROR(s_isp_declaim_dvp_controller(dvp_ctlr), TAG, "controller isn't in use"); + ESP_RETURN_ON_ERROR(dvp_shared_ctrl_declaim_io_signals(), TAG, "failed to declaim io signals"); + if (!dvp_ctlr->bk_buffer_dis) { + free(dvp_ctlr->backup_buffer); + } + if (dvp_ctlr->trans_que) { + vQueueDeleteWithCaps(dvp_ctlr->trans_que); + } + free(dvp_ctlr); + + return ESP_OK; +} + +static esp_err_t s_isp_dvp_get_frame_buffer(esp_cam_ctlr_handle_t handle, uint32_t fb_num, const void **fb0, ...) +{ + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + ESP_RETURN_ON_FALSE((dvp_ctlr->fsm >= ISP_FSM_INIT) && (dvp_ctlr->backup_buffer), ESP_ERR_INVALID_STATE, TAG, "driver isn't initialized or back_buffer isn't available"); + ESP_RETURN_ON_FALSE(fb_num && fb_num <= 1, ESP_ERR_INVALID_ARG, TAG, "invalid frame buffer number"); + + dvp_ctlr->bk_buffer_exposed = true; + const void **fb_itor = fb0; + va_list args; + va_start(args, fb0); + for (uint32_t i = 0; i < fb_num; i++) { + if (fb_itor) { + *fb_itor = dvp_ctlr->backup_buffer; + fb_itor = va_arg(args, const void **); + } + } + va_end(args); + + return ESP_OK; +} + +static esp_err_t s_isp_dvp_get_frame_buffer_length(esp_cam_ctlr_handle_t handle, size_t *ret_fb_len) +{ + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + ESP_RETURN_ON_FALSE((dvp_ctlr->fsm >= ISP_FSM_INIT) && (dvp_ctlr->backup_buffer), ESP_ERR_INVALID_STATE, TAG, "driver isn't initialized or back_buffer isn't available"); + + *ret_fb_len = dvp_ctlr->fb_size_in_bytes; + return ESP_OK; +} + +static esp_err_t s_isp_dvp_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_data) +{ + ESP_RETURN_ON_FALSE(handle && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + ESP_RETURN_ON_FALSE(dvp_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state"); + +#if CONFIG_CAM_CTLR_MIPI_CSI_ISR_IRAM_SAFE + if (cbs->on_get_new_trans) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_get_new_trans), ESP_ERR_INVALID_ARG, TAG, "on_get_new_trans callback not in IRAM"); + } + if (cbs->on_trans_finished) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_finished), ESP_ERR_INVALID_ARG, TAG, "on_trans_finished callback not in IRAM"); + } +#endif + + if (!dvp_ctlr->isr_installed) { + dw_gdma_event_callbacks_t csi_dma_cbs = { + .on_full_trans_done = s_dvp_dma_trans_done_callback, + }; + ESP_RETURN_ON_ERROR(dw_gdma_channel_register_event_callbacks(dvp_ctlr->dma_chan, &csi_dma_cbs, dvp_ctlr), TAG, "failed to register dma callbacks"); + dvp_ctlr->isr_installed = true; + } + + dvp_ctlr->cbs.on_get_new_trans = cbs->on_get_new_trans; + dvp_ctlr->cbs.on_trans_finished = cbs->on_trans_finished; + dvp_ctlr->cbs_user_data = user_data; + + return ESP_OK; +} + +static esp_err_t s_isp_dvp_enable(esp_cam_ctlr_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + ESP_RETURN_ON_FALSE(dvp_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state"); + + portENTER_CRITICAL(&dvp_ctlr->spinlock); + dvp_ctlr->fsm = ISP_FSM_ENABLE; + portEXIT_CRITICAL(&dvp_ctlr->spinlock); + + return ESP_OK; +} + +static esp_err_t s_isp_dvp_disable(esp_cam_ctlr_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + ESP_RETURN_ON_FALSE(dvp_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); + + portENTER_CRITICAL(&dvp_ctlr->spinlock); + dvp_ctlr->fsm = ISP_FSM_INIT; + portEXIT_CRITICAL(&dvp_ctlr->spinlock); + + return ESP_OK; +} + +static esp_err_t s_isp_dvp_start(esp_cam_ctlr_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + ESP_RETURN_ON_FALSE(dvp_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); + ESP_RETURN_ON_FALSE(dvp_ctlr->isp_proc->isp_fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "ISP processor isn't in enable state"); + ESP_RETURN_ON_FALSE(dvp_ctlr->cbs.on_trans_finished, ESP_ERR_INVALID_STATE, TAG, "no on_trans_finished callback registered"); + + mipi_csi_brg_ll_enable(dvp_ctlr->isp_proc->csi_brg_hw, true); + isp_ll_cam_enable(dvp_ctlr->isp_proc->hal.hw, true); + + esp_cam_ctlr_trans_t trans = {}; + bool has_new_trans = false; + + if (dvp_ctlr->cbs.on_get_new_trans) { + dvp_ctlr->cbs.on_get_new_trans(handle, &trans, dvp_ctlr->cbs_user_data); + if (trans.buffer) { + has_new_trans = true; + } + } + + if (!has_new_trans) { + if (!dvp_ctlr->bk_buffer_dis) { + trans.buffer = dvp_ctlr->backup_buffer; + trans.buflen = dvp_ctlr->fb_size_in_bytes; + } else { + ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_STATE, TAG, "no ready transaction, and no backup buffer"); + } + } + + ESP_LOGD(TAG, "trans.buffer: %p, trans.buflen: %d", trans.buffer, trans.buflen); + dvp_ctlr->trans = trans; + + portENTER_CRITICAL(&dvp_ctlr->spinlock); + dvp_ctlr->fsm = ISP_FSM_START; + portEXIT_CRITICAL(&dvp_ctlr->spinlock); + + dw_gdma_block_transfer_config_t dvp_dma_transfer_config = {}; + dvp_dma_transfer_config = (dw_gdma_block_transfer_config_t) { + .src = { + .addr = MIPI_CSI_BRG_MEM_BASE, + .burst_mode = DW_GDMA_BURST_MODE_FIXED, + .burst_items = DW_GDMA_BURST_ITEMS_512, + .burst_len = 16, + .width = DW_GDMA_TRANS_WIDTH_64, + }, + .dst = { + .addr = (uint32_t)(trans.buffer), + .burst_mode = DW_GDMA_BURST_MODE_INCREMENT, + .burst_items = DW_GDMA_BURST_ITEMS_512, + .burst_len = 16, + .width = DW_GDMA_TRANS_WIDTH_64, + }, + .size = dvp_ctlr->dvp_transfer_size, + }; + ESP_RETURN_ON_ERROR(dw_gdma_channel_config_transfer(dvp_ctlr->dma_chan, &dvp_dma_transfer_config), TAG, "failed to configure dwgdma transfer"); + ESP_RETURN_ON_ERROR(dw_gdma_channel_enable_ctrl(dvp_ctlr->dma_chan, true), TAG, "failed to enable dwgdma"); + + return ESP_OK; +} + +static esp_err_t s_isp_dvp_stop(esp_cam_ctlr_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + ESP_RETURN_ON_FALSE(dvp_ctlr->fsm == ISP_FSM_START, ESP_ERR_INVALID_STATE, TAG, "driver isn't started"); + + isp_ll_cam_enable(dvp_ctlr->isp_proc->hal.hw, false); + mipi_csi_brg_ll_enable(dvp_ctlr->isp_proc->csi_brg_hw, false); + ESP_RETURN_ON_ERROR(dw_gdma_channel_enable_ctrl(dvp_ctlr->dma_chan, false), TAG, "failed to disable dwgdma"); + + portENTER_CRITICAL(&dvp_ctlr->spinlock); + dvp_ctlr->fsm = ISP_FSM_INIT; + portEXIT_CRITICAL(&dvp_ctlr->spinlock); + + return ESP_OK; +} + +static esp_err_t s_isp_dvp_receive(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, uint32_t timeout_ms) +{ + esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + + ESP_RETURN_ON_FALSE(trans->buffer, ESP_ERR_INVALID_ARG, TAG, "invalid argument: no trans buffer"); + ESP_RETURN_ON_FALSE((trans->buflen >= dvp_ctlr->fb_size_in_bytes), ESP_ERR_INVALID_ARG, TAG, "invalid argument: trans buffer smaller than framebuffer size"); + + TickType_t ticks_to_wait = timeout_ms / portTICK_PERIOD_MS; + if (timeout_ms == ESP_CAM_CTLR_MAX_DELAY) { + ticks_to_wait = portMAX_DELAY; + } + + BaseType_t r = xQueueSend(dvp_ctlr->trans_que, trans, ticks_to_wait); + if (r != pdTRUE) { + ret = ESP_ERR_TIMEOUT; + ESP_LOGW(TAG, "csi recv API, transaction queue is full, failed to send transaction to the queue"); + return ret; + } + + return ESP_OK; +} + +IRAM_ATTR static bool s_dvp_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_gdma_trans_done_event_data_t *event_data, void *user_data) +{ + bool need_yield = false; + BaseType_t high_task_woken = pdFALSE; + isp_dvp_controller_t *dvp_ctlr = (isp_dvp_controller_t *)user_data; + bool has_new_trans = false; + + dw_gdma_block_transfer_config_t dvp_dma_transfer_config = {}; + dvp_dma_transfer_config = (dw_gdma_block_transfer_config_t) { + .src = { + .addr = MIPI_CSI_BRG_MEM_BASE, + .burst_mode = DW_GDMA_BURST_MODE_FIXED, + .burst_items = DW_GDMA_BURST_ITEMS_512, + .burst_len = 16, + .width = DW_GDMA_TRANS_WIDTH_64, + }, + .dst = { + .addr = 0, + .burst_mode = DW_GDMA_BURST_MODE_INCREMENT, + .burst_items = DW_GDMA_BURST_ITEMS_512, + .burst_len = 16, + .width = DW_GDMA_TRANS_WIDTH_64, + }, + .size = dvp_ctlr->dvp_transfer_size, + }; + esp_cam_ctlr_trans_t new_trans = {}; + + if (dvp_ctlr->cbs.on_get_new_trans) { + need_yield = dvp_ctlr->cbs.on_get_new_trans(&(dvp_ctlr->base), &new_trans, dvp_ctlr->cbs_user_data); + if (new_trans.buffer && new_trans.buflen >= dvp_ctlr->fb_size_in_bytes) { + dvp_dma_transfer_config.dst.addr = (uint32_t)(new_trans.buffer); + has_new_trans = true; + } + } else if (xQueueReceiveFromISR(dvp_ctlr->trans_que, &new_trans, &high_task_woken) == pdTRUE) { + if (new_trans.buffer && new_trans.buflen >= dvp_ctlr->fb_size_in_bytes) { + dvp_dma_transfer_config.dst.addr = (uint32_t)(new_trans.buffer); + has_new_trans = true; + } + } + + if (!has_new_trans) { + if (!dvp_ctlr->bk_buffer_dis) { + new_trans.buffer = dvp_ctlr->backup_buffer; + new_trans.buflen = dvp_ctlr->fb_size_in_bytes; + ESP_EARLY_LOGD(TAG, "no new buffer or no long enough new buffer, use driver internal buffer"); + dvp_dma_transfer_config.dst.addr = (uint32_t)dvp_ctlr->backup_buffer; + } else { + assert(false && "no new buffer, and no driver internal buffer"); + } + } + + ESP_EARLY_LOGD(TAG, "new_trans.buffer: %p, new_trans.buflen: %d", new_trans.buffer, new_trans.buflen); + dw_gdma_channel_config_transfer(chan, &dvp_dma_transfer_config); + dw_gdma_channel_enable_ctrl(chan, true); + + if ((dvp_ctlr->trans.buffer != dvp_ctlr->backup_buffer) || dvp_ctlr->bk_buffer_exposed) { + esp_err_t ret = esp_cache_msync((void *)(dvp_ctlr->trans.buffer), dvp_ctlr->trans.received_size, ESP_CACHE_MSYNC_FLAG_INVALIDATE); + assert(ret == ESP_OK); + assert(dvp_ctlr->cbs.on_trans_finished); + if (dvp_ctlr->cbs.on_trans_finished) { + dvp_ctlr->trans.received_size = dvp_ctlr->fb_size_in_bytes; + need_yield |= dvp_ctlr->cbs.on_trans_finished(&(dvp_ctlr->base), &dvp_ctlr->trans, dvp_ctlr->cbs_user_data); + } + } + + //dvp_ctlr->trans is the transaction saved before dma starts + memset(&dvp_ctlr->trans, 0x0, sizeof(esp_cam_ctlr_trans_t)); + dvp_ctlr->trans = new_trans; + + need_yield |= high_task_woken == pdTRUE; + return need_yield; +} + +static esp_err_t s_isp_io_init(isp_dvp_controller_t *dvp_ctlr, const esp_cam_ctlr_isp_dvp_cfg_t *ctlr_config) +{ + gpio_config_t gpio_conf = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_INPUT, + .pull_down_en = false, + .pull_up_en = true, + }; + + if (ctlr_config->pclk_io) { + gpio_conf.pin_bit_mask = 1ULL << ctlr_config->pclk_io; + ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "failed to configure pclk gpio"); + ESP_LOGD(TAG, "pclk_io: %d, dvp_pclk_sig: %"PRId32, ctlr_config->pclk_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_pclk_sig); + esp_rom_gpio_connect_in_signal(ctlr_config->pclk_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_pclk_sig, false); + } + + if (ctlr_config->hsync_io) { + gpio_conf.pin_bit_mask = 1ULL << ctlr_config->hsync_io; + ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "failed to configure hsync gpio"); + ESP_LOGD(TAG, "hsync_io: %d, dvp_hsync_sig: %"PRId32, ctlr_config->hsync_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_hsync_sig); + esp_rom_gpio_connect_in_signal(ctlr_config->hsync_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_hsync_sig, false); + } + + if (ctlr_config->vsync_io) { + gpio_conf.pin_bit_mask = 1ULL << ctlr_config->vsync_io; + ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "failed to configure vsync gpio"); + ESP_LOGD(TAG, "vsync_io: %d, dvp_vsync_sig: %"PRId32, ctlr_config->vsync_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_vsync_sig); + esp_rom_gpio_connect_in_signal(ctlr_config->vsync_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_vsync_sig, false); + } + + if (ctlr_config->de_io) { + gpio_conf.pin_bit_mask = 1ULL << ctlr_config->de_io; + ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "failed to configure de gpio"); + ESP_LOGD(TAG, "de_io: %d, dvp_de_sig: %"PRId32, ctlr_config->de_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_de_sig); + esp_rom_gpio_connect_in_signal(ctlr_config->de_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_de_sig, false); + } + + for (size_t i = 0; i < ctlr_config->data_width; i++) { + gpio_conf.pin_bit_mask = 1ULL << ctlr_config->data_io[i]; + ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "failed to configure data gpio"); + ESP_LOGD(TAG, "data_io: %d, dvp_data_sig: %"PRId32, ctlr_config->data_io[i], isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_data_sig[i]); + esp_rom_gpio_connect_in_signal(ctlr_config->data_io[i], isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_data_sig[i], false); + } + + return ESP_OK; +} + +static esp_err_t s_isp_claim_dvp_controller(isp_proc_handle_t isp_proc, isp_dvp_controller_t *dvp_ctlr) +{ + assert(isp_proc && dvp_ctlr); + + _lock_acquire(&s_ctx.mutex); + bool found = false; + for (int i = 0; i < SOC_ISP_DVP_CTLR_NUMS; i++) { + found = !s_ctx.dvp_ctlr[i]; + if (found) { + s_ctx.dvp_ctlr[i] = dvp_ctlr; + dvp_ctlr->id = i; + + break; + } + } + _lock_release(&s_ctx.mutex); + + if (!found) { + return ESP_ERR_NOT_FOUND; + } + return ESP_OK; +} + +static esp_err_t s_isp_declaim_dvp_controller(isp_dvp_controller_t *dvp_ctlr) +{ + assert(dvp_ctlr); + + _lock_acquire(&s_ctx.mutex); + s_ctx.dvp_ctlr[dvp_ctlr->id] = NULL; + _lock_release(&s_ctx.mutex); + + return ESP_OK; +} diff --git a/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c b/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c index f9890e9c21..28a995d1b1 100644 --- a/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c +++ b/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c @@ -16,8 +16,8 @@ TEST_CASE("TEST CSI driver allocation", "[csi]") .h_res = 800, .v_res = 640, .lane_bit_rate_mbps = 200, - .input_data_color_type = MIPI_CSI_COLOR_RAW8, - .output_data_color_type = MIPI_CSI_COLOR_RGB565, + .input_data_color_type = CAM_CTLR_COLOR_RAW8, + .output_data_color_type = CAM_CTLR_COLOR_RGB565, .data_lane_num = 2, .byte_swap_en = false, .queue_items = 1, @@ -42,8 +42,8 @@ TEST_CASE("TEST CSI driver no backup buffer usage", "[csi]") .h_res = 800, .v_res = 640, .lane_bit_rate_mbps = 200, - .input_data_color_type = MIPI_CSI_COLOR_RAW8, - .output_data_color_type = MIPI_CSI_COLOR_RGB565, + .input_data_color_type = CAM_CTLR_COLOR_RAW8, + .output_data_color_type = CAM_CTLR_COLOR_RGB565, .data_lane_num = 2, .byte_swap_en = false, .queue_items = 1, diff --git a/components/esp_driver_cam/test_apps/isp_dvp/sdkconfig.defaults b/components/esp_driver_cam/test_apps/isp_dvp/sdkconfig.defaults new file mode 100644 index 0000000000..3f0207c5d6 --- /dev/null +++ b/components/esp_driver_cam/test_apps/isp_dvp/sdkconfig.defaults @@ -0,0 +1,6 @@ +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP_TASK_WDT_EN=n + +CONFIG_SPIRAM=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_SPIRAM_SPEED_200M=y diff --git a/components/esp_driver_isp/CMakeLists.txt b/components/esp_driver_isp/CMakeLists.txt index ac99867c00..2a6b037115 100644 --- a/components/esp_driver_isp/CMakeLists.txt +++ b/components/esp_driver_isp/CMakeLists.txt @@ -1,7 +1,13 @@ +idf_build_get_property(target IDF_TARGET) + set(srcs) set(public_include "include") +set(priv_requires "esp_driver_gpio") + +set(requires) + if(CONFIG_SOC_ISP_SUPPORTED) list(APPEND srcs "src/isp_core.c" "src/isp_af.c") @@ -11,7 +17,12 @@ if(CONFIG_SOC_ISP_BF_SUPPORTED) list(APPEND srcs "src/isp_bf.c") endif() +if(NOT ${target} STREQUAL "linux") + list(APPEND requires esp_mm) +endif() + idf_component_register(SRCS ${srcs} INCLUDE_DIRS ${public_include} - PRIV_REQUIRES esp_driver_gpio + REQUIRES ${requires} + PRIV_REQUIRES ${priv_requires} ) diff --git a/components/esp_driver_isp/include/driver/isp_af.h b/components/esp_driver_isp/include/driver/isp_af.h index 23348117d5..9058ea7445 100644 --- a/components/esp_driver_isp/include/driver/isp_af.h +++ b/components/esp_driver_isp/include/driver/isp_af.h @@ -38,7 +38,7 @@ typedef struct { * - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags * - ESP_ERR_NO_MEM If out of memory */ -esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af_config_t *af_config, isp_af_ctrlr_t *ret_hdl); +esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af_config_t *af_config, isp_af_ctlr_t *ret_hdl); /** * @brief Delete an ISP AF controller @@ -50,7 +50,7 @@ esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_del_af_controller(isp_af_ctrlr_t af_ctrlr); +esp_err_t esp_isp_del_af_controller(isp_af_ctlr_t af_ctrlr); /** * @brief Enable an ISP AF controller @@ -62,7 +62,7 @@ esp_err_t esp_isp_del_af_controller(isp_af_ctrlr_t af_ctrlr); * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_af_controller_enable(isp_af_ctrlr_t af_ctrlr); +esp_err_t esp_isp_af_controller_enable(isp_af_ctlr_t af_ctrlr); /** * @brief Disable an ISP AF controller @@ -74,7 +74,7 @@ esp_err_t esp_isp_af_controller_enable(isp_af_ctrlr_t af_ctrlr); * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_af_controller_disable(isp_af_ctrlr_t af_ctrlr); +esp_err_t esp_isp_af_controller_disable(isp_af_ctlr_t af_ctrlr); /** * @brief Trigger AF luminance and definition statistics for one time and get the result @@ -97,7 +97,7 @@ esp_err_t esp_isp_af_controller_disable(isp_af_ctrlr_t af_ctrlr); * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctrlr_t af_ctrlr, int timeout_ms, isp_af_result_t *out_res); +esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctlr_t af_ctrlr, int timeout_ms, isp_af_result_t *out_res); /** @cond */ #define esp_isp_af_controller_get_oneshot_result(af_ctrlr, out_res) \ @@ -116,7 +116,7 @@ esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctrlr_t af_ctrlr, * - ESP_ERR_INVALID_ARG Null pointer * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctrlr_t af_ctrlr); +esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctlr_t af_ctrlr); /** * @brief Stop AF continuous statistics of the luminance and definition in the windows @@ -127,7 +127,7 @@ esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctrlr_t af_ct * - ESP_ERR_INVALID_ARG Null pointer * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctrlr_t af_ctrlr); +esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctlr_t af_ctrlr); /*--------------------------------------------- AF Env Monitor @@ -152,7 +152,7 @@ typedef struct { * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctrlr_t af_ctrlr, const esp_isp_af_env_config_t *env_config); +esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctlr_t af_ctrlr, const esp_isp_af_env_config_t *env_config); /** * @brief Set ISP AF environment detector detecting threshold @@ -166,7 +166,7 @@ esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctrlr_t af_ctrlr, const * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_af_controller_set_env_detector_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_ctlr_t af_ctrlr, int definition_thresh, int luminance_thresh); /** * @brief Event data structure @@ -184,7 +184,7 @@ typedef struct { * * @return Whether a high priority task is woken up by this function */ -typedef bool (*esp_isp_af_env_detector_callback_t)(isp_af_ctrlr_t af_ctrlr, const esp_isp_af_env_detector_evt_data_t *edata, void *user_data); +typedef bool (*esp_isp_af_env_detector_callback_t)(isp_af_ctlr_t af_ctrlr, const esp_isp_af_env_detector_evt_data_t *edata, void *user_data); /** * @brief Group of ISP AF Env detector callbacks @@ -215,7 +215,7 @@ typedef struct { * - ESP_ERR_INVALID_ARG: Invalid arguments * - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment */ -esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_ctrlr_t af_ctrlr, const esp_isp_af_env_detector_evt_cbs_t *cbs, void *user_data); +esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_ctlr_t af_ctrlr, const esp_isp_af_env_detector_evt_cbs_t *cbs, void *user_data); #ifdef __cplusplus } diff --git a/components/esp_driver_isp/include/driver/isp_types.h b/components/esp_driver_isp/include/driver/isp_types.h index 14e0f6568f..f374793d2c 100644 --- a/components/esp_driver_isp/include/driver/isp_types.h +++ b/components/esp_driver_isp/include/driver/isp_types.h @@ -20,7 +20,7 @@ typedef struct isp_processor_t *isp_proc_handle_t; /** * @brief Type of ISP AF controller handle */ -typedef struct isp_af_controller_t *isp_af_ctrlr_t; +typedef struct isp_af_controller_t *isp_af_ctlr_t; #ifdef __cplusplus } diff --git a/components/esp_driver_isp/src/isp_internal.h b/components/esp_driver_isp/include/esp_private/isp_private.h similarity index 70% rename from components/esp_driver_isp/src/isp_internal.h rename to components/esp_driver_isp/include/esp_private/isp_private.h index 3d38838677..7b25b29882 100644 --- a/components/esp_driver_isp/src/isp_internal.h +++ b/components/esp_driver_isp/include/esp_private/isp_private.h @@ -19,11 +19,13 @@ #include "freertos/queue.h" #include "freertos/idf_additions.h" #include "driver/isp_types.h" +#include "soc/soc_caps.h" +#if SOC_ISP_SUPPORTED #include "hal/isp_hal.h" #include "hal/isp_ll.h" #include "hal/isp_types.h" #include "soc/isp_periph.h" -#include "soc/soc_caps.h" +#endif #ifdef __cplusplus extern "C" { @@ -43,23 +45,28 @@ typedef enum { ISP_FSM_START, } isp_fsm_t; +#if SOC_ISP_SUPPORTED /*--------------------------------------------------------------- Driver Context ---------------------------------------------------------------*/ typedef struct isp_processor_t { - int proc_id; - isp_hal_context_t hal; + int proc_id; + isp_hal_context_t hal; #if SOC_ISP_SHARE_CSI_BRG - int csi_brg_id; - void *csi_brg_hw; + int csi_brg_id; + void *csi_brg_hw; #endif - isp_fsm_t isp_fsm; - portMUX_TYPE spinlock; - + isp_fsm_t isp_fsm; + portMUX_TYPE spinlock; + color_space_pixel_format_t in_color_format; + color_space_pixel_format_t out_color_format; + uint32_t h_res; + uint32_t v_res; /* sub module contexts */ - isp_af_ctrlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS]; - isp_fsm_t bf_fsm; + isp_af_ctlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS]; + isp_fsm_t bf_fsm; } isp_processor_t; +#endif #ifdef __cplusplus } diff --git a/components/esp_driver_isp/src/isp_af.c b/components/esp_driver_isp/src/isp_af.c index c534b785cf..02f289a441 100644 --- a/components/esp_driver_isp/src/isp_af.c +++ b/components/esp_driver_isp/src/isp_af.c @@ -12,7 +12,7 @@ #include "esp_heap_caps.h" #include "freertos/FreeRTOS.h" #include "driver/isp_af.h" -#include "isp_internal.h" +#include "esp_private/isp_private.h" static const char *TAG = "ISP_AF"; @@ -33,7 +33,7 @@ static void s_isp_af_default_isr(void *arg); /*--------------------------------------------- AF ----------------------------------------------*/ -static esp_err_t s_isp_claim_af_controller(isp_proc_handle_t isp_proc, isp_af_ctrlr_t af_ctlr) +static esp_err_t s_isp_claim_af_controller(isp_proc_handle_t isp_proc, isp_af_ctlr_t af_ctlr) { assert(isp_proc && af_ctlr); @@ -56,7 +56,7 @@ static esp_err_t s_isp_claim_af_controller(isp_proc_handle_t isp_proc, isp_af_ct return ESP_OK; } -static void s_isp_declaim_af_controller(isp_af_ctrlr_t af_ctlr) +static void s_isp_declaim_af_controller(isp_af_ctlr_t af_ctlr) { assert(af_ctlr && af_ctlr->isp_proc); @@ -65,7 +65,7 @@ static void s_isp_declaim_af_controller(isp_af_ctrlr_t af_ctlr) portEXIT_CRITICAL(&af_ctlr->isp_proc->spinlock); } -static void s_isp_af_free_controller(isp_af_ctrlr_t af_ctlr) +static void s_isp_af_free_controller(isp_af_ctlr_t af_ctlr) { if (af_ctlr) { if (af_ctlr->intr_handle) { @@ -78,7 +78,7 @@ static void s_isp_af_free_controller(isp_af_ctrlr_t af_ctlr) } } -esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af_config_t *af_config, isp_af_ctrlr_t *ret_hdl) +esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af_config_t *af_config, isp_af_ctlr_t *ret_hdl) { esp_err_t ret = ESP_FAIL; ESP_RETURN_ON_FALSE(isp_proc && af_config && ret_hdl, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); @@ -102,7 +102,7 @@ esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af } ESP_RETURN_ON_FALSE(af_config->edge_thresh > 0, ESP_ERR_INVALID_ARG, TAG, "edge threshold should be larger than 0"); - isp_af_ctrlr_t af_ctlr = heap_caps_calloc(1, sizeof(isp_af_controller_t), ISP_MEM_ALLOC_CAPS); + isp_af_ctlr_t af_ctlr = heap_caps_calloc(1, sizeof(isp_af_controller_t), ISP_MEM_ALLOC_CAPS); ESP_RETURN_ON_FALSE(af_ctlr, ESP_ERR_NO_MEM, TAG, "no mem"); af_ctlr->evt_que = xQueueCreateWithCaps(1, sizeof(isp_af_result_t), ISP_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(af_ctlr->evt_que, ESP_ERR_NO_MEM, err1, TAG, "no mem for af event queue"); @@ -141,7 +141,7 @@ err1: return ret; } -esp_err_t esp_isp_del_af_controller(isp_af_ctrlr_t af_ctlr) +esp_err_t esp_isp_del_af_controller(isp_af_ctlr_t af_ctlr) { ESP_RETURN_ON_FALSE(af_ctlr && af_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(af_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state"); @@ -159,7 +159,7 @@ esp_err_t esp_isp_del_af_controller(isp_af_ctrlr_t af_ctlr) return ESP_OK; } -esp_err_t esp_isp_af_controller_enable(isp_af_ctrlr_t af_ctlr) +esp_err_t esp_isp_af_controller_enable(isp_af_ctlr_t af_ctlr) { ESP_RETURN_ON_FALSE(af_ctlr && af_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(af_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state"); @@ -173,7 +173,7 @@ esp_err_t esp_isp_af_controller_enable(isp_af_ctrlr_t af_ctlr) return ESP_OK; } -esp_err_t esp_isp_af_controller_disable(isp_af_ctrlr_t af_ctlr) +esp_err_t esp_isp_af_controller_disable(isp_af_ctlr_t af_ctlr) { ESP_RETURN_ON_FALSE(af_ctlr && af_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(af_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); @@ -187,7 +187,7 @@ esp_err_t esp_isp_af_controller_disable(isp_af_ctrlr_t af_ctlr) return ESP_OK; } -esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctrlr_t af_ctrlr, int timeout_ms, isp_af_result_t *out_res) +esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctlr_t af_ctrlr, int timeout_ms, isp_af_result_t *out_res) { ESP_RETURN_ON_FALSE_ISR(af_ctrlr && (out_res || timeout_ms == 0), ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't enabled or continuous statistics has started"); @@ -206,7 +206,7 @@ esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctrlr_t af_ctrlr, return ret; } -esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctrlr_t af_ctrlr) +esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctlr_t af_ctrlr) { ESP_RETURN_ON_FALSE_ISR(af_ctrlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); @@ -217,7 +217,7 @@ esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctrlr_t af_ct return ESP_OK; } -esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctrlr_t af_ctrlr) +esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctlr_t af_ctrlr) { ESP_RETURN_ON_FALSE_ISR(af_ctrlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_START, ESP_ERR_INVALID_STATE, TAG, "controller isn't in continuous state"); @@ -231,7 +231,7 @@ esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctrlr_t af_ctr /*--------------------------------------------- AF Env Monitor ----------------------------------------------*/ -esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctrlr_t af_ctrlr, const esp_isp_af_env_config_t *env_config) +esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctlr_t af_ctrlr, const esp_isp_af_env_config_t *env_config) { ESP_RETURN_ON_FALSE(af_ctrlr && env_config, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(af_ctrlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "invalid fsm, should be called when in init state"); @@ -248,7 +248,7 @@ esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctrlr_t af_ctrlr, const return ESP_OK; } -esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_ctrlr_t af_ctrlr, const esp_isp_af_env_detector_evt_cbs_t *cbs, void *user_data) +esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_ctlr_t af_ctrlr, const esp_isp_af_env_detector_evt_cbs_t *cbs, void *user_data) { ESP_RETURN_ON_FALSE(af_ctrlr && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(af_ctrlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "detector isn't in the init state"); @@ -271,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_controller_set_env_detector_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_ctlr_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"); @@ -286,7 +286,7 @@ esp_err_t esp_isp_af_controller_set_env_detector_threshold(isp_af_ctrlr_t af_ctr ---------------------------------------------------------------*/ static void IRAM_ATTR s_isp_af_default_isr(void *arg) { - isp_af_ctrlr_t af_ctrlr = (isp_af_ctrlr_t)arg; + isp_af_ctlr_t af_ctrlr = (isp_af_ctlr_t)arg; isp_proc_handle_t proc = af_ctrlr->isp_proc; uint32_t af_events = isp_hal_check_clear_intr_event(&proc->hal, ISP_LL_EVENT_AF_MASK); diff --git a/components/esp_driver_isp/src/isp_bf.c b/components/esp_driver_isp/src/isp_bf.c index 00bf4d1902..e2258216f4 100644 --- a/components/esp_driver_isp/src/isp_bf.c +++ b/components/esp_driver_isp/src/isp_bf.c @@ -19,7 +19,7 @@ #include "hal/hal_utils.h" #include "soc/mipi_csi_bridge_struct.h" #include "soc/isp_periph.h" -#include "isp_internal.h" +#include "esp_private/isp_private.h" static const char *TAG = "ISP_BF"; diff --git a/components/esp_driver_isp/src/isp_core.c b/components/esp_driver_isp/src/isp_core.c index b34057f9ab..d1aa78784c 100644 --- a/components/esp_driver_isp/src/isp_core.c +++ b/components/esp_driver_isp/src/isp_core.c @@ -19,7 +19,7 @@ #include "hal/hal_utils.h" #include "soc/mipi_csi_bridge_struct.h" #include "soc/isp_periph.h" -#include "isp_internal.h" +#include "esp_private/isp_private.h" typedef struct isp_platform_t { _lock_t mutex; @@ -73,7 +73,7 @@ esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_ { esp_err_t ret = ESP_FAIL; ESP_RETURN_ON_FALSE(proc_config && ret_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); - ESP_RETURN_ON_FALSE(proc_config->input_data_source == ISP_INPUT_DATA_SOURCE_CSI, ESP_ERR_NOT_SUPPORTED, TAG, "only support CSI as input source at this moment"); + ESP_RETURN_ON_FALSE(proc_config->input_data_source != ISP_INPUT_DATA_SOURCE_DWGDMA, ESP_ERR_NOT_SUPPORTED, TAG, "input source not supported yet"); ESP_RETURN_ON_FALSE(proc_config->input_data_color_type == ISP_COLOR_RAW8, ESP_ERR_NOT_SUPPORTED, TAG, "input data type not supported"); isp_processor_t *proc = heap_caps_calloc(1, sizeof(isp_processor_t), ISP_MEM_ALLOC_CAPS); @@ -143,6 +143,11 @@ esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_ isp_ll_set_intput_data_h_pixel_num(proc->hal.hw, proc_config->h_res); isp_ll_set_intput_data_v_row_num(proc->hal.hw, proc_config->v_res); + proc->in_color_format = in_color_format; + proc->out_color_format = out_color_format; + proc->h_res = proc_config->h_res; + proc->v_res = proc_config->v_res; + *ret_proc = proc; return ESP_OK; diff --git a/components/esp_driver_isp/test_apps/isp/main/CMakeLists.txt b/components/esp_driver_isp/test_apps/isp/main/CMakeLists.txt index 49f618de17..941c781eaf 100644 --- a/components/esp_driver_isp/test_apps/isp/main/CMakeLists.txt +++ b/components/esp_driver_isp/test_apps/isp/main/CMakeLists.txt @@ -8,6 +8,7 @@ endif() set(priv_requires unity esp_driver_isp + esp_psram ) idf_component_register(SRCS ${srcs} diff --git a/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c b/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c index 310124e0e2..ff4f976246 100644 --- a/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c +++ b/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c @@ -7,8 +7,8 @@ #include "sdkconfig.h" #include "unity.h" #include "driver/isp.h" - -#include "esp_rom_sys.h" +#include "esp_private/isp_dvp_private.h" +#include "soc/soc_caps.h" TEST_CASE("ISP processor exhausted allocation", "[isp]") { @@ -31,6 +31,45 @@ TEST_CASE("ISP processor exhausted allocation", "[isp]") } } +#if SOC_ISP_DVP_SUPPORTED +TEST_CASE("ISP DVP controller exhausted allocation", "[isp]") +{ + esp_isp_processor_cfg_t isp_config = { + .clk_hz = 120 * 1000 * 1000, + .input_data_source = ISP_INPUT_DATA_SOURCE_DVP, + .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 = 800, + .v_res = 640, + }; + isp_proc_handle_t isp_proc = NULL; + TEST_ESP_OK(esp_isp_new_processor(&isp_config, &isp_proc)); + + esp_cam_ctlr_isp_dvp_cfg_t dvp_ctlr_config = { + .data_width = 8, + .data_io = {53, 54, 52, 0, 1, 45, 46, 47, -1, -1, -1, -1, -1, -1, -1, -1}, + .pclk_io = 21, + .hsync_io = 5, + .vsync_io = 23, + .de_io = 22, + .io_flags.vsync_invert = 1, + }; + esp_cam_ctlr_handle_t dvp_ctrlr[SOC_ISP_DVP_CTLR_NUMS + 1] = {}; + for (int i = 0; i < SOC_ISP_DVP_CTLR_NUMS; i++) { + TEST_ESP_OK(esp_isp_new_dvp_controller(isp_proc, &dvp_ctlr_config, &dvp_ctrlr[i])); + } + + TEST_ASSERT(esp_isp_new_dvp_controller(isp_proc, &dvp_ctlr_config, &dvp_ctrlr[SOC_ISP_DVP_CTLR_NUMS]) == ESP_ERR_NOT_FOUND); + + for (int i = 0; i < SOC_ISP_DVP_CTLR_NUMS; i++) { + TEST_ESP_OK(esp_isp_del_dvp_controller(dvp_ctrlr[i])); + } + TEST_ESP_OK(esp_isp_del_processor(isp_proc)); +} +#endif + TEST_CASE("ISP AF controller exhausted allocation", "[isp]") { esp_isp_processor_cfg_t isp_config = { @@ -45,7 +84,7 @@ TEST_CASE("ISP AF controller exhausted allocation", "[isp]") esp_isp_af_config_t af_config = { .edge_thresh = 128, }; - isp_af_ctrlr_t af_ctrlr[SOC_ISP_AF_CTLR_NUMS + 1] = {}; + isp_af_ctlr_t af_ctrlr[SOC_ISP_AF_CTLR_NUMS + 1] = {}; for (int i = 0; i < SOC_ISP_AF_CTLR_NUMS; i++) { TEST_ESP_OK(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr[i])); } diff --git a/components/esp_driver_isp/test_apps/isp/sdkconfig.defaults b/components/esp_driver_isp/test_apps/isp/sdkconfig.defaults index fa8ac618b9..5bce69ad38 100644 --- a/components/esp_driver_isp/test_apps/isp/sdkconfig.defaults +++ b/components/esp_driver_isp/test_apps/isp/sdkconfig.defaults @@ -1,2 +1,5 @@ CONFIG_FREERTOS_HZ=1000 CONFIG_ESP_TASK_WDT_EN=n +CONFIG_SPIRAM=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_SPIRAM_SPEED_200M=y diff --git a/components/esp_hw_support/port/esp32p4/esp_clk_tree.c b/components/esp_hw_support/port/esp32p4/esp_clk_tree.c index 835f427078..788ddfcfac 100644 --- a/components/esp_hw_support/port/esp32p4/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32p4/esp_clk_tree.c @@ -16,7 +16,7 @@ static const char *TAG = "esp_clk_tree"; esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_src_freq_precision_t precision, -uint32_t *freq_value) + uint32_t *freq_value) { ESP_RETURN_ON_FALSE(clk_src > 0 && clk_src < SOC_MOD_CLK_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown clk src"); ESP_RETURN_ON_FALSE(precision < ESP_CLK_TREE_SRC_FREQ_PRECISION_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown precision"); diff --git a/components/hal/esp32p4/include/hal/isp_ll.h b/components/hal/esp32p4/include/hal/isp_ll.h index c91c8efb25..eaf0760e1a 100644 --- a/components/hal/esp32p4/include/hal/isp_ll.h +++ b/components/hal/esp32p4/include/hal/isp_ll.h @@ -76,6 +76,13 @@ extern "C" { ---------------------------------------------------------------*/ #define ISP_LL_BF_DEFAULT_TEMPLATE_VAL 15 +/*--------------------------------------------------------------- + DVP +---------------------------------------------------------------*/ +#define ISP_LL_DVP_DATA_TYPE_RAW8 0x2A +#define ISP_LL_DVP_DATA_TYPE_RAW10 0x2B +#define ISP_LL_DVP_DATA_TYPE_RAW12 0x2C + /** * @brief Env monitor mode */ @@ -791,6 +798,130 @@ static inline void isp_ll_color_enable(isp_dev_t *hw, bool enable) hw->cntl.color_en = enable; } +/*--------------------------------------------------------------- + DVP Camera +---------------------------------------------------------------*/ +/** + * @brief Set dvp data color format + * + * @param[in] hw Hardware instance address + * @param[in] format color format, see `color_space_pixel_format_t` + * + * @return true for valid format, false for invalid format + */ +static inline bool isp_ll_dvp_set_data_type(isp_dev_t *hw, color_space_pixel_format_t format) +{ + bool valid = false; + + if (format.color_space == COLOR_SPACE_RAW) { + switch(format.pixel_format) { + case COLOR_PIXEL_RAW8: + hw->cam_conf.cam_data_type = ISP_LL_DVP_DATA_TYPE_RAW8; + valid = true; + break; + case COLOR_PIXEL_RAW10: + hw->cam_conf.cam_data_type = ISP_LL_DVP_DATA_TYPE_RAW10; + valid = true; + break; + case COLOR_PIXEL_RAW12: + hw->cam_conf.cam_data_type = ISP_LL_DVP_DATA_TYPE_RAW12; + valid = true; + break; + default: + break; + } + } + + return valid; +} + +/** + * @brief Enable / Disable 2B mode + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable / Disable + */ +static inline void isp_ll_dvp_enable_2byte_mode(isp_dev_t *hw, bool enable) +{ + if (enable) { + HAL_ASSERT(hw->cam_conf.cam_data_type == ISP_LL_DVP_DATA_TYPE_RAW8); + hw->cam_conf.cam_2byte_mode = 1; + } else { + hw->cam_conf.cam_2byte_mode = 0; + } +} + +/** + * @brief Reset DVP CAM module + * + * @param[in] hw Hardware instance address + */ +static inline void isp_ll_dvp_cam_reset(isp_dev_t *hw) +{ + hw->cam_cntl.cam_reset = 1; + hw->cam_cntl.cam_reset = 0; +} + +/** + * @brief Enable DVP CAM pclk invert + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable / Disable + */ +static inline void isp_ll_cam_enable_pclk_invert(isp_dev_t *hw, bool enable) +{ + hw->cam_cntl.cam_clk_inv = enable; +} + +/** + * @brief Enable DVP CAM de invert + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable / Disable + */ +static inline void isp_ll_cam_enable_de_invert(isp_dev_t *hw, bool enable) +{ + hw->cam_conf.cam_de_inv = enable; +} + +/** + * @brief Enable DVP CAM hsync invert + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable / Disable + */ +static inline void isp_ll_cam_enable_hsync_invert(isp_dev_t *hw, bool enable) +{ + hw->cam_conf.cam_hsync_inv = enable; +} + +/** + * @brief Enable DVP CAM vsync invert + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable / Disable + */ +static inline void isp_ll_cam_enable_vsync_invert(isp_dev_t *hw, bool enable) +{ + hw->cam_conf.cam_vsync_inv = enable; +} + +/** + * @brief Enable DVP CAM + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable / Disable + */ +static inline void isp_ll_cam_enable(isp_dev_t *hw, bool enable) +{ + if (enable) { + hw->cam_cntl.cam_update_reg = 1; + hw->cam_cntl.cam_en = 1; + while (hw->cam_cntl.cam_update_reg); + } else { + hw->cam_cntl.cam_en = 0; + } +} /*--------------------------------------------------------------- INTR ---------------------------------------------------------------*/ diff --git a/components/hal/include/hal/cam_ctlr_types.h b/components/hal/include/hal/cam_ctlr_types.h new file mode 100644 index 0000000000..5830723821 --- /dev/null +++ b/components/hal/include/hal/cam_ctlr_types.h @@ -0,0 +1,42 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "soc/soc_caps.h" +#include "hal/color_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Camera Controller Color Type + */ +typedef enum { + CAM_CTLR_COLOR_RAW8 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW8), ///< RAW8 + CAM_CTLR_COLOR_RAW10 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW10), ///< RAW10 + CAM_CTLR_COLOR_RAW12 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW12), ///< RAW12 + CAM_CTLR_COLOR_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), ///< RGB565 + CAM_CTLR_COLOR_RGB666 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB666), ///< RGB666 + CAM_CTLR_COLOR_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), ///< RGB888 + CAM_CTLR_COLOR_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), ///< YUV420 + CAM_CTLR_COLOR_YUV422 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV422), ///< YUV422 +} cam_ctlr_color_t; + +/** + * @brief Camera Controller Data Width + */ +typedef enum { + CAM_CTLR_DATA_WIDTH_8 = 8, ///< 8-bit data width + CAM_CTLR_DATA_WIDTH_10 = 10, ///< 10-bit data width + CAM_CTLR_DATA_WIDTH_12 = 12, ////< 12-bit data width + CAM_CTLR_DATA_WIDTH_16 = 16, ///< 16-bit data width +} cam_ctlr_data_width_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/include/hal/isp_types.h b/components/hal/include/hal/isp_types.h index 0d5bc4be3f..399cbc1ee0 100644 --- a/components/hal/include/hal/isp_types.h +++ b/components/hal/include/hal/isp_types.h @@ -45,6 +45,15 @@ typedef enum { ISP_COLOR_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), ///< YUV420 } isp_color_t; +/*--------------------------------------------------------------- + DVP +---------------------------------------------------------------*/ +#if SOC_ISP_AF_WINDOW_NUMS +#define ISP_DVP_DATA_SIG_NUM SOC_ISP_DVP_DATA_WIDTH_MAX // The ISP DVP data signal number +#else +#define ISP_DVP_DATA_SIG_NUM 0 +#endif + /*--------------------------------------------------------------- AF ---------------------------------------------------------------*/ diff --git a/components/hal/include/hal/mipi_csi_types.h b/components/hal/include/hal/mipi_csi_types.h index 5614a43b21..9458bc6ddb 100644 --- a/components/hal/include/hal/mipi_csi_types.h +++ b/components/hal/include/hal/mipi_csi_types.h @@ -10,6 +10,7 @@ #include "soc/soc_caps.h" #include "soc/clk_tree_defs.h" #include "hal/color_types.h" +#include "hal/cam_ctlr_types.h" #ifdef __cplusplus extern "C" { @@ -24,20 +25,6 @@ typedef soc_periph_mipi_csi_phy_clk_src_t mipi_csi_phy_clock_source_t; typedef int mipi_csi_phy_clock_source_t; #endif // SOC_MIPI_CSI_SUPPORTED -/** - * @brief MIPI CSI Color Type - */ -typedef enum { - MIPI_CSI_COLOR_RAW8 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW8), ///< RAW8 - MIPI_CSI_COLOR_RAW10 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW10), ///< RAW10 - MIPI_CSI_COLOR_RAW12 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW12), ///< RAW12 - MIPI_CSI_COLOR_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), ///< RGB565 - MIPI_CSI_COLOR_RGB666 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB666), ///< RGB666 - MIPI_CSI_COLOR_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), ///< RGB888 - MIPI_CSI_COLOR_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), ///< YUV420 - MIPI_CSI_COLOR_YUV422 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV422), ///< YUV422 -} mipi_csi_color_t; - #ifdef __cplusplus } #endif diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index c5a429bcec..90e655d3c5 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -763,10 +763,18 @@ config SOC_ISP_BF_SUPPORTED bool default y +config SOC_ISP_DVP_SUPPORTED + bool + default y + config SOC_ISP_NUMS int default 1 +config SOC_ISP_DVP_CTLR_NUMS + int + default 1 + config SOC_ISP_AF_CTLR_NUMS int default 1 @@ -787,6 +795,10 @@ config SOC_ISP_BF_TEMPLATE_Y_NUMS int default 3 +config SOC_ISP_DVP_DATA_WIDTH_MAX + int + default 16 + config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 2f2d903f23..5c869f7b99 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -313,13 +313,16 @@ /*-------------------------- ISP CAPS ----------------------------------------*/ #define SOC_ISP_BF_SUPPORTED 1 +#define SOC_ISP_DVP_SUPPORTED 1 #define SOC_ISP_NUMS 1U +#define SOC_ISP_DVP_CTLR_NUMS 1U #define SOC_ISP_AF_CTLR_NUMS 1U #define SOC_ISP_AF_WINDOW_NUMS 3 #define SOC_ISP_SHARE_CSI_BRG 1 #define SOC_ISP_BF_TEMPLATE_X_NUMS 3 #define SOC_ISP_BF_TEMPLATE_Y_NUMS 3 +#define SOC_ISP_DVP_DATA_WIDTH_MAX 16 /*-------------------------- LEDC CAPS ---------------------------------------*/ #define SOC_LEDC_SUPPORT_PLL_DIV_CLOCK (1) diff --git a/components/soc/esp32p4/isp_periph.c b/components/soc/esp32p4/isp_periph.c index e46c183356..7ecdb372fc 100644 --- a/components/soc/esp32p4/isp_periph.c +++ b/components/soc/esp32p4/isp_periph.c @@ -16,6 +16,32 @@ const isp_info_t isp_hw_info = { [0] = { .irq = ETS_ISP_INTR_SOURCE, } + }, + .dvp_ctlr = { + [0] = { + .dvp_pclk_sig = CAM_PCLK_PAD_IN_IDX, + .dvp_hsync_sig = CAM_H_SYNC_PAD_IN_IDX, + .dvp_vsync_sig = CAM_V_SYNC_PAD_IN_IDX, + .dvp_de_sig = CAM_H_ENABLE_PAD_IN_IDX, + .dvp_data_sig = { + CAM_DATA_IN_PAD_IN0_IDX, + CAM_DATA_IN_PAD_IN1_IDX, + CAM_DATA_IN_PAD_IN2_IDX, + CAM_DATA_IN_PAD_IN3_IDX, + CAM_DATA_IN_PAD_IN4_IDX, + CAM_DATA_IN_PAD_IN5_IDX, + CAM_DATA_IN_PAD_IN6_IDX, + CAM_DATA_IN_PAD_IN7_IDX, + CAM_DATA_IN_PAD_IN8_IDX, + CAM_DATA_IN_PAD_IN9_IDX, + CAM_DATA_IN_PAD_IN10_IDX, + CAM_DATA_IN_PAD_IN11_IDX, + CAM_DATA_IN_PAD_IN12_IDX, + CAM_DATA_IN_PAD_IN13_IDX, + CAM_DATA_IN_PAD_IN14_IDX, + CAM_DATA_IN_PAD_IN15_IDX + }, + }, } }; diff --git a/components/soc/include/soc/isp_periph.h b/components/soc/include/soc/isp_periph.h index 54185323d6..288ed884c6 100644 --- a/components/soc/include/soc/isp_periph.h +++ b/components/soc/include/soc/isp_periph.h @@ -9,6 +9,7 @@ #include #include "soc/soc_caps.h" #include "soc/periph_defs.h" +#include "soc/gpio_sig_map.h" #ifdef __cplusplus extern "C" { @@ -19,6 +20,13 @@ typedef struct { struct { const uint32_t irq; } instances[SOC_ISP_NUMS]; + struct { + const uint32_t dvp_pclk_sig; + const uint32_t dvp_hsync_sig; + const uint32_t dvp_vsync_sig; + const uint32_t dvp_de_sig; + const uint32_t dvp_data_sig[SOC_ISP_DVP_DATA_WIDTH_MAX]; + } dvp_ctlr[SOC_ISP_DVP_CTLR_NUMS]; } isp_info_t; extern const isp_info_t isp_hw_info; diff --git a/docs/en/api-reference/peripherals/camera_driver.rst b/docs/en/api-reference/peripherals/camera_driver.rst index 18bb537b8b..bc9bec1c57 100644 --- a/docs/en/api-reference/peripherals/camera_driver.rst +++ b/docs/en/api-reference/peripherals/camera_driver.rst @@ -48,8 +48,8 @@ Resource Allocation .h_res = MIPI_CSI_DISP_HSIZE, .v_res = MIPI_CSI_DISP_VSIZE_640P, .lane_bit_rate_mbps = MIPI_CSI_LANE_BITRATE_MBPS, - .input_data_color_type = MIPI_CSI_COLOR_RAW8, - .output_data_color_type = MIPI_CSI_COLOR_RGB565, + .input_data_color_type = CAM_CTLR_COLOR_RAW8, + .output_data_color_type = CAM_CTLR_COLOR_RGB565, .data_lane_num = 2, .byte_swap_en = false, .queue_items = 1, @@ -134,7 +134,7 @@ The factory function :cpp:func:`esp_cam_new_csi_ctlr` and :cpp:func:`esp_cam_ctl Kconfig Options ^^^^^^^^^^^^^^^ -- :ref:`CONFIG_MIPI_CSI_ISR_IRAM_SAFE` controls whether the default ISR handler should be masked when the cache is disabled +- :ref:`CONFIG_CAM_CTLR_MIPI_CSI_ISR_IRAM_SAFE` controls whether the default ISR handler should be masked when the cache is disabled .. _cam-iram-safe: @@ -144,7 +144,7 @@ IRAM Safe By default, the CSI interrupt will be deferred when the cache is disabled because of writing or erasing the flash. -There is a Kconfig option :ref:`CONFIG_MIPI_CSI_ISR_IRAM_SAFE` that: +There is a Kconfig option :ref:`CONFIG_CAM_CTLR_MIPI_CSI_ISR_IRAM_SAFE` that: - Enables the interrupt being serviced even when the cache is disabled - Places all functions that used by the ISR into IRAM diff --git a/docs/en/api-reference/peripherals/isp.rst b/docs/en/api-reference/peripherals/isp.rst index 1a2ff494d2..4188719809 100644 --- a/docs/en/api-reference/peripherals/isp.rst +++ b/docs/en/api-reference/peripherals/isp.rst @@ -71,7 +71,7 @@ If the configurations in :cpp:type:`esp_isp_af_config_t` is specified, users can esp_isp_af_config_t af_config = { .edge_thresh = 128, }; - isp_af_ctrlr_t af_ctrlr = NULL; + isp_af_ctlr_t af_ctrlr = NULL; ESP_ERROR_CHECK(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr)); You can use the created handle to do driver enable / disable the ISP AF driver and ISP AF Env module installation. @@ -122,7 +122,7 @@ Calling :cpp:func:`esp_isp_af_controller_get_oneshot_statistics` to get oneshot esp_isp_af_config_t af_config = { .edge_thresh = 128, }; - isp_af_ctrlr_t af_ctrlr = NULL; + isp_af_ctlr_t af_ctrlr = NULL; ESP_ERROR_CHECK(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr)); ESP_ERROR_CHECK(esp_isp_af_controller_enable(af_ctrlr)); isp_af_result_t result = {}; @@ -140,7 +140,7 @@ Note that if you want to use the continuous statistics, you need to register the .. code:: c - isp_af_ctrlr_t af_ctrlr = NULL; + isp_af_ctlr_t af_ctrlr = NULL; esp_isp_af_config_t af_config = { .edge_thresh = 128, }; @@ -171,7 +171,7 @@ Calling :cpp:func:`esp_isp_af_controller_set_env_detector` to set an ISP AF envi esp_isp_af_env_config_t env_config = { .interval = 10, }; - isp_af_ctrlr_t af_ctrlr = NULL; + isp_af_ctlr_t af_ctrlr = NULL; ESP_ERROR_CHECK(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr)); ESP_ERROR_CHECK(esp_isp_af_controller_set_env_detector(af_ctrlr, &env_config)); diff --git a/examples/peripherals/camera/components/dsi_init/CMakeLists.txt b/examples/peripherals/camera/camera_dsi/components/dsi_init/CMakeLists.txt similarity index 71% rename from examples/peripherals/camera/components/dsi_init/CMakeLists.txt rename to examples/peripherals/camera/camera_dsi/components/dsi_init/CMakeLists.txt index 348bb31726..f8432fc1e7 100644 --- a/examples/peripherals/camera/components/dsi_init/CMakeLists.txt +++ b/examples/peripherals/camera/camera_dsi/components/dsi_init/CMakeLists.txt @@ -1,4 +1,4 @@ idf_component_register(SRCS "example_dsi_init.c" - INCLUDE_DIRS "." + INCLUDE_DIRS "include" REQUIRES esp_lcd ) diff --git a/examples/peripherals/camera/camera_dsi/components/dsi_init/Kconfig.projbuild b/examples/peripherals/camera/camera_dsi/components/dsi_init/Kconfig.projbuild new file mode 100644 index 0000000000..c67e3516ad --- /dev/null +++ b/examples/peripherals/camera/camera_dsi/components/dsi_init/Kconfig.projbuild @@ -0,0 +1,25 @@ +menu "Example DSI Configuration" + choice EXAMPLE_MIPI_DSI_DISP_HRES + bool "Set MIPI CSI horizontal resolution" + default EXAMPLE_MIPI_DSI_DISP_HRES_800 + + config EXAMPLE_MIPI_DSI_DISP_HRES_800 + bool "800" + endchoice + + config EXAMPLE_MIPI_DSI_DISP_HRES + int + default 800 if EXAMPLE_MIPI_DSI_DISP_HRES_800 + + choice EXAMPLE_MIPI_DSI_DISP_VRES + bool "Set MIPI CSI vertical resolution" + default EXAMPLE_MIPI_DSI_DISP_VRES_1280 + + config EXAMPLE_MIPI_DSI_DISP_VRES_1280 + bool "1280" + endchoice + + config EXAMPLE_MIPI_DSI_DISP_VRES + int + default 1280 if EXAMPLE_MIPI_DSI_DISP_VRES_1280 +endmenu diff --git a/examples/peripherals/camera/components/dsi_init/example_dsi_init.c b/examples/peripherals/camera/camera_dsi/components/dsi_init/example_dsi_init.c similarity index 94% rename from examples/peripherals/camera/components/dsi_init/example_dsi_init.c rename to examples/peripherals/camera/camera_dsi/components/dsi_init/example_dsi_init.c index 1cf9f3768a..1579014319 100644 --- a/examples/peripherals/camera/components/dsi_init/example_dsi_init.c +++ b/examples/peripherals/camera/camera_dsi/components/dsi_init/example_dsi_init.c @@ -10,6 +10,7 @@ #include "esp_lcd_panel_ops.h" #include "esp_lcd_ili9881c.h" #include "example_dsi_init.h" +#include "example_dsi_init_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) { @@ -45,8 +46,8 @@ void example_dsi_resource_alloc(esp_lcd_panel_handle_t *ili9881c_ctrl_panel, esp .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, + .h_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES, + .v_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, .hsync_back_porch = EXAMPLE_MIPI_DSI_IMAGE_HBP, .hsync_pulse_width = EXAMPLE_MIPI_DSI_IMAGE_HSYNC, .hsync_front_porch = EXAMPLE_MIPI_DSI_IMAGE_HFP, diff --git a/examples/peripherals/camera/components/dsi_init/idf_component.yml b/examples/peripherals/camera/camera_dsi/components/dsi_init/idf_component.yml similarity index 53% rename from examples/peripherals/camera/components/dsi_init/idf_component.yml rename to examples/peripherals/camera/camera_dsi/components/dsi_init/idf_component.yml index 6e0028e6a5..d43fae9657 100644 --- a/examples/peripherals/camera/components/dsi_init/idf_component.yml +++ b/examples/peripherals/camera/camera_dsi/components/dsi_init/idf_component.yml @@ -1,4 +1,4 @@ dependencies: - espressif/esp_lcd_ili9881c: "^0.2.0" + esp_lcd_ili9881c: ">=0.1.0" idf: version: ">=5.3.0" diff --git a/examples/peripherals/camera/components/dsi_init/example_dsi_init.h b/examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init.h similarity index 68% rename from examples/peripherals/camera/components/dsi_init/example_dsi_init.h rename to examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init.h index 5cffbc3cdf..df04c79eb1 100644 --- a/examples/peripherals/camera/components/dsi_init/example_dsi_init.h +++ b/examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init.h @@ -6,19 +6,14 @@ #pragma once +#include "esp_lcd_mipi_dsi.h" +#include "esp_lcd_panel_ops.h" +#include "esp_lcd_ili9881c.h" + #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 * diff --git a/examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init_config.h b/examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init_config.h new file mode 100644 index 0000000000..c804154298 --- /dev/null +++ b/examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init_config.h @@ -0,0 +1,22 @@ +/* + * 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_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 + +#ifdef __cplusplus +} +#endif diff --git a/examples/peripherals/camera/camera_dsi/main/CMakeLists.txt b/examples/peripherals/camera/camera_dsi/main/CMakeLists.txt index 8910b7da40..e760975a48 100644 --- a/examples/peripherals/camera/camera_dsi/main/CMakeLists.txt +++ b/examples/peripherals/camera/camera_dsi/main/CMakeLists.txt @@ -1,4 +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 + REQUIRES esp_mm esp_driver_isp esp_driver_cam esp_driver_i2c dsi_init ) diff --git a/examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c b/examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c index 9087aa28fb..a5c5c2dcb7 100644 --- a/examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c +++ b/examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c @@ -23,6 +23,7 @@ #include "esp_cam_sensor.h" #include "ov5647.h" #include "example_dsi_init.h" +#include "example_dsi_init_config.h" #include "example_config.h" static const char *TAG = "cam_dsi"; @@ -55,9 +56,9 @@ void app_main(void) 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; + frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * 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, "CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES: %d, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, 8); ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size); ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer); @@ -92,8 +93,8 @@ void app_main(void) .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, + .input_data_color_type = CAM_CTLR_COLOR_RAW8, + .output_data_color_type = CAM_CTLR_COLOR_RGB565, .data_lane_num = 2, .byte_swap_en = false, .queue_items = 1, diff --git a/examples/peripherals/camera/camera_dsi/main/idf_component.yml b/examples/peripherals/camera/camera_dsi/main/idf_component.yml index f7121dc8c5..47d0275f00 100644 --- a/examples/peripherals/camera/camera_dsi/main/idf_component.yml +++ b/examples/peripherals/camera/camera_dsi/main/idf_component.yml @@ -4,4 +4,4 @@ dependencies: idf: version: ">=5.3.0" dsi_init: - path: ${IDF_PATH}/examples/peripherals/camera/components/dsi_init + path: ${IDF_PATH}/examples/peripherals/camera/camera_dsi/components/dsi_init diff --git a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme_sa.h b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme_sa.h index dd70f17d0c..b01ab5db66 100644 --- a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme_sa.h +++ b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme_sa.h @@ -52,7 +52,7 @@ typedef struct { * - ESP_ERR_INVALID_STATE Invalid state * - ESP_ERR_NO_MEM If out of memory */ -esp_err_t isp_af_create_sa_scheme(isp_af_ctrlr_t af_ctrlr, const isp_af_sa_scheme_config_t *config, isp_af_scheme_handle_t *ret_scheme); +esp_err_t isp_af_create_sa_scheme(isp_af_ctlr_t af_ctrlr, const isp_af_sa_scheme_config_t *config, isp_af_scheme_handle_t *ret_scheme); /** * @brief Delete an AF step approximation scheme diff --git a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c index b7b5502d52..9e8830b00d 100644 --- a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c +++ b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c @@ -21,7 +21,7 @@ static const char *TAG = "AF_SCHEME"; typedef struct { - isp_af_ctrlr_t af_ctlr; + isp_af_ctlr_t af_ctlr; int first_step_val; int first_approx_cycles; int second_step_val; @@ -36,7 +36,7 @@ typedef struct { static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_luminance_thresh); /* ------------------------- Public API ------------------------------------- */ -esp_err_t isp_af_create_sa_scheme(isp_af_ctrlr_t af_ctlr, const isp_af_sa_scheme_config_t *config, isp_af_scheme_handle_t *ret_scheme) +esp_err_t isp_af_create_sa_scheme(isp_af_ctlr_t af_ctlr, const isp_af_sa_scheme_config_t *config, isp_af_scheme_handle_t *ret_scheme) { esp_err_t ret = ESP_FAIL; ESP_RETURN_ON_FALSE(af_ctlr && config && ret_scheme, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer"); diff --git a/examples/peripherals/isp/auto_focus/main/idf_component.yml b/examples/peripherals/isp/auto_focus/main/idf_component.yml index 803bff156a..e424be9e27 100644 --- a/examples/peripherals/isp/auto_focus/main/idf_component.yml +++ b/examples/peripherals/isp/auto_focus/main/idf_component.yml @@ -6,4 +6,4 @@ dependencies: 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 + path: ${IDF_PATH}/examples/peripherals/camera/camera_dsi/components/dsi_init diff --git a/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c b/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c index 4ff9f323ef..0d8be2f9bb 100644 --- a/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c +++ b/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c @@ -25,6 +25,7 @@ #include "esp_cam_sensor.h" #include "ov5647.h" #include "example_dsi_init.h" +#include "example_dsi_init_config.h" #include "example_config.h" static const char *TAG = "isp_dsi"; @@ -46,7 +47,7 @@ typedef union { 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) +static bool IRAM_ATTR s_env_change_cb(isp_af_ctlr_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; @@ -119,7 +120,7 @@ static void af_task(void *arg) .edge_thresh = 128, }; - isp_af_ctrlr_t af_ctrlr = NULL; + isp_af_ctlr_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 = { @@ -185,9 +186,9 @@ void app_main(void) 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; + frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * 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, "CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES: %d, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, 8); ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size); ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer); @@ -226,8 +227,8 @@ void app_main(void) .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, + .input_data_color_type = CAM_CTLR_COLOR_RAW8, + .output_data_color_type = CAM_CTLR_COLOR_RGB565, .data_lane_num = 2, .byte_swap_en = false, .queue_items = 1,