feat(cam): esp_cam add pm lock function and test

This commit is contained in:
gaoxu
2025-05-12 15:30:13 +08:00
parent 3058e24af9
commit 6599ba3c00
9 changed files with 108 additions and 9 deletions

View File

@@ -34,3 +34,7 @@ idf_component_register(SRCS ${srcs}
REQUIRES ${requires}
PRIV_REQUIRES ${priv_requires}
)
if(CONFIG_PM_ENABLE)
idf_component_optional_requires(PRIVATE esp_pm)
endif()

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -210,6 +210,10 @@ esp_err_t esp_cam_new_csi_ctlr(const esp_cam_ctlr_csi_config_t *config, esp_cam_
};
ESP_GOTO_ON_ERROR(dw_gdma_channel_register_event_callbacks(csi_dma_chan, &csi_dma_cbs, ctlr), err, TAG, "failed to register dwgdma callback");
#if CONFIG_PM_ENABLE
ESP_GOTO_ON_ERROR(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "cam_csi_ctlr", &ctlr->pm_lock), err, TAG, "failed to create pm lock");
#endif //CONFIG_PM_ENABLE
ctlr->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
ctlr->csi_fsm = CSI_FSM_INIT;
ctlr->base.del = s_ctlr_del;
@@ -237,6 +241,12 @@ esp_err_t s_del_csi_ctlr(csi_controller_t *ctlr)
ESP_RETURN_ON_FALSE(ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
ESP_RETURN_ON_FALSE(ctlr->csi_fsm == CSI_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "processor isn't in init state");
#if CONFIG_PM_ENABLE
if (ctlr->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_delete(ctlr->pm_lock), TAG, "delete pm_lock failed");
}
#endif // CONFIG_PM_ENABLE
if (ctlr->dma_chan) {
ESP_RETURN_ON_ERROR(dw_gdma_del_channel(ctlr->dma_chan), TAG, "failed to delete dwgdma channel");
}
@@ -400,6 +410,11 @@ esp_err_t s_csi_ctlr_enable(esp_cam_ctlr_handle_t handle)
portENTER_CRITICAL(&ctlr->spinlock);
ctlr->csi_fsm = CSI_FSM_ENABLED;
#if CONFIG_PM_ENABLE
if (ctlr->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(ctlr->pm_lock), TAG, "acquire pm_lock failed");
}
#endif // CONFIG_PM_ENABLE
portEXIT_CRITICAL(&ctlr->spinlock);
return ESP_OK;
@@ -413,6 +428,11 @@ esp_err_t s_csi_ctlr_disable(esp_cam_ctlr_handle_t handle)
portENTER_CRITICAL(&ctlr->spinlock);
ctlr->csi_fsm = CSI_FSM_INIT;
#if CONFIG_PM_ENABLE
if (ctlr->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_release(ctlr->pm_lock), TAG, "release pm_lock failed");
}
#endif // CONFIG_PM_ENABLE
portEXIT_CRITICAL(&ctlr->spinlock);
return ESP_OK;

View File

@@ -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
*/
@@ -21,6 +21,10 @@
#include "soc/soc_caps.h"
#include "esp_private/dw_gdma.h"
#if CONFIG_PM_ENABLE
#include "esp_pm.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
@@ -62,6 +66,9 @@ struct csi_controller_t {
void *cbs_user_data; //callback userdata
dw_gdma_channel_handle_t dma_chan; //dwgdma channel handle
size_t csi_transfer_size; //csi transfer size for dwgdma
#if CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock; //Power management lock
#endif
esp_cam_ctlr_t base;
};

View File

@@ -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
*/
@@ -12,6 +12,10 @@
#include "esp_cam_ctlr_dvp_dma.h"
#include "esp_cam_ctlr_dvp.h"
#if CONFIG_PM_ENABLE
#include "esp_pm.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
@@ -49,6 +53,9 @@ typedef struct esp_cam_ctlr_dvp_cam {
uint8_t *backup_buffer; /*!< DVP CAM backup buffer */
bool bk_buffer_exposed; /*!< status of if back_buffer is exposed to users */
portMUX_TYPE spinlock; /*!< DVP CAM spinlock */
#if CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock; /*!< Power management lock */
#endif
} esp_cam_ctlr_dvp_cam_t;
#ifdef __cplusplus

