feat(isp): added isp dvp driver

This commit is contained in:
Armando 2024-05-15 18:53:04 +08:00
parent 7425154472
commit 70d2ed5ee8
45 changed files with 1172 additions and 123 deletions

View File

@ -1,21 +1,29 @@
idf_build_get_property(target IDF_TARGET) 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) if(CONFIG_SOC_MIPI_CSI_SUPPORTED)
list(APPEND srcs "csi/src/esp_cam_ctlr_csi.c") list(APPEND srcs "csi/src/esp_cam_ctlr_csi.c")
list(APPEND include "csi/include") list(APPEND includes "csi/include")
endif() endif()
if(${target} STREQUAL "linux") if(CONFIG_SOC_ISP_DVP_SUPPORTED)
set(priv_requires "") list(APPEND srcs "isp_dvp/src/esp_cam_ctlr_isp_dvp.c")
else() list(APPEND includes "isp_dvp/include")
set(priv_requires esp_mm) endif()
if(NOT ${target} STREQUAL "linux")
list(APPEND requires esp_mm)
endif() endif()
idf_component_register(SRCS ${srcs} idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${include} INCLUDE_DIRS ${includes}
PRIV_REQUIRES "${priv_requires}" REQUIRES ${requires}
PRIV_REQUIRES ${priv_requires}
) )

View File

@ -1,11 +1,27 @@
menu "ESP Camera Controller Configurations" menu "ESP-Driver:Camera Controller Configurations"
depends on SOC_MIPI_CSI_SUPPORTED 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" bool "CSI ISR IRAM-Safe"
default n 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 help
Ensure the CSI driver ISR is IRAM-Safe. When enabled, the ISR handler Ensure the CSI driver ISR is IRAM-Safe. When enabled, the ISR handler
will be available when the cache is disabled. 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 endmenu # ESP Camera Controller Configurations

View File

@ -15,11 +15,6 @@
extern "C" { extern "C" {
#endif #endif
/**
* @brief ESP CAM controller max timeout value
*/
#define ESP_CAM_CTLR_MAX_DELAY UINT32_MAX
/** /**
* @brief ESP CAM CSI controller configurations * @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 uint32_t v_res; ///< Input vertical resolution, i.e. the number of lines in a frame
uint8_t data_lane_num; ///< Data lane num uint8_t data_lane_num; ///< Data lane num
int lane_bit_rate_mbps; ///< Lane bit rate in Mbps int lane_bit_rate_mbps; ///< Lane bit rate in Mbps
mipi_csi_color_t input_data_color_type; ///< Input color type cam_ctlr_color_t input_data_color_type; ///< Input color type
mipi_csi_color_t output_data_color_type; ///< Output color type cam_ctlr_color_t output_data_color_type; ///< Output color type
int queue_items; ///< Queue items int queue_items; ///< Queue items
struct { struct {
uint32_t byte_swap_en : 1; ///< Enable byte swap uint32_t byte_swap_en : 1; ///< Enable byte swap

View File

@ -24,7 +24,7 @@
#include "esp_private/esp_cache_private.h" #include "esp_private/esp_cache_private.h"
#include "esp_cache.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) #define CSI_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
#else #else
#define CSI_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT #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_enable_host_bus_clock(i, 1);
mipi_csi_ll_reset_host_clock(i); mipi_csi_ll_reset_host_clock(i);
} }
_lock_release(&s_platform.mutex);
break; 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; 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; bool need_yield = false;
BaseType_t high_task_woken = pdFALSE; 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); 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"); 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) { 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"); 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");
} }

View File

@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <esp_types.h>
#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;
}

View File

@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <esp_types.h>
#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

View File

@ -14,6 +14,11 @@
extern "C" { extern "C" {
#endif #endif
/**
* @brief ESP CAM controller max timeout value
*/
#define ESP_CAM_CTLR_MAX_DELAY UINT32_MAX
/** /**
* @brief ESP CAM controller handle * @brief ESP CAM controller handle
*/ */

View File

@ -0,0 +1,59 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#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

View File

@ -0,0 +1,568 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <esp_types.h>
#include <sys/lock.h>
#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;
}

View File

@ -16,8 +16,8 @@ TEST_CASE("TEST CSI driver allocation", "[csi]")
.h_res = 800, .h_res = 800,
.v_res = 640, .v_res = 640,
.lane_bit_rate_mbps = 200, .lane_bit_rate_mbps = 200,
.input_data_color_type = MIPI_CSI_COLOR_RAW8, .input_data_color_type = CAM_CTLR_COLOR_RAW8,
.output_data_color_type = MIPI_CSI_COLOR_RGB565, .output_data_color_type = CAM_CTLR_COLOR_RGB565,
.data_lane_num = 2, .data_lane_num = 2,
.byte_swap_en = false, .byte_swap_en = false,
.queue_items = 1, .queue_items = 1,
@ -42,8 +42,8 @@ TEST_CASE("TEST CSI driver no backup buffer usage", "[csi]")
.h_res = 800, .h_res = 800,
.v_res = 640, .v_res = 640,
.lane_bit_rate_mbps = 200, .lane_bit_rate_mbps = 200,
.input_data_color_type = MIPI_CSI_COLOR_RAW8, .input_data_color_type = CAM_CTLR_COLOR_RAW8,
.output_data_color_type = MIPI_CSI_COLOR_RGB565, .output_data_color_type = CAM_CTLR_COLOR_RGB565,
.data_lane_num = 2, .data_lane_num = 2,
.byte_swap_en = false, .byte_swap_en = false,
.queue_items = 1, .queue_items = 1,

View File

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

View File

@ -1,7 +1,13 @@
idf_build_get_property(target IDF_TARGET)
set(srcs) set(srcs)
set(public_include "include") set(public_include "include")
set(priv_requires "esp_driver_gpio")
set(requires)
if(CONFIG_SOC_ISP_SUPPORTED) if(CONFIG_SOC_ISP_SUPPORTED)
list(APPEND srcs "src/isp_core.c" list(APPEND srcs "src/isp_core.c"
"src/isp_af.c") "src/isp_af.c")
@ -11,7 +17,12 @@ if(CONFIG_SOC_ISP_BF_SUPPORTED)
list(APPEND srcs "src/isp_bf.c") list(APPEND srcs "src/isp_bf.c")
endif() endif()
if(NOT ${target} STREQUAL "linux")
list(APPEND requires esp_mm)
endif()
idf_component_register(SRCS ${srcs} idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${public_include} INCLUDE_DIRS ${public_include}
PRIV_REQUIRES esp_driver_gpio REQUIRES ${requires}
PRIV_REQUIRES ${priv_requires}
) )

