/* * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include "esp_log.h" #include "esp_check.h" #include "freertos/FreeRTOS.h" #include "driver/isp_core.h" #include "driver/isp_ccm.h" #include "esp_private/isp_private.h" static const char *TAG = "ISP_CCM"; /*--------------------------------------------------------------- CCM ---------------------------------------------------------------*/ esp_err_t esp_isp_ccm_configure(isp_proc_handle_t proc, const esp_isp_ccm_config_t *ccm_cfg) { ESP_RETURN_ON_FALSE(proc && ccm_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); // Check matrix values are within valid range float max_range = (1 << ISP_LL_CCM_MATRIX_INT_BITS); float min_range = -(1 << ISP_LL_CCM_MATRIX_INT_BITS); for (int i = 0; i < ISP_CCM_DIMENSION; i++) { for (int j = 0; j < ISP_CCM_DIMENSION; j++) { float value = ccm_cfg->matrix[i][j]; ESP_RETURN_ON_FALSE(value >= min_range && value <= max_range, ESP_ERR_INVALID_ARG, TAG, "Matrix[%d][%d] value %f is out of range [%f, %f]", i, j, value, min_range, max_range); } } bool ret = true; bool valid = false; esp_os_enter_critical(&proc->spinlock); isp_ll_ccm_set_clk_ctrl_mode(proc->hal.hw, ISP_LL_PIPELINE_CLK_CTRL_AUTO); ret = isp_hal_ccm_set_matrix(&proc->hal, ccm_cfg->saturation, ccm_cfg->matrix); valid = isp_ll_shadow_update_ccm(proc->hal.hw, ccm_cfg->flags.update_once_configured); esp_os_exit_critical(&proc->spinlock); ESP_RETURN_ON_FALSE(ret, ESP_ERR_INVALID_ARG, TAG, "invalid argument: ccm matrix contain NaN or out of range"); ESP_RETURN_ON_FALSE(valid, ESP_ERR_INVALID_STATE, TAG, "failed to update ccm shadow register"); return ESP_OK; } esp_err_t esp_isp_ccm_enable(isp_proc_handle_t proc) { ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); isp_fsm_t expected_fsm = ISP_FSM_INIT; ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&proc->ccm_fsm, &expected_fsm, ISP_FSM_ENABLE), ESP_ERR_INVALID_STATE, TAG, "ccm is enabled already"); esp_os_enter_critical(&proc->spinlock); isp_ll_ccm_enable(proc->hal.hw, true); esp_os_exit_critical(&proc->spinlock); return ESP_OK; } esp_err_t esp_isp_ccm_disable(isp_proc_handle_t proc) { ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); isp_fsm_t expected_fsm = ISP_FSM_ENABLE; ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&proc->ccm_fsm, &expected_fsm, ISP_FSM_INIT), ESP_ERR_INVALID_STATE, TAG, "ccm isn't enabled yet"); esp_os_enter_critical(&proc->spinlock); isp_ll_ccm_enable(proc->hal.hw, false); esp_os_exit_critical(&proc->spinlock); return ESP_OK; }