View File

@@ -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
*/
@@ -423,6 +423,12 @@ static esp_err_t esp_cam_ctlr_dvp_cam_enable(esp_cam_ctlr_handle_t handle)
ctlr->dvp_fsm = ESP_CAM_CTLR_DVP_CAM_FSM_ENABLED;
ret = ESP_OK;
}
#if CONFIG_PM_ENABLE
if (ctlr->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(ctlr->pm_lock), TAG, "acquire pm_lock failed");
}
#endif // CONFIG_PM_ENABLE
portEXIT_CRITICAL(&ctlr->spinlock);
return ret;
@@ -449,6 +455,11 @@ static esp_err_t esp_cam_ctlr_dvp_cam_disable(esp_cam_ctlr_handle_t handle)
ctlr->dvp_fsm = ESP_CAM_CTLR_DVP_CAM_FSM_INIT;
ret = ESP_OK;
}
#if CONFIG_PM_ENABLE
if (ctlr->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_release(ctlr->pm_lock), TAG, "release pm_lock failed");
}
#endif // CONFIG_PM_ENABLE
portEXIT_CRITICAL(&ctlr->spinlock);
return ret;
@@ -546,6 +557,12 @@ static esp_err_t esp_cam_ctlr_dvp_cam_del(esp_cam_ctlr_handle_t handle)
heap_caps_free(ctlr->backup_buffer);
}
#if CONFIG_PM_ENABLE
if (ctlr->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_delete(ctlr->pm_lock), TAG, "delete pm_lock failed");
}
#endif // CONFIG_PM_ENABLE
s_dvp_declaim_ctlr(ctlr->ctlr_id);
heap_caps_free(ctlr);
@@ -714,6 +731,10 @@ esp_err_t esp_cam_new_dvp_ctlr(const esp_cam_ctlr_dvp_config_t *config, esp_cam_
ESP_GOTO_ON_ERROR(gdma_register_rx_event_callbacks(ctlr->dma.dma_chan, &cbs, ctlr),
fail4, TAG, "failed to register DMA event callbacks");
#if CONFIG_PM_ENABLE
ESP_GOTO_ON_ERROR(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "dvp_cam_ctlr", &ctlr->pm_lock), fail5, TAG, "failed to create pm lock");
#endif //CONFIG_PM_ENABLE
/* Initialize DVP controller */
cam_hal_config_t cam_hal_config = {

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -31,6 +31,10 @@
#include "esp_cam_ctlr_isp_dvp.h"
#include "../../dvp_share_ctrl.h"
#if CONFIG_PM_ENABLE
#include "esp_pm.h"
#endif
#if CONFIG_CAM_CTLR_ISP_DVP_ISR_CACHE_SAFE
#define ISP_DVP_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
#else
@@ -55,6 +59,9 @@ typedef struct isp_dvp_controller_t {
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
#if CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock; //Power management lock
#endif
esp_cam_ctlr_t base;
} isp_dvp_controller_t;
@@ -180,6 +187,11 @@ esp_err_t esp_cam_new_isp_dvp_ctlr(isp_proc_handle_t isp_proc, const esp_cam_ctl
mipi_csi_brg_ll_set_burst_len(isp_proc->csi_brg_hw, 512);
esp_cam_ctlr_t *cam_ctlr = &(dvp_ctlr->base);
#if CONFIG_PM_ENABLE
ESP_GOTO_ON_ERROR(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "isp_dvp_cam_ctlr", &dvp_ctlr->pm_lock), err, TAG, "failed to create pm lock");
#endif //CONFIG_PM_ENABLE
cam_ctlr->del = s_isp_del_dvp_controller;
cam_ctlr->enable = s_isp_dvp_enable;
cam_ctlr->start = s_isp_dvp_start;
@@ -221,6 +233,12 @@ esp_err_t s_isp_del_dvp_controller(esp_cam_ctlr_handle_t handle)
if (dvp_ctlr->trans_que) {
vQueueDeleteWithCaps(dvp_ctlr->trans_que);
}
#if CONFIG_PM_ENABLE
if (dvp_ctlr->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_delete(dvp_ctlr->pm_lock), TAG, "delete pm_lock failed");
}
#endif // CONFIG_PM_ENABLE
free(dvp_ctlr);
return ESP_OK;
@@ -294,6 +312,11 @@ static esp_err_t s_isp_dvp_enable(esp_cam_ctlr_handle_t handle)
portENTER_CRITICAL(&dvp_ctlr->spinlock);
dvp_ctlr->fsm = ISP_FSM_ENABLE;
#if CONFIG_PM_ENABLE
if (dvp_ctlr->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(dvp_ctlr->pm_lock), TAG, "acquire pm_lock failed");
}
#endif // CONFIG_PM_ENABLE
portEXIT_CRITICAL(&dvp_ctlr->spinlock);
return ESP_OK;
@@ -307,6 +330,11 @@ static esp_err_t s_isp_dvp_disable(esp_cam_ctlr_handle_t handle)
portENTER_CRITICAL(&dvp_ctlr->spinlock);
dvp_ctlr->fsm = ISP_FSM_INIT;
#if CONFIG_PM_ENABLE
if (dvp_ctlr->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_release(dvp_ctlr->pm_lock), TAG, "release pm_lock failed");
}
#endif // CONFIG_PM_ENABLE
portEXIT_CRITICAL(&dvp_ctlr->spinlock);
return ESP_OK;