View File

@ -38,7 +38,7 @@ typedef struct {
* - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags * - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags
* - ESP_ERR_NO_MEM If out of memory * - 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 * @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_ARG If the combination of arguments is invalid.
* - ESP_ERR_INVALID_STATE Driver state 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 * @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_ARG If the combination of arguments is invalid.
* - ESP_ERR_INVALID_STATE Driver state 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 * @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_ARG If the combination of arguments is invalid.
* - ESP_ERR_INVALID_STATE Driver state 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 * @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_ARG If the combination of arguments is invalid.
* - ESP_ERR_INVALID_STATE Driver state 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 */ /** @cond */
#define esp_isp_af_controller_get_oneshot_result(af_ctrlr, out_res) \ #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_ARG Null pointer
* - ESP_ERR_INVALID_STATE Driver state is invalid. * - 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 * @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_ARG Null pointer
* - ESP_ERR_INVALID_STATE Driver state is invalid. * - 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 AF Env Monitor
@ -152,7 +152,7 @@ typedef struct {
* - 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 Driver state 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 * @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_ARG If the combination of arguments is invalid.
* - ESP_ERR_INVALID_STATE Driver state 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 * @brief Event data structure
@ -184,7 +184,7 @@ typedef struct {
* *
* @return Whether a high priority task is woken up by this function * @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 * @brief Group of ISP AF Env detector callbacks
@ -215,7 +215,7 @@ typedef struct {
* - ESP_ERR_INVALID_ARG: Invalid arguments * - 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_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 #ifdef __cplusplus
} }

View File

@ -20,7 +20,7 @@ typedef struct isp_processor_t *isp_proc_handle_t;
/** /**
* @brief Type of ISP AF controller handle * @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 #ifdef __cplusplus
} }

View File

@ -19,11 +19,13 @@
#include "freertos/queue.h" #include "freertos/queue.h"
#include "freertos/idf_additions.h" #include "freertos/idf_additions.h"
#include "driver/isp_types.h" #include "driver/isp_types.h"
#include "soc/soc_caps.h"
#if SOC_ISP_SUPPORTED
#include "hal/isp_hal.h" #include "hal/isp_hal.h"
#include "hal/isp_ll.h" #include "hal/isp_ll.h"
#include "hal/isp_types.h" #include "hal/isp_types.h"
#include "soc/isp_periph.h" #include "soc/isp_periph.h"
#include "soc/soc_caps.h" #endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -43,23 +45,28 @@ typedef enum {
ISP_FSM_START, ISP_FSM_START,
} isp_fsm_t; } isp_fsm_t;
#if SOC_ISP_SUPPORTED
/*--------------------------------------------------------------- /*---------------------------------------------------------------
Driver Context Driver Context
---------------------------------------------------------------*/ ---------------------------------------------------------------*/
typedef struct isp_processor_t { typedef struct isp_processor_t {
int proc_id; int proc_id;
isp_hal_context_t hal; isp_hal_context_t hal;
#if SOC_ISP_SHARE_CSI_BRG #if SOC_ISP_SHARE_CSI_BRG
int csi_brg_id; int csi_brg_id;
void *csi_brg_hw; void *csi_brg_hw;
#endif #endif
isp_fsm_t isp_fsm; isp_fsm_t isp_fsm;
portMUX_TYPE spinlock; 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 */ /* sub module contexts */
isp_af_ctrlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS]; isp_af_ctlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS];
isp_fsm_t bf_fsm; isp_fsm_t bf_fsm;
} isp_processor_t; } isp_processor_t;
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -12,7 +12,7 @@
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "driver/isp_af.h" #include "driver/isp_af.h"
#include "isp_internal.h" #include "esp_private/isp_private.h"
static const char *TAG = "ISP_AF"; static const char *TAG = "ISP_AF";
@ -33,7 +33,7 @@ static void s_isp_af_default_isr(void *arg);
/*--------------------------------------------- /*---------------------------------------------
AF 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); 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; 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); 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); 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) {
if (af_ctlr->intr_handle) { 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_err_t ret = ESP_FAIL;
ESP_RETURN_ON_FALSE(isp_proc && af_config && ret_hdl, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); 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"); 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"); 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); 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"); 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; 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 && 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"); 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; 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 && 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"); 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; 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 && 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"); 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; 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 && (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"); 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; 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, 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"); 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; 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, 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"); 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 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 && 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"); 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; 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 && 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"); 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; 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, 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"); 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) 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; 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); uint32_t af_events = isp_hal_check_clear_intr_event(&proc->hal, ISP_LL_EVENT_AF_MASK);

View File

@ -19,7 +19,7 @@
#include "hal/hal_utils.h" #include "hal/hal_utils.h"
#include "soc/mipi_csi_bridge_struct.h" #include "soc/mipi_csi_bridge_struct.h"
#include "soc/isp_periph.h" #include "soc/isp_periph.h"
#include "isp_internal.h" #include "esp_private/isp_private.h"
static const char *TAG = "ISP_BF"; static const char *TAG = "ISP_BF";

View File

@ -19,7 +19,7 @@
#include "hal/hal_utils.h" #include "hal/hal_utils.h"
#include "soc/mipi_csi_bridge_struct.h" #include "soc/mipi_csi_bridge_struct.h"
#include "soc/isp_periph.h" #include "soc/isp_periph.h"
#include "isp_internal.h" #include "esp_private/isp_private.h"
typedef struct isp_platform_t { typedef struct isp_platform_t {
_lock_t mutex; _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_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 && 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"); 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); 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_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); 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; *ret_proc = proc;
return ESP_OK; return ESP_OK;

View File

@ -8,6 +8,7 @@ endif()
set(priv_requires set(priv_requires
unity unity
esp_driver_isp esp_driver_isp
esp_psram
) )
idf_component_register(SRCS ${srcs} idf_component_register(SRCS ${srcs}

View File

@ -7,8 +7,8 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#include "unity.h" #include "unity.h"
#include "driver/isp.h" #include "driver/isp.h"
#include "esp_private/isp_dvp_private.h"
#include "esp_rom_sys.h" #include "soc/soc_caps.h"
TEST_CASE("ISP processor exhausted allocation", "[isp]") 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]") TEST_CASE("ISP AF controller exhausted allocation", "[isp]")
{ {
esp_isp_processor_cfg_t isp_config = { 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 = { esp_isp_af_config_t af_config = {
.edge_thresh = 128, .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++) { 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])); TEST_ESP_OK(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr[i]));
} }

View File

@ -1,2 +1,5 @@
CONFIG_FREERTOS_HZ=1000 CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT_EN=n CONFIG_ESP_TASK_WDT_EN=n
CONFIG_SPIRAM=y
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
CONFIG_SPIRAM_SPEED_200M=y

View File

@ -16,7 +16,7 @@
static const char *TAG = "esp_clk_tree"; 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, 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(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"); ESP_RETURN_ON_FALSE(precision < ESP_CLK_TREE_SRC_FREQ_PRECISION_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown precision");

View File

@ -76,6 +76,13 @@ extern "C" {
---------------------------------------------------------------*/ ---------------------------------------------------------------*/
#define ISP_LL_BF_DEFAULT_TEMPLATE_VAL 15 #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 * @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; 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 INTR
---------------------------------------------------------------*/ ---------------------------------------------------------------*/

