Merge branch 'feat/csi_driver' into 'master'

feat(csi): added csi driver

See merge request espressif/esp-idf!28751
pull/12800/head
Armando (Dou Yiwen) 2024-02-05 09:59:35 +08:00
commit 116c9494c7
36 zmienionych plików z 1658 dodań i 9 usunięć

Wyświetl plik

@ -82,6 +82,7 @@
/components/esp_adc/ @esp-idf-codeowners/peripherals
/components/esp_app_format/ @esp-idf-codeowners/system @esp-idf-codeowners/app-utilities
/components/esp_bootloader_format/ @esp-idf-codeowners/system @esp-idf-codeowners/app-utilities
/components/esp_cam_ctlr/ @esp-idf-codeowners/peripherals
/components/esp_coex/ @esp-idf-codeowners/wifi @esp-idf-codeowners/bluetooth @esp-idf-codeowners/ieee802154
/components/esp_common/ @esp-idf-codeowners/system
/components/esp_driver_*/ @esp-idf-codeowners/peripherals

Wyświetl plik

@ -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
)

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -0,0 +1,5 @@
components/esp_cam_ctlr/test_apps/csi:
disable:
- if: SOC_MIPI_CSI_SUPPORTED != 1
depends_components:
- esp_cam_ctlr

Wyświetl plik

@ -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)

Wyświetl plik

@ -0,0 +1,2 @@
| Supported Targets | ESP32-P4 |
| ----------------- | -------- |

Wyświetl plik

@ -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)

Wyświetl plik

@ -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();
}

Wyświetl plik

@ -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));
}

Wyświetl plik

@ -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()

Wyświetl plik

@ -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

Wyświetl plik

@ -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,

Wyświetl plik

@ -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()

Wyświetl plik

@ -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;

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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()

Wyświetl plik

@ -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

Wyświetl plik

@ -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
*/

Wyświetl plik

@ -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;

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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);

Wyświetl plik

@ -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