View File

@@ -51,6 +51,9 @@ static bool IRAM_ATTR camera_trans_finished(esp_cam_ctlr_handle_t handle, esp_ca
TEST_CASE("TEST esp_cam on ov5647", "[csi][camera][ov5647]")
{
new_buffer_count = 0;
trans_finished_count = 0;
size_t frame_buffer_size = TEST_MIPI_CSI_DISP_HRES *
TEST_MIPI_DSI_DISP_VRES *
TEST_RGB565_BITS_PER_PIXEL / 8;
@@ -127,11 +130,12 @@ TEST_CASE("TEST esp_cam on ov5647", "[csi][camera][ov5647]")
TEST_ESP_OK(esp_isp_enable(isp_proc));
TEST_ESP_OK(esp_cam_ctlr_start(cam_handle));
TEST_ESP_OK(esp_cam_ctlr_receive(cam_handle, &trans_data, ESP_CAM_CTLR_MAX_DELAY));
vTaskDelay(100 / portTICK_PERIOD_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
TEST_ESP_OK(esp_cam_ctlr_stop(cam_handle));
TEST_ASSERT_GREATER_THAN(2, new_buffer_count);
TEST_ASSERT_GREATER_THAN(2, trans_finished_count);
// At least 35 new buffers callback and 34 completed transfer callback are expected within 1 second when camera is 50fps.
TEST_ASSERT_GREATER_OR_EQUAL(35, new_buffer_count);
TEST_ASSERT_GREATER_OR_EQUAL(34, trans_finished_count);
TEST_ESP_OK(esp_cam_ctlr_disable(cam_handle));
TEST_ESP_OK(esp_cam_ctlr_del(cam_handle));

View File

@@ -8,7 +8,7 @@ from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
['cache_safe', 'release'],
['cache_safe', 'release', 'pm_enable'],
indirect=True,
)
@idf_parametrize('target', ['esp32p4'], indirect=['target'])

View File

@@ -0,0 +1,8 @@
# silent the error check, as the error string are stored in rodata, causing RTL check failure
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
CONFIG_HAL_ASSERTION_SILENT=y
CONFIG_PM_ENABLE=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_PM_DFS_INIT_AUTO=y