View File

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

View File

@ -45,6 +45,15 @@ typedef enum {
ISP_COLOR_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), ///< YUV420 ISP_COLOR_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), ///< YUV420
} isp_color_t; } 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 AF
---------------------------------------------------------------*/ ---------------------------------------------------------------*/

View File

@ -10,6 +10,7 @@
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "soc/clk_tree_defs.h" #include "soc/clk_tree_defs.h"
#include "hal/color_types.h" #include "hal/color_types.h"
#include "hal/cam_ctlr_types.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { 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; typedef int mipi_csi_phy_clock_source_t;
#endif // SOC_MIPI_CSI_SUPPORTED #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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -763,10 +763,18 @@ config SOC_ISP_BF_SUPPORTED
bool bool
default y default y
config SOC_ISP_DVP_SUPPORTED
bool
default y
config SOC_ISP_NUMS config SOC_ISP_NUMS
int int
default 1 default 1
config SOC_ISP_DVP_CTLR_NUMS
int
default 1
config SOC_ISP_AF_CTLR_NUMS config SOC_ISP_AF_CTLR_NUMS
int int
default 1 default 1
@ -787,6 +795,10 @@ config SOC_ISP_BF_TEMPLATE_Y_NUMS
int int
default 3 default 3
config SOC_ISP_DVP_DATA_WIDTH_MAX
int
default 16
config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
bool bool
default y default y

