Merge branch 'feat/csi_error_event_v6.0' into 'release/v6.0'

Add MIPI-CSI error event (v6.0)

See merge request espressif/esp-idf!50681
This commit is contained in:
morris
2026-07-17 12:17:02 +08:00
8 changed files with 352 additions and 15 deletions

View File

@@ -19,6 +19,7 @@
#include "esp_cam_ctlr_interface.h"
#include "esp_cam_ctlr_csi_internal.h"
#include "hal/mipi_csi_ll.h"
#include "hal/mipi_csi_periph.h"
#include "hal/color_hal.h"
#include "hal/efuse_hal.h"
#include "soc/chip_revision.h"
@@ -30,8 +31,12 @@
#if CONFIG_CAM_CTLR_MIPI_CSI_ISR_CACHE_SAFE
#define CSI_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
#define CSI_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM)
#define CSI_ISR_ATTR IRAM_ATTR
#else
#define CSI_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
#define CSI_INTR_ALLOC_FLAGS ESP_INTR_FLAG_LOWMED
#define CSI_ISR_ATTR
#endif
typedef struct csi_platform_t {
@@ -43,6 +48,7 @@ static const char *TAG = "CSI";
static csi_platform_t s_platform;
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);
static void s_csi_default_isr(void *arg);
static esp_err_t s_del_csi_ctlr(csi_controller_t *ctlr);
static esp_err_t s_ctlr_del(esp_cam_ctlr_t *cam_ctlr);
static esp_err_t s_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_data);
@@ -296,6 +302,12 @@ esp_err_t s_del_csi_ctlr(csi_controller_t *ctlr)
}
#endif // CONFIG_PM_ENABLE
if (ctlr->intr_handle) {
mipi_csi_host_ll_enable_intr(ctlr->hal.host_dev, MIPI_CSI_HOST_LL_INTR_ERR_ALL, false);
ESP_RETURN_ON_ERROR(esp_intr_free(ctlr->intr_handle), TAG, "failed to free csi host interrupt");
ctlr->intr_handle = NULL;
}
if (ctlr->dma_chan) {
ESP_RETURN_ON_ERROR(dw_gdma_del_channel(ctlr->dma_chan), TAG, "failed to delete dwgdma channel");
}
@@ -449,15 +461,72 @@ esp_err_t s_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam
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");
}
if (cbs->on_error) {
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_error), ESP_ERR_INVALID_ARG, TAG, "on_error callback not in IRAM");
}
if (user_data) {
ESP_RETURN_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, TAG, "user_data not in internal RAM");
}
#endif
bool enable_error_intr = false;
// The error interrupt service is lazy installed, only when an on_error callback is registered.
if (cbs->on_error && !ctlr->intr_handle) {
ESP_RETURN_ON_ERROR(esp_intr_alloc(soc_mipi_csi_signals[ctlr->csi_id].host_irq_id, CSI_INTR_ALLOC_FLAGS,
s_csi_default_isr, ctlr, &ctlr->intr_handle),
TAG, "failed to allocate csi host interrupt");
enable_error_intr = true;
}
ctlr->cbs.on_get_new_trans = cbs->on_get_new_trans;
ctlr->cbs.on_trans_finished = cbs->on_trans_finished;
ctlr->cbs.on_error = cbs->on_error;
ctlr->cbs_user_data = user_data;
if (enable_error_intr) {
// clear any stale status, then unmask all error interrupts
mipi_csi_host_ll_clear_intr_status(ctlr->hal.host_dev, MIPI_CSI_HOST_LL_INTR_ERR_ALL);
mipi_csi_host_ll_enable_intr(ctlr->hal.host_dev, MIPI_CSI_HOST_LL_INTR_ERR_ALL, true);
}
return ESP_OK;
}
static void CSI_ISR_ATTR s_csi_default_isr(void *arg)
{
bool need_yield = false;
csi_controller_t *ctlr = (csi_controller_t *)arg;
uint32_t status = mipi_csi_host_ll_get_intr_status(ctlr->hal.host_dev);
// clear the detected error sources before invoking the callback
mipi_csi_host_ll_clear_intr_status(ctlr->hal.host_dev, status);
if (ctlr->cbs.on_error) {
esp_cam_ctlr_error_event_data_t edata = {};
if (status & (MIPI_CSI_HOST_LL_INTR_PHY_FATAL | MIPI_CSI_HOST_LL_INTR_PHY)) {
edata.csi_host_err_evts |= ESP_CAM_CTLR_CSI_HOST_ERR_PHY;
}
if (status & (MIPI_CSI_HOST_LL_INTR_PKT_FATAL | MIPI_CSI_HOST_LL_INTR_ECC_CORRECTED)) {
edata.csi_host_err_evts |= ESP_CAM_CTLR_CSI_HOST_ERR_PACKET;
}
if (status & (MIPI_CSI_HOST_LL_INTR_BNDRY_FRAME_FATAL | MIPI_CSI_HOST_LL_INTR_SEQ_FRAME_FATAL)) {
edata.csi_host_err_evts |= ESP_CAM_CTLR_CSI_HOST_ERR_FRAME;
}
if (status & (MIPI_CSI_HOST_LL_INTR_CRC_FRAME_FATAL | MIPI_CSI_HOST_LL_INTR_PLD_CRC_FATAL)) {
edata.csi_host_err_evts |= ESP_CAM_CTLR_CSI_HOST_ERR_CRC;
}
if (status & MIPI_CSI_HOST_LL_INTR_DATA_ID) {
edata.csi_host_err_evts |= ESP_CAM_CTLR_CSI_HOST_ERR_DATA_ID;
}
need_yield = ctlr->cbs.on_error(&(ctlr->base), &edata, ctlr->cbs_user_data);
}
if (need_yield) {
portYIELD_FROM_ISR();
}
}
esp_err_t s_csi_ctlr_enable(esp_cam_ctlr_handle_t handle)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");

