mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-11-04 06:11:06 +00:00 
			
		
		
		
	feat(cam): add esp32s3 dvp cam support
This commit is contained in:
		@@ -26,12 +26,24 @@
 | 
				
			|||||||
#include "../../dvp_share_ctrl.h"
 | 
					#include "../../dvp_share_ctrl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_CAM_CTLR_DVP_CAM_ISR_CACHE_SAFE
 | 
					#ifdef CONFIG_CAM_CTLR_DVP_CAM_ISR_CACHE_SAFE
 | 
				
			||||||
#define CAM_DVP_MEM_ALLOC_CAPS      (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
 | 
					#define DVP_CAM_CTLR_ALLOC_CAPS             (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define CAM_DVP_MEM_ALLOC_CAPS      (MALLOC_CAP_DEFAULT)
 | 
					#define DVP_CAM_CTLR_ALLOC_CAPS             (MALLOC_CAP_DEFAULT)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ALIGN_UP_BY(num, align)     (((num) + ((align) - 1)) & ~((align) - 1))
 | 
					#if CONFIG_SPIRAM
 | 
				
			||||||
 | 
					#define DVP_CAM_BK_BUFFER_ALLOC_CAPS        (MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define DVP_CAM_BK_BUFFER_ALLOC_CAPS        (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if SOC_PERIPH_CLK_CTRL_SHARED
 | 
				
			||||||
 | 
					#define DVP_CAM_CLK_ATOMIC()                PERIPH_RCC_ATOMIC()
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define DVP_CAM_CLK_ATOMIC()
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ALIGN_UP_BY(num, align) ((align) == 0 ? (num) : (((num) + ((align) - 1)) & ~((align) - 1)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DVP_CAM_CONFIG_INPUT_PIN(pin, sig, inv)                 \
 | 
					#define DVP_CAM_CONFIG_INPUT_PIN(pin, sig, inv)                 \
 | 
				
			||||||
{                                                               \
 | 
					{                                                               \
 | 
				
			||||||
@@ -209,7 +221,6 @@ static uint32_t IRAM_ATTR esp_cam_ctlr_dvp_get_jpeg_size(const uint8_t *buffer,
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
static uint32_t IRAM_ATTR esp_cam_ctlr_dvp_get_recved_size(esp_cam_ctlr_dvp_cam_t *ctlr, uint8_t *rx_buffer, uint32_t dma_recv_size)
 | 
					static uint32_t IRAM_ATTR esp_cam_ctlr_dvp_get_recved_size(esp_cam_ctlr_dvp_cam_t *ctlr, uint8_t *rx_buffer, uint32_t dma_recv_size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    esp_err_t ret;
 | 
					 | 
				
			||||||
    uint32_t recv_buffer_size;
 | 
					    uint32_t recv_buffer_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ctlr->pic_format_jpeg) {
 | 
					    if (ctlr->pic_format_jpeg) {
 | 
				
			||||||
@@ -218,8 +229,10 @@ static uint32_t IRAM_ATTR esp_cam_ctlr_dvp_get_recved_size(esp_cam_ctlr_dvp_cam_
 | 
				
			|||||||
        recv_buffer_size = ctlr->fb_size_in_bytes;
 | 
					        recv_buffer_size = ctlr->fb_size_in_bytes;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = esp_cache_msync(rx_buffer, recv_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
 | 
					    if (esp_ptr_external_ram(rx_buffer)) {
 | 
				
			||||||
 | 
					        esp_err_t ret = esp_cache_msync(rx_buffer, recv_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
 | 
				
			||||||
        assert(ret == ESP_OK);
 | 
					        assert(ret == ESP_OK);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ctlr->pic_format_jpeg) {
 | 
					    if (ctlr->pic_format_jpeg) {
 | 
				
			||||||
        recv_buffer_size = esp_cam_ctlr_dvp_get_jpeg_size(rx_buffer, dma_recv_size);
 | 
					        recv_buffer_size = esp_cam_ctlr_dvp_get_jpeg_size(rx_buffer, dma_recv_size);
 | 
				
			||||||
@@ -336,7 +349,7 @@ esp_err_t esp_cam_ctlr_dvp_init(int ctlr_id, cam_clock_source_t clk_src, const e
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true));
 | 
					    ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true));
 | 
				
			||||||
    PERIPH_RCC_ATOMIC() {
 | 
					    DVP_CAM_CLK_ATOMIC() {
 | 
				
			||||||
        cam_ll_enable_clk(ctlr_id, true);
 | 
					        cam_ll_enable_clk(ctlr_id, true);
 | 
				
			||||||
        cam_ll_select_clk_src(ctlr_id, clk_src);
 | 
					        cam_ll_select_clk_src(ctlr_id, clk_src);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -367,7 +380,7 @@ esp_err_t esp_cam_ctlr_dvp_output_clock(int ctlr_id, cam_clock_source_t clk_src,
 | 
				
			|||||||
    ESP_LOGD(TAG, "DVP clock source frequency %" PRIu32 "Hz", src_clk_hz);
 | 
					    ESP_LOGD(TAG, "DVP clock source frequency %" PRIu32 "Hz", src_clk_hz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((src_clk_hz % xclk_freq) == 0) {
 | 
					    if ((src_clk_hz % xclk_freq) == 0) {
 | 
				
			||||||
        PERIPH_RCC_ATOMIC() {
 | 
					        DVP_CAM_CLK_ATOMIC() {
 | 
				
			||||||
            cam_ll_set_group_clock_coeff(ctlr_id, src_clk_hz / xclk_freq, 0, 0);
 | 
					            cam_ll_set_group_clock_coeff(ctlr_id, src_clk_hz / xclk_freq, 0, 0);
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -390,7 +403,7 @@ esp_err_t esp_cam_ctlr_dvp_deinit(int ctlr_id)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    ESP_RETURN_ON_FALSE(ctlr_id < CAP_DVP_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid argument: ctlr_id >= %d", CAP_DVP_PERIPH_NUM);
 | 
					    ESP_RETURN_ON_FALSE(ctlr_id < CAP_DVP_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid argument: ctlr_id >= %d", CAP_DVP_PERIPH_NUM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    PERIPH_RCC_ATOMIC() {
 | 
					    DVP_CAM_CLK_ATOMIC() {
 | 
				
			||||||
        cam_ll_enable_clk(ctlr_id, false);
 | 
					        cam_ll_enable_clk(ctlr_id, false);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -710,11 +723,11 @@ esp_err_t esp_cam_new_dvp_ctlr(const esp_cam_ctlr_dvp_config_t *config, esp_cam_
 | 
				
			|||||||
    ESP_RETURN_ON_FALSE(config->external_xtal || config->pin_dont_init || config->pin->xclk_io != GPIO_NUM_NC, ESP_ERR_INVALID_ARG, TAG, "invalid argument: xclk_io is not set");
 | 
					    ESP_RETURN_ON_FALSE(config->external_xtal || config->pin_dont_init || config->pin->xclk_io != GPIO_NUM_NC, ESP_ERR_INVALID_ARG, TAG, "invalid argument: xclk_io is not set");
 | 
				
			||||||
    ESP_RETURN_ON_FALSE(config->external_xtal || config->xclk_freq, ESP_ERR_INVALID_ARG, TAG, "invalid argument: xclk_freq is not set");
 | 
					    ESP_RETURN_ON_FALSE(config->external_xtal || config->xclk_freq, ESP_ERR_INVALID_ARG, TAG, "invalid argument: xclk_freq is not set");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ESP_RETURN_ON_ERROR(esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &alignment_size), TAG, "failed to get cache alignment");
 | 
					    ESP_RETURN_ON_ERROR(esp_cache_get_alignment(DVP_CAM_BK_BUFFER_ALLOC_CAPS, &alignment_size), TAG, "failed to get cache alignment");
 | 
				
			||||||
    ESP_RETURN_ON_ERROR(esp_cam_ctlr_dvp_cam_get_frame_size(config, &fb_size_in_bytes), TAG, "invalid argument: input frame pixel format is not supported");
 | 
					    ESP_RETURN_ON_ERROR(esp_cam_ctlr_dvp_cam_get_frame_size(config, &fb_size_in_bytes), TAG, "invalid argument: input frame pixel format is not supported");
 | 
				
			||||||
    ESP_RETURN_ON_ERROR(dvp_shared_ctrl_claim_io_signals(), TAG, "failed to claim io signals");
 | 
					    ESP_RETURN_ON_ERROR(dvp_shared_ctrl_claim_io_signals(), TAG, "failed to claim io signals");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    esp_cam_ctlr_dvp_cam_t *ctlr = heap_caps_calloc(1, sizeof(esp_cam_ctlr_dvp_cam_t), CAM_DVP_MEM_ALLOC_CAPS);
 | 
					    esp_cam_ctlr_dvp_cam_t *ctlr = heap_caps_calloc(1, sizeof(esp_cam_ctlr_dvp_cam_t), DVP_CAM_CTLR_ALLOC_CAPS);
 | 
				
			||||||
    ESP_GOTO_ON_FALSE(ctlr, ESP_ERR_NO_MEM, fail0, TAG, "no mem for CAM DVP controller context");
 | 
					    ESP_GOTO_ON_FALSE(ctlr, ESP_ERR_NO_MEM, fail0, TAG, "no mem for CAM DVP controller context");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ESP_GOTO_ON_ERROR(s_dvp_claim_ctlr(config->ctlr_id, ctlr), fail1, TAG, "no available DVP controller");
 | 
					    ESP_GOTO_ON_ERROR(s_dvp_claim_ctlr(config->ctlr_id, ctlr), fail1, TAG, "no available DVP controller");
 | 
				
			||||||
@@ -722,7 +735,7 @@ esp_err_t esp_cam_new_dvp_ctlr(const esp_cam_ctlr_dvp_config_t *config, esp_cam_
 | 
				
			|||||||
    ESP_LOGD(TAG, "alignment: 0x%x\n", alignment_size);
 | 
					    ESP_LOGD(TAG, "alignment: 0x%x\n", alignment_size);
 | 
				
			||||||
    fb_size_in_bytes = ALIGN_UP_BY(fb_size_in_bytes, alignment_size);
 | 
					    fb_size_in_bytes = ALIGN_UP_BY(fb_size_in_bytes, alignment_size);
 | 
				
			||||||
    if (!config->bk_buffer_dis) {
 | 
					    if (!config->bk_buffer_dis) {
 | 
				
			||||||
        ctlr->backup_buffer = heap_caps_aligned_alloc(alignment_size, fb_size_in_bytes, MALLOC_CAP_SPIRAM);
 | 
					        ctlr->backup_buffer = heap_caps_aligned_alloc(alignment_size, fb_size_in_bytes, DVP_CAM_BK_BUFFER_ALLOC_CAPS);
 | 
				
			||||||
        ESP_GOTO_ON_FALSE(ctlr->backup_buffer, ESP_ERR_NO_MEM, fail2, TAG, "no mem for DVP backup buffer");
 | 
					        ESP_GOTO_ON_FALSE(ctlr->backup_buffer, ESP_ERR_NO_MEM, fail2, TAG, "no mem for DVP backup buffer");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
 | 
					 * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * SPDX-License-Identifier: Apache-2.0
 | 
					 * SPDX-License-Identifier: Apache-2.0
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -10,9 +10,24 @@
 | 
				
			|||||||
#include "esp_cache.h"
 | 
					#include "esp_cache.h"
 | 
				
			||||||
#include "esp_private/esp_cache_private.h"
 | 
					#include "esp_private/esp_cache_private.h"
 | 
				
			||||||
#include "esp_cam_ctlr_dvp_dma.h"
 | 
					#include "esp_cam_ctlr_dvp_dma.h"
 | 
				
			||||||
 | 
					#include "esp_memory_utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ALIGN_UP_BY(num, align)             (((num) + ((align) - 1)) & ~((align) - 1))
 | 
					#define ALIGN_UP_BY(num, align)             (((num) + ((align) - 1)) & ~((align) - 1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(SOC_GDMA_TRIG_PERIPH_CAM0_BUS) && (SOC_GDMA_TRIG_PERIPH_CAM0_BUS == SOC_GDMA_BUS_AHB)
 | 
				
			||||||
 | 
					#define DVP_GDMA_NEW_CHANNEL            gdma_new_ahb_channel
 | 
				
			||||||
 | 
					#define DVP_GDMA_DESC_ALLOC_CAPS        (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
 | 
				
			||||||
 | 
					#elif defined(SOC_GDMA_TRIG_PERIPH_CAM0_BUS) && (SOC_GDMA_TRIG_PERIPH_CAM0_BUS == SOC_GDMA_BUS_AXI)
 | 
				
			||||||
 | 
					#define DVP_GDMA_NEW_CHANNEL            gdma_new_axi_channel
 | 
				
			||||||
 | 
					#if CONFIG_SPIRAM
 | 
				
			||||||
 | 
					#define DVP_GDMA_DESC_ALLOC_CAPS        (MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define DVP_GDMA_DESC_ALLOC_CAPS        (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#error "Unsupported GDMA bus type for DVP"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "dvp_gdma";
 | 
					static const char *TAG = "dvp_gdma";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -72,9 +87,9 @@ esp_err_t esp_cam_ctlr_dvp_dma_init(esp_cam_ctlr_dvp_dma_t *dma, uint32_t burst_
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ESP_RETURN_ON_ERROR(esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &alignment_size), TAG, "failed to get cache alignment");
 | 
					    ESP_RETURN_ON_ERROR(esp_cache_get_alignment(DVP_GDMA_DESC_ALLOC_CAPS, &alignment_size), TAG, "failed to get cache alignment");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ESP_RETURN_ON_ERROR(gdma_new_axi_channel(&rx_alloc_config, &dma->dma_chan), TAG, "new channel failed");
 | 
					    ESP_RETURN_ON_ERROR(DVP_GDMA_NEW_CHANNEL(&rx_alloc_config, &dma->dma_chan), TAG, "new channel failed");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ESP_GOTO_ON_ERROR(gdma_connect(dma->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_CAM, 0)), fail0, TAG, "connect failed");
 | 
					    ESP_GOTO_ON_ERROR(gdma_connect(dma->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_CAM, 0)), fail0, TAG, "connect failed");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -90,17 +105,20 @@ esp_err_t esp_cam_ctlr_dvp_dma_init(esp_cam_ctlr_dvp_dma_t *dma, uint32_t burst_
 | 
				
			|||||||
        .access_ext_mem = true,
 | 
					        .access_ext_mem = true,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    ESP_GOTO_ON_ERROR(gdma_config_transfer(dma->dma_chan, &transfer_config), fail1, TAG, "set trans ability failed");
 | 
					    ESP_GOTO_ON_ERROR(gdma_config_transfer(dma->dma_chan, &transfer_config), fail1, TAG, "set trans ability failed");
 | 
				
			||||||
 | 
					    size_t int_mem_align = 0;
 | 
				
			||||||
 | 
					    size_t ext_mem_align = 0;
 | 
				
			||||||
 | 
					    gdma_get_alignment_constraints(dma->dma_chan, &int_mem_align, &ext_mem_align);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dma->desc_count = size / ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE;
 | 
					    dma->desc_count = size / ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE;
 | 
				
			||||||
    if (size % ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE) {
 | 
					    if (size % ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE) {
 | 
				
			||||||
        dma->desc_count++;
 | 
					        dma->desc_count++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    dma->size = size;
 | 
					    dma->size = size;
 | 
				
			||||||
 | 
					    alignment_size = (alignment_size == 0) ? 1 : alignment_size;
 | 
				
			||||||
    ESP_LOGD(TAG, "alignment: 0x%x\n", alignment_size);
 | 
					 | 
				
			||||||
    dma->desc_size = ALIGN_UP_BY(dma->desc_count * sizeof(esp_cam_ctlr_dvp_dma_desc_t), alignment_size);
 | 
					    dma->desc_size = ALIGN_UP_BY(dma->desc_count * sizeof(esp_cam_ctlr_dvp_dma_desc_t), alignment_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dma->desc = heap_caps_aligned_alloc(alignment_size, dma->desc_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA);
 | 
					    ESP_LOGD(TAG, "alignment_size: %d, dma->desc_count: %d, dma->desc_size: %d", alignment_size, dma->desc_count, dma->desc_size);
 | 
				
			||||||
 | 
					    dma->desc = heap_caps_aligned_alloc(alignment_size, dma->desc_size, DVP_GDMA_DESC_ALLOC_CAPS);
 | 
				
			||||||
    ESP_GOTO_ON_FALSE(dma->desc, ESP_ERR_NO_MEM, fail1, TAG, "no mem for DVP DMA descriptor");
 | 
					    ESP_GOTO_ON_FALSE(dma->desc, ESP_ERR_NO_MEM, fail1, TAG, "no mem for DVP DMA descriptor");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ESP_OK;
 | 
					    return ESP_OK;
 | 
				
			||||||
@@ -144,15 +162,15 @@ esp_err_t esp_cam_ctlr_dvp_dma_deinit(esp_cam_ctlr_dvp_dma_t *dma)
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
esp_err_t IRAM_ATTR esp_cam_ctlr_dvp_dma_start(esp_cam_ctlr_dvp_dma_t *dma, uint8_t *buffer, size_t size)
 | 
					esp_err_t IRAM_ATTR esp_cam_ctlr_dvp_dma_start(esp_cam_ctlr_dvp_dma_t *dma, uint8_t *buffer, size_t size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    esp_err_t ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ESP_RETURN_ON_FALSE_ISR(dma, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
 | 
					    ESP_RETURN_ON_FALSE_ISR(dma, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
 | 
				
			||||||
    ESP_RETURN_ON_FALSE_ISR(dma->size >= size, ESP_ERR_INVALID_ARG, TAG, "input buffer size is out of range");
 | 
					    ESP_RETURN_ON_FALSE_ISR(dma->size >= size, ESP_ERR_INVALID_ARG, TAG, "input buffer size is out of range");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    esp_cam_ctlr_dvp_config_dma_desc(dma->desc, buffer, size);
 | 
					    esp_cam_ctlr_dvp_config_dma_desc(dma->desc, buffer, size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = esp_cache_msync(dma->desc, dma->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE);
 | 
					    if (esp_ptr_external_ram(dma->desc)) {
 | 
				
			||||||
 | 
					        esp_err_t ret = esp_cache_msync(dma->desc, dma->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE);
 | 
				
			||||||
        assert(ret == ESP_OK);
 | 
					        assert(ret == ESP_OK);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return gdma_start(dma->dma_chan, (intptr_t)dma->desc);
 | 
					    return gdma_start(dma->dma_chan, (intptr_t)dma->desc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,2 +1,2 @@
 | 
				
			|||||||
| Supported Targets | ESP32-P4 |
 | 
					| Supported Targets | ESP32-P4 | ESP32-S3 |
 | 
				
			||||||
| ----------------- | -------- |
 | 
					| ----------------- | -------- | -------- |
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@ TEST_CASE("TEST DVP driver allocation", "[DVP]")
 | 
				
			|||||||
        .h_res = 800,
 | 
					        .h_res = 800,
 | 
				
			||||||
        .v_res = 640,
 | 
					        .v_res = 640,
 | 
				
			||||||
        .input_data_color_type = CAM_CTLR_COLOR_RGB565,
 | 
					        .input_data_color_type = CAM_CTLR_COLOR_RGB565,
 | 
				
			||||||
        .dma_burst_size = 128,
 | 
					        .dma_burst_size = 64,
 | 
				
			||||||
        .byte_swap_en = false,
 | 
					        .byte_swap_en = false,
 | 
				
			||||||
        .pin_dont_init = true,
 | 
					        .pin_dont_init = true,
 | 
				
			||||||
        .external_xtal = true,
 | 
					        .external_xtal = true,
 | 
				
			||||||
@@ -42,7 +42,7 @@ TEST_CASE("TEST DVP driver allocation with JPEG input", "[DVP]")
 | 
				
			|||||||
        .clk_src = CAM_CLK_SRC_DEFAULT,
 | 
					        .clk_src = CAM_CLK_SRC_DEFAULT,
 | 
				
			||||||
        .h_res = 800,
 | 
					        .h_res = 800,
 | 
				
			||||||
        .v_res = 640,
 | 
					        .v_res = 640,
 | 
				
			||||||
        .dma_burst_size = 128,
 | 
					        .dma_burst_size = 64,
 | 
				
			||||||
        .byte_swap_en = false,
 | 
					        .byte_swap_en = false,
 | 
				
			||||||
        .pin_dont_init = true,
 | 
					        .pin_dont_init = true,
 | 
				
			||||||
        .pic_format_jpeg = true,
 | 
					        .pic_format_jpeg = true,
 | 
				
			||||||
@@ -69,7 +69,7 @@ TEST_CASE("TEST DVP driver no backup buffer usage", "[DVP]")
 | 
				
			|||||||
        .h_res = 800,
 | 
					        .h_res = 800,
 | 
				
			||||||
        .v_res = 640,
 | 
					        .v_res = 640,
 | 
				
			||||||
        .input_data_color_type = CAM_CTLR_COLOR_RGB565,
 | 
					        .input_data_color_type = CAM_CTLR_COLOR_RGB565,
 | 
				
			||||||
        .dma_burst_size = 128,
 | 
					        .dma_burst_size = 64,
 | 
				
			||||||
        .byte_swap_en = false,
 | 
					        .byte_swap_en = false,
 | 
				
			||||||
        .bk_buffer_dis = true,
 | 
					        .bk_buffer_dis = true,
 | 
				
			||||||
        .pin_dont_init = true,
 | 
					        .pin_dont_init = true,
 | 
				
			||||||
@@ -96,7 +96,7 @@ TEST_CASE("TEST DVP driver intern/extern init", "[DVP]")
 | 
				
			|||||||
        .h_res = 800,
 | 
					        .h_res = 800,
 | 
				
			||||||
        .v_res = 640,
 | 
					        .v_res = 640,
 | 
				
			||||||
        .input_data_color_type = CAM_CTLR_COLOR_RGB565,
 | 
					        .input_data_color_type = CAM_CTLR_COLOR_RGB565,
 | 
				
			||||||
        .dma_burst_size = 128,
 | 
					        .dma_burst_size = 64,
 | 
				
			||||||
        .byte_swap_en = false,
 | 
					        .byte_swap_en = false,
 | 
				
			||||||
        .external_xtal = true,
 | 
					        .external_xtal = true,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -128,7 +128,7 @@ TEST_CASE("TEST DVP driver intern/extern generate xclk", "[DVP]")
 | 
				
			|||||||
        .h_res = 800,
 | 
					        .h_res = 800,
 | 
				
			||||||
        .v_res = 640,
 | 
					        .v_res = 640,
 | 
				
			||||||
        .input_data_color_type = CAM_CTLR_COLOR_RGB565,
 | 
					        .input_data_color_type = CAM_CTLR_COLOR_RGB565,
 | 
				
			||||||
        .dma_burst_size = 128,
 | 
					        .dma_burst_size = 64,
 | 
				
			||||||
        .byte_swap_en = false,
 | 
					        .byte_swap_en = false,
 | 
				
			||||||
        .external_xtal = true,
 | 
					        .external_xtal = true,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,3 +14,14 @@ from pytest_embedded_idf.utils import idf_parametrize
 | 
				
			|||||||
@idf_parametrize('target', ['esp32p4'], indirect=['target'])
 | 
					@idf_parametrize('target', ['esp32p4'], indirect=['target'])
 | 
				
			||||||
def test_dvp(dut: Dut) -> None:
 | 
					def test_dvp(dut: Dut) -> None:
 | 
				
			||||||
    dut.run_all_single_board_cases()
 | 
					    dut.run_all_single_board_cases()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.octal_psram
 | 
				
			||||||
 | 
					@pytest.mark.parametrize(
 | 
				
			||||||
 | 
					    'config',
 | 
				
			||||||
 | 
					    ['cache_safe', 'release', 'pm_enable'],
 | 
				
			||||||
 | 
					    indirect=True,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					@idf_parametrize('target', ['esp32s3'], indirect=['target'])
 | 
				
			||||||
 | 
					def test_dvp_octal(dut: Dut) -> None:
 | 
				
			||||||
 | 
					    dut.run_all_single_board_cases()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,4 +2,3 @@
 | 
				
			|||||||
# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration
 | 
					# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
CONFIG_ESP_TASK_WDT_EN=n
 | 
					CONFIG_ESP_TASK_WDT_EN=n
 | 
				
			||||||
CONFIG_FREERTOS_HZ=1000
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					CONFIG_IDF_TARGET="esp32s3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG_SPIRAM=y
 | 
				
			||||||
 | 
					CONFIG_SPIRAM_MODE_OCT=y
 | 
				
			||||||
							
								
								
									
										615
									
								
								components/hal/esp32s3/include/hal/cam_ll.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										615
									
								
								components/hal/esp32s3/include/hal/cam_ll.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,615 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * SPDX-FileCopyrightText: 2025 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/lcd_cam_struct.h"
 | 
				
			||||||
 | 
					#include "soc/system_struct.h"
 | 
				
			||||||
 | 
					#include "hal/cam_types.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CAM_LL_GET_HW(id) (((id) == 0) ? (&LCD_CAM) : NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CAM_LL_CLK_FRAC_DIV_N_MAX  256 // CAM_CLK = CAM_CLK_S / (N + b/a), the N register is 8 bit-width
 | 
				
			||||||
 | 
					#define CAM_LL_CLK_FRAC_DIV_AB_MAX 64  // CAM_CLK = CAM_CLK_S / (N + b/a), the a/b register is 6 bit-width
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Enable the bus clock for CAM module
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param group_id Group ID
 | 
				
			||||||
 | 
					 * @param enable true to enable, false to disable
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_enable_bus_clock(int group_id, bool en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)group_id;
 | 
				
			||||||
 | 
					    SYSTEM.perip_clk_en1.lcd_cam_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_RC_ATOMIC_ENV variable in advance
 | 
				
			||||||
 | 
					#define cam_ll_enable_bus_clock(...) do { \
 | 
				
			||||||
 | 
					        (void)__DECLARE_RCC_RC_ATOMIC_ENV; \
 | 
				
			||||||
 | 
					        cam_ll_enable_bus_clock(__VA_ARGS__); \
 | 
				
			||||||
 | 
					    } while(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Reset the CAM module
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param group_id Group ID
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_reset_register(int group_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)group_id;
 | 
				
			||||||
 | 
					    SYSTEM.perip_rst_en1.lcd_cam_rst = 1;
 | 
				
			||||||
 | 
					    SYSTEM.perip_rst_en1.lcd_cam_rst = 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_RC_ATOMIC_ENV variable in advance
 | 
				
			||||||
 | 
					#define cam_ll_reset_register(...) do { \
 | 
				
			||||||
 | 
					        (void)__DECLARE_RCC_RC_ATOMIC_ENV; \
 | 
				
			||||||
 | 
					        cam_ll_reset_register(__VA_ARGS__); \
 | 
				
			||||||
 | 
					    } while(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Enable clock gating
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param group_id Group ID
 | 
				
			||||||
 | 
					 * @param en True to enable, False to disable
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_enable_clk(int group_id, bool en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (void)group_id;
 | 
				
			||||||
 | 
					    (void)en;
 | 
				
			||||||
 | 
					    //For compatibility
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Select clock source for CAM peripheral
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param group_id Group ID
 | 
				
			||||||
 | 
					 * @param src Clock source
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_select_clk_src(int group_id, cam_clock_source_t src)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    switch (src) {
 | 
				
			||||||
 | 
					        case CAM_CLK_SRC_XTAL:
 | 
				
			||||||
 | 
					            LCD_CAM.cam_ctrl.cam_clk_sel = 1;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case CAM_CLK_SRC_PLL240M:
 | 
				
			||||||
 | 
					            LCD_CAM.cam_ctrl.cam_clk_sel = 2;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case CAM_CLK_SRC_PLL160M:
 | 
				
			||||||
 | 
					            LCD_CAM.cam_ctrl.cam_clk_sel = 3;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            // disable LCD clock source
 | 
				
			||||||
 | 
					            LCD_CAM.cam_ctrl.cam_clk_sel = 0;
 | 
				
			||||||
 | 
					            HAL_ASSERT(false);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Get the CAM source clock type
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param src The pointer to accept the CAM source clock type
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_get_clk_src(lcd_cam_dev_t *dev, cam_clock_source_t *src)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    switch (LCD_CAM.cam_ctrl.cam_clk_sel) {
 | 
				
			||||||
 | 
					    case 1:
 | 
				
			||||||
 | 
					        *src = CAM_CLK_SRC_XTAL;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 2:
 | 
				
			||||||
 | 
					        *src = CAM_CLK_SRC_PLL240M;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 3:
 | 
				
			||||||
 | 
					        *src = CAM_CLK_SRC_PLL160M;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        HAL_ASSERT(false);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Set clock coefficient of CAM peripheral
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param group_id Group ID
 | 
				
			||||||
 | 
					 * @param div_num Integer part of the divider
 | 
				
			||||||
 | 
					 * @param div_a denominator of the divider
 | 
				
			||||||
 | 
					 * @param div_b numerator of the divider
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					__attribute__((always_inline))
 | 
				
			||||||
 | 
					static inline void cam_ll_set_group_clock_coeff(int group_id, int div_num, int div_a, int div_b)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    HAL_ASSERT(div_num >= 2 && div_num < CAM_LL_CLK_FRAC_DIV_N_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    LCD_CAM.cam_ctrl.cam_clkm_div_num = div_num;
 | 
				
			||||||
 | 
					    LCD_CAM.cam_ctrl.cam_clkm_div_a = div_a;
 | 
				
			||||||
 | 
					    LCD_CAM.cam_ctrl.cam_clkm_div_b = div_b;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Enable stop signal for CAM peripheral
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param en True to stop when GDMA Rx FIFO is full, False to not stop
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_enable_stop_signal(lcd_cam_dev_t *dev, bool en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl.cam_stop_en = en;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Set vsync filter threshold value
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param value Filter threshold value for CAM_VSYNC_SIGNAL, range [0, 7]
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_set_vsync_filter_thres(lcd_cam_dev_t *dev, uint32_t value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl.cam_vsync_filter_thres = value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Enable to generate LCD_CAM_CAM_HS_INT
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param en True to enable to generate LCD_CAM_CAM_HS_INT, False to disable
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_enable_hs_line_int(lcd_cam_dev_t *dev, bool en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl.cam_line_int_en = en;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Enable CAM_VSYNC to generate in_suc_eof
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param en True to enable CAM_VSYNC to generate in_suc_eof, False to use LCD_CAM_CAM_REC_DATA_BYTELEN to control in_suc_eof
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_enable_vsync_generate_eof(lcd_cam_dev_t *dev, bool en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl.cam_vs_eof_en = en;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Enable to swap every two 8-bit input data
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param en True to enable invert, False to disable invert
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_enable_8bits_data_invert(lcd_cam_dev_t *dev, bool en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_rgb_yuv.cam_conv_8bits_data_inv = en;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Enable YUV-RGB converter
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param en True to enable converter, False to disable converter
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_enable_rgb_yuv_convert(lcd_cam_dev_t *dev, bool en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_rgb_yuv.cam_conv_bypass = en;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Set convert data line width
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param width data line width (8 or 16)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_set_convert_data_width(lcd_cam_dev_t *dev, uint32_t width)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    HAL_ASSERT(width == 8 || width == 16);
 | 
				
			||||||
 | 
					    dev->cam_rgb_yuv.cam_conv_mode_8bits_on = (width == 8) ? 1 : 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Set the color range of input data
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param range Color range
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_set_input_color_range(lcd_cam_dev_t *dev, color_range_t range)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (range == COLOR_RANGE_LIMIT) {
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_data_in_mode = 0;
 | 
				
			||||||
 | 
					    } else if (range == COLOR_RANGE_FULL) {
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_data_in_mode = 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Set the color range of output data
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param range Color range
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_set_output_color_range(lcd_cam_dev_t *dev, color_range_t range)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (range == COLOR_RANGE_LIMIT) {
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_data_out_mode = 0;
 | 
				
			||||||
 | 
					    } else if (range == COLOR_RANGE_FULL) {
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_data_out_mode = 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Set YUV conversion standard
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param std YUV conversion standard
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_set_yuv_convert_std(lcd_cam_dev_t *dev, color_conv_std_rgb_yuv_t std)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (std == COLOR_CONV_STD_RGB_YUV_BT601) {
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_protocol_mode = 0;
 | 
				
			||||||
 | 
					    } else if (std == COLOR_CONV_STD_RGB_YUV_BT709) {
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_protocol_mode = 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Set the converter mode: RGB565 to YUV
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param yuv_sample YUV sample mode
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_set_convert_mode_rgb_to_yuv(lcd_cam_dev_t *dev, color_pixel_yuv_format_t yuv_sample)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_rgb_yuv.cam_conv_trans_mode = 1;
 | 
				
			||||||
 | 
					    dev->cam_rgb_yuv.cam_conv_yuv2yuv_mode = 3;
 | 
				
			||||||
 | 
					    switch (yuv_sample) {
 | 
				
			||||||
 | 
					    case COLOR_PIXEL_YUV422:
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_yuv_mode = 0;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case COLOR_PIXEL_YUV420:
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_yuv_mode = 1;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case COLOR_PIXEL_YUV411:
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_yuv_mode = 2;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Set the converter mode: YUV to RGB565
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param yuv_sample YUV sample mode
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_set_convert_mode_yuv_to_rgb(lcd_cam_dev_t *dev, color_pixel_yuv_format_t yuv_sample)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_rgb_yuv.cam_conv_trans_mode = 0;
 | 
				
			||||||
 | 
					    dev->cam_rgb_yuv.cam_conv_yuv2yuv_mode = 3;
 | 
				
			||||||
 | 
					    switch (yuv_sample) {
 | 
				
			||||||
 | 
					    case COLOR_PIXEL_YUV422:
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_yuv_mode = 0;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case COLOR_PIXEL_YUV420:
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_yuv_mode = 1;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case COLOR_PIXEL_YUV411:
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_yuv_mode = 2;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Set the converter mode: YUV to YUV
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param src_sample Source YUV sample mode
 | 
				
			||||||
 | 
					 * @param dst_sample Destination YUV sample mode
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_set_convert_mode_yuv_to_yuv(lcd_cam_dev_t *dev, color_pixel_yuv_format_t src_sample, color_pixel_yuv_format_t dst_sample)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    HAL_ASSERT(src_sample != dst_sample);
 | 
				
			||||||
 | 
					    dev->cam_rgb_yuv.cam_conv_trans_mode = 1;
 | 
				
			||||||
 | 
					    switch (src_sample) {
 | 
				
			||||||
 | 
					    case COLOR_PIXEL_YUV422:
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_yuv_mode = 0;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case COLOR_PIXEL_YUV420:
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_yuv_mode = 1;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case COLOR_PIXEL_YUV411:
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_yuv_mode = 2;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    switch (dst_sample) {
 | 
				
			||||||
 | 
					    case COLOR_PIXEL_YUV422:
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_yuv2yuv_mode = 0;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case COLOR_PIXEL_YUV420:
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_yuv2yuv_mode = 1;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case COLOR_PIXEL_YUV411:
 | 
				
			||||||
 | 
					        dev->cam_rgb_yuv.cam_conv_yuv2yuv_mode = 2;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Set camera received data byte length
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param length received data byte length, range [0, 0xFFFF]
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_set_recv_data_bytelen(lcd_cam_dev_t *dev, uint32_t length)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    HAL_FORCE_MODIFY_U32_REG_FIELD(dev->cam_ctrl1, cam_rec_data_bytelen, length);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Set line number to trigger interrupt
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param number line number to trigger hs interrupt, range [0, 0x3F]
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_set_line_int_num(lcd_cam_dev_t *dev, uint32_t number)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl1.cam_line_int_num = number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Whether to invert the input signal CAM_PCLK
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param en True to invert, False to not invert
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_enable_invert_pclk(lcd_cam_dev_t *dev, bool en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl1.cam_clk_inv = en;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Enable CAM_VSYNC filter function
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param en True to enable, False to bypass
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_enable_vsync_filter(lcd_cam_dev_t *dev, bool en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl1.cam_vsync_filter_en = en;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Set CAM input data width
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param stride 16: The bit number of input data is 9~16.  8: The bit number of input data is 0~8.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_set_input_data_width(lcd_cam_dev_t *dev, uint32_t stride)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    switch (stride) {
 | 
				
			||||||
 | 
					    case 8:
 | 
				
			||||||
 | 
					        dev->cam_ctrl1.cam_2byte_en = 0;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 16:
 | 
				
			||||||
 | 
					        dev->cam_ctrl1.cam_2byte_en = 1;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        HAL_ASSERT(false);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Whether to invert CAM_DE
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param en True to invert, False to not invert
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_enable_invert_de(lcd_cam_dev_t *dev, bool en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl1.cam_de_inv = en;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Whether to invert CAM_HSYNC
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param en True to invert, False to not invert
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_enable_invert_hsync(lcd_cam_dev_t *dev, bool en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl1.cam_hsync_inv = en;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Whether to invert CAM_VSYNC
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param en True to invert, False to not invert
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_enable_invert_vsync(lcd_cam_dev_t *dev, bool en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl1.cam_vsync_inv = en;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Enable the mode to control the input control signals
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param mode 1: Input control signals are CAM_DE, CAM_HSYNC and CAM_VSYNC;
 | 
				
			||||||
 | 
					 *             0: Input control signals are CAM_DE and CAM_VSYNC. CAM_HSYNC and CAM_DE are all 1 the the same time.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_set_vh_de_mode(lcd_cam_dev_t *dev, bool enable)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl1.cam_vh_de_mode_en = enable;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Get the mode of input control signals
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param en The pointer to accept the vh_de mode status. 1: Input control signals are CAM_DE, CAM_HSYNC and CAM_VSYNC;
 | 
				
			||||||
 | 
					 * 0: Input control signals are CAM_DE and CAM_VSYNC. CAM_HSYNC and CAM_DE are all 1 the the same time.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_get_vh_de_mode(lcd_cam_dev_t *dev, bool *en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    *en = dev->cam_ctrl1.cam_vh_de_mode_en;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Set the wire width of CAM output
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param width CAM output wire width
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_set_data_wire_width(lcd_cam_dev_t *dev, uint32_t width)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // data line width is same as data stride that set in `cam_ll_set_input_data_width`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Start the CAM transaction
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					__attribute__((always_inline))
 | 
				
			||||||
 | 
					static inline void cam_ll_start(lcd_cam_dev_t *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl.cam_update = 1;
 | 
				
			||||||
 | 
					    dev->cam_ctrl1.cam_start = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Stop the CAM transaction
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					__attribute__((always_inline))
 | 
				
			||||||
 | 
					static inline void cam_ll_stop(lcd_cam_dev_t *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl1.cam_start = 0;
 | 
				
			||||||
 | 
					    dev->cam_ctrl.cam_update = 1; // self clear
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Whether to reverse the data bit order
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @note It acts before the YUV-RGB converter
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param en True to reverse, False to not reverse
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					__attribute__((always_inline))
 | 
				
			||||||
 | 
					static inline void cam_ll_reverse_dma_data_bit_order(lcd_cam_dev_t *dev, bool en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl.cam_bit_order = en;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Whether to swap adjacent two bytes
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @note This acts before the YUV-RGB converter, mainly to change the data endian.
 | 
				
			||||||
 | 
					 *       {B1,B0},{B3,B2} => {B0,B1}{B2,B3}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param en True to swap the byte order, False to not swap
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					__attribute__((always_inline))
 | 
				
			||||||
 | 
					static inline void cam_ll_swap_dma_data_byte_order(lcd_cam_dev_t *dev, bool en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl.cam_byte_order = en;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Reset camera module
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					__attribute__((always_inline))
 | 
				
			||||||
 | 
					static inline void cam_ll_reset(lcd_cam_dev_t *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl1.cam_reset = 1; // self clear
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Reset Async RX FIFO
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					__attribute__((always_inline))
 | 
				
			||||||
 | 
					static inline void cam_ll_fifo_reset(lcd_cam_dev_t *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->cam_ctrl1.cam_afifo_reset = 1; // self clear
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Enable/disable interrupt by mask
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param mask Interrupt mask
 | 
				
			||||||
 | 
					 * @param en True to enable interrupt, False to disable interrupt
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void cam_ll_enable_interrupt(lcd_cam_dev_t *dev, uint32_t mask, bool en)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (en) {
 | 
				
			||||||
 | 
					        dev->lc_dma_int_ena.val |= mask & 0x0c;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        dev->lc_dma_int_ena.val &= ~(mask & 0x0c);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Get interrupt status value
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @return Interrupt status value
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					__attribute__((always_inline))
 | 
				
			||||||
 | 
					static inline uint32_t cam_ll_get_interrupt_status(lcd_cam_dev_t *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return dev->lc_dma_int_st.val & 0x0c;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Clear interrupt status by mask
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @param mask Interrupt status mask
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					__attribute__((always_inline))
 | 
				
			||||||
 | 
					static inline void cam_ll_clear_interrupt_status(lcd_cam_dev_t *dev, uint32_t mask)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    dev->lc_dma_int_clr.val = mask & 0x0c;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Get address of interrupt status register address
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param dev CAM register base address
 | 
				
			||||||
 | 
					 * @return Interrupt status register address
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline volatile void *cam_ll_get_interrupt_status_reg(lcd_cam_dev_t *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return &dev->lc_dma_int_st;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										40
									
								
								components/soc/esp32s3/cam_periph.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								components/soc/esp32s3/cam_periph.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * SPDX-License-Identifier: Apache-2.0
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "soc/gpio_sig_map.h"
 | 
				
			||||||
 | 
					#include "soc/cam_periph.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const cam_signal_conn_t cam_periph_signals = {
 | 
				
			||||||
 | 
					    .buses = {
 | 
				
			||||||
 | 
					        [0] = {
 | 
				
			||||||
 | 
					            .module = PERIPH_LCD_CAM_MODULE,
 | 
				
			||||||
 | 
					            .irq_id = ETS_LCD_CAM_INTR_SOURCE,
 | 
				
			||||||
 | 
					            .data_sigs = {
 | 
				
			||||||
 | 
					                CAM_DATA_IN0_IDX,
 | 
				
			||||||
 | 
					                CAM_DATA_IN1_IDX,
 | 
				
			||||||
 | 
					                CAM_DATA_IN2_IDX,
 | 
				
			||||||
 | 
					                CAM_DATA_IN3_IDX,
 | 
				
			||||||
 | 
					                CAM_DATA_IN4_IDX,
 | 
				
			||||||
 | 
					                CAM_DATA_IN5_IDX,
 | 
				
			||||||
 | 
					                CAM_DATA_IN6_IDX,
 | 
				
			||||||
 | 
					                CAM_DATA_IN7_IDX,
 | 
				
			||||||
 | 
					                CAM_DATA_IN8_IDX,
 | 
				
			||||||
 | 
					                CAM_DATA_IN9_IDX,
 | 
				
			||||||
 | 
					                CAM_DATA_IN10_IDX,
 | 
				
			||||||
 | 
					                CAM_DATA_IN11_IDX,
 | 
				
			||||||
 | 
					                CAM_DATA_IN12_IDX,
 | 
				
			||||||
 | 
					                CAM_DATA_IN13_IDX,
 | 
				
			||||||
 | 
					                CAM_DATA_IN14_IDX,
 | 
				
			||||||
 | 
					                CAM_DATA_IN15_IDX
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            .hsync_sig = CAM_H_SYNC_IDX,
 | 
				
			||||||
 | 
					            .vsync_sig = CAM_V_SYNC_IDX,
 | 
				
			||||||
 | 
					            .pclk_sig = CAM_PCLK_IDX,
 | 
				
			||||||
 | 
					            .de_sig = CAM_H_ENABLE_IDX,
 | 
				
			||||||
 | 
					            .clk_sig = CAM_CLK_IDX
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -47,6 +47,10 @@ config SOC_LCDCAM_SUPPORTED
 | 
				
			|||||||
    bool
 | 
					    bool
 | 
				
			||||||
    default y
 | 
					    default y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config SOC_LCDCAM_CAM_SUPPORTED
 | 
				
			||||||
 | 
					    bool
 | 
				
			||||||
 | 
					    default y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config SOC_LCDCAM_I80_LCD_SUPPORTED
 | 
					config SOC_LCDCAM_I80_LCD_SUPPORTED
 | 
				
			||||||
    bool
 | 
					    bool
 | 
				
			||||||
    default y
 | 
					    default y
 | 
				
			||||||
@@ -1538,3 +1542,15 @@ config SOC_ULP_HAS_ADC
 | 
				
			|||||||
config SOC_PHY_COMBO_MODULE
 | 
					config SOC_PHY_COMBO_MODULE
 | 
				
			||||||
    bool
 | 
					    bool
 | 
				
			||||||
    default y
 | 
					    default y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config SOC_LCDCAM_CAM_SUPPORT_RGB_YUV_CONV
 | 
				
			||||||
 | 
					    bool
 | 
				
			||||||
 | 
					    default y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config SOC_LCDCAM_CAM_PERIPH_NUM
 | 
				
			||||||
 | 
					    int
 | 
				
			||||||
 | 
					    default 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config SOC_LCDCAM_CAM_DATA_WIDTH_MAX
 | 
				
			||||||
 | 
					    int
 | 
				
			||||||
 | 
					    default 16
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
 | 
					 * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * SPDX-License-Identifier: Apache-2.0
 | 
					 * SPDX-License-Identifier: Apache-2.0
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -190,6 +190,23 @@ typedef enum {
 | 
				
			|||||||
    LCD_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default choice */
 | 
					    LCD_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default choice */
 | 
				
			||||||
} soc_periph_lcd_clk_src_t;
 | 
					} soc_periph_lcd_clk_src_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////LCD///////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Array initializer for all supported clock sources of CAM
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define SOC_CAM_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_PLL_D2, SOC_MOD_CLK_XTAL}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Type of CAM clock source
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    CAM_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */
 | 
				
			||||||
 | 
					    CAM_CLK_SRC_PLL240M = SOC_MOD_CLK_PLL_D2,    /*!< Select PLL_D2 as the source clock */
 | 
				
			||||||
 | 
					    CAM_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL,         /*!< Select XTAL as the source clock */
 | 
				
			||||||
 | 
					    CAM_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_D2,    /*!< Select PLL_D2 as the default choice */
 | 
				
			||||||
 | 
					} soc_periph_cam_clk_src_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//////////////////////////////////////////////////RMT///////////////////////////////////////////////////////////////////
 | 
					//////////////////////////////////////////////////RMT///////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,7 @@
 | 
				
			|||||||
#define SOC_AHB_GDMA_SUPPORTED          1
 | 
					#define SOC_AHB_GDMA_SUPPORTED          1
 | 
				
			||||||
#define SOC_GPTIMER_SUPPORTED           1
 | 
					#define SOC_GPTIMER_SUPPORTED           1
 | 
				
			||||||
#define SOC_LCDCAM_SUPPORTED            1
 | 
					#define SOC_LCDCAM_SUPPORTED            1
 | 
				
			||||||
 | 
					#define SOC_LCDCAM_CAM_SUPPORTED        1 // support the camera driver based on the LCD_CAM peripheral
 | 
				
			||||||
#define SOC_LCDCAM_I80_LCD_SUPPORTED    1
 | 
					#define SOC_LCDCAM_I80_LCD_SUPPORTED    1
 | 
				
			||||||
#define SOC_LCDCAM_RGB_LCD_SUPPORTED    1
 | 
					#define SOC_LCDCAM_RGB_LCD_SUPPORTED    1
 | 
				
			||||||
#define SOC_MCPWM_SUPPORTED             1
 | 
					#define SOC_MCPWM_SUPPORTED             1
 | 
				
			||||||
@@ -605,3 +606,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*------------------------------------- PHY CAPS -------------------------------------*/
 | 
					/*------------------------------------- PHY CAPS -------------------------------------*/
 | 
				
			||||||
#define SOC_PHY_COMBO_MODULE                  (1) /*!< Support Wi-Fi and BLE*/
 | 
					#define SOC_PHY_COMBO_MODULE                  (1) /*!< Support Wi-Fi and BLE*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*--------------------------- CAM ---------------------------------*/
 | 
				
			||||||
 | 
					#define SOC_LCDCAM_CAM_SUPPORT_RGB_YUV_CONV         (1)
 | 
				
			||||||
 | 
					#define SOC_LCDCAM_CAM_PERIPH_NUM                   (1U)
 | 
				
			||||||
 | 
					#define SOC_LCDCAM_CAM_DATA_WIDTH_MAX               (16U)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user