View File

@ -313,13 +313,16 @@
/*-------------------------- ISP CAPS ----------------------------------------*/ /*-------------------------- ISP CAPS ----------------------------------------*/
#define SOC_ISP_BF_SUPPORTED 1 #define SOC_ISP_BF_SUPPORTED 1
#define SOC_ISP_DVP_SUPPORTED 1
#define SOC_ISP_NUMS 1U #define SOC_ISP_NUMS 1U
#define SOC_ISP_DVP_CTLR_NUMS 1U
#define SOC_ISP_AF_CTLR_NUMS 1U #define SOC_ISP_AF_CTLR_NUMS 1U
#define SOC_ISP_AF_WINDOW_NUMS 3 #define SOC_ISP_AF_WINDOW_NUMS 3
#define SOC_ISP_SHARE_CSI_BRG 1 #define SOC_ISP_SHARE_CSI_BRG 1
#define SOC_ISP_BF_TEMPLATE_X_NUMS 3 #define SOC_ISP_BF_TEMPLATE_X_NUMS 3
#define SOC_ISP_BF_TEMPLATE_Y_NUMS 3 #define SOC_ISP_BF_TEMPLATE_Y_NUMS 3
#define SOC_ISP_DVP_DATA_WIDTH_MAX 16
/*-------------------------- LEDC CAPS ---------------------------------------*/ /*-------------------------- LEDC CAPS ---------------------------------------*/
#define SOC_LEDC_SUPPORT_PLL_DIV_CLOCK (1) #define SOC_LEDC_SUPPORT_PLL_DIV_CLOCK (1)

View File

@ -16,6 +16,32 @@ const isp_info_t isp_hw_info = {
[0] = { [0] = {
.irq = ETS_ISP_INTR_SOURCE, .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
},
},
} }
}; };

View File

@ -9,6 +9,7 @@
#include <stdint.h> #include <stdint.h>
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "soc/periph_defs.h" #include "soc/periph_defs.h"
#include "soc/gpio_sig_map.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -19,6 +20,13 @@ typedef struct {
struct { struct {
const uint32_t irq; const uint32_t irq;
} instances[SOC_ISP_NUMS]; } 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; } isp_info_t;
extern const isp_info_t isp_hw_info; extern const isp_info_t isp_hw_info;

