mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(csi): added csi driver
This commit is contained in:
parent
4c190c56e6
commit
f918079e8e
13
components/esp_cam_ctlr/CMakeLists.txt
Normal file
13
components/esp_cam_ctlr/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
set(srcs "esp_cam_ctlr.c")
|
||||
|
||||
set(include "include" "interface")
|
||||
|
||||
if(CONFIG_SOC_MIPI_CSI_SUPPORTED)
|
||||
list(APPEND srcs "csi/src/esp_cam_ctlr_csi.c")
|
||||
list(APPEND include "csi/include")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${include}
|
||||
PRIV_REQUIRES esp_mm
|
||||
)
|
11
components/esp_cam_ctlr/Kconfig
Normal file
11
components/esp_cam_ctlr/Kconfig
Normal file
@ -0,0 +1,11 @@
|
||||
menu "ESP Camera Controller Configurations"
|
||||
depends on SOC_MIPI_CSI_SUPPORTED
|
||||
|
||||
config MIPI_CSI_ISR_IRAM_SAFE
|
||||
bool "CSI ISR IRAM-Safe"
|
||||
default n
|
||||
help
|
||||
Ensure the CSI driver ISR is IRAM-Safe. When enabled, the ISR handler
|
||||
will be available when the cache is disabled.
|
||||
|
||||
endmenu # ESP Camera Controller Configurations
|
56
components/esp_cam_ctlr/csi/include/esp_cam_ctlr_csi.h
Normal file
56
components/esp_cam_ctlr/csi/include/esp_cam_ctlr_csi.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "hal/mipi_csi_types.h"
|
||||
#include "esp_cam_ctlr_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ESP CAM controller max timeout value
|
||||
*/
|
||||
#define ESP_CAM_CTLR_MAX_DELAY UINT32_MAX
|
||||
|
||||
/**
|
||||
* @brief ESP CAM CSI controller configurations
|
||||
*/
|
||||
typedef struct {
|
||||
int ctlr_id; ///< CSI controller ID
|
||||
mipi_csi_phy_clock_source_t clk_src; ///< CSI phy clock source
|
||||
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
|
||||
uint8_t data_lane_num; ///< Data lane num
|
||||
int clk_freq_hz; ///< Frequency of CLK, in Hz.
|
||||
mipi_csi_color_t input_data_color_type; ///< Input color type
|
||||
mipi_csi_color_t output_data_color_type; ///< Output color type
|
||||
bool byte_swap_en; ///< Enable byte swap
|
||||
int queue_items; ///< Queue itmes
|
||||
} esp_cam_ctlr_csi_config_t;
|
||||
|
||||
/**
|
||||
* @brief New ESP CAM CSI controller
|
||||
*
|
||||
* @param[in] config CSI controller configurations
|
||||
* @param[out] ret_handle Returned ESP CAM controller handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_NO_MEM: Out of memory
|
||||
* - ESP_ERR_NOT_SUPPORTED: Currently not support modes or types
|
||||
* - ESP_ERR_NOT_FOUND: CSI is registered already
|
||||
*/
|
||||
esp_err_t esp_cam_new_csi_ctlr(const esp_cam_ctlr_csi_config_t *config, esp_cam_ctlr_handle_t *ret_handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
458
components/esp_cam_ctlr/csi/src/esp_cam_ctlr_csi.c
Normal file
458
components/esp_cam_ctlr/csi/src/esp_cam_ctlr_csi.c
Normal file
@ -0,0 +1,458 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <sys/lock.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/idf_additions.h"
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_cam_ctlr.h"
|
||||
#include "esp_cam_ctlr_csi.h"
|
||||
#include "esp_cam_ctlr_interface.h"
|
||||
#include "esp_cam_ctlr_csi_internal.h"
|
||||
#include "hal/mipi_csi_ll.h"
|
||||
#include "hal/color_hal.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/mipi_csi_share_hw_ctrl.h"
|
||||
#include "esp_private/esp_cache_private.h"
|
||||
#include "esp_cache.h"
|
||||
|
||||
#if CONFIG_MIPI_CSI_ISR_IRAM_SAFE
|
||||
#define CSI_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#else
|
||||
#define CSI_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||
#endif
|
||||
|
||||
typedef struct csi_platform_t {
|
||||
_lock_t mutex;
|
||||
csi_controller_t *controllers[MIPI_CSI_LL_HOST_CTLR_NUMS];
|
||||
} csi_platform_t;
|
||||
|
||||
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 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);
|
||||
static esp_err_t s_csi_ctlr_enable(esp_cam_ctlr_handle_t ctlr);
|
||||
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 esp_err_t s_csi_claim_controller(csi_controller_t *controller)
|
||||
{
|
||||
assert(controller);
|
||||
|
||||
_lock_acquire(&s_platform.mutex);
|
||||
bool found = false;
|
||||
for (int i = 0; i < MIPI_CSI_LL_HOST_CTLR_NUMS; i ++) {
|
||||
found = !s_platform.controllers[i];
|
||||
if (found) {
|
||||
s_platform.controllers[i] = controller;
|
||||
controller->csi_id = i;
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
mipi_csi_ll_enable_host_bus_clock(i, 0);
|
||||
mipi_csi_ll_enable_host_bus_clock(i, 1);
|
||||
mipi_csi_ll_reset_host_clock(i);
|
||||
}
|
||||
_lock_release(&s_platform.mutex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_lock_release(&s_platform.mutex);
|
||||
|
||||
if (!found) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t s_csi_declaim_controller(csi_controller_t *controller)
|
||||
{
|
||||
assert(controller);
|
||||
|
||||
_lock_acquire(&s_platform.mutex);
|
||||
s_platform.controllers[controller->csi_id] = NULL;
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
mipi_csi_ll_enable_host_bus_clock(controller->csi_id, 0);
|
||||
}
|
||||
_lock_release(&s_platform.mutex);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_cam_new_csi_ctlr(const esp_cam_ctlr_csi_config_t *config, esp_cam_ctlr_handle_t *ret_handle)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
ESP_RETURN_ON_FALSE(config && ret_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(config->data_lane_num <= MIPI_CSI_HOST_LL_LANE_NUM_MAX, ESP_ERR_INVALID_ARG, TAG, "lane num should be equal or smaller than %d", MIPI_CSI_HOST_LL_LANE_NUM_MAX);
|
||||
|
||||
csi_controller_t *ctlr = heap_caps_calloc(1, sizeof(csi_controller_t), CSI_MEM_ALLOC_CAPS);
|
||||
ESP_RETURN_ON_FALSE(ctlr, ESP_ERR_NO_MEM, TAG, "no mem for csi controller context");
|
||||
|
||||
ESP_LOGD(TAG, "config->queue_items: %d", config->queue_items);
|
||||
ctlr->trans_que = xQueueCreateWithCaps(config->queue_items, sizeof(esp_cam_ctlr_trans_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
ESP_GOTO_ON_FALSE(ctlr->trans_que, ESP_ERR_NO_MEM, err, TAG, "no memory for transaction queue");
|
||||
|
||||
//claim a controller, then do assignment
|
||||
ESP_GOTO_ON_ERROR(s_csi_claim_controller(ctlr), err, TAG, "no available csi controller");
|
||||
#if SOC_ISP_SHARE_CSI_BRG
|
||||
ESP_GOTO_ON_ERROR(mipi_csi_brg_claim(MIPI_CSI_BRG_USER_CSI, &ctlr->csi_brg_id), err, TAG, "csi bridge is in use already");
|
||||
ctlr->csi_brg_in_use = true;
|
||||
#endif
|
||||
|
||||
mipi_csi_phy_clock_source_t clk_src = !config->clk_src ? MIPI_CSI_PHY_CLK_SRC_DEFAULT : config->clk_src;
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
// phy clock source setting
|
||||
mipi_csi_ll_set_phy_clock_source(ctlr->csi_id, clk_src);
|
||||
// phy clock reset
|
||||
mipi_csi_ll_enable_phy_config_clock(ctlr->csi_id, 0);
|
||||
mipi_csi_ll_enable_phy_config_clock(ctlr->csi_id, 1);
|
||||
}
|
||||
|
||||
ctlr->h_res = config->h_res;
|
||||
ctlr->v_res = config->v_res;
|
||||
ESP_LOGD(TAG, "ctlr->h_res: 0d %"PRId32, ctlr->h_res);
|
||||
ESP_LOGD(TAG, "ctlr->v_res: 0d %"PRId32, ctlr->v_res);
|
||||
|
||||
//in color type
|
||||
color_space_pixel_format_t in_color_format = {
|
||||
.color_type_id = config->input_data_color_type,
|
||||
};
|
||||
int in_bits_per_pixel = color_hal_pixel_format_get_bit_depth(in_color_format);
|
||||
ctlr->in_color_format = in_color_format;
|
||||
ctlr->in_bpp = in_bits_per_pixel;
|
||||
ESP_LOGD(TAG, "ctlr->in_bpp: 0d %d", ctlr->in_bpp);
|
||||
|
||||
//out color type
|
||||
color_space_pixel_format_t out_color_format = {
|
||||
.color_type_id = config->output_data_color_type,
|
||||
};
|
||||
int out_bits_per_pixel = color_hal_pixel_format_get_bit_depth(out_color_format);
|
||||
ctlr->out_bpp = out_bits_per_pixel;
|
||||
ESP_LOGD(TAG, "ctlr->out_bpp: 0d %d", ctlr->out_bpp);
|
||||
|
||||
// Note: Width * Height * BitsPerPixel must be divisible by 8
|
||||
int fb_size_in_bits = config->v_res * config->h_res * out_bits_per_pixel;
|
||||
ESP_GOTO_ON_FALSE((fb_size_in_bits % 8 == 0), ESP_ERR_INVALID_ARG, err, TAG, "framesize not 8bit aligned");
|
||||
ctlr->fb_size_in_bytes = fb_size_in_bits / 8;
|
||||
ESP_LOGD(TAG, "ctlr->fb_size_in_bytes=%d", ctlr->fb_size_in_bytes);
|
||||
|
||||
size_t dma_alignment = 4; //TODO: IDF-9126, replace with dwgdma alignment API
|
||||
size_t cache_alignment = 1;
|
||||
ESP_GOTO_ON_ERROR(esp_cache_get_alignment(ESP_CACHE_MALLOC_FLAG_PSRAM | ESP_CACHE_MALLOC_FLAG_DMA, &cache_alignment), err, TAG, "failed to get cache alignment");
|
||||
size_t alignment = MAX(cache_alignment, dma_alignment);
|
||||
ESP_LOGD(TAG, "alignment: 0x%x\n", alignment);
|
||||
|
||||
ctlr->backup_buffer = heap_caps_aligned_alloc(alignment, ctlr->fb_size_in_bytes, MALLOC_CAP_SPIRAM);
|
||||
ESP_GOTO_ON_FALSE(ctlr->backup_buffer, ESP_ERR_NO_MEM, err, TAG, "no mem for backup buffer");
|
||||
ESP_LOGD(TAG, "ctlr->backup_buffer: %p\n", ctlr->backup_buffer);
|
||||
esp_cache_msync((void *)(ctlr->backup_buffer), ctlr->fb_size_in_bytes, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
|
||||
|
||||
mipi_csi_hal_config_t hal_config;
|
||||
hal_config.frame_height = config->h_res;
|
||||
hal_config.frame_width = config->v_res;
|
||||
hal_config.clk_freq_hz = config->clk_freq_hz;
|
||||
hal_config.lanes_num = config->data_lane_num;
|
||||
hal_config.byte_swap_en = config->byte_swap_en;
|
||||
mipi_csi_hal_init(&ctlr->hal, &hal_config);
|
||||
mipi_csi_brg_ll_set_burst_len(ctlr->hal.bridge_dev, 512);
|
||||
|
||||
//---------------DWGDMA Init For CSI------------------//
|
||||
dw_gdma_channel_handle_t csi_dma_chan = NULL;
|
||||
dw_gdma_channel_alloc_config_t csi_dma_alloc_config = {
|
||||
.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(&csi_dma_alloc_config, &csi_dma_chan), err, TAG, "failed to new dwgdma channle");
|
||||
ctlr->dma_chan = csi_dma_chan;
|
||||
|
||||
size_t csi_transfer_size = ctlr->h_res * ctlr->v_res * ctlr->in_bpp / 64;
|
||||
ctlr->csi_transfer_size = csi_transfer_size;
|
||||
ESP_LOGD(TAG, "csi_transfer_size: 0d %d", csi_transfer_size);
|
||||
|
||||
dw_gdma_event_callbacks_t csi_dma_cbs = {
|
||||
.on_full_trans_done = csi_dma_trans_done_callback,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(dw_gdma_channel_register_event_callbacks(csi_dma_chan, &csi_dma_cbs, ctlr), err, TAG, "failed to register dwgdma callback");
|
||||
|
||||
ctlr->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
ctlr->csi_fsm = CSI_FSM_INIT;
|
||||
ctlr->base.del = s_ctlr_del;
|
||||
ctlr->base.enable = s_csi_ctlr_enable;
|
||||
ctlr->base.start = s_ctlr_csi_start;
|
||||
ctlr->base.stop = s_ctlr_csi_stop;
|
||||
ctlr->base.disable = s_csi_ctlr_disable;
|
||||
ctlr->base.receive = s_ctlr_csi_receive;
|
||||
ctlr->base.register_event_callbacks = s_register_event_callbacks;
|
||||
|
||||
*ret_handle = &(ctlr->base);
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
s_del_csi_ctlr(ctlr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 (ctlr->dma_chan) {
|
||||
ESP_RETURN_ON_ERROR(dw_gdma_del_channel(ctlr->dma_chan), TAG, "failed to delete dwgdma channel");
|
||||
}
|
||||
//declaim first, then do free
|
||||
ESP_RETURN_ON_ERROR(s_csi_declaim_controller(ctlr), TAG, "declaim processor fail");
|
||||
#if SOC_ISP_SHARE_CSI_BRG
|
||||
if (ctlr->csi_brg_in_use) {
|
||||
ESP_RETURN_ON_ERROR(mipi_csi_brg_declaim(ctlr->csi_brg_id), TAG, "declaim csi bridge fail");
|
||||
ctlr->csi_brg_in_use = false;
|
||||
}
|
||||
#endif
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
mipi_csi_ll_enable_phy_config_clock(ctlr->csi_id, 0);
|
||||
}
|
||||
free(ctlr->backup_buffer);
|
||||
vQueueDeleteWithCaps(ctlr->trans_que);
|
||||
free(ctlr);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t s_ctlr_del(esp_cam_ctlr_t *cam_ctlr)
|
||||
{
|
||||
csi_controller_t *csi_ctlr = __containerof(cam_ctlr, csi_controller_t, base);
|
||||
ESP_RETURN_ON_ERROR(s_del_csi_ctlr(csi_ctlr), TAG, "failed to del csi_ctlr");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
bool need_yield = false;
|
||||
BaseType_t high_task_woken = pdFALSE;
|
||||
csi_controller_t *ctlr = (csi_controller_t *)user_data;
|
||||
bool use_backup = false;
|
||||
|
||||
dw_gdma_block_transfer_config_t csi_dma_transfer_config = {};
|
||||
csi_dma_transfer_config = (dw_gdma_block_transfer_config_t) {
|
||||
.src = {
|
||||
.addr = MIPI_CSI_BRG_MEM_BASE,
|
||||
.burst_mode = DW_GDMA_BURST_MODE_FIXED,
|
||||
.burst_items = DW_GDMA_BURST_ITEMS_512,
|
||||
.burst_len = 16,
|
||||
.width = DW_GDMA_TRANS_WIDTH_64,
|
||||
},
|
||||
.dst = {
|
||||
.addr = 0,
|
||||
.burst_mode = DW_GDMA_BURST_MODE_INCREMENT,
|
||||
.burst_items = DW_GDMA_BURST_ITEMS_512,
|
||||
.burst_len = 16,
|
||||
.width = DW_GDMA_TRANS_WIDTH_64,
|
||||
},
|
||||
.size = ctlr->csi_transfer_size,
|
||||
};
|
||||
esp_cam_ctlr_trans_t new_trans = {};
|
||||
|
||||
if (ctlr->cbs.on_get_new_trans) {
|
||||
need_yield = ctlr->cbs.on_get_new_trans(&(ctlr->base), &new_trans, ctlr->cbs_user_data);
|
||||
assert(new_trans.buflen >= ctlr->fb_size_in_bytes);
|
||||
csi_dma_transfer_config.dst.addr = (uint32_t)(new_trans.buffer);
|
||||
} else if (xQueueReceiveFromISR(ctlr->trans_que, &new_trans, &high_task_woken) == pdTRUE) {
|
||||
assert(new_trans.buflen >= ctlr->fb_size_in_bytes);
|
||||
csi_dma_transfer_config.dst.addr = (uint32_t)(new_trans.buffer);
|
||||
} else {
|
||||
use_backup = true;
|
||||
new_trans.buffer = ctlr->backup_buffer;
|
||||
new_trans.buflen = ctlr->fb_size_in_bytes;
|
||||
ESP_EARLY_LOGD(TAG, "no new buffer, use driver internal buffer");
|
||||
csi_dma_transfer_config.dst.addr = (uint32_t)ctlr->backup_buffer;
|
||||
}
|
||||
|
||||
if (!use_backup) {
|
||||
esp_err_t ret = esp_cache_msync((void *)(ctlr->trans.buffer), ctlr->trans.received_size, ESP_CACHE_MSYNC_FLAG_INVALIDATE);
|
||||
assert(ret == ESP_OK);
|
||||
}
|
||||
|
||||
ESP_EARLY_LOGD(TAG, "new_trans.buffer: %p, new_trans.buflen: %d", new_trans.buffer, new_trans.buflen);
|
||||
dw_gdma_channel_config_transfer(chan, &csi_dma_transfer_config);
|
||||
dw_gdma_channel_enable_ctrl(chan, true);
|
||||
|
||||
if (!use_backup) {
|
||||
assert(ctlr->cbs.on_trans_finished);
|
||||
if (ctlr->cbs.on_trans_finished) {
|
||||
ctlr->trans.received_size = ctlr->fb_size_in_bytes;
|
||||
need_yield = ctlr->cbs.on_trans_finished(&(ctlr->base), &ctlr->trans, ctlr->cbs_user_data);
|
||||
}
|
||||
}
|
||||
|
||||
//ctlr->trans is the transaction saved before dma starts
|
||||
memset(&ctlr->trans, 0x0, sizeof(esp_cam_ctlr_trans_t));
|
||||
ctlr->trans = new_trans;
|
||||
|
||||
need_yield |= high_task_woken == pdTRUE;
|
||||
return need_yield;
|
||||
}
|
||||
|
||||
esp_err_t s_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_data)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
csi_controller_t *ctlr = __containerof(handle, csi_controller_t, base);
|
||||
ESP_RETURN_ON_FALSE(ctlr->csi_fsm == CSI_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "driver starts already, not allow cbs register");
|
||||
|
||||
#if CONFIG_MIPI_CSI_ISR_IRAM_SAFE
|
||||
if (cbs->on_get_new_trans) {
|
||||
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_get_new_trans), ESP_ERR_INVALID_ARG, TAG, "on_get_new_trans callback not in IRAM");
|
||||
}
|
||||
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");
|
||||
}
|
||||
#endif
|
||||
|
||||
ctlr->cbs.on_get_new_trans = cbs->on_get_new_trans;
|
||||
ctlr->cbs.on_trans_finished = cbs->on_trans_finished;
|
||||
ctlr->cbs_user_data = user_data;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
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");
|
||||
csi_controller_t *ctlr = __containerof(handle, csi_controller_t, base);
|
||||
ESP_RETURN_ON_FALSE(ctlr->csi_fsm == CSI_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "processor isn't in init state");
|
||||
|
||||
portENTER_CRITICAL(&ctlr->spinlock);
|
||||
ctlr->csi_fsm = CSI_FSM_ENABLED;
|
||||
portEXIT_CRITICAL(&ctlr->spinlock);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t s_csi_ctlr_disable(esp_cam_ctlr_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
csi_controller_t *ctlr = __containerof(handle, csi_controller_t, base);
|
||||
ESP_RETURN_ON_FALSE(ctlr->csi_fsm == CSI_FSM_ENABLED, ESP_ERR_INVALID_STATE, TAG, "processor isn't in init state");
|
||||
|
||||
portENTER_CRITICAL(&ctlr->spinlock);
|
||||
ctlr->csi_fsm = CSI_FSM_INIT;
|
||||
portEXIT_CRITICAL(&ctlr->spinlock);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t s_ctlr_csi_start(esp_cam_ctlr_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
csi_controller_t *ctlr = __containerof(handle, csi_controller_t, base);
|
||||
ESP_RETURN_ON_FALSE(ctlr->csi_fsm == CSI_FSM_ENABLED, ESP_ERR_INVALID_STATE, TAG, "driver starts already, should not start again");
|
||||
ESP_RETURN_ON_FALSE(ctlr->cbs.on_trans_finished, ESP_ERR_INVALID_STATE, TAG, "no on_trans_finished callback registered");
|
||||
|
||||
esp_cam_ctlr_trans_t trans = {};
|
||||
if (ctlr->cbs.on_get_new_trans) {
|
||||
ctlr->cbs.on_get_new_trans(handle, &trans, ctlr->cbs_user_data);
|
||||
ESP_RETURN_ON_FALSE(trans.buffer, ESP_ERR_INVALID_STATE, TAG, "no ready transaction, cannot start");
|
||||
} else {
|
||||
trans.buffer = ctlr->backup_buffer;
|
||||
trans.buflen = ctlr->fb_size_in_bytes;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "trans.buffer: %p, trans.buflen: %d", trans.buffer, trans.buflen);
|
||||
ctlr->trans = trans;
|
||||
|
||||
portENTER_CRITICAL(&ctlr->spinlock);
|
||||
ctlr->csi_fsm = CSI_FSM_STARTED;
|
||||
portEXIT_CRITICAL(&ctlr->spinlock);
|
||||
|
||||
dw_gdma_block_transfer_config_t csi_dma_transfer_config = {};
|
||||
csi_dma_transfer_config = (dw_gdma_block_transfer_config_t) {
|
||||
.src = {
|
||||
.addr = MIPI_CSI_BRG_MEM_BASE,
|
||||
.burst_mode = DW_GDMA_BURST_MODE_FIXED,
|
||||
.burst_items = DW_GDMA_BURST_ITEMS_512,
|
||||
.burst_len = 16,
|
||||
.width = DW_GDMA_TRANS_WIDTH_64,
|
||||
},
|
||||
.dst = {
|
||||
.addr = (uint32_t)(trans.buffer),
|
||||
.burst_mode = DW_GDMA_BURST_MODE_INCREMENT,
|
||||
.burst_items = DW_GDMA_BURST_ITEMS_512,
|
||||
.burst_len = 16,
|
||||
.width = DW_GDMA_TRANS_WIDTH_64,
|
||||
},
|
||||
.size = ctlr->csi_transfer_size,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(dw_gdma_channel_config_transfer(ctlr->dma_chan, &csi_dma_transfer_config), TAG, "failed to configure dwgdma transfer");
|
||||
ESP_RETURN_ON_ERROR(dw_gdma_channel_enable_ctrl(ctlr->dma_chan, true), TAG, "failed to enable dwgdma");
|
||||
|
||||
//enable CSI bridge
|
||||
mipi_csi_brg_ll_enable(ctlr->hal.bridge_dev, true);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t s_ctlr_csi_stop(esp_cam_ctlr_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
csi_controller_t *ctlr = __containerof(handle, csi_controller_t, base);
|
||||
ESP_RETURN_ON_FALSE(ctlr->csi_fsm == CSI_FSM_ENABLED, ESP_ERR_INVALID_STATE, TAG, "driver isn't started");
|
||||
|
||||
//disable CSI bridge
|
||||
mipi_csi_brg_ll_enable(ctlr->hal.bridge_dev, false);
|
||||
ESP_RETURN_ON_ERROR(dw_gdma_channel_enable_ctrl(ctlr->dma_chan, false), TAG, "failed to disable dwgdma");
|
||||
|
||||
portENTER_CRITICAL(&ctlr->spinlock);
|
||||
ctlr->csi_fsm = CSI_FSM_INIT;
|
||||
portEXIT_CRITICAL(&ctlr->spinlock);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t s_ctlr_csi_receive(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, uint32_t timeout_ms)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE(handle && trans, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
csi_controller_t *ctlr = __containerof(handle, csi_controller_t, base);
|
||||
|
||||
ESP_RETURN_ON_FALSE(trans->buffer, ESP_ERR_INVALID_ARG, TAG, "invalid argument: no trans buffer");
|
||||
ESP_RETURN_ON_FALSE((trans->buflen >= ctlr->fb_size_in_bytes), ESP_ERR_INVALID_ARG, TAG, "invalid argument: trans buffer smaller than framebuffer size");
|
||||
|
||||
TickType_t ticks_to_wait = timeout_ms / portTICK_PERIOD_MS;
|
||||
if (timeout_ms == ESP_CAM_CTLR_MAX_DELAY) {
|
||||
ticks_to_wait = portMAX_DELAY;
|
||||
}
|
||||
|
||||
BaseType_t r = xQueueSend(ctlr->trans_que, trans, ticks_to_wait);
|
||||
if (r != pdTRUE) {
|
||||
ret = ESP_ERR_TIMEOUT;
|
||||
ESP_LOGW(TAG, "csi recv API, transaction queue is full, failed to send transaction to the queue");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
68
components/esp_cam_ctlr/csi/src/esp_cam_ctlr_csi_internal.h
Normal file
68
components/esp_cam_ctlr/csi/src/esp_cam_ctlr_csi_internal.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <esp_types.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_cam_ctlr_csi.h"
|
||||
#include "hal/mipi_csi_hal.h"
|
||||
#include "hal/mipi_csi_types.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_private/dw_gdma.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
CSI_FSM_INIT,
|
||||
CSI_FSM_ENABLED,
|
||||
CSI_FSM_STARTED,
|
||||
} csi_fsm_t;
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Driver Context
|
||||
---------------------------------------------------------------*/
|
||||
typedef struct csi_controller_t csi_controller_t;
|
||||
|
||||
struct csi_controller_t {
|
||||
int csi_id; //csi id
|
||||
#if SOC_ISP_SHARE_CSI_BRG
|
||||
int csi_brg_id; //csi bridge id
|
||||
void *csi_brg_hw; //csi bridge hardware context
|
||||
bool csi_brg_in_use; //csi bridge is in use
|
||||
#endif
|
||||
mipi_csi_hal_context_t hal; //hal context
|
||||
csi_fsm_t csi_fsm; //driver fsm
|
||||
portMUX_TYPE spinlock; //spinlock
|
||||
color_space_pixel_format_t in_color_format; //input color format
|
||||
color_space_pixel_format_t out_color_format; //output color format
|
||||
uint32_t h_res; //input horizontal resolution
|
||||
uint32_t v_res; //input vertical resolution
|
||||
int in_bpp; //input data type, bit per pixel
|
||||
int out_bpp; //output data type, bit per pixel
|
||||
size_t fb_size_in_bytes; //Frame buffer size, in bytes
|
||||
esp_cam_ctlr_trans_t trans; //Saved done transaction to be given out to callers
|
||||
void *backup_buffer; //backup buffer to make csi bridge can work to avoid wrong state
|
||||
QueueHandle_t trans_que; //transaction queue
|
||||
esp_cam_ctlr_evt_cbs_t cbs; //user callbacks
|
||||
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
|
||||
esp_cam_ctlr_t base;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
73
components/esp_cam_ctlr/esp_cam_ctlr.c
Normal file
73
components/esp_cam_ctlr/esp_cam_ctlr.c
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include "esp_types.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_cam_ctlr.h"
|
||||
#include "esp_cam_ctlr_interface.h"
|
||||
|
||||
static const char *TAG = "CAM_CTLR";
|
||||
|
||||
esp_err_t esp_cam_ctlr_enable(esp_cam_ctlr_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(handle->enable, ESP_ERR_NOT_SUPPORTED, TAG, "controller driver function not supported");
|
||||
|
||||
return handle->enable(handle);
|
||||
}
|
||||
|
||||
esp_err_t esp_cam_ctlr_start(esp_cam_ctlr_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(handle->start, ESP_ERR_NOT_SUPPORTED, TAG, "controller driver function not supported");
|
||||
|
||||
return handle->start(handle);
|
||||
}
|
||||
|
||||
esp_err_t esp_cam_ctlr_stop(esp_cam_ctlr_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(handle->stop, ESP_ERR_NOT_SUPPORTED, TAG, "controller driver function not supported");
|
||||
|
||||
return handle->stop(handle);
|
||||
}
|
||||
|
||||
esp_err_t esp_cam_ctlr_disable(esp_cam_ctlr_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(handle->disable, ESP_ERR_NOT_SUPPORTED, TAG, "controller driver function not supported");
|
||||
|
||||
return handle->disable(handle);
|
||||
}
|
||||
|
||||
esp_err_t esp_cam_ctlr_receive(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, uint32_t timeout_ms)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(handle->receive, ESP_ERR_NOT_SUPPORTED, TAG, "controller driver function not supported");
|
||||
|
||||
return handle->receive(handle, trans, timeout_ms);
|
||||
}
|
||||
|
||||
esp_err_t esp_cam_ctlr_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_data)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(handle->register_event_callbacks, ESP_ERR_NOT_SUPPORTED, TAG, "controller driver function not supported");
|
||||
|
||||
return handle->register_event_callbacks(handle, cbs, user_data);
|
||||
}
|
||||
|
||||
esp_err_t esp_cam_del_ctlr(esp_cam_ctlr_handle_t handle)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(handle->del, ESP_ERR_NOT_SUPPORTED, TAG, "controller driver function not supported");
|
||||
|
||||
return handle->del(handle);
|
||||
}
|
106
components/esp_cam_ctlr/include/esp_cam_ctlr.h
Normal file
106
components/esp_cam_ctlr/include/esp_cam_ctlr.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_cam_ctlr_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable ESP CAM controller
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||
*/
|
||||
esp_err_t esp_cam_ctlr_enable(esp_cam_ctlr_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Start ESP CAM controller
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||
*/
|
||||
esp_err_t esp_cam_ctlr_start(esp_cam_ctlr_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Stop ESP CAM controller
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||
*/
|
||||
esp_err_t esp_cam_ctlr_stop(esp_cam_ctlr_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Disable ESP CAM controller
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||
*/
|
||||
esp_err_t esp_cam_ctlr_disable(esp_cam_ctlr_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Receive data to the given transaction
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
* @param[in] trans ESP CAM controller transaction type
|
||||
* @param[in] timeout_ms Timeout in ms
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||
*/
|
||||
esp_err_t esp_cam_ctlr_receive(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Delete ESP CAM controller handle
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||
*/
|
||||
esp_err_t esp_cam_del_ctlr(esp_cam_ctlr_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Register ESP CAM controller event callbacks
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||
*/
|
||||
esp_err_t esp_cam_ctlr_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
61
components/esp_cam_ctlr/include/esp_cam_ctlr_types.h
Normal file
61
components/esp_cam_ctlr/include/esp_cam_ctlr_types.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ESP CAM controller handle
|
||||
*/
|
||||
typedef struct esp_cam_ctlr_t *esp_cam_ctlr_handle_t;
|
||||
|
||||
/**
|
||||
* @brief ESP CAM controller transaction type
|
||||
*/
|
||||
typedef struct {
|
||||
void *buffer; ///< Transaction buffer
|
||||
size_t buflen; ///< Len of the transaction buffer
|
||||
size_t received_size; ///< Received size, this received_size will be written by the driver, indicating the real received size
|
||||
} esp_cam_ctlr_trans_t;
|
||||
|
||||
/**
|
||||
* @brief ESP CAM controller event callbacks
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief On get new transaction callback
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
* @param[in] trans New transaction
|
||||
* @param[in] user_data User registered data
|
||||
*
|
||||
* @return Whether a high priority task is woken up by this function
|
||||
*/
|
||||
bool (*on_get_new_trans)(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief On transaction finish callback
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
* @param[out] trans Finished transaction
|
||||
* @param[in] user_data User registered data
|
||||
*
|
||||
* @return Whether a high priority task is woken up by this function
|
||||
*/
|
||||
bool (*on_trans_finished)(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data);
|
||||
|
||||
} esp_cam_ctlr_evt_cbs_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
113
components/esp_cam_ctlr/interface/esp_cam_ctlr_interface.h
Normal file
113
components/esp_cam_ctlr/interface/esp_cam_ctlr_interface.h
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_cam_ctlr_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct esp_cam_ctlr_t esp_cam_ctlr_t; /*!< Type of CAM controller */
|
||||
|
||||
/**
|
||||
* @brief Cam controller interface
|
||||
*/
|
||||
struct esp_cam_ctlr_t {
|
||||
/**
|
||||
* @brief Enable ESP CAM controller
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||
*/
|
||||
esp_err_t (*enable)(esp_cam_ctlr_t *ctlr);
|
||||
|
||||
/**
|
||||
* @brief Start ESP CAM controller
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||
*/
|
||||
esp_err_t (*start)(esp_cam_ctlr_t *ctlr);
|
||||
|
||||
/**
|
||||
* @brief Stop ESP CAM controller
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||
*/
|
||||
esp_err_t (*stop)(esp_cam_ctlr_t *ctlr);
|
||||
|
||||
/**
|
||||
* @brief Disable ESP CAM controller
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||
*/
|
||||
esp_err_t (*disable)(esp_cam_ctlr_t *ctlr);
|
||||
|
||||
/**
|
||||
* @brief Receive data to the given transaction
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
* @param[in] trans ESP CAM controller transaction type
|
||||
* @param[in] timeout_ms Timeout in ms
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||
*/
|
||||
esp_err_t (*receive)(esp_cam_ctlr_t *ctlr, esp_cam_ctlr_trans_t *trans, uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Delete ESP CAM controller handle
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||
*/
|
||||
esp_err_t (*del)(esp_cam_ctlr_t *ctlr);
|
||||
|
||||
/**
|
||||
* @brief Register ESP CAM controller event callbacks
|
||||
*
|
||||
* @param[in] handle ESP CAM controller handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||
*/
|
||||
esp_err_t (*register_event_callbacks)(esp_cam_ctlr_t *ctlr, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_ctx);
|
||||
|
||||
void *user_data; ///< User data
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
5
components/esp_cam_ctlr/test_apps/.build-test-rules.yml
Normal file
5
components/esp_cam_ctlr/test_apps/.build-test-rules.yml
Normal file
@ -0,0 +1,5 @@
|
||||
components/esp_cam_ctlr/test_apps/csi:
|
||||
disable:
|
||||
- if: SOC_MIPI_CSI_SUPPORTED != 1
|
||||
depends_components:
|
||||
- esp_cam_ctlr
|
8
components/esp_cam_ctlr/test_apps/csi/CMakeLists.txt
Normal file
8
components/esp_cam_ctlr/test_apps/csi/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||
|
||||
set(COMPONENTS main)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(test_csi)
|
2
components/esp_cam_ctlr/test_apps/csi/README.md
Normal file
2
components/esp_cam_ctlr/test_apps/csi/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32-P4 |
|
||||
| ----------------- | -------- |
|
16
components/esp_cam_ctlr/test_apps/csi/main/CMakeLists.txt
Normal file
16
components/esp_cam_ctlr/test_apps/csi/main/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
||||
set(srcs "test_app_main.c")
|
||||
|
||||
if(CONFIG_SOC_MIPI_CSI_SUPPORTED)
|
||||
list(APPEND srcs "test_csi_driver.c")
|
||||
endif()
|
||||
|
||||
set(priv_requires
|
||||
unity
|
||||
esp_cam_ctlr
|
||||
esp_psram
|
||||
)
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES ${priv_requires}
|
||||
WHOLE_ARCHIVE TRUE)
|
27
components/esp_cam_ctlr/test_apps/csi/main/test_app_main.c
Normal file
27
components/esp_cam_ctlr/test_apps/csi/main/test_app_main.c
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_utils.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (400)
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
unity_run_menu();
|
||||
}
|
29
components/esp_cam_ctlr/test_apps/csi/main/test_csi_driver.c
Normal file
29
components/esp_cam_ctlr/test_apps/csi/main/test_csi_driver.c
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
#include "esp_cam_ctlr_csi.h"
|
||||
#include "esp_cam_ctlr.h"
|
||||
|
||||
TEST_CASE("TEST CSI driver allocation", "[csi]")
|
||||
{
|
||||
esp_cam_ctlr_csi_config_t csi_config = {
|
||||
.ctlr_id = 0,
|
||||
.h_res = 800,
|
||||
.v_res = 640,
|
||||
.clk_freq_hz = 200000000,
|
||||
.input_data_color_type = MIPI_CSI_COLOR_RAW8,
|
||||
.output_data_color_type = MIPI_CSI_COLOR_RGB565,
|
||||
.data_lane_num = 2,
|
||||
.byte_swap_en = false,
|
||||
.queue_items = 1,
|
||||
};
|
||||
esp_cam_ctlr_handle_t handle = NULL;
|
||||
TEST_ESP_OK(esp_cam_new_csi_ctlr(&csi_config, &handle));
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, esp_cam_new_csi_ctlr(&csi_config, &handle));
|
||||
TEST_ESP_OK(esp_cam_del_ctlr(handle));
|
||||
}
|
10
components/esp_cam_ctlr/test_apps/csi/pytest_csi.py
Normal file
10
components/esp_cam_ctlr/test_apps/csi/pytest_csi.py
Normal file
@ -0,0 +1,10 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.generic
|
||||
def test_csi(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases()
|
7
components/esp_cam_ctlr/test_apps/csi/sdkconfig.defaults
Normal file
7
components/esp_cam_ctlr/test_apps/csi/sdkconfig.defaults
Normal file
@ -0,0 +1,7 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
|
||||
CONFIG_SPIRAM_SPEED_200M=y
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
@ -310,7 +310,7 @@ static esp_err_t dpi_panel_init(esp_lcd_panel_t *panel)
|
||||
.width = DW_GDMA_TRANS_WIDTH_64,
|
||||
},
|
||||
.dst = {
|
||||
.addr = MIPI_DSI_MEM_BASE,
|
||||
.addr = MIPI_DSI_BRG_MEM_BASE,
|
||||
.burst_mode = DW_GDMA_BURST_MODE_FIXED,
|
||||
.burst_items = DW_GDMA_BURST_ITEMS_256,
|
||||
.burst_len = 16,
|
||||
|
@ -177,6 +177,10 @@ if(NOT BOOTLOADER_BUILD)
|
||||
list(APPEND srcs "mipi_dsi_hal.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_MIPI_CSI_SUPPORTED)
|
||||
list(APPEND srcs "mipi_csi_hal.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_ECC_SUPPORTED)
|
||||
list(APPEND srcs "ecc_hal.c")
|
||||
endif()
|
||||
|
@ -377,7 +377,7 @@ static inline void dw_gdma_ll_channel_set_trans_block_size(dw_gdma_dev_t *dev, u
|
||||
__attribute__((always_inline))
|
||||
static inline void dw_gdma_ll_channel_set_src_master_port(dw_gdma_dev_t *dev, uint8_t channel, intptr_t mem_addr)
|
||||
{
|
||||
if (mem_addr == MIPI_CSI_MEM_BASE) {
|
||||
if (mem_addr == MIPI_CSI_BRG_MEM_BASE) {
|
||||
dev->ch[channel].ctl0.sms = DW_GDMA_LL_MASTER_PORT_MIPI_CSI;
|
||||
} else {
|
||||
dev->ch[channel].ctl0.sms = DW_GDMA_LL_MASTER_PORT_MEMORY;
|
||||
@ -394,7 +394,7 @@ static inline void dw_gdma_ll_channel_set_src_master_port(dw_gdma_dev_t *dev, ui
|
||||
__attribute__((always_inline))
|
||||
static inline void dw_gdma_ll_channel_set_dst_master_port(dw_gdma_dev_t *dev, uint8_t channel, intptr_t mem_addr)
|
||||
{
|
||||
if (mem_addr == MIPI_DSI_MEM_BASE) {
|
||||
if (mem_addr == MIPI_DSI_BRG_MEM_BASE) {
|
||||
dev->ch[channel].ctl0.dms = DW_GDMA_LL_MASTER_PORT_MIPI_DSI;
|
||||
} else {
|
||||
dev->ch[channel].ctl0.dms = DW_GDMA_LL_MASTER_PORT_MEMORY;
|
||||
@ -986,7 +986,7 @@ static inline void dw_gdma_ll_lli_set_dst_trans_width(dw_gdma_link_list_item_t *
|
||||
__attribute__((always_inline))
|
||||
static inline void dw_gdma_ll_lli_set_src_master_port(dw_gdma_link_list_item_t *lli, intptr_t mem_addr)
|
||||
{
|
||||
if (mem_addr == MIPI_CSI_MEM_BASE) {
|
||||
if (mem_addr == MIPI_CSI_BRG_MEM_BASE) {
|
||||
lli->ctrl_lo.sms = DW_GDMA_LL_MASTER_PORT_MIPI_CSI;
|
||||
} else {
|
||||
lli->ctrl_lo.sms = DW_GDMA_LL_MASTER_PORT_MEMORY;
|
||||
@ -1002,7 +1002,7 @@ static inline void dw_gdma_ll_lli_set_src_master_port(dw_gdma_link_list_item_t *
|
||||
__attribute__((always_inline))
|
||||
static inline void dw_gdma_ll_lli_set_dst_master_port(dw_gdma_link_list_item_t *lli, intptr_t mem_addr)
|
||||
{
|
||||
if (mem_addr == MIPI_DSI_MEM_BASE) {
|
||||
if (mem_addr == MIPI_DSI_BRG_MEM_BASE) {
|
||||
lli->ctrl_lo.dms = DW_GDMA_LL_MASTER_PORT_MIPI_DSI;
|
||||
} else {
|
||||
lli->ctrl_lo.dms = DW_GDMA_LL_MASTER_PORT_MEMORY;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "hal/misc.h"
|
||||
#include "hal/assert.h"
|
||||
#include "hal/hal_utils.h"
|
||||
#include "hal/mipi_csi_types.h"
|
||||
#include "soc/mipi_csi_bridge_struct.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -65,6 +66,74 @@ static inline void mipi_csi_brg_ll_set_intput_data_v_row_num(csi_brg_dev_t *dev,
|
||||
dev->frame_cfg.vadr_num = row_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the buffer almost full threshold for the MIPI CSI bridge
|
||||
*
|
||||
* @param dev Pointer to the CSI bridge controller register base address
|
||||
* @param afull_thrd full threshold
|
||||
*/
|
||||
static inline void mipi_csi_brg_ll_set_flow_ctl_buf_afull_thrd(csi_brg_dev_t *dev, size_t afull_thrd)
|
||||
{
|
||||
dev->buf_flow_ctl.csi_buf_afull_thrd = afull_thrd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the frame data whether contain hsync
|
||||
*
|
||||
* @param dev Pointer to the CSI bridge controller register base address
|
||||
* @param en 0: frame data doesn't contain hsync. 1: frame data contains hsync.
|
||||
*/
|
||||
static inline void mipi_csi_brg_ll_enable_has_hsync(csi_brg_dev_t *dev, bool en)
|
||||
{
|
||||
dev->frame_cfg.has_hsync_e = en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the min value of data type used for pixel filter.
|
||||
*
|
||||
* @param dev Pointer to the CSI bridge controller register base address
|
||||
* @param type_min The min data type allowed by bridge's pixel filter.
|
||||
* The data type specifie the format and the content of the payload data.
|
||||
*/
|
||||
static inline void mipi_csi_brg_ll_set_data_type_min(csi_brg_dev_t *dev, uint16_t type_min)
|
||||
{
|
||||
dev->data_type_cfg.data_type_min = type_min;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the the max value of data type used for pixel filter.
|
||||
*
|
||||
* @param dev Pointer to the CSI bridge controller register base address
|
||||
* @param type_max The max data type allowed by bridge's pixel filter.
|
||||
* The data type specifie the format and the content of the payload data.
|
||||
*/
|
||||
static inline void mipi_csi_brg_ll_set_data_type_max(csi_brg_dev_t *dev, uint16_t type_max)
|
||||
{
|
||||
dev->data_type_cfg.data_type_max = type_max;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the DMA interval configuration.
|
||||
*
|
||||
* @param dev Pointer to the CSI bridge controller register base address
|
||||
* @param interval 16'b1: 1 cycle. 16'b11: 2 cycle. ... ... 16'hFFFF: 16 cycle.
|
||||
*/
|
||||
static inline void mipi_csi_brg_ll_set_dma_req_interval(csi_brg_dev_t *dev, uint16_t interval)
|
||||
{
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->dma_req_interval, dma_req_interval, interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the data endianness order in bytes
|
||||
*
|
||||
* @param dev Pointer to the CSI bridge controller register base address
|
||||
* @param byte_swap_en byte swap enable or not
|
||||
*/
|
||||
static inline void mipi_csi_brg_ll_set_byte_endian(csi_brg_dev_t *dev, bool byte_swap_en)
|
||||
{
|
||||
dev->endian_mode.byte_endian_order = byte_swap_en;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
69
components/hal/esp32p4/include/hal/mipi_csi_host_ll.h
Normal file
69
components/hal/esp32p4/include/hal/mipi_csi_host_ll.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "hal/misc.h"
|
||||
#include "hal/assert.h"
|
||||
#include "soc/mipi_csi_host_struct.h"
|
||||
#include "hal/mipi_csi_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MIPI_CSI_HOST_LL_GET_HW(num) (((num) == 0) ? (&MIPI_CSI_HOST) : NULL)
|
||||
|
||||
#define MIPI_CSI_HOST_LL_LANE_NUM_MAX 2
|
||||
|
||||
/**
|
||||
* @brief Enable CSI host reset output
|
||||
*
|
||||
* @param dev Pointer to the CSI Host controller register base address
|
||||
* @param en True to enable, False to disable
|
||||
*/
|
||||
static inline void mipi_csi_host_ll_enable_reset_output(csi_host_dev_t *dev, bool en)
|
||||
{
|
||||
dev->csi2_resetn.csi2_resetn = !en; // host reset output, active low
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the MIPI CSI lane num
|
||||
*
|
||||
* @param dev Pointer to the CSI Host controller register base address
|
||||
* @param lanes_num Number of MIPI CSI lanes
|
||||
*/
|
||||
static inline void mipi_csi_host_ll_set_active_lanes_num(csi_host_dev_t *dev, int lanes_num)
|
||||
{
|
||||
dev->n_lanes.n_lanes = lanes_num - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the CSI virtual channel extension
|
||||
*
|
||||
* @param dev Pointer to the CSI Host controller register base address
|
||||
* @param en True to enable, False to disable
|
||||
*/
|
||||
static inline void mipi_csi_host_ll_enable_virtual_channel_extension(csi_host_dev_t *dev, bool en)
|
||||
{
|
||||
dev->vc_extension.vcx = !en; // 0 is enable
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the data de-scrambling on the controller side
|
||||
*
|
||||
* @param dev Pointer to the CSI Host controller register base address
|
||||
* @param en True to enable, False to disable
|
||||
*/
|
||||
static inline void mipi_csi_host_ll_enable_scrambling(csi_host_dev_t *dev, bool en)
|
||||
{
|
||||
dev->scrambling.scramble_enable = en;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -10,13 +10,18 @@
|
||||
#include "hal/misc.h"
|
||||
#include "hal/assert.h"
|
||||
#include "hal/hal_utils.h"
|
||||
#include "hal/mipi_csi_types.h"
|
||||
#include "hal/mipi_csi_brg_ll.h"
|
||||
#include "hal/mipi_csi_phy_ll.h"
|
||||
#include "hal/mipi_csi_host_ll.h"
|
||||
#include "soc/hp_sys_clkrst_struct.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MIPI_CSI_LL_HOST_CTLR_NUMS 1
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
CSI Bridge
|
||||
---------------------------------------------------------------*/
|
||||
@ -50,6 +55,88 @@ static inline void mipi_csi_ll_reset_brg_module_clock(int csi_bridge_id)
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define mipi_csi_ll_reset_brg_module_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_csi_ll_reset_brg_module_clock(__VA_ARGS__)
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
CSI PHY
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Set the clock source for the MIPI CSI D-PHY
|
||||
*
|
||||
* @param group_id Group ID
|
||||
* @param source Clock source
|
||||
*/
|
||||
static inline void mipi_csi_ll_set_phy_clock_source(int group_id, mipi_csi_phy_clock_source_t source)
|
||||
{
|
||||
(void)group_id;
|
||||
switch (source) {
|
||||
case MIPI_CSI_PHY_CLK_SRC_PLL_F20M:
|
||||
HP_SYS_CLKRST.peri_clk_ctrl03.reg_mipi_csi_dphy_clk_src_sel = 0;
|
||||
break;
|
||||
case MIPI_CSI_PHY_CLK_SRC_RC_FAST:
|
||||
HP_SYS_CLKRST.peri_clk_ctrl03.reg_mipi_csi_dphy_clk_src_sel = 1;
|
||||
break;
|
||||
case MIPI_CSI_PHY_CLK_SRC_PLL_F25M:
|
||||
HP_SYS_CLKRST.peri_clk_ctrl03.reg_mipi_csi_dphy_clk_src_sel = 2;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define mipi_csi_ll_set_phy_clock_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_csi_ll_set_phy_clock_source(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Enable MIPI CSI PHY configuration clock
|
||||
*
|
||||
* @param group_id Group ID
|
||||
* @param en true to enable, false to disable
|
||||
*/
|
||||
static inline void mipi_csi_ll_enable_phy_config_clock(int group_id, bool en)
|
||||
{
|
||||
(void)group_id;
|
||||
HP_SYS_CLKRST.peri_clk_ctrl03.reg_mipi_csi_dphy_cfg_clk_en = en;
|
||||
}
|
||||
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define mipi_csi_ll_enable_phy_config_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_csi_ll_enable_phy_config_clock(__VA_ARGS__)
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
CSI Host
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Enable the bus clock for MIPI CSI host
|
||||
*
|
||||
* @param group_id Group ID
|
||||
* @param en true to enable, false to disable
|
||||
*/
|
||||
static inline void mipi_csi_ll_enable_host_bus_clock(int group_id, bool en)
|
||||
{
|
||||
(void)group_id;
|
||||
HP_SYS_CLKRST.soc_clk_ctrl1.reg_csi_host_sys_clk_en = en;
|
||||
}
|
||||
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define mipi_csi_ll_enable_host_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_csi_ll_enable_host_bus_clock(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Reset the MIPI CSI host CLK
|
||||
*
|
||||
* @param group_id Group ID
|
||||
*/
|
||||
static inline void mipi_csi_ll_reset_host_clock(int group_id)
|
||||
{
|
||||
(void)group_id;
|
||||
HP_SYS_CLKRST.hp_rst_en0.reg_rst_en_csi_host = 1;
|
||||
HP_SYS_CLKRST.hp_rst_en0.reg_rst_en_csi_host = 0;
|
||||
}
|
||||
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define mipi_csi_ll_reset_host_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mipi_csi_ll_reset_host_clock(__VA_ARGS__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
76
components/hal/esp32p4/include/hal/mipi_csi_phy_ll.h
Normal file
76
components/hal/esp32p4/include/hal/mipi_csi_phy_ll.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "hal/misc.h"
|
||||
#include "hal/assert.h"
|
||||
#include "soc/mipi_csi_host_struct.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Control the internal interface (clock and pins) between the CSI Host and the d-PHY
|
||||
*
|
||||
* @param dev Pointer to the CSI Host controller register base address
|
||||
* @param clock_level Level of the clock
|
||||
* @param clear Whether to clear the pins of the PHY
|
||||
*/
|
||||
static inline void mipi_csi_phy_ll_write_clock(csi_host_dev_t *dev, uint32_t clock_level, bool clear)
|
||||
{
|
||||
dev->phy_test_ctrl0.val = clock_level << 1 | clear;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write the PHY register via test interface
|
||||
*
|
||||
* @param dev Pointer to the CSI Host controller register base address
|
||||
* @param reg_addr Address of the PHY register
|
||||
*/
|
||||
static inline void mipi_csi_phy_ll_write_reg_addr(csi_host_dev_t *dev, uint8_t reg_addr)
|
||||
{
|
||||
dev->phy_test_ctrl1.val = (1 << 16) | (reg_addr & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write the PHY register value via test interface
|
||||
*
|
||||
* @param dev Pointer to the CSI Host controller register base address
|
||||
* @param reg_val Value to write to the PHY register
|
||||
*/
|
||||
static inline void mipi_csi_phy_ll_write_reg_val(csi_host_dev_t *dev, uint8_t reg_val)
|
||||
{
|
||||
dev->phy_test_ctrl1.val = reg_val & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable dphy shutdown input
|
||||
*
|
||||
* @param dev Pointer to the CSI Host controller register base address
|
||||
* @param en True to enable, False to disable
|
||||
*/
|
||||
static inline void mipi_csi_phy_ll_enable_shutdown_input(csi_host_dev_t *dev, bool en)
|
||||
{
|
||||
dev->phy_shutdownz.phy_shutdownz = !en; // shutdown input, active low
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable dphy reset output
|
||||
*
|
||||
* @param dev Pointer to the CSI Host controller register base address
|
||||
* @param en True to enable, False to disable
|
||||
*/
|
||||
static inline void mipi_csi_phy_ll_enable_reset_output(csi_host_dev_t *dev, bool en)
|
||||
{
|
||||
dev->dphy_rstz.dphy_rstz = !en; // phy reset output, active low
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
59
components/hal/include/hal/mipi_csi_hal.h
Normal file
59
components/hal/include/hal/mipi_csi_hal.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "hal/mipi_csi_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief MIPI CSI SOC layer representation of the host controller
|
||||
*/
|
||||
typedef struct csi_host_dev_t *mipi_csi_host_soc_handle_t;
|
||||
|
||||
/**
|
||||
* @brief MIPI CSI SOC layer representation of the bridge controller
|
||||
*/
|
||||
typedef struct csi_brg_dev_t *mipi_csi_bridge_soc_handle_t;
|
||||
|
||||
/**
|
||||
* @brief MIPI CSI HAL driver context
|
||||
*/
|
||||
typedef struct {
|
||||
mipi_csi_host_soc_handle_t host_dev;
|
||||
mipi_csi_bridge_soc_handle_t bridge_dev;
|
||||
} mipi_csi_hal_context_t;
|
||||
|
||||
/**
|
||||
* @brief MIPI CSI HAL driver configuration
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t lanes_num; ///< Lane num
|
||||
uint32_t frame_width; ///< Frame width
|
||||
uint32_t frame_height; ///< Frame height
|
||||
uint32_t in_bpp; ///< In bits per pixel
|
||||
uint32_t out_bpp; ///< Out bits per pixel
|
||||
bool byte_swap_en; ///< Enable byte swap
|
||||
int clk_freq_hz; ///< Clock frequency in hz
|
||||
} mipi_csi_hal_config_t;
|
||||
|
||||
/**
|
||||
* @brief MIPI CSI HAL layer initialization
|
||||
*
|
||||
* @param hal Pointer to the HAL driver context
|
||||
* @param config Pointer to the HAL configuration
|
||||
*/
|
||||
void mipi_csi_hal_init(mipi_csi_hal_context_t *hal, const mipi_csi_hal_config_t *config);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
43
components/hal/include/hal/mipi_csi_types.h
Normal file
43
components/hal/include/hal/mipi_csi_types.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_assert.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/clk_tree_defs.h"
|
||||
#include "hal/color_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if SOC_MIPI_CSI_SUPPORTED
|
||||
/**
|
||||
* @brief MIPI CSI PHY clock source
|
||||
*/
|
||||
typedef soc_periph_mipi_csi_phy_clk_src_t mipi_csi_phy_clock_source_t;
|
||||
#else
|
||||
typedef int mipi_csi_phy_clock_source_t;
|
||||
#endif // SOC_MIPI_CSI_SUPPORTED
|
||||
|
||||
/**
|
||||
* @brief MIPI CSI Color Type
|
||||
*/
|
||||
typedef enum {
|
||||
MIPI_CSI_COLOR_RAW8 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW8), ///< RAW8
|
||||
MIPI_CSI_COLOR_RAW10 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW10), ///< RAW10
|
||||
MIPI_CSI_COLOR_RAW12 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW12), ///< RAW12
|
||||
MIPI_CSI_COLOR_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), ///< RGB565
|
||||
MIPI_CSI_COLOR_RGB666 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB666), ///< RGB666
|
||||
MIPI_CSI_COLOR_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), ///< RGB888
|
||||
MIPI_CSI_COLOR_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), ///< YUV420
|
||||
MIPI_CSI_COLOR_YUV422 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV422), ///< YUV422
|
||||
} mipi_csi_color_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
73
components/hal/mipi_csi_hal.c
Normal file
73
components/hal/mipi_csi_hal.c
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "hal/log.h"
|
||||
#include "hal/mipi_csi_hal.h"
|
||||
#include "hal/mipi_csi_ll.h"
|
||||
#include "soc/mipi_csi_periph.h"
|
||||
|
||||
void s_mipi_csi_hal_phy_write_register(mipi_csi_hal_context_t *hal, uint8_t reg_addr, uint8_t reg_val)
|
||||
{
|
||||
mipi_csi_phy_ll_write_clock(hal->host_dev, 0, false);
|
||||
mipi_csi_phy_ll_write_reg_addr(hal->host_dev, reg_addr);
|
||||
mipi_csi_phy_ll_write_clock(hal->host_dev, 1, false);
|
||||
mipi_csi_phy_ll_write_clock(hal->host_dev, 0, false);
|
||||
mipi_csi_phy_ll_write_reg_val(hal->host_dev, reg_val);
|
||||
mipi_csi_phy_ll_write_clock(hal->host_dev, 1, false);
|
||||
mipi_csi_phy_ll_write_clock(hal->host_dev, 0, false);
|
||||
}
|
||||
|
||||
void mipi_csi_hal_init(mipi_csi_hal_context_t *hal, const mipi_csi_hal_config_t *config)
|
||||
{
|
||||
hal->bridge_dev = MIPI_CSI_BRG_LL_GET_HW(0);
|
||||
hal->host_dev = MIPI_CSI_HOST_LL_GET_HW(0);
|
||||
int csi_lane_rate = config->clk_freq_hz;
|
||||
|
||||
// reset PHY
|
||||
mipi_csi_phy_ll_enable_shutdown_input(hal->host_dev, true);
|
||||
mipi_csi_phy_ll_enable_reset_output(hal->host_dev, true);
|
||||
mipi_csi_host_ll_enable_reset_output(hal->host_dev, true);
|
||||
//reset reg addr to default value
|
||||
mipi_csi_phy_ll_write_reg_addr(hal->host_dev, 0x0);
|
||||
//reset reg val to default value
|
||||
mipi_csi_phy_ll_write_clock(hal->host_dev, 0, 1);
|
||||
mipi_csi_phy_ll_write_clock(hal->host_dev, 0, 0);
|
||||
|
||||
uint8_t hs_freq_sel = 0;
|
||||
for (size_t i = 0; i < num_of_soc_mipi_csi_phy_pll_ranges; i++) {
|
||||
if ((csi_lane_rate / 1000000) >= soc_mipi_csi_phy_pll_ranges[i].start_mbps &&
|
||||
(csi_lane_rate / 1000000) <= soc_mipi_csi_phy_pll_ranges[i].end_mbps) {
|
||||
hs_freq_sel = soc_mipi_csi_phy_pll_ranges[i].hs_freq_range_sel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
s_mipi_csi_hal_phy_write_register(hal, 0x44, hs_freq_sel << 1);
|
||||
HAL_LOGD("csi_hal", "CSI-DPHY lane_rate: %d Hz, hs_freq: 0x%x, lane_num: 0x%x", csi_lane_rate, hs_freq_sel, config->lanes_num);
|
||||
mipi_csi_phy_ll_enable_shutdown_input(hal->host_dev, false);
|
||||
mipi_csi_phy_ll_enable_reset_output(hal->host_dev, false);
|
||||
mipi_csi_host_ll_enable_reset_output(hal->host_dev, false);
|
||||
|
||||
// Configure the host controller.
|
||||
// Configure the number of active lanes.
|
||||
mipi_csi_host_ll_set_active_lanes_num(hal->host_dev, config->lanes_num);
|
||||
/**
|
||||
* We ignore the virtual channel and virtual channel extension info, there is only one virtual channel.
|
||||
* VC is by default there, VCX needs enable or disable.
|
||||
* So we disable VCX here.
|
||||
*/
|
||||
mipi_csi_host_ll_enable_virtual_channel_extension(hal->host_dev, false);
|
||||
// Set Scrambler.
|
||||
mipi_csi_host_ll_enable_scrambling(hal->host_dev, false);
|
||||
|
||||
//CSI bridge
|
||||
//TODO: IDF-9126, make csi bridge updates into `mipi_csi_share_hw_ctrl.c` and share with ISP
|
||||
mipi_csi_brg_ll_set_intput_data_h_pixel_num(hal->bridge_dev, config->frame_height);
|
||||
mipi_csi_brg_ll_set_intput_data_v_row_num(hal->bridge_dev, config->frame_width);
|
||||
mipi_csi_brg_ll_set_flow_ctl_buf_afull_thrd(hal->bridge_dev, 960);
|
||||
mipi_csi_brg_ll_set_data_type_min(hal->bridge_dev, 0x12);
|
||||
mipi_csi_brg_ll_set_data_type_max(hal->bridge_dev, 0x2f);
|
||||
mipi_csi_brg_ll_set_byte_endian(hal->bridge_dev, config->byte_swap_en);
|
||||
}
|
@ -83,6 +83,10 @@ if(CONFIG_SOC_MIPI_DSI_SUPPORTED)
|
||||
list(APPEND srcs "${target}/mipi_dsi_periph.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_MIPI_CSI_SUPPORTED)
|
||||
list(APPEND srcs "${target}/mipi_csi_periph.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_PARLIO_SUPPORTED)
|
||||
list(APPEND srcs "${target}/parlio_periph.c")
|
||||
endif()
|
||||
|
@ -39,6 +39,10 @@ config SOC_PCNT_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_MIPI_CSI_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_MIPI_DSI_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
@ -358,6 +358,21 @@ typedef enum {
|
||||
|
||||
/////////////////////////////////////////////////MIPI///////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @brief Array initializer for all supported clock sources of MIPI CSI PHY interface
|
||||
*/
|
||||
#define SOC_MIPI_CSI_PHY_CLKS {SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_PLL_F25M, SOC_MOD_CLK_PLL_F20M}
|
||||
|
||||
/**
|
||||
* @brief Type of MIPI CSI PHY clock source
|
||||
*/
|
||||
typedef enum {
|
||||
MIPI_CSI_PHY_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as MIPI CSI PHY source clock */
|
||||
MIPI_CSI_PHY_CLK_SRC_PLL_F25M = SOC_MOD_CLK_PLL_F25M, /*!< Select PLL_F25M as MIPI CSI PHY source clock */
|
||||
MIPI_CSI_PHY_CLK_SRC_PLL_F20M = SOC_MOD_CLK_PLL_F20M, /*!< Select PLL_F20M as MIPI CSI PHY source clock */
|
||||
MIPI_CSI_PHY_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F20M, /*!< Select PLL_F20M as default clock */
|
||||
} soc_periph_mipi_csi_phy_clk_src_t;
|
||||
|
||||
/**
|
||||
* @brief Array initializer for all supported clock sources of MIPI DSI DPI interface
|
||||
*/
|
||||
|
@ -170,11 +170,11 @@ typedef union {
|
||||
* endianness order in bytes. 2'h0 is normal mode and 2'h3 is useful to YUV420(Legacy)
|
||||
* when isp is bapassed.
|
||||
*/
|
||||
uint32_t byte_endian_order:1;
|
||||
uint32_t byte_endian_order:1; //byte_swap_en
|
||||
/** bit_endian_order : R/W; bitpos: [1]; default: 0;
|
||||
* N/A
|
||||
*/
|
||||
uint32_t bit_endian_order:1;
|
||||
uint32_t bit_endian_order:1; //reserved
|
||||
uint32_t reserved_2:30;
|
||||
};
|
||||
uint32_t val;
|
||||
|
@ -160,8 +160,8 @@
|
||||
/**
|
||||
* @brief: Special memory address
|
||||
*/
|
||||
#define MIPI_CSI_MEM_BASE 0x50104000
|
||||
#define MIPI_DSI_MEM_BASE 0x50105000
|
||||
#define MIPI_CSI_BRG_MEM_BASE 0x50104000
|
||||
#define MIPI_DSI_BRG_MEM_BASE 0x50105000
|
||||
|
||||
/**
|
||||
* This are module helper MACROs for quick module reference
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define SOC_GPTIMER_SUPPORTED 1
|
||||
#define SOC_PCNT_SUPPORTED 1
|
||||
// #define SOC_LCDCAM_SUPPORTED 1 // TODO: IDF-7465
|
||||
#define SOC_MIPI_CSI_SUPPORTED 1
|
||||
#define SOC_MIPI_DSI_SUPPORTED 1
|
||||
#define SOC_MCPWM_SUPPORTED 1
|
||||
#define SOC_TWAI_SUPPORTED 1
|
||||
|
50
components/soc/esp32p4/mipi_csi_periph.c
Normal file
50
components/soc/esp32p4/mipi_csi_periph.c
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/mipi_csi_periph.h"
|
||||
|
||||
const soc_mipi_csi_phy_pll_freq_range_t soc_mipi_csi_phy_pll_ranges[] = {
|
||||
{90, 99, 0x00}, // [90,100) Mbps
|
||||
{100, 109, 0x10}, // [100,110) Mbps
|
||||
{110, 129, 0x20}, // [110,130) Mbps
|
||||
{130, 139, 0x01}, // [130,140) Mbps
|
||||
{140, 149, 0x11}, // [140,150) Mbps
|
||||
{150, 169, 0x21}, // [150,170) Mbps
|
||||
{170, 179, 0x02}, // [170,180) Mbps
|
||||
{180, 199, 0x12}, // [180,200) Mbps
|
||||
{200, 219, 0x22}, // [200,220) Mbps
|
||||
{220, 239, 0x03}, // [220,240) Mbps
|
||||
{240, 249, 0x13}, // [240,250) Mbps
|
||||
{250, 269, 0x23}, // [250,270) Mbps
|
||||
{270, 299, 0x04}, // [270,300) Mbps
|
||||
{300, 329, 0x14}, // [300,330) Mbps
|
||||
{330, 359, 0x05}, // [330,360) Mbps
|
||||
{360, 399, 0x15}, // [360,400) Mbps
|
||||
{400, 449, 0x25}, // [400,450) Mbps
|
||||
{450, 499, 0x06}, // [450,500) Mbps
|
||||
{500, 549, 0x16}, // [500,550) Mbps
|
||||
{550, 599, 0x07}, // [550,600) Mbps
|
||||
{600, 649, 0x17}, // [600,650) Mbps
|
||||
{650, 699, 0x08}, // [650,700) Mbps
|
||||
{700, 749, 0x18}, // [700,750) Mbps
|
||||
{750, 799, 0x09}, // [750,800) Mbps
|
||||
{800, 849, 0x19}, // [800,850) Mbps
|
||||
{850, 899, 0x29}, // [850,900) Mbps
|
||||
{900, 949, 0x39}, // [900,950) Mbps
|
||||
{950, 999, 0x0A}, // [950,1000) Mbps
|
||||
{1000, 1049, 0x1A}, // [1000,1050) Mbps
|
||||
{1050, 1099, 0x2A}, // [1050,1100) Mbps
|
||||
{1100, 1149, 0x3A}, // [1100,1150) Mbps
|
||||
{1150, 1199, 0x0B}, // [1150,1200) Mbps
|
||||
{1200, 1249, 0x1B}, // [1200,1250) Mbps
|
||||
{1250, 1299, 0x2B}, // [1250,1300) Mbps
|
||||
{1300, 1349, 0x3B}, // [1300,1350) Mbps
|
||||
{1350, 1399, 0x0C}, // [1350,1400) Mbps
|
||||
{1400, 1449, 0x1C}, // [1400,1450) Mbps
|
||||
{1450, 1500, 0x2C}, // [1450,1500] Mbps
|
||||
};
|
||||
|
||||
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);
|
31
components/soc/include/soc/mipi_csi_periph.h
Normal file
31
components/soc/include/soc/mipi_csi_periph.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief MIPI CSI PHY PLL frequency range
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t start_mbps; /*!< Start frequency of the range (included) */
|
||||
uint32_t end_mbps; /*!< End frequency of the range (included) */
|
||||
uint8_t hs_freq_range_sel; /*!< HS operating frequency range selection */
|
||||
} soc_mipi_csi_phy_pll_freq_range_t;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user