View File

@@ -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
*/
@@ -8,13 +8,10 @@
#include <stdint.h>
#include <stdbool.h>
#include <esp_types.h>
#include <stddef.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "freertos/FreeRTOS.h"
#include "esp_intr_alloc.h"
#include "esp_cam_ctlr_csi.h"
#include "hal/mipi_csi_hal.h"
#include "hal/mipi_csi_types.h"
@@ -67,6 +64,7 @@ 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
intr_handle_t intr_handle; //csi host error interrupt handle
#if CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock; //Power management lock
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -8,7 +8,7 @@
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
@@ -33,6 +33,26 @@ typedef struct {
size_t received_size; /*!< Received size. This value is written by the driver and indicates the actual received size. */
} esp_cam_ctlr_trans_t;
/**
* @brief ESP CAM controller CSI host error flags.
*
* @note These flags summarize the CSI host error type(s) and avoid exposing hardware bit layout.
*/
typedef enum {
ESP_CAM_CTLR_CSI_HOST_ERR_PHY = (1U << 0), /*!< PHY error. */
ESP_CAM_CTLR_CSI_HOST_ERR_PACKET = (1U << 1), /*!< Packet error. */
ESP_CAM_CTLR_CSI_HOST_ERR_FRAME = (1U << 2), /*!< Frame boundary or sequence error. */
ESP_CAM_CTLR_CSI_HOST_ERR_CRC = (1U << 3), /*!< Frame or payload CRC error. */
ESP_CAM_CTLR_CSI_HOST_ERR_DATA_ID = (1U << 4), /*!< Unrecognized or unsupported data type detected. */
} esp_cam_ctlr_csi_host_error_t;
/**
* @brief ESP CAM controller "error" event data.
*/
typedef struct {
uint32_t csi_host_err_evts; /*!< Bitwise OR of `esp_cam_ctlr_csi_host_error_t`. */
} esp_cam_ctlr_error_event_data_t;
/**
* @brief Event callbacks for the ESP CAM controller.
*/
@@ -59,6 +79,21 @@ typedef struct {
*/
bool (*on_trans_finished)(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data);
/**
* @brief Callback for when an error is detected.
*
* @note This callback is invoked from ISR context, so it must not call any blocking APIs.
* When the controller's ISR cache-safe option is enabled, this callback and its
* user data must be placed in internal RAM.
*
* @param[in] handle ESP CAM controller handle.
* @param[in] edata Error event data.
* @param[in] user_data User-registered data.
*
* @return Whether a high-priority task is woken up by this function.
*/
bool (*on_error)(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_error_event_data_t *edata, void *user_data);
} esp_cam_ctlr_evt_cbs_t;
#ifdef __cplusplus