View File

@ -48,8 +48,8 @@ Resource Allocation
.h_res = MIPI_CSI_DISP_HSIZE, .h_res = MIPI_CSI_DISP_HSIZE,
.v_res = MIPI_CSI_DISP_VSIZE_640P, .v_res = MIPI_CSI_DISP_VSIZE_640P,
.lane_bit_rate_mbps = MIPI_CSI_LANE_BITRATE_MBPS, .lane_bit_rate_mbps = MIPI_CSI_LANE_BITRATE_MBPS,
.input_data_color_type = MIPI_CSI_COLOR_RAW8, .input_data_color_type = CAM_CTLR_COLOR_RAW8,
.output_data_color_type = MIPI_CSI_COLOR_RGB565, .output_data_color_type = CAM_CTLR_COLOR_RGB565,
.data_lane_num = 2, .data_lane_num = 2,
.byte_swap_en = false, .byte_swap_en = false,
.queue_items = 1, .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 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: .. _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. 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 - Enables the interrupt being serviced even when the cache is disabled
- Places all functions that used by the ISR into IRAM - Places all functions that used by the ISR into IRAM

View File

@ -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 = { esp_isp_af_config_t af_config = {
.edge_thresh = 128, .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_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. 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 = { esp_isp_af_config_t af_config = {
.edge_thresh = 128, .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_new_af_controller(isp_proc, &af_config, &af_ctrlr));
ESP_ERROR_CHECK(esp_isp_af_controller_enable(af_ctrlr)); ESP_ERROR_CHECK(esp_isp_af_controller_enable(af_ctrlr));
isp_af_result_t result = {}; 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 .. code:: c
isp_af_ctrlr_t af_ctrlr = NULL; isp_af_ctlr_t af_ctrlr = NULL;
esp_isp_af_config_t af_config = { esp_isp_af_config_t af_config = {
.edge_thresh = 128, .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 = { esp_isp_af_env_config_t env_config = {
.interval = 10, .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_new_af_controller(isp_proc, &af_config, &af_ctrlr));
ESP_ERROR_CHECK(esp_isp_af_controller_set_env_detector(af_ctrlr, &env_config)); ESP_ERROR_CHECK(esp_isp_af_controller_set_env_detector(af_ctrlr, &env_config));

View File

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

View File

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

View File

@ -10,6 +10,7 @@
#include "esp_lcd_panel_ops.h" #include "esp_lcd_panel_ops.h"
#include "esp_lcd_ili9881c.h" #include "esp_lcd_ili9881c.h"
#include "example_dsi_init.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) 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, .virtual_channel = 0,
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565, .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
.video_timing = { .video_timing = {
.h_size = EXAMPLE_MIPI_DSI_IMAGE_HSIZE, .h_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES,
.v_size = EXAMPLE_MIPI_DSI_IMAGE_VSIZE, .v_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES,
.hsync_back_porch = EXAMPLE_MIPI_DSI_IMAGE_HBP, .hsync_back_porch = EXAMPLE_MIPI_DSI_IMAGE_HBP,
.hsync_pulse_width = EXAMPLE_MIPI_DSI_IMAGE_HSYNC, .hsync_pulse_width = EXAMPLE_MIPI_DSI_IMAGE_HSYNC,
.hsync_front_porch = EXAMPLE_MIPI_DSI_IMAGE_HFP, .hsync_front_porch = EXAMPLE_MIPI_DSI_IMAGE_HFP,

View File

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

View File

@ -6,19 +6,14 @@
#pragma once #pragma once
#include "esp_lcd_mipi_dsi.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_ili9881c.h"
#ifdef __cplusplus #ifdef __cplusplus
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,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

View File

@ -1,4 +1,4 @@
idf_component_register(SRCS "camera_dsi_main.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 dsi_init REQUIRES esp_mm esp_driver_isp esp_driver_cam esp_driver_i2c dsi_init
) )

View File

@ -23,6 +23,7 @@
#include "esp_cam_sensor.h" #include "esp_cam_sensor.h"
#include "ov5647.h" #include "ov5647.h"
#include "example_dsi_init.h" #include "example_dsi_init.h"
#include "example_dsi_init_config.h"
#include "example_config.h" #include "example_config.h"
static const char *TAG = "cam_dsi"; 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); example_dsi_resource_alloc(&ili9881c_ctrl_panel, &mipi_dpi_panel, &frame_buffer);
//---------------Necessary variable config------------------// //---------------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_size: %zu", frame_buffer_size);
ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer); ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer);
@ -92,8 +93,8 @@ void app_main(void)
.h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, .h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES,
.v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES, .v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES,
.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 = CAM_CTLR_COLOR_RAW8,
.output_data_color_type = MIPI_CSI_COLOR_RGB565, .output_data_color_type = CAM_CTLR_COLOR_RGB565,
.data_lane_num = 2, .data_lane_num = 2,
.byte_swap_en = false, .byte_swap_en = false,
.queue_items = 1, .queue_items = 1,

View File

@ -4,4 +4,4 @@ dependencies:
idf: idf:
version: ">=5.3.0" version: ">=5.3.0"
dsi_init: dsi_init:
path: ${IDF_PATH}/examples/peripherals/camera/components/dsi_init path: ${IDF_PATH}/examples/peripherals/camera/camera_dsi/components/dsi_init

View File

@ -52,7 +52,7 @@ typedef struct {
* - ESP_ERR_INVALID_STATE Invalid state * - ESP_ERR_INVALID_STATE Invalid state
* - ESP_ERR_NO_MEM If out of memory * - 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 * @brief Delete an AF step approximation scheme

View File

@ -21,7 +21,7 @@
static const char *TAG = "AF_SCHEME"; static const char *TAG = "AF_SCHEME";
typedef struct { typedef struct {
isp_af_ctrlr_t af_ctlr; isp_af_ctlr_t af_ctlr;
int first_step_val; int first_step_val;
int first_approx_cycles; int first_approx_cycles;
int second_step_val; 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); static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_luminance_thresh);
/* ------------------------- Public API ------------------------------------- */ /* ------------------------- 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_err_t ret = ESP_FAIL;
ESP_RETURN_ON_FALSE(af_ctlr && config && ret_scheme, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer"); ESP_RETURN_ON_FALSE(af_ctlr && config && ret_scheme, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer");

View File

@ -6,4 +6,4 @@ dependencies:
isp_af_schemes: isp_af_schemes:
path: ${IDF_PATH}/examples/peripherals/isp/auto_focus/components/isp_af_schemes path: ${IDF_PATH}/examples/peripherals/isp/auto_focus/components/isp_af_schemes
dsi_init: dsi_init:
path: ${IDF_PATH}/examples/peripherals/camera/components/dsi_init path: ${IDF_PATH}/examples/peripherals/camera/camera_dsi/components/dsi_init

View File

@ -25,6 +25,7 @@
#include "esp_cam_sensor.h" #include "esp_cam_sensor.h"
#include "ov5647.h" #include "ov5647.h"
#include "example_dsi_init.h" #include "example_dsi_init.h"
#include "example_dsi_init_config.h"
#include "example_config.h" #include "example_config.h"
static const char *TAG = "isp_dsi"; static const char *TAG = "isp_dsi";
@ -46,7 +47,7 @@ typedef union {
uint16_t val; uint16_t val;
} dw9714_reg_t; } 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; BaseType_t mustYield = pdFALSE;
TaskHandle_t task_handle = (TaskHandle_t)user_data; TaskHandle_t task_handle = (TaskHandle_t)user_data;
@ -119,7 +120,7 @@ static void af_task(void *arg)
.edge_thresh = 128, .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_ERROR_CHECK(esp_isp_new_af_controller(af_task_param.isp_proc, &af_config, &af_ctrlr));
esp_isp_af_env_config_t env_config = { 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); example_dsi_resource_alloc(&ili9881c_ctrl_panel, &mipi_dpi_panel, &frame_buffer);
//---------------Necessary variable config------------------// //---------------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_size: %zu", frame_buffer_size);
ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer); ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer);
@ -226,8 +227,8 @@ void app_main(void)
.h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, .h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES,
.v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES, .v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES,
.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 = CAM_CTLR_COLOR_RAW8,
.output_data_color_type = MIPI_CSI_COLOR_RGB565, .output_data_color_type = CAM_CTLR_COLOR_RGB565,
.data_lane_num = 2, .data_lane_num = 2,
.byte_swap_en = false, .byte_swap_en = false,
.queue_items = 1, .queue_items = 1,