diff --git a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c index 5dbaf54ba6..21477d445e 100644 --- a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c +++ b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c @@ -51,6 +51,7 @@ static esp_err_t s_ctlr_csi_start(esp_cam_ctlr_handle_t handle); static esp_err_t s_ctlr_csi_stop(esp_cam_ctlr_handle_t handle); static esp_err_t s_csi_ctlr_disable(esp_cam_ctlr_handle_t ctlr); static esp_err_t s_ctlr_csi_receive(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, uint32_t timeout_ms); +static void *s_csi_ctlr_alloc_buffer(esp_cam_ctlr_t *handle, size_t size, uint32_t buf_caps); static esp_err_t s_csi_claim_controller(csi_controller_t *controller) { @@ -225,6 +226,7 @@ esp_err_t esp_cam_new_csi_ctlr(const esp_cam_ctlr_csi_config_t *config, esp_cam_ ctlr->base.register_event_callbacks = s_register_event_callbacks; ctlr->base.get_internal_buffer = s_csi_ctlr_get_internal_buffer; ctlr->base.get_buffer_len = s_csi_ctlr_get_buffer_length; + ctlr->base.alloc_buffer = s_csi_ctlr_alloc_buffer; *ret_handle = &(ctlr->base); @@ -538,3 +540,23 @@ esp_err_t s_ctlr_csi_receive(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t return ESP_OK; } + +static void *s_csi_ctlr_alloc_buffer(esp_cam_ctlr_t *handle, size_t size, uint32_t buf_caps) +{ + csi_controller_t *ctlr = __containerof(handle, csi_controller_t, base); + + if (!ctlr) { + ESP_LOGE(TAG, "invalid argument: handle is null"); + return NULL; + } + + void *buffer = heap_caps_calloc(1, size, buf_caps); + if (!buffer) { + ESP_LOGE(TAG, "failed to allocate buffer"); + return NULL; + } + + ESP_LOGD(TAG, "Allocated camera buffer: %p, size: %zu", buffer, size); + + return buffer; +} diff --git a/components/esp_driver_cam/dvp/private_include/esp_cam_ctlr_dvp_dma.h b/components/esp_driver_cam/dvp/private_include/esp_cam_ctlr_dvp_dma.h index 0846d6ccd6..1a61d26104 100644 --- a/components/esp_driver_cam/dvp/private_include/esp_cam_ctlr_dvp_dma.h +++ b/components/esp_driver_cam/dvp/private_include/esp_cam_ctlr_dvp_dma.h @@ -29,6 +29,8 @@ typedef struct esp_cam_ctlr_dvp_dma { esp_cam_ctlr_dvp_dma_desc_t *desc; /*!< DVP DMA description buffer */ size_t desc_count; /*!< DVP DMA description count */ size_t desc_size; /*!< DVP DMA description buffer size in byte */ + size_t int_mem_align; /*!< DVP DMA internal memory alignment */ + size_t ext_mem_align; /*!< DVP DMA external memory alignment */ } esp_cam_ctlr_dvp_dma_t; /** diff --git a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c index 4df9ad9029..c1b0df3156 100644 --- a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c +++ b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c @@ -700,6 +700,47 @@ static esp_err_t esp_cam_ctlr_get_dvp_cam_frame_buffer_len(esp_cam_ctlr_handle_t return ret; } +/** + * @brief Allocate aligned camera buffer for ESP CAM DVP controller + * + * @note This function must be called after esp_cam_new_dvp_ctlr + * + * @param handle ESP CAM controller handle + * @param size Buffer size in bytes + * @param buf_caps Buffer allocation capabilities (e.g., MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA) + * + * @return + * - Buffer pointer on success + * - NULL on failure + */ +static void *esp_cam_ctlr_dvp_cam_alloc_buffer(esp_cam_ctlr_t *handle, size_t size, uint32_t buf_caps) +{ + esp_cam_ctlr_dvp_cam_t *ctlr = (esp_cam_ctlr_dvp_cam_t *)handle; + + if (!ctlr) { + ESP_LOGE(TAG, "invalid argument: handle is null"); + return NULL; + } + + size_t alignment = 1; + + if (buf_caps & MALLOC_CAP_SPIRAM) { + alignment = ctlr->dma.ext_mem_align; + } else { + alignment = ctlr->dma.int_mem_align; + } + + void *buffer = heap_caps_aligned_calloc(alignment, 1, size, buf_caps); + if (!buffer) { + ESP_LOGE(TAG, "failed to allocate buffer"); + return NULL; + } + + ESP_LOGD(TAG, "Allocated aligned camera buffer: %p, size: %zu, alignment: %zu", buffer, size, alignment); + + return buffer; +} + /** * @brief New ESP CAM DVP controller * @@ -793,6 +834,7 @@ esp_err_t esp_cam_new_dvp_ctlr(const esp_cam_ctlr_dvp_config_t *config, esp_cam_ ctlr->base.register_event_callbacks = esp_cam_ctlr_dvp_cam_register_event_callbacks; ctlr->base.get_internal_buffer = esp_cam_ctlr_dvp_cam_get_internal_buffer; ctlr->base.get_buffer_len = esp_cam_ctlr_get_dvp_cam_frame_buffer_len; + ctlr->base.alloc_buffer = esp_cam_ctlr_dvp_cam_alloc_buffer; *ret_handle = &ctlr->base; diff --git a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c index f9d82503cc..65b2794c33 100644 --- a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c +++ b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c @@ -105,9 +105,8 @@ esp_err_t esp_cam_ctlr_dvp_dma_init(esp_cam_ctlr_dvp_dma_t *dma, uint32_t burst_ .access_ext_mem = true, }; ESP_GOTO_ON_ERROR(gdma_config_transfer(dma->dma_chan, &transfer_config), fail1, TAG, "set trans ability failed"); - size_t int_mem_align = 0; - size_t ext_mem_align = 0; - gdma_get_alignment_constraints(dma->dma_chan, &int_mem_align, &ext_mem_align); + + gdma_get_alignment_constraints(dma->dma_chan, &dma->int_mem_align, &dma->ext_mem_align); dma->desc_count = size / ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE; if (size % ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE) { diff --git a/components/esp_driver_cam/esp_cam_ctlr.c b/components/esp_driver_cam/esp_cam_ctlr.c index a2a4e2e9d0..43361addc9 100644 --- a/components/esp_driver_cam/esp_cam_ctlr.c +++ b/components/esp_driver_cam/esp_cam_ctlr.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -91,3 +91,11 @@ esp_err_t esp_cam_ctlr_del(esp_cam_ctlr_handle_t handle) return handle->del(handle); } + +void *esp_cam_ctlr_alloc_buffer(esp_cam_ctlr_handle_t handle, size_t size, uint32_t buf_caps) +{ + ESP_RETURN_ON_FALSE(handle, NULL, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(handle->alloc_buffer, NULL, TAG, "alloc_buffer function not supported"); + + return handle->alloc_buffer(handle, size, buf_caps); +} diff --git a/components/esp_driver_cam/include/esp_cam_ctlr.h b/components/esp_driver_cam/include/esp_cam_ctlr.h index 6365ad6b73..ed01642ad6 100644 --- a/components/esp_driver_cam/include/esp_cam_ctlr.h +++ b/components/esp_driver_cam/include/esp_cam_ctlr.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,6 +9,7 @@ #include #include #include "esp_err.h" +#include "esp_heap_caps.h" #include "esp_cam_ctlr_types.h" #ifdef __cplusplus @@ -132,6 +133,23 @@ esp_err_t esp_cam_ctlr_get_frame_buffer(esp_cam_ctlr_handle_t handle, uint32_t f */ esp_err_t esp_cam_ctlr_get_frame_buffer_len(esp_cam_ctlr_handle_t handle, size_t *ret_fb_len); +/** + * @brief Allocate camera buffer for ESP CAM controller + * + * @note This function must be called after esp_cam_new_*_ctlr + * + * @param[in] handle ESP CAM controller handle + * @param[in] size Buffer size in bytes + * @param[in] buf_caps Buffer allocation capabilities: + * - MALLOC_CAP_SPIRAM || MALLOC_CAP_DMA: Memory in external SPI RAM + * - MALLOC_CAP_INTERNAL || MALLOC_CAP_DMA: Memory in internal SRAM + * + * @return + * - Buffer pointer on success + * - NULL on failure + */ +void *esp_cam_ctlr_alloc_buffer(esp_cam_ctlr_handle_t handle, size_t size, uint32_t buf_caps); + #ifdef __cplusplus } #endif diff --git a/components/esp_driver_cam/interface/esp_cam_ctlr_interface.h b/components/esp_driver_cam/interface/esp_cam_ctlr_interface.h index 031b9f66da..893e48413d 100644 --- a/components/esp_driver_cam/interface/esp_cam_ctlr_interface.h +++ b/components/esp_driver_cam/interface/esp_cam_ctlr_interface.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -133,6 +133,19 @@ struct esp_cam_ctlr_t { */ esp_err_t (*get_buffer_len)(esp_cam_ctlr_t *, size_t *); + /** + * @brief Allocate aligned camera buffer for ESP CAM controller + * + * @param[in] esp_cam_ctlr_t * ESP CAM controller handle + * @param[in] size_t Buffer size in bytes + * @param[in] uint32_t Buffer allocation capabilities + * + * @return + * - Buffer pointer on success + * - NULL on failure + */ + void *(*alloc_buffer)(esp_cam_ctlr_t *, size_t, uint32_t); + void *user_data; ///< User data }; diff --git a/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c b/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c index 31ff7fe060..324b86ac86 100644 --- a/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c +++ b/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c @@ -85,6 +85,7 @@ 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); +static void *s_isp_dvp_alloc_buffer(esp_cam_ctlr_t *handle, size_t size, uint32_t buf_caps); 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) { @@ -200,6 +201,7 @@ esp_err_t esp_cam_new_isp_dvp_ctlr(isp_proc_handle_t isp_proc, const esp_cam_ctl 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; + cam_ctlr->alloc_buffer = s_isp_dvp_alloc_buffer; *ret_handle = cam_ctlr; return ESP_OK; @@ -594,3 +596,23 @@ static esp_err_t s_isp_declaim_dvp_controller(isp_dvp_controller_t *dvp_ctlr) return ESP_OK; } + +static void *s_isp_dvp_alloc_buffer(esp_cam_ctlr_t *handle, size_t size, uint32_t buf_caps) +{ + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + + if (!dvp_ctlr) { + ESP_LOGE(TAG, "invalid argument: handle is null"); + return NULL; + } + + void *buffer = heap_caps_calloc(1, size, buf_caps); + if (!buffer) { + ESP_LOGE(TAG, "failed to allocate buffer"); + return NULL; + } + + ESP_LOGD(TAG, "Allocated camera buffer: %p, size: %zu", buffer, size); + + return buffer; +} diff --git a/docs/en/api-reference/peripherals/camera_driver.rst b/docs/en/api-reference/peripherals/camera_driver.rst index 3d34c21cef..e86e9d8294 100644 --- a/docs/en/api-reference/peripherals/camera_driver.rst +++ b/docs/en/api-reference/peripherals/camera_driver.rst @@ -112,6 +112,8 @@ Camera controller driver can be implemented in one of following ways: If :cpp:type:`esp_cam_ctlr_lcd_cam_cfg_t` is specified, users can call :cpp:func:`esp_cam_new_lcd_cam_ctlr` to allocate and initialize a DVP camera controller handle. This function will return an DVP camera controller handle if it runs correctly. You can take following code as reference. + After calling :cpp:func:`esp_cam_new_dvp_ctlr`, you should allocate a camera buffer that meets the alignment constraints, or call :cpp:func:`esp_cam_ctlr_alloc_buffer` to automatically allocate. + .. code:: c esp_cam_ctlr_handle_t cam_handle = NULL; diff --git a/docs/zh_CN/api-reference/peripherals/camera_driver.rst b/docs/zh_CN/api-reference/peripherals/camera_driver.rst index 82484235fe..7cfafc968b 100644 --- a/docs/zh_CN/api-reference/peripherals/camera_driver.rst +++ b/docs/zh_CN/api-reference/peripherals/camera_driver.rst @@ -112,6 +112,8 @@ 如果指定了 :cpp:type:`esp_cam_ctlr_dvp_config_t` 中的配置,就可以调用 :cpp:func:`esp_cam_new_dvp_ctlr` 来分配和初始化 DVP 摄像头控制器句柄。如果函数运行正确,将返回一个 DVP 摄像头控制器句柄。请参考以下代码。 + 在调用 :cpp:func:`esp_cam_new_dvp_ctlr` 之后,需要分配符合对齐约束的摄像头缓冲区,或调用 :cpp:func:`esp_cam_ctlr_alloc_buffer` 来自动分配。 + .. code:: c esp_cam_ctlr_handle_t cam_handle = NULL; diff --git a/examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c b/examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c index 5e5f6d4053..a3392ca965 100644 --- a/examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c +++ b/examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c @@ -66,17 +66,6 @@ void app_main(void) ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size); ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer); - size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; - void *cam_buffer = heap_caps_calloc(1, cam_buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM); - if (!cam_buffer) { - ESP_LOGE(TAG, "no mem for cam_buffer"); - return; - } - esp_cam_ctlr_trans_t cam_trans = { - .buffer = cam_buffer, - .buflen = cam_buffer_size, - }; - //----------CAM Controller Init------------// esp_cam_ctlr_handle_t cam_handle = NULL; esp_cam_ctlr_dvp_pin_config_t pin_cfg = { @@ -115,6 +104,18 @@ void app_main(void) return; } + //--------Allocate Camera Buffer----------// + size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + void *cam_buffer = esp_cam_ctlr_alloc_buffer(cam_handle, cam_buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM); + if (!cam_buffer) { + ESP_LOGE(TAG, "no mem for cam_buffer"); + return; + } + esp_cam_ctlr_trans_t cam_trans = { + .buffer = cam_buffer, + .buflen = cam_buffer_size, + }; + //--------Camera Sensor and SCCB Init-----------// example_sensor_config_t cam_sensor_config = { .i2c_port_num = I2C_NUM_0, diff --git a/examples/peripherals/camera/dvp_isp_dsi/main/dvp_isp_dsi_main.c b/examples/peripherals/camera/dvp_isp_dsi/main/dvp_isp_dsi_main.c index 6b56a12233..9b6c049dfb 100644 --- a/examples/peripherals/camera/dvp_isp_dsi/main/dvp_isp_dsi_main.c +++ b/examples/peripherals/camera/dvp_isp_dsi/main/dvp_isp_dsi_main.c @@ -98,17 +98,6 @@ void app_main(void) ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size); ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer); - size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; - void *cam_buffer = heap_caps_calloc(1, cam_buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM); - if (!cam_buffer) { - ESP_LOGE(TAG, "no mem for cam_buffer"); - return; - } - esp_cam_ctlr_trans_t cam_trans = { - .buffer = cam_buffer, - .buflen = cam_buffer_size, - }; - //--------Camera Sensor and SCCB Init-----------// s_ledc_generate_dvp_xclk(); @@ -167,6 +156,18 @@ void app_main(void) return; } + //--------Allocate Camera Buffer----------// + size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + void *cam_buffer = esp_cam_ctlr_alloc_buffer(cam_handle, cam_buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM); + if (!cam_buffer) { + ESP_LOGE(TAG, "no mem for cam_buffer"); + return; + } + esp_cam_ctlr_trans_t cam_trans = { + .buffer = cam_buffer, + .buflen = cam_buffer_size, + }; + esp_cam_ctlr_evt_cbs_t cbs = { .on_get_new_trans = s_camera_get_new_vb, .on_trans_finished = s_camera_get_finished_trans, diff --git a/examples/peripherals/camera/dvp_spi_lcd/main/dvp_spi_lcd_main.c b/examples/peripherals/camera/dvp_spi_lcd/main/dvp_spi_lcd_main.c index ef57a1a2e7..bd9b1855fa 100644 --- a/examples/peripherals/camera/dvp_spi_lcd/main/dvp_spi_lcd_main.c +++ b/examples/peripherals/camera/dvp_spi_lcd/main/dvp_spi_lcd_main.c @@ -119,13 +119,6 @@ void app_main(void) esp_lcd_panel_handle_t lcd_panel_hdl = NULL; esp_lcd_panel_io_handle_t lcd_io_hdl = NULL; - size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; - void *cam_buffer = heap_caps_malloc(cam_buffer_size, EXAMPLE_DVP_CAM_BUF_ALLOC_CAPS); - if (!cam_buffer) { - ESP_LOGE(TAG, "no mem for cam_buffer"); - return; - } - lcd_display_init(&lcd_panel_hdl, lcd_io_hdl); //----------CAM Controller Init------------// @@ -166,6 +159,12 @@ void app_main(void) return; } + //--------Allocate Camera Buffer----------// + size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + void *cam_buffer = NULL; + + cam_buffer = esp_cam_ctlr_alloc_buffer(cam_handle, cam_buffer_size, EXAMPLE_DVP_CAM_BUF_ALLOC_CAPS); + //--------Camera Sensor and SCCB Init-----------// example_sensor_config_t cam_sensor_config = { .i2c_port_num = I2C_NUM_0,