View File

@@ -3,14 +3,13 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "unity.h"
#include "esp_attr.h"
#include "esp_cam_ctlr_csi.h"
#include "esp_cam_ctlr.h"
#include "esp_ldo_regulator.h"
#include "sdkconfig.h"
#include "driver/isp.h"
#include "example_sensor_init.h"
#include "esp_private/esp_cache_private.h"
@@ -34,6 +33,11 @@
static int new_buffer_count = 0;
static int trans_finished_count = 0;
typedef struct {
SemaphoreHandle_t sem;
uint32_t flags;
} test_csi_error_ctx_t;
static bool IRAM_ATTR camera_get_new_buffer(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data)
{
esp_cam_ctlr_trans_t *new_trans = (esp_cam_ctlr_trans_t *)user_data;
@@ -49,6 +53,16 @@ static bool IRAM_ATTR camera_trans_finished(esp_cam_ctlr_handle_t handle, esp_ca
return false;
}
static bool IRAM_ATTR camera_error_callback(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_error_event_data_t *edata, void *user_data)
{
test_csi_error_ctx_t *ctx = (test_csi_error_ctx_t *)user_data;
ctx->flags = edata->csi_host_err_evts;
BaseType_t high_task_woken = pdFALSE;
xSemaphoreGiveFromISR(ctx->sem, &high_task_woken);
return high_task_woken == pdTRUE;
}
TEST_CASE("TEST esp_cam on ov5647", "[csi][camera][ov5647]")
{
new_buffer_count = 0;
@@ -149,3 +163,87 @@ TEST_CASE("TEST esp_cam on ov5647", "[csi][camera][ov5647]")
heap_caps_free(frame_buffer);
}
TEST_CASE("TEST CSI error callback on lane mismatch", "[csi][camera][ov5647]")
{
size_t frame_buffer_size = TEST_MIPI_CSI_DISP_HRES *
TEST_MIPI_CSI_DISP_VRES *
TEST_RGB565_BITS_PER_PIXEL / 8;
esp_ldo_channel_handle_t ldo_mipi_phy = NULL;
esp_ldo_channel_config_t ldo_config = {
.chan_id = TEST_USED_LDO_CHAN_ID,
.voltage_mv = TEST_USED_LDO_VOLTAGE_MV,
};
TEST_ESP_OK(esp_ldo_acquire_channel(&ldo_config, &ldo_mipi_phy));
size_t frame_buffer_alignment = 0;
TEST_ESP_OK(esp_cache_get_alignment(0, &frame_buffer_alignment));
void *frame_buffer = heap_caps_aligned_calloc(frame_buffer_alignment, 1, frame_buffer_size,
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
TEST_ASSERT_NOT_NULL(frame_buffer);
esp_cam_ctlr_trans_t trans_data = {
.buffer = frame_buffer,
.buflen = frame_buffer_size,
};
example_sensor_handle_t sensor_handle = {
.sccb_handle = NULL,
.i2c_bus_handle = NULL,
};
example_sensor_config_t sensor_config = {
.i2c_port_num = I2C_NUM_0,
.i2c_sda_io_num = TEST_MIPI_CSI_CAM_SCCB_SDA_IO,
.i2c_scl_io_num = TEST_MIPI_CSI_CAM_SCCB_SCL_IO,
.port = ESP_CAM_SENSOR_MIPI_CSI,
.format_name = TEST_CAM_FORMAT,
};
esp_cam_ctlr_csi_config_t csi_config = {
.ctlr_id = 0,
.h_res = TEST_MIPI_CSI_DISP_HRES,
.v_res = TEST_MIPI_CSI_DISP_VRES,
.lane_bit_rate_mbps = TEST_MIPI_CSI_LANE_BITRATE_MBPS,
.input_data_color_type = CAM_CTLR_COLOR_RAW8,
.output_data_color_type = CAM_CTLR_COLOR_RAW8,
.data_lane_num = 1,
.byte_swap_en = false,
.queue_items = 1,
};
esp_cam_ctlr_handle_t cam_handle = NULL;
TEST_ESP_OK(esp_cam_new_csi_ctlr(&csi_config, &cam_handle));
test_csi_error_ctx_t error_ctx = {};
error_ctx.sem = xSemaphoreCreateBinary();
TEST_ASSERT_NOT_NULL(error_ctx.sem);
esp_cam_ctlr_evt_cbs_t cbs = {
.on_trans_finished = camera_trans_finished,
.on_error = camera_error_callback,
};
TEST_ESP_OK(esp_cam_ctlr_register_event_callbacks(cam_handle, &cbs, &error_ctx));
TEST_ASSERT_EQUAL(pdFALSE, xSemaphoreTake(error_ctx.sem, pdMS_TO_TICKS(100)));
example_sensor_init(&sensor_config, &sensor_handle);
TEST_ESP_OK(esp_cam_ctlr_enable(cam_handle));
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));
bool error_reported = xSemaphoreTake(error_ctx.sem, pdMS_TO_TICKS(1000)) == pdTRUE;
uint32_t err_flags = error_ctx.flags;
TEST_ESP_OK(esp_cam_ctlr_stop(cam_handle));
TEST_ESP_OK(esp_cam_ctlr_disable(cam_handle));
TEST_ESP_OK(esp_cam_ctlr_del(cam_handle));
vSemaphoreDelete(error_ctx.sem);
TEST_ESP_OK(esp_ldo_release_channel(ldo_mipi_phy));
example_sensor_deinit(sensor_handle);
heap_caps_free(frame_buffer);
TEST_ASSERT_TRUE(error_reported);
TEST_ASSERT_NOT_EQUAL(0, err_flags);
}

