feat(isp): support isp dma input and add example

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
gaoxu
2026-07-28 14:37:45 +08:00
committed by Gao Xu
co-authored by Cursor
parent 4966865e30
commit 2a02c7e55c
17 changed files with 906 additions and 20 deletions
+7 -1
View File
@@ -6,10 +6,16 @@ set(public_include "include")
set(priv_requires "esp_driver_gpio")
set(requires)
if(${target} STREQUAL "linux")
set(requires "")
else()
set(requires "esp_hw_support" "esp_mm")
endif()
if(CONFIG_SOC_ISP_SUPPORTED)
list(APPEND srcs "src/isp_core.c"
"src/isp_dma.c"
"src/isp_af.c"
"src/isp_ccm.c"
"src/isp_awb.c"
@@ -32,6 +32,7 @@ typedef struct {
uint32_t h_res; ///< Input horizontal resolution, i.e. the number of pixels in a line
uint32_t v_res; ///< Input vertical resolution, i.e. the number of lines in a frame
color_raw_element_order_t bayer_order; ///< Bayer order
uint32_t dma_burst_size; ///< DMA output burst length in units of 64-bit beats. Set to 0 to use default value 16
int intr_priority; ///< The interrupt priority, range 0~3, if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3)
struct {
uint32_t bypass_isp : 1; ///< Bypass ISP pipelines
@@ -0,0 +1,39 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stddef.h>
#include "esp_err.h"
#include "driver/isp_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Process one ISP DMA frame: feed the input buffer through the ISP and wait for completion
*
* @note Input buffer content should be ready before calling this function. If the buffers are in
* cacheable memory, the caller should synchronize them around DMA access. Buffer sizes are
* derived from the ISP processor resolution and pixel formats. Both buffers must be 8-byte
* aligned. This function blocks until both input and output DMA channels finish.
*
* @param[in] proc Processor handle
* @param[in] output_buffer Destination buffer for ISP output (8-byte aligned)
* @param[in] input_buffer Source input buffer for RAW frame data (8-byte aligned)
* @param[in] timeout_ms Timeout in milliseconds for waiting transfer completion
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_ARG Invalid argument
* - ESP_ERR_TIMEOUT Wait timeout
*/
esp_err_t esp_isp_dma_process_frame(isp_proc_handle_t proc, void *output_buffer, const void *input_buffer, uint32_t timeout_ms);
#ifdef __cplusplus
}
#endif
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -60,6 +60,8 @@ typedef enum {
/*---------------------------------------------------------------
Driver Context
---------------------------------------------------------------*/
typedef struct esp_isp_dma_frame_ctx_t esp_isp_dma_frame_ctx_t;
typedef struct isp_processor_t {
int proc_id;
isp_clk_src_t clk_src;
@@ -72,10 +74,14 @@ typedef struct isp_processor_t {
portMUX_TYPE spinlock;
color_space_pixel_format_t in_color_format;
color_space_pixel_format_t out_color_format;
isp_input_data_source_t input_data_source;
uint32_t h_res;
uint32_t v_res;
color_raw_element_order_t bayer_order;
bool bypass_isp;
uint32_t dma_in_burst_len; // ISP DMA input burst length (64-bit beats), kept in sync with the input GDMA dst MSIZE
uint32_t dma_out_burst_len; // ISP DMA output burst length (64-bit beats)
esp_isp_dma_frame_ctx_t *dma_frame_ctx;
/* sub module contexts */
isp_af_ctlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS];
isp_awb_ctlr_t awb_ctlr;
@@ -133,6 +139,45 @@ bool esp_isp_awb_isr(isp_proc_handle_t proc, uint32_t awb_events);
bool esp_isp_sharpen_isr(isp_proc_handle_t proc, uint32_t sharp_events);
bool esp_isp_hist_isr(isp_proc_handle_t proc, uint32_t hist_events);
/*---------------------------------------------------------------
DMA INPUT
---------------------------------------------------------------*/
/**
* @brief Configure the ISP DMA input path (frame size, burst length, data type)
*
* @note Internal helper invoked while creating a processor whose input source is DWGDMA.
*
* @param[in] proc Processor handle
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_ARG Invalid input color format or frame size
*/
esp_err_t isp_dma_configure_input(isp_proc_handle_t proc);
/**
* @brief Create the ISP DMA frame context
*
* @note Internal helper invoked while creating a processor whose input source is DWGDMA.
*
* @param[in] proc Processor handle
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_ARG Invalid processor, burst length, or frame size
* - ESP_ERR_INVALID_STATE Processor input source is not DWGDMA or the context already exists
* - ESP_ERR_NO_MEM Failed to allocate the context or synchronization objects
* - Other errors returned by the underlying DMA driver
*/
esp_err_t isp_dma_new_frame_ctx(isp_proc_handle_t proc);
/**
* @brief Delete the ISP DMA frame context
*
* @param[in] proc Processor handle
*/
void isp_dma_del_frame_ctx(isp_proc_handle_t proc);
#ifdef __cplusplus
}
#endif
+46 -16
View File
@@ -18,6 +18,7 @@
#include "esp_private/mipi_csi_share_hw_ctrl.h"
#include "hal/hal_utils.h"
#include "hal/color_hal.h"
#include "hal/mipi_csi_brg_ll.h"
#include "soc/mipi_csi_bridge_struct.h"
#include "soc/isp_periph.h"
#include "soc/soc_caps.h"
@@ -79,7 +80,19 @@ 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->h_res <= ISP_LL_HSIZE_MAX, ESP_ERR_INVALID_ARG, TAG, "invalid h_res");
ESP_RETURN_ON_FALSE(proc_config->input_data_source != ISP_INPUT_DATA_SOURCE_DWGDMA, ESP_ERR_NOT_SUPPORTED, TAG, "input source not supported yet");
if (proc_config->input_data_source == ISP_INPUT_DATA_SOURCE_DWGDMA) {
ESP_RETURN_ON_FALSE((proc_config->input_data_color_type == ISP_COLOR_RAW8) ||
(proc_config->input_data_color_type == ISP_COLOR_RAW10) ||
(proc_config->input_data_color_type == ISP_COLOR_RAW12),
ESP_ERR_INVALID_ARG, TAG, "dma input only supports RAW8/RAW10/RAW12");
uint32_t in_bits_per_pixel = color_hal_pixel_format_get_bit_depth((color_space_pixel_format_t) {
.color_type_id = proc_config->input_data_color_type,
});
uint64_t frame_bits = (uint64_t)proc_config->h_res * proc_config->v_res * in_bits_per_pixel;
ESP_RETURN_ON_FALSE((frame_bits % 64) == 0, ESP_ERR_INVALID_ARG, TAG, "frame bits should be 64-bit aligned");
ESP_RETURN_ON_FALSE((frame_bits / 64) <= ((1UL << 22) - 1), ESP_ERR_INVALID_ARG, TAG, "frame size exceeds hardware limit");
ESP_RETURN_ON_FALSE(proc_config->dma_burst_size <= 16, ESP_ERR_INVALID_ARG, TAG, "dma burst size out of range");
}
if (proc_config->flags.bypass_isp) {
ESP_RETURN_ON_FALSE(proc_config->input_data_color_type == proc_config->output_data_color_type, ESP_ERR_INVALID_ARG, TAG, "isp is bypassed, input and output data color type should be same");
}
@@ -176,7 +189,9 @@ esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_
isp_ll_yuv_set_range(proc->hal.hw, proc_config->yuv_range);
}
if (out_color_format.color_space == COLOR_SPACE_RGB && proc_config->input_data_source == ISP_INPUT_DATA_SOURCE_DVP) {
if ((out_color_format.color_type_id == ISP_COLOR_RGB888 || out_color_format.color_type_id == ISP_COLOR_RGB565) &&
(proc_config->input_data_source == ISP_INPUT_DATA_SOURCE_DVP ||
proc_config->input_data_source == ISP_INPUT_DATA_SOURCE_DWGDMA)) {
isp_ll_color_enable(proc->hal.hw, true); // workaround for DIG-474
}
if (proc_config->flags.byte_swap_en) {
@@ -187,16 +202,23 @@ esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_
proc->in_color_format = in_color_format;
proc->out_color_format = out_color_format;
proc->input_data_source = proc_config->input_data_source;
proc->h_res = proc_config->h_res;
proc->v_res = proc_config->v_res;
proc->bayer_order = proc_config->bayer_order;
proc->bypass_isp = proc_config->flags.bypass_isp;
proc->dma_out_burst_len = proc_config->dma_burst_size;
if (proc->input_data_source == ISP_INPUT_DATA_SOURCE_DWGDMA) {
ESP_GOTO_ON_ERROR(isp_dma_configure_input(proc), err, TAG, "configure dma input failed");
ESP_GOTO_ON_ERROR(isp_dma_new_frame_ctx(proc), err, TAG, "create dma frame context failed");
}
*ret_proc = proc;
return ESP_OK;
err:
isp_dma_del_frame_ctx(proc);
if (proc->intr_hdl) {
esp_isp_deregister_isr(proc, ISP_SUBMODULE_GENERAL);
}
@@ -210,6 +232,8 @@ esp_err_t esp_isp_del_processor(isp_proc_handle_t proc)
ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
ESP_RETURN_ON_FALSE(atomic_load(&proc->isp_fsm) == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "processor isn't in init state");
isp_dma_del_frame_ctx(proc);
//declaim first, then do free
ESP_RETURN_ON_ERROR(s_isp_declaim_processor(proc), TAG, "declaim processor fail");
#if SOC_ISP_SHARE_CSI_BRG
@@ -341,20 +365,26 @@ static void IRAM_ATTR s_isp_isr_dispatcher(void *arg)
do_dispatch = false;
}
if ((error_events & ISP_LL_EVENT_DATA_TYPE_ERR) || (error_events & ISP_LL_EVENT_DATA_TYPE_SETTING_ERR)) {
ESP_EARLY_LOGE(TAG, "data type error");
}
if ((error_events & ISP_LL_EVENT_ASYNC_FIFO_OVF) || (error_events & ISP_LL_EVENT_BUF_FULL)) {
ESP_EARLY_LOGE(TAG, "fifo overflow");
}
if ((error_events & ISP_LL_EVENT_HVNUM_SETTING_ERR) || (error_events & ISP_LL_EVENT_MIPI_HNUM_UNMATCH)) {
ESP_EARLY_LOGE(TAG, "hnum / vnum setting error");
}
if (error_events & ISP_LL_EVENT_GAMMA_XCOORD_ERR) {
ESP_EARLY_LOGE(TAG, "gamma xcoord error");
}
if (error_events & ISP_LL_EVENT_CROP_ERR) {
ESP_EARLY_LOGE(TAG, "crop error");
if (error_events) {
if ((error_events & ISP_LL_EVENT_DATA_TYPE_ERR) || (error_events & ISP_LL_EVENT_DATA_TYPE_SETTING_ERR)) {
ESP_EARLY_LOGE(TAG, "data type error");
}
if ((error_events & ISP_LL_EVENT_ASYNC_FIFO_OVF)) {
ESP_EARLY_LOGE(TAG, "fifo overflow");
}
if ((error_events & ISP_LL_EVENT_BUF_FULL)) {
//This error does not affect the operation of the ISP
ESP_EARLY_LOGD(TAG, "buffer full");
}
if ((error_events & ISP_LL_EVENT_HVNUM_SETTING_ERR) || (error_events & ISP_LL_EVENT_MIPI_HNUM_UNMATCH)) {
ESP_EARLY_LOGE(TAG, "hnum / vnum setting error");
}
if (error_events & ISP_LL_EVENT_GAMMA_XCOORD_ERR) {
ESP_EARLY_LOGE(TAG, "gamma xcoord error");
}
if (error_events & ISP_LL_EVENT_CROP_ERR) {
ESP_EARLY_LOGE(TAG, "crop error");
}
}
if (need_yield) {
+265
View File
@@ -0,0 +1,265 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <assert.h>
#include <esp_types.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "driver/isp_dma.h"
#include "esp_private/dw_gdma.h"
#include "esp_private/isp_private.h"
#include "hal/color_hal.h"
#include "hal/isp_ll.h"
#include "hal/mipi_csi_brg_ll.h"
#define ISP_DMA_IN_BURST_LEN_DFT 8
#define ISP_DMA_OUT_BURST_LEN_DFT 16
struct esp_isp_dma_frame_ctx_t {
isp_proc_handle_t proc;
csi_brg_dev_t *csi_brg_hw;
dw_gdma_channel_handle_t dma_in_chan;
dw_gdma_channel_handle_t dma_out_chan;
SemaphoreHandle_t in_done_sem;
SemaphoreHandle_t out_done_sem;
dw_gdma_block_transfer_config_t dma_out_trans;
dw_gdma_block_transfer_config_t dma_in_trans;
uint32_t input_frame_size_64bit;
uint32_t output_frame_size_64bit;
};
static const char *TAG = "ISP_DMA";
static bool IRAM_ATTR s_isp_dma_done_cb(dw_gdma_channel_handle_t chan, const dw_gdma_trans_done_event_data_t *event_data, void *user_data)
{
(void)chan;
(void)event_data;
BaseType_t high_task_woken = pdFALSE;
xSemaphoreGiveFromISR(*(SemaphoreHandle_t *)user_data, &high_task_woken);
return high_task_woken == pdTRUE;
}
static dw_gdma_burst_items_t s_isp_dma_burst_len_to_items(uint32_t burst_len)
{
switch (burst_len) {
case 1: return DW_GDMA_BURST_ITEMS_1;
case 4: return DW_GDMA_BURST_ITEMS_4;
case 8: return DW_GDMA_BURST_ITEMS_8;
default: return DW_GDMA_BURST_ITEMS_8;
}
}
static void s_isp_dma_frame_ctx_destroy(struct esp_isp_dma_frame_ctx_t *ctx)
{
if (!ctx) {
return;
}
if (ctx->csi_brg_hw) {
mipi_csi_brg_ll_enable(ctx->csi_brg_hw, false);
}
if (ctx->dma_in_chan) {
dw_gdma_channel_enable_ctrl(ctx->dma_in_chan, false);
dw_gdma_del_channel(ctx->dma_in_chan);
}
if (ctx->dma_out_chan) {
dw_gdma_channel_enable_ctrl(ctx->dma_out_chan, false);
dw_gdma_del_channel(ctx->dma_out_chan);
}
if (ctx->in_done_sem) {
vSemaphoreDelete(ctx->in_done_sem);
}
if (ctx->out_done_sem) {
vSemaphoreDelete(ctx->out_done_sem);
}
free(ctx);
}
esp_err_t isp_dma_configure_input(isp_proc_handle_t proc)
{
ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(proc->input_data_source == ISP_INPUT_DATA_SOURCE_DWGDMA, ESP_ERR_INVALID_ARG, TAG, "processor input source is not dwgdma");
bool valid_format = isp_ll_dma_set_data_type(proc->hal.hw, (isp_color_t)proc->in_color_format.color_type_id);
ESP_RETURN_ON_FALSE(valid_format, ESP_ERR_INVALID_ARG, TAG, "dma input only supports RAW8/RAW10/RAW12");
uint32_t in_bits_per_pixel = color_hal_pixel_format_get_bit_depth(proc->in_color_format);
uint64_t frame_bits = (uint64_t)proc->h_res * proc->v_res * in_bits_per_pixel;
ESP_RETURN_ON_FALSE((frame_bits % 64) == 0, ESP_ERR_INVALID_ARG, TAG, "frame bits should be 64-bit aligned");
uint64_t frame_size_in_64bit = frame_bits / 64;
ESP_RETURN_ON_FALSE(frame_size_in_64bit <= ((1UL << 22) - 1), ESP_ERR_INVALID_ARG, TAG, "frame size exceeds hardware limit");
/*
* The input burst length is fixed at ISP_DMA_IN_BURST_LEN_DFT: it must be representable as a
* DW-GDMA MSIZE (1/4/8) and not exceed the ISP input async FIFO capacity (8 x 64-bit). It also
* has to equal the input GDMA dst MSIZE (derived from proc->dma_in_burst_len in
* isp_dma_new_frame_ctx), otherwise the async FIFO overflows.
*/
isp_ll_dma_set_frame_size(proc->hal.hw, (uint32_t)frame_size_in_64bit);
isp_ll_dma_set_burst_len(proc->hal.hw, ISP_DMA_IN_BURST_LEN_DFT);
isp_ll_dma_apply_config(proc->hal.hw);
proc->dma_in_burst_len = ISP_DMA_IN_BURST_LEN_DFT;
return ESP_OK;
}
esp_err_t isp_dma_new_frame_ctx(isp_proc_handle_t proc)
{
esp_err_t ret = ESP_FAIL;
ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(proc->input_data_source == ISP_INPUT_DATA_SOURCE_DWGDMA, ESP_ERR_INVALID_STATE, TAG, "processor input source is not dwgdma");
ESP_RETURN_ON_FALSE(!proc->dma_frame_ctx, ESP_ERR_INVALID_STATE, TAG, "dma frame context already exists");
uint32_t output_burst_len = proc->dma_out_burst_len ? proc->dma_out_burst_len : ISP_DMA_OUT_BURST_LEN_DFT;
ESP_RETURN_ON_FALSE(output_burst_len > 0 && output_burst_len <= 16, ESP_ERR_INVALID_ARG, TAG, "output burst len out of range");
uint32_t in_bits_per_pixel = color_hal_pixel_format_get_bit_depth(proc->in_color_format);
uint32_t out_bits_per_pixel = color_hal_pixel_format_get_bit_depth(proc->out_color_format);
uint64_t input_frame_bits = (uint64_t)proc->h_res * proc->v_res * in_bits_per_pixel;
uint64_t output_frame_bits = (uint64_t)proc->h_res * proc->v_res * out_bits_per_pixel;
ESP_RETURN_ON_FALSE((input_frame_bits % 64) == 0, ESP_ERR_INVALID_ARG, TAG, "input frame bits should be 64-bit aligned");
ESP_RETURN_ON_FALSE((output_frame_bits % 64) == 0, ESP_ERR_INVALID_ARG, TAG, "output frame bits should be 64-bit aligned");
struct esp_isp_dma_frame_ctx_t *ctx = heap_caps_calloc(1, sizeof(struct esp_isp_dma_frame_ctx_t), ISP_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(ctx, ESP_ERR_NO_MEM, err, TAG, "no mem for dma frame context");
ctx->proc = proc;
ctx->input_frame_size_64bit = input_frame_bits / 64;
ctx->output_frame_size_64bit = output_frame_bits / 64;
csi_brg_dev_t *csi_brg_hw = MIPI_CSI_BRG_LL_GET_HW(proc->csi_brg_id);
ctx->csi_brg_hw = csi_brg_hw;
mipi_csi_brg_ll_set_intput_data_h_pixel_num(csi_brg_hw, proc->h_res);
mipi_csi_brg_ll_set_intput_data_v_row_num(csi_brg_hw, proc->v_res);
mipi_csi_brg_ll_set_burst_len(csi_brg_hw, 512);
mipi_csi_brg_ll_enable(csi_brg_hw, true);
ctx->out_done_sem = xSemaphoreCreateBinary();
ESP_GOTO_ON_FALSE(ctx->out_done_sem, ESP_ERR_NO_MEM, err, TAG, "no mem for output semaphore");
ctx->in_done_sem = xSemaphoreCreateBinary();
ESP_GOTO_ON_FALSE(ctx->in_done_sem, ESP_ERR_NO_MEM, err, TAG, "no mem for input semaphore");
dw_gdma_channel_alloc_config_t dma_out_alloc = {
.src = {
.block_transfer_type = DW_GDMA_BLOCK_TRANSFER_CONTIGUOUS,
.role = DW_GDMA_ROLE_PERIPH_CSI,
.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_GOTO_ON_ERROR(dw_gdma_new_channel(&dma_out_alloc, &ctx->dma_out_chan), err, TAG, "create output dma channel failed");
dw_gdma_channel_alloc_config_t dma_in_alloc = {
.src = {
.block_transfer_type = DW_GDMA_BLOCK_TRANSFER_CONTIGUOUS,
.role = DW_GDMA_ROLE_MEM,
.handshake_type = DW_GDMA_HANDSHAKE_SW,
.num_outstanding_requests = 2,
},
.dst = {
.block_transfer_type = DW_GDMA_BLOCK_TRANSFER_CONTIGUOUS,
.role = DW_GDMA_ROLE_PERIPH_ISP,
.handshake_type = DW_GDMA_HANDSHAKE_HW,
.num_outstanding_requests = 1,
},
.flow_controller = DW_GDMA_FLOW_CTRL_DST,
.chan_priority = 1,
};
ESP_GOTO_ON_ERROR(dw_gdma_new_channel(&dma_in_alloc, &ctx->dma_in_chan), err, TAG, "create input dma channel failed");
ctx->dma_out_trans = (dw_gdma_block_transfer_config_t) {
.src = {
.addr = MIPI_CSI_BRG_MEM_BASE,
.width = DW_GDMA_TRANS_WIDTH_64,
.burst_mode = DW_GDMA_BURST_MODE_FIXED,
.burst_items = DW_GDMA_BURST_ITEMS_512,
.burst_len = output_burst_len,
},
.dst = {
.width = DW_GDMA_TRANS_WIDTH_64,
.burst_mode = DW_GDMA_BURST_MODE_INCREMENT,
.burst_items = DW_GDMA_BURST_ITEMS_512,
.burst_len = output_burst_len,
},
.size = ctx->output_frame_size_64bit,
};
ctx->dma_in_trans = (dw_gdma_block_transfer_config_t) {
.src = {
.width = DW_GDMA_TRANS_WIDTH_64,
.burst_mode = DW_GDMA_BURST_MODE_INCREMENT,
.burst_items = DW_GDMA_BURST_ITEMS_32,
},
.dst = {
.addr = MIPI_CSI_BRG_MEM_BASE,
.width = DW_GDMA_TRANS_WIDTH_64,
.burst_mode = DW_GDMA_BURST_MODE_FIXED,
.burst_items = s_isp_dma_burst_len_to_items(proc->dma_in_burst_len),
},
.size = ctx->input_frame_size_64bit,
};
dw_gdma_event_callbacks_t dma_cbs = {
.on_full_trans_done = s_isp_dma_done_cb,
};
ESP_GOTO_ON_ERROR(dw_gdma_channel_register_event_callbacks(ctx->dma_out_chan, &dma_cbs, &ctx->out_done_sem), err, TAG, "register output dma callback failed");
ESP_GOTO_ON_ERROR(dw_gdma_channel_register_event_callbacks(ctx->dma_in_chan, &dma_cbs, &ctx->in_done_sem), err, TAG, "register input dma callback failed");
proc->dma_frame_ctx = ctx;
return ESP_OK;
err:
s_isp_dma_frame_ctx_destroy(ctx);
return ret;
}
void isp_dma_del_frame_ctx(isp_proc_handle_t proc)
{
if (!proc || !proc->dma_frame_ctx) {
return;
}
s_isp_dma_frame_ctx_destroy(proc->dma_frame_ctx);
proc->dma_frame_ctx = NULL;
}
esp_err_t esp_isp_dma_process_frame(isp_proc_handle_t proc, void *output_buffer, const void *input_buffer, uint32_t timeout_ms)
{
ESP_RETURN_ON_FALSE(proc && proc->dma_frame_ctx && output_buffer && input_buffer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE((((uintptr_t)output_buffer) % 8) == 0, ESP_ERR_INVALID_ARG, TAG, "output buffer not 8-byte aligned");
ESP_RETURN_ON_FALSE((((uintptr_t)input_buffer) % 8) == 0, ESP_ERR_INVALID_ARG, TAG, "input buffer not 8-byte aligned");
esp_isp_dma_frame_ctx_t *ctx = proc->dma_frame_ctx;
ctx->dma_out_trans.dst.addr = (uint32_t)output_buffer;
ctx->dma_in_trans.src.addr = (uint32_t)input_buffer;
ESP_RETURN_ON_ERROR(dw_gdma_channel_config_transfer(ctx->dma_out_chan, &ctx->dma_out_trans), TAG, "configure output transfer failed");
ESP_RETURN_ON_ERROR(dw_gdma_channel_config_transfer(ctx->dma_in_chan, &ctx->dma_in_trans), TAG, "configure input transfer failed");
dw_gdma_channel_enable_ctrl(ctx->dma_out_chan, true);
dw_gdma_channel_enable_ctrl(ctx->dma_in_chan, true);
isp_ll_dma_trigger_frame(ctx->proc->hal.hw);
if (xSemaphoreTake(ctx->in_done_sem, pdMS_TO_TICKS(timeout_ms)) != pdTRUE) {
ESP_LOGE(TAG, "wait input done timeout");
return ESP_ERR_TIMEOUT;
}
if (xSemaphoreTake(ctx->out_done_sem, pdMS_TO_TICKS(timeout_ms)) != pdTRUE) {
ESP_LOGE(TAG, "wait output done timeout");
return ESP_ERR_TIMEOUT;
}
return ESP_OK;
}