View File

@@ -14,7 +14,7 @@ from pytest_embedded_idf.utils import idf_parametrize
@idf_parametrize('target', ['esp32p4'], indirect=['target'])
def test_csi_driver(case_tester) -> None: # type: ignore
for case in case_tester.test_menu:
if 'TEST esp_cam on ov5647' in case.name:
if 'camera' in case.groups:
continue
case_tester.run_normal_case(case=case, reset=True)

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -20,6 +20,32 @@ extern "C" {
#define MIPI_CSI_HOST_LL_LANE_NUM_MAX 2
/**
* @brief MIPI CSI host interrupt categories, bit layout aligned with the `int_st_main` register
*/
typedef enum {
MIPI_CSI_HOST_LL_INTR_PHY_FATAL = (1 << 0), /*!< PHY fatal error, e.g. data lane Start-of-Transmission sync error (ErrSotSyncHS) */
MIPI_CSI_HOST_LL_INTR_PKT_FATAL = (1 << 1), /*!< Packet fatal error, e.g. header double-bit ECC error or shorter payload */
MIPI_CSI_HOST_LL_INTR_BNDRY_FRAME_FATAL = (1 << 2), /*!< Frame boundary error, e.g. unpaired Frame Start / Frame End */
MIPI_CSI_HOST_LL_INTR_SEQ_FRAME_FATAL = (1 << 3), /*!< Frame sequence error */
MIPI_CSI_HOST_LL_INTR_CRC_FRAME_FATAL = (1 << 4), /*!< A frame containing at least one CRC error */
MIPI_CSI_HOST_LL_INTR_PLD_CRC_FATAL = (1 << 5), /*!< Payload CRC error */
MIPI_CSI_HOST_LL_INTR_DATA_ID = (1 << 6), /*!< Unrecognized or unsupported data type detected */
MIPI_CSI_HOST_LL_INTR_ECC_CORRECTED = (1 << 7), /*!< Header single-bit ECC error (corrected by hardware) */
MIPI_CSI_HOST_LL_INTR_PHY = (1 << 16), /*!< PHY error, e.g. Start-of-Transmission error (ErrSotHS) or escape entry error (ErrEsc) */
} mipi_csi_host_ll_intr_t;
/// Mask covering all MIPI CSI host error interrupts
#define MIPI_CSI_HOST_LL_INTR_ERR_ALL (MIPI_CSI_HOST_LL_INTR_PHY_FATAL | \
MIPI_CSI_HOST_LL_INTR_PKT_FATAL | \
MIPI_CSI_HOST_LL_INTR_BNDRY_FRAME_FATAL | \
MIPI_CSI_HOST_LL_INTR_SEQ_FRAME_FATAL | \
MIPI_CSI_HOST_LL_INTR_CRC_FRAME_FATAL | \
MIPI_CSI_HOST_LL_INTR_PLD_CRC_FATAL | \
MIPI_CSI_HOST_LL_INTR_DATA_ID | \
MIPI_CSI_HOST_LL_INTR_ECC_CORRECTED | \
MIPI_CSI_HOST_LL_INTR_PHY)
/**
* @brief Enable CSI host reset output
*
@@ -64,6 +90,96 @@ static inline void mipi_csi_host_ll_enable_scrambling(csi_host_dev_t *dev, bool
dev->scrambling.scramble_enable = en;
}
/**
* @brief Enable or disable the MIPI CSI host error interrupts
*
* @param dev Pointer to the CSI Host controller register base address
* @param mask Interrupt categories to operate on, see `mipi_csi_host_ll_intr_t`
* @param en True to enable (unmask), false to disable (mask)
*/
static inline void mipi_csi_host_ll_enable_intr(csi_host_dev_t *dev, uint32_t mask, bool en)
{
if (mask & MIPI_CSI_HOST_LL_INTR_PHY_FATAL) {
dev->int_msk_phy_fatal.val = en ? 0x3 : 0x0;
}
if (mask & MIPI_CSI_HOST_LL_INTR_PKT_FATAL) {
dev->int_msk_pkt_fatal.val = en ? 0x3 : 0x0;
}
if (mask & MIPI_CSI_HOST_LL_INTR_BNDRY_FRAME_FATAL) {
dev->int_msk_bndry_frame_fatal.val = en ? 0xffff : 0x0;
}
if (mask & MIPI_CSI_HOST_LL_INTR_SEQ_FRAME_FATAL) {
dev->int_msk_seq_frame_fatal.val = en ? 0xffff : 0x0;
}
if (mask & MIPI_CSI_HOST_LL_INTR_CRC_FRAME_FATAL) {
dev->int_msk_crc_frame_fatal.val = en ? 0xffff : 0x0;
}
if (mask & MIPI_CSI_HOST_LL_INTR_PLD_CRC_FATAL) {
dev->int_msk_pld_crc_fatal.val = en ? 0xffff : 0x0;
}
if (mask & MIPI_CSI_HOST_LL_INTR_DATA_ID) {
dev->int_msk_data_id.val = en ? 0xffff : 0x0;
}
if (mask & MIPI_CSI_HOST_LL_INTR_ECC_CORRECTED) {
dev->int_msk_ecc_corrected.val = en ? 0xffff : 0x0;
}
if (mask & MIPI_CSI_HOST_LL_INTR_PHY) {
dev->int_msk_phy.val = en ? 0x30003 : 0x0;
}
}
/**
* @brief Get the MIPI CSI host top-level interrupt status
*
* @param dev Pointer to the CSI Host controller register base address
*
* @return The top-level interrupt status, a combination of `mipi_csi_host_ll_intr_t`
*/
static inline uint32_t mipi_csi_host_ll_get_intr_status(csi_host_dev_t *dev)
{
return dev->int_st_main.val;
}
/**
* @brief Clear the MIPI CSI host interrupt status
*
* @note The per-category status registers are clear-on-read, reading them also clears the
* corresponding bit in the `int_st_main` register.
*
* @param dev Pointer to the CSI Host controller register base address
* @param mask Interrupt categories to clear, see `mipi_csi_host_ll_intr_t`
*/
static inline void mipi_csi_host_ll_clear_intr_status(csi_host_dev_t *dev, uint32_t mask)
{
if (mask & MIPI_CSI_HOST_LL_INTR_PHY_FATAL) {
(void)dev->int_st_phy_fatal.val;
}
if (mask & MIPI_CSI_HOST_LL_INTR_PKT_FATAL) {
(void)dev->int_st_pkt_fatal.val;
}
if (mask & MIPI_CSI_HOST_LL_INTR_BNDRY_FRAME_FATAL) {
(void)dev->int_st_bndry_frame_fatal.val;
}
if (mask & MIPI_CSI_HOST_LL_INTR_SEQ_FRAME_FATAL) {
(void)dev->int_st_seq_frame_fatal.val;
}
if (mask & MIPI_CSI_HOST_LL_INTR_CRC_FRAME_FATAL) {
(void)dev->int_st_crc_frame_fatal.val;
}
if (mask & MIPI_CSI_HOST_LL_INTR_PLD_CRC_FATAL) {
(void)dev->int_st_pld_crc_fatal.val;
}
if (mask & MIPI_CSI_HOST_LL_INTR_DATA_ID) {
(void)dev->int_st_data_id.val;
}
if (mask & MIPI_CSI_HOST_LL_INTR_ECC_CORRECTED) {
(void)dev->int_st_ecc_corrected.val;
}
if (mask & MIPI_CSI_HOST_LL_INTR_PHY) {
(void)dev->int_st_phy.val;
}
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,10 +1,11 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "hal/mipi_csi_periph.h"
#include "soc/interrupts.h"
const soc_mipi_csi_phy_pll_freq_range_t soc_mipi_csi_phy_pll_ranges[] = {
{90, 99, 0x00}, // [90,100) Mbps
@@ -48,3 +49,9 @@ const soc_mipi_csi_phy_pll_freq_range_t soc_mipi_csi_phy_pll_ranges[] = {
};
const size_t num_of_soc_mipi_csi_phy_pll_ranges = sizeof(soc_mipi_csi_phy_pll_ranges) / sizeof(soc_mipi_csi_phy_pll_freq_range_t);
const soc_mipi_csi_signal_desc_t soc_mipi_csi_signals[MIPI_CSI_LL_HOST_CTLR_NUMS] = {
[0] = {
.host_irq_id = ETS_CSI_INTR_SOURCE,
}
};

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -8,11 +8,17 @@
#include <stdint.h>
#include <stddef.h>
#include "soc/soc_caps.h"
#if SOC_HAS(MIPI_CSI)
#include "hal/mipi_csi_ll.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if SOC_HAS(MIPI_CSI)
/**
* @brief MIPI CSI PHY PLL frequency range
*/
@@ -25,6 +31,14 @@ typedef struct {
extern const soc_mipi_csi_phy_pll_freq_range_t soc_mipi_csi_phy_pll_ranges[];
extern const size_t num_of_soc_mipi_csi_phy_pll_ranges;
typedef struct {
const int host_irq_id; // interrupt source ID for MIPI CSI Host
} soc_mipi_csi_signal_desc_t;
extern const soc_mipi_csi_signal_desc_t soc_mipi_csi_signals[MIPI_CSI_LL_HOST_CTLR_NUMS];
#endif // SOC_HAS(MIPI_CSI)
#ifdef __cplusplus
}
#endif