diff --git a/components/esp_driver_ppa/src/ppa_blend.c b/components/esp_driver_ppa/src/ppa_blend.c index e3cd6816c04..f80252f60c9 100644 --- a/components/esp_driver_ppa/src/ppa_blend.c +++ b/components/esp_driver_ppa/src/ppa_blend.c @@ -260,26 +260,34 @@ esp_err_t ppa_do_blend(ppa_client_handle_t ppa_client, const ppa_blend_oper_conf // Write back and invalidate necessary data (note that the window content is not continuous in the buffer) // Write back in_bg_buffer, in_fg_buffer extended windows (alignment not necessary on C2M direction) - uint32_t buf_alignment_size = (uint32_t)ppa_client->engine->platform->buf_alignment_size; - uint32_t in_bg_pixel_depth = color_hal_pixel_format_fourcc_get_bit_depth((esp_color_fourcc_t)config->in_bg.blend_cm); // bits - // Usually C2M can let the msync do alignment internally, however, it only do L1-cacheline-size alignment for L1->L2, and then L2-cacheline-size alignment for L2->mem - // While M2C direction manual alignment is L2-cacheline-size alignment for mem->L2->L1 - // Mismatching writeback and invalidate data size could cause synchronization error if in_bg/fg_buffer and out_buffer are the same one - uint32_t in_bg_ext_window = (uint32_t)config->in_bg.buffer + config->in_bg.block_offset_y * config->in_bg.pic_w * in_bg_pixel_depth / 8; - uint32_t in_bg_ext_window_aligned = PPA_ALIGN_DOWN(in_bg_ext_window, buf_alignment_size); - uint32_t in_bg_ext_window_len = config->in_bg.pic_w * config->in_bg.block_h * in_bg_pixel_depth / 8; - esp_cache_msync((void *)in_bg_ext_window_aligned, PPA_ALIGN_UP(in_bg_ext_window_len + (in_bg_ext_window - in_bg_ext_window_aligned), buf_alignment_size), ESP_CACHE_MSYNC_FLAG_DIR_C2M); - uint32_t in_fg_pixel_depth = color_hal_pixel_format_fourcc_get_bit_depth((esp_color_fourcc_t)config->in_fg.blend_cm); // bits - uint32_t in_fg_ext_window = (uint32_t)config->in_fg.buffer + config->in_fg.block_offset_y * config->in_fg.pic_w * in_fg_pixel_depth / 8; - // Same for fg_buffer msync, do manual alignment - uint32_t in_fg_ext_window_aligned = PPA_ALIGN_DOWN(in_fg_ext_window, buf_alignment_size); - uint32_t in_fg_ext_window_len = config->in_fg.pic_w * config->in_fg.block_h * in_fg_pixel_depth / 8; - esp_cache_msync((void *)in_fg_ext_window_aligned, PPA_ALIGN_UP(in_fg_ext_window_len + (in_fg_ext_window - in_fg_ext_window_aligned), buf_alignment_size), ESP_CACHE_MSYNC_FLAG_DIR_C2M); + size_t in_bg_buf_alignment = esp_ptr_external_ram(config->in_bg.buffer) ? ppa_client->engine->platform->ext_mem_align : ppa_client->engine->platform->int_mem_align; + if (in_bg_buf_alignment > 0) { + uint32_t in_bg_pixel_depth = color_hal_pixel_format_fourcc_get_bit_depth((esp_color_fourcc_t)config->in_bg.blend_cm); // bits + // Usually C2M can let the msync do alignment internally, however, it only do L1-cacheline-size alignment for L1->L2, and then L2-cacheline-size alignment for L2->mem + // While M2C direction manual alignment is L2-cacheline-size alignment for mem->L2->L1 + // Mismatching writeback and invalidate data size could cause synchronization error if in_bg/fg_buffer and out_buffer are the same one + uint32_t in_bg_ext_window = (uint32_t)config->in_bg.buffer + config->in_bg.block_offset_y * config->in_bg.pic_w * in_bg_pixel_depth / 8; + uint32_t in_bg_ext_window_aligned = PPA_ALIGN_DOWN(in_bg_ext_window, in_bg_buf_alignment); + uint32_t in_bg_ext_window_len = config->in_bg.pic_w * config->in_bg.block_h * in_bg_pixel_depth / 8; + esp_cache_msync((void *)in_bg_ext_window_aligned, PPA_ALIGN_UP(in_bg_ext_window_len + (in_bg_ext_window - in_bg_ext_window_aligned), in_bg_buf_alignment), ESP_CACHE_MSYNC_FLAG_DIR_C2M); + } + size_t in_fg_buf_alignment = esp_ptr_external_ram(config->in_fg.buffer) ? ppa_client->engine->platform->ext_mem_align : ppa_client->engine->platform->int_mem_align; + if (in_fg_buf_alignment > 0) { + uint32_t in_fg_pixel_depth = color_hal_pixel_format_fourcc_get_bit_depth((esp_color_fourcc_t)config->in_fg.blend_cm); // bits + uint32_t in_fg_ext_window = (uint32_t)config->in_fg.buffer + config->in_fg.block_offset_y * config->in_fg.pic_w * in_fg_pixel_depth / 8; + // Same for fg_buffer msync, do manual alignment + uint32_t in_fg_ext_window_aligned = PPA_ALIGN_DOWN(in_fg_ext_window, in_fg_buf_alignment); + uint32_t in_fg_ext_window_len = config->in_fg.pic_w * config->in_fg.block_h * in_fg_pixel_depth / 8; + esp_cache_msync((void *)in_fg_ext_window_aligned, PPA_ALIGN_UP(in_fg_ext_window_len + (in_fg_ext_window - in_fg_ext_window_aligned), in_fg_buf_alignment), ESP_CACHE_MSYNC_FLAG_DIR_C2M); + } // Invalidate out_buffer extended window (alignment strict on M2C direction) - uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; - uint32_t out_ext_window_aligned = PPA_ALIGN_DOWN(out_ext_window, buf_alignment_size); - uint32_t out_ext_window_len = config->out.pic_w * config->in_bg.block_h * out_pixel_depth / 8; - esp_cache_msync((void *)out_ext_window_aligned, PPA_ALIGN_UP(out_ext_window_len + (out_ext_window - out_ext_window_aligned), buf_alignment_size), ESP_CACHE_MSYNC_FLAG_DIR_M2C); + size_t out_buf_alignment = esp_ptr_external_ram(config->out.buffer) ? ppa_client->engine->platform->ext_mem_align : ppa_client->engine->platform->int_mem_align; + if (out_buf_alignment > 0) { + uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; + uint32_t out_ext_window_aligned = PPA_ALIGN_DOWN(out_ext_window, out_buf_alignment); + uint32_t out_ext_window_len = config->out.pic_w * config->in_bg.block_h * out_pixel_depth / 8; + esp_cache_msync((void *)out_ext_window_aligned, PPA_ALIGN_UP(out_ext_window_len + (out_ext_window - out_ext_window_aligned), out_buf_alignment), ESP_CACHE_MSYNC_FLAG_DIR_M2C); + } esp_err_t ret = ESP_OK; ppa_trans_t *trans_elm = NULL; diff --git a/components/esp_driver_ppa/src/ppa_core.c b/components/esp_driver_ppa/src/ppa_core.c index d0047524b04..49289c22dc3 100644 --- a/components/esp_driver_ppa/src/ppa_core.c +++ b/components/esp_driver_ppa/src/ppa_core.c @@ -67,11 +67,11 @@ static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engin size_t alignment = MAX(DMA2D_LL_DESC_ALIGNMENT, data_cache_line_size); _lock_acquire(&s_platform.mutex); - if (s_platform.dma_desc_mem_size == 0) { + if (s_platform.srm_engine_ref_count + s_platform.blend_engine_ref_count == 0) { + // Initialize the platform level alignment requirements s_platform.dma_desc_mem_size = PPA_ALIGN_UP(sizeof(dma2d_descriptor_align8_t), alignment); - } - if (s_platform.buf_alignment_size == 0) { - esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &s_platform.buf_alignment_size); + esp_cache_get_alignment(MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA, &s_platform.int_mem_align); + esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &s_platform.ext_mem_align); } if (config->engine == PPA_ENGINE_TYPE_SRM) { @@ -540,10 +540,11 @@ esp_err_t ppa_set_rgb2gray_formula(uint8_t r_weight, uint8_t g_weight, uint8_t b bool ppa_check_buffer_alignment(ppa_client_handle_t ppa_client, const void *pic_blk_config, bool is_input, uint32_t block_width) { // 1. check with cache line size alignment (output buffer only) - uint32_t buf_alignment_size = (uint32_t)ppa_client->engine->platform->buf_alignment_size; if (!is_input) { ppa_out_pic_blk_config_t *out_pic_blk_config = (ppa_out_pic_blk_config_t *)pic_blk_config; - if (((uint32_t)out_pic_blk_config->buffer & (buf_alignment_size - 1)) != 0 || (out_pic_blk_config->buffer_size & (buf_alignment_size - 1)) != 0) { + size_t alignment = esp_ptr_external_ram(out_pic_blk_config->buffer) ? ppa_client->engine->platform->ext_mem_align : ppa_client->engine->platform->int_mem_align; + // if cache line size alignment is 0, means no msync is needed, so no check is needed + if (alignment > 0 && (((uint32_t)out_pic_blk_config->buffer & (alignment - 1)) != 0 || (out_pic_blk_config->buffer_size & (alignment - 1)) != 0)) { ESP_LOGE(TAG, "out.buffer addr or out.buffer_size not aligned to cache line size"); return false; } diff --git a/components/esp_driver_ppa/src/ppa_fill.c b/components/esp_driver_ppa/src/ppa_fill.c index 70fe4278d91..12682780bc9 100644 --- a/components/esp_driver_ppa/src/ppa_fill.c +++ b/components/esp_driver_ppa/src/ppa_fill.c @@ -116,11 +116,13 @@ esp_err_t ppa_do_fill(ppa_client_handle_t ppa_client, const ppa_fill_oper_config // Write back and invalidate necessary data (note that the window content is not continuous in the buffer) // Write back and invalidate buffer extended window (alignment not necessary on C2M direction, but alignment strict on M2C direction) - uint32_t buf_alignment_size = (uint32_t)ppa_client->engine->platform->buf_alignment_size; - uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; - uint32_t out_ext_window_aligned = PPA_ALIGN_DOWN(out_ext_window, buf_alignment_size); - uint32_t out_ext_window_len = config->out.pic_w * config->fill_block_h * out_pixel_depth / 8; - esp_cache_msync((void *)out_ext_window_aligned, PPA_ALIGN_UP(out_ext_window_len + (out_ext_window - out_ext_window_aligned), buf_alignment_size), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); + size_t out_buf_alignment = esp_ptr_external_ram(config->out.buffer) ? ppa_client->engine->platform->ext_mem_align : ppa_client->engine->platform->int_mem_align; + if (out_buf_alignment > 0) { + uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; + uint32_t out_ext_window_aligned = PPA_ALIGN_DOWN(out_ext_window, out_buf_alignment); + uint32_t out_ext_window_len = config->out.pic_w * config->fill_block_h * out_pixel_depth / 8; + esp_cache_msync((void *)out_ext_window_aligned, PPA_ALIGN_UP(out_ext_window_len + (out_ext_window - out_ext_window_aligned), out_buf_alignment), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); + } esp_err_t ret = ESP_OK; ppa_trans_t *trans_elm = NULL; diff --git a/components/esp_driver_ppa/src/ppa_priv.h b/components/esp_driver_ppa/src/ppa_priv.h index 4f629f4bb85..d6ff470c8af 100644 --- a/components/esp_driver_ppa/src/ppa_priv.h +++ b/components/esp_driver_ppa/src/ppa_priv.h @@ -244,7 +244,8 @@ struct ppa_platform_t { ppa_blend_engine_t *blending; // Pointer to the PPA blending engine uint32_t srm_engine_ref_count; // Reference count used to protect PPA SRM engine acquire and release uint32_t blend_engine_ref_count; // Reference count used to protect PPA blending engine acquire and release - size_t buf_alignment_size; // Alignment requirement for the outgoing buffer addr and size to satisfy cache line size + size_t int_mem_align; // Alignment requirement for the internal outgoing buffer to satisfy cache line size + size_t ext_mem_align; // Alignment requirement for the external outgoing buffer to satisfy cache line size uint32_t dma_desc_mem_size; // Alignment requirement for the 2D-DMA descriptor to satisfy cache line size }; diff --git a/components/esp_driver_ppa/src/ppa_srm.c b/components/esp_driver_ppa/src/ppa_srm.c index 88b7d6cfeed..cbd7e109f78 100644 --- a/components/esp_driver_ppa/src/ppa_srm.c +++ b/components/esp_driver_ppa/src/ppa_srm.c @@ -12,6 +12,7 @@ #include "esp_cache.h" #include "esp_memory_utils.h" #include "soc/dma2d_channel.h" +#include "sdkconfig.h" static const char *TAG = "ppa_srm"; @@ -153,6 +154,7 @@ bool ppa_srm_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel ppa_ll_srm_enable_mirror_x(platform->hal.dev, srm_trans_desc->mirror_x); ppa_ll_srm_enable_mirror_y(platform->hal.dev, srm_trans_desc->mirror_y); +#if CONFIG_IDF_TARGET_ESP32P4 // Hardware bug workaround (DIG-734) uint32_t w_out = srm_trans_desc->in.block_w * srm_trans_desc->scale_x_int + srm_trans_desc->in.block_w * srm_trans_desc->scale_x_frag / PPA_LL_SRM_SCALING_FRAG_MAX; uint32_t w_divisor = (ppa_out_color_mode == PPA_SRM_COLOR_MODE_ARGB8888 || ppa_out_color_mode == PPA_SRM_COLOR_MODE_RGB888) ? 32 : 64; @@ -171,6 +173,7 @@ bool ppa_srm_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel bypass_mb_order = true; } ppa_ll_srm_bypass_mb_order(platform->hal.dev, bypass_mb_order); +#endif ppa_ll_srm_start(platform->hal.dev); @@ -256,17 +259,22 @@ esp_err_t ppa_do_scale_rotate_mirror(ppa_client_handle_t ppa_client, const ppa_s // Write back and invalidate necessary data (note that the window content is not continuous in the buffer) // Write back in_buffer extended window (alignment not necessary on C2M direction) - uint32_t buf_alignment_size = (uint32_t)ppa_client->engine->platform->buf_alignment_size; - uint32_t in_pixel_depth = color_hal_pixel_format_fourcc_get_bit_depth((esp_color_fourcc_t)config->in.srm_cm); // bits - uint32_t in_ext_window = (uint32_t)config->in.buffer + config->in.block_offset_y * config->in.pic_w * in_pixel_depth / 8; - uint32_t in_ext_window_len = config->in.pic_w * config->in.block_h * in_pixel_depth / 8; - esp_cache_msync((void *)in_ext_window, in_ext_window_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); + size_t in_buf_alignment = esp_ptr_external_ram(config->in.buffer) ? ppa_client->engine->platform->ext_mem_align : ppa_client->engine->platform->int_mem_align; + if (in_buf_alignment > 0) { + uint32_t in_pixel_depth = color_hal_pixel_format_fourcc_get_bit_depth((esp_color_fourcc_t)config->in.srm_cm); // bits + uint32_t in_ext_window = (uint32_t)config->in.buffer + config->in.block_offset_y * config->in.pic_w * in_pixel_depth / 8; + uint32_t in_ext_window_len = config->in.pic_w * config->in.block_h * in_pixel_depth / 8; + esp_cache_msync((void *)in_ext_window, in_ext_window_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); + } // Invalidate out_buffer extended window (alignment strict on M2C direction) - uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; - uint32_t out_ext_window_aligned = PPA_ALIGN_DOWN(out_ext_window, buf_alignment_size); - uint32_t out_ext_window_len = config->out.pic_w * new_block_h * out_pixel_depth / 8; // actual ext_window_len must be less than or equal to this, since actual block_h <= new_block_h (may round down) - assert(out_ext_window + out_ext_window_len <= (uint32_t)config->out.buffer + config->out.buffer_size); - esp_cache_msync((void *)out_ext_window_aligned, PPA_ALIGN_UP(out_ext_window_len + (out_ext_window - out_ext_window_aligned), buf_alignment_size), ESP_CACHE_MSYNC_FLAG_DIR_M2C); + size_t out_buf_alignment = esp_ptr_external_ram(config->out.buffer) ? ppa_client->engine->platform->ext_mem_align : ppa_client->engine->platform->int_mem_align; + if (out_buf_alignment > 0) { + uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; + uint32_t out_ext_window_aligned = PPA_ALIGN_DOWN(out_ext_window, out_buf_alignment); + uint32_t out_ext_window_len = config->out.pic_w * new_block_h * out_pixel_depth / 8; // actual ext_window_len must be less than or equal to this, since actual block_h <= new_block_h (may round down) + assert(out_ext_window + out_ext_window_len <= (uint32_t)config->out.buffer + config->out.buffer_size); + esp_cache_msync((void *)out_ext_window_aligned, PPA_ALIGN_UP(out_ext_window_len + (out_ext_window - out_ext_window_aligned), out_buf_alignment), ESP_CACHE_MSYNC_FLAG_DIR_M2C); + } esp_err_t ret = ESP_OK; ppa_trans_t *trans_elm = NULL; diff --git a/components/esp_driver_ppa/test_apps/README.md b/components/esp_driver_ppa/test_apps/README.md index 909282018f2..6980aa681b4 100644 --- a/components/esp_driver_ppa/test_apps/README.md +++ b/components/esp_driver_ppa/test_apps/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32-P4 | -| ----------------- | -------- | +| Supported Targets | ESP32-P4 | ESP32-S31 | +| ----------------- | -------- | --------- | diff --git a/components/esp_driver_ppa/test_apps/main/ppa_performance.h b/components/esp_driver_ppa/test_apps/main/ppa_performance.h index edab08fc14b..0dc047aed1d 100644 --- a/components/esp_driver_ppa/test_apps/main/ppa_performance.h +++ b/components/esp_driver_ppa/test_apps/main/ppa_performance.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,7 @@ */ #if CONFIG_IDF_TARGET_ESP32P4 + #if CONFIG_ESP32P4_SELECTS_REV_LESS_V3 #define PPA_SRM_MIN_PERFORMANCE_PX_PER_SEC (21000 * 1000) // k_min #define PPA_SRM_TIME_OFFSET (-26000) // b_approx @@ -28,4 +29,15 @@ #define PPA_FILL_MIN_PERFORMANCE_PX_PER_SEC (150000 * 1000) // k_min #define PPA_FILL_TIME_OFFSET (-106000) // b_approx + +#elif CONFIG_IDF_TARGET_ESP32S31 + +#define PPA_SRM_MIN_PERFORMANCE_PX_PER_SEC (25900 * 1000) // k_min +#define PPA_SRM_TIME_OFFSET (-64000) // b_approx + +#define PPA_BLEND_MIN_PERFORMANCE_PX_PER_SEC (22000 * 1000) // k_min +#define PPA_BLEND_TIME_OFFSET (-57000) // b_approx + +#define PPA_FILL_MIN_PERFORMANCE_PX_PER_SEC (79800 * 1000) // k_min +#define PPA_FILL_TIME_OFFSET (-137000) // b_approx #endif diff --git a/components/esp_driver_ppa/test_apps/pytest_ppa.py b/components/esp_driver_ppa/test_apps/pytest_ppa.py index 688a0fcccd6..797e50d36d9 100644 --- a/components/esp_driver_ppa/test_apps/pytest_ppa.py +++ b/components/esp_driver_ppa/test_apps/pytest_ppa.py @@ -42,5 +42,6 @@ def test_ppa_esp32p4_rev1(dut: Dut) -> None: indirect=True, ) @idf_parametrize('target', soc_filtered_targets('SOC_PPA_SUPPORTED == 1'), indirect=['target']) +@pytest.mark.temp_skip_ci(targets=['esp32s31'], reason='TODO: IDFCI-10377 no runner yet') def test_ppa_flash_encryption(dut: Dut) -> None: dut.run_all_single_board_cases() diff --git a/examples/peripherals/ppa/ppa_dsi/sdkconfig.defaults b/components/esp_driver_ppa/test_apps/sdkconfig.defaults.esp32s31 similarity index 55% rename from examples/peripherals/ppa/ppa_dsi/sdkconfig.defaults rename to components/esp_driver_ppa/test_apps/sdkconfig.defaults.esp32s31 index 73cebe337da..a773458c533 100644 --- a/examples/peripherals/ppa/ppa_dsi/sdkconfig.defaults +++ b/components/esp_driver_ppa/test_apps/sdkconfig.defaults.esp32s31 @@ -1,3 +1,3 @@ CONFIG_SPIRAM=y -CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_SPIRAM_MODE_OCT=y CONFIG_SPIRAM_SPEED_200M=y diff --git a/components/esp_hal_ppa/esp32p4/include/hal/ppa_ll.h b/components/esp_hal_ppa/esp32p4/include/hal/ppa_ll.h index c45e66806ed..b20fc4c909c 100644 --- a/components/esp_hal_ppa/esp32p4/include/hal/ppa_ll.h +++ b/components/esp_hal_ppa/esp32p4/include/hal/ppa_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -28,6 +28,10 @@ extern "C" { #endif +typedef enum { + PPA_LL_MEM_LP_MODE_SHUT_DOWN, // memory will be powered down during low power stage +} ppa_ll_mem_lp_mode_t; + /** * @brief Enumeration of PPA SRM macro block size options */ @@ -81,6 +85,48 @@ static inline void ppa_ll_reset_register(void) ppa_ll_reset_register(__VA_ARGS__); \ } while(0) +/** + * @brief Force power on the PPA memory block, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_mem_force_power_on(ppa_dev_t *dev) +{ + (void)dev; +} + +/** + * @brief Force the PPA memory block into low power mode, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_mem_force_low_power(ppa_dev_t *dev) +{ + (void)dev; +} + +/** + * @brief Power control the PPA memory block by the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_mem_power_by_pmu(ppa_dev_t *dev) +{ + (void)dev; +} + +/** + * @brief Set low power mode for PPA memory block + * + * @param dev Peripheral instance address + * @param mode PPA memory low power mode in low power stage + */ +static inline void ppa_ll_mem_set_low_power_mode(ppa_dev_t *dev, ppa_ll_mem_lp_mode_t mode) +{ + (void)dev; + HAL_ASSERT(mode == PPA_LL_MEM_LP_MODE_SHUT_DOWN); +} + /** * @brief Configure the RGB888 to GRAY8 color conversion coefficients for SRM and Blending (excluding Fill) * @@ -1110,6 +1156,7 @@ static inline void ppa_ll_blend_configure_filling_block(ppa_dev_t *dev, ppa_fill fill_color_data = ((yuv_data->y) << 24) | ((yuv_data->v) << 16) | ((yuv_data->y) << 8) | (yuv_data->u); break; } + // Non-typical YUV420, U and V components have to be the same value // case PPA_FILL_COLOR_MODE_YUV420: { // color_macroblock_yuv_data_t *yuv_data = (color_macroblock_yuv_data_t *)data; // if (yuv_data->u != yuv_data->v) { diff --git a/components/esp_hal_ppa/esp32s31/include/hal/ppa_ll.h b/components/esp_hal_ppa/esp32s31/include/hal/ppa_ll.h new file mode 100644 index 00000000000..25d6a92132f --- /dev/null +++ b/components/esp_hal_ppa/esp32s31/include/hal/ppa_ll.h @@ -0,0 +1,1295 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include +#include "hal/ppa_types.h" +#include "hal/color_types.h" +#include "soc/ppa_struct.h" +#include "soc/ppa_reg.h" +#include "soc/hp_sys_clkrst_struct.h" +#include "soc/hp_system_struct.h" +#include "hal/assert.h" +#include "hal/misc.h" +#include "hal/config.h" + +#define PPA_LL_GET_HW &PPA + +#define PPA_LL_BLEND0_CLUT_MEM_ADDR_OFFSET 0x400 +#define PPA_LL_BLEND1_CLUT_MEM_ADDR_OFFSET 0x800 + +#define PPA_LL_SRM_SCALING_INT_MAX (PPA_SRM_SCAL_X_INT_V + 1) +#define PPA_LL_SRM_SCALING_FRAG_MAX (PPA_SRM_SCAL_X_FRAG_V + 1) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + PPA_LL_MEM_LP_MODE_DEEP_SLEEP, // memory will enter deep sleep during low power stage, keep memory data + PPA_LL_MEM_LP_MODE_LIGHT_SLEEP, // memory will enter light sleep during low power stage, keep memory data + PPA_LL_MEM_LP_MODE_SHUT_DOWN, // memory will be powered down during low power stage + PPA_LL_MEM_LP_MODE_DISABLE, // disable the low power stage +} ppa_ll_mem_lp_mode_t; + +/** + * @brief Enumeration of PPA SRM macro block size options + */ +typedef enum { + PPA_LL_SRM_MB_SIZE_16_16, /*!< SRM engine processes with a macro block size of 16 x 16 */ + PPA_LL_SRM_MB_SIZE_32_32, /*!< SRM engine processes with a macro block size of 32 x 32 */ +} ppa_ll_srm_mb_size_t; + +/** + * @brief Enumeration of PPA blending mode + */ +typedef enum { + PPA_LL_BLEND_TRANS_MODE_BLEND, /*!< Blending engine performs blend operation */ + PPA_LL_BLEND_TRANS_MODE_FILL, /*!< Blending engine performs fill operation */ + PPA_LL_BLEND_TRANS_MODE_BYPASS_BLEND, /*!< Blending engine bypasses blender, background will be output directly. Useful for color space conversion (ARGB). */ +} ppa_ll_blend_trans_mode_t; + +///////////////////////////////////// Common ///////////////////////////////////////// +/** + * @brief Enable or disable the PPA peripheral bus clock + * + * @param enable Set true to enable, false to disable + */ +static inline void ppa_ll_enable_bus_clock(bool enable) +{ + HP_SYS_CLKRST.ppa_ctrl0.reg_ppa_sys_clk_en = enable; +} + +/** + * @brief Reset the PPA module + */ +static inline void ppa_ll_reset_register(void) +{ + HP_SYS_CLKRST.ppa_ctrl0.reg_ppa_rst_en = 1; + HP_SYS_CLKRST.ppa_ctrl0.reg_ppa_rst_en = 0; +} + +/** + * @brief Force power on the PPA memory block, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_mem_force_power_on(ppa_dev_t *dev) +{ + HP_SYSTEM.sys_ppa_mem_lp_ctrl.sys_ppa_sprf_mem_force_ctrl = 1; + HP_SYSTEM.sys_ppa_mem_lp_ctrl.sys_ppa_sprf_mem_lp_en = 0; +} + +/** + * @brief Force the PPA memory block into low power mode, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_mem_force_low_power(ppa_dev_t *dev) +{ + HP_SYSTEM.sys_ppa_mem_lp_ctrl.sys_ppa_sprf_mem_force_ctrl = 1; + HP_SYSTEM.sys_ppa_mem_lp_ctrl.sys_ppa_sprf_mem_lp_en = 1; +} + +/** + * @brief Power control the PPA memory block by the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_mem_power_by_pmu(ppa_dev_t *dev) +{ + HP_SYSTEM.sys_ppa_mem_lp_ctrl.sys_ppa_sprf_mem_force_ctrl = 0; + HP_SYSTEM.sys_ppa_mem_lp_ctrl.sys_ppa_sprf_mem_lp_en = 0; +} + +/** + * @brief Set low power mode for PPA memory block + * + * @param dev Peripheral instance address + * @param mode PPA memory low power mode in low power stage + */ +static inline void ppa_ll_mem_set_low_power_mode(ppa_dev_t *dev, ppa_ll_mem_lp_mode_t mode) +{ + HP_SYSTEM.sys_ppa_mem_lp_ctrl.sys_ppa_sprf_mem_lp_mode = mode; +} + +/** + * @brief Configure the RGB888 to GRAY8 color conversion coefficients for SRM and Blending (excluding Fill) + * + * The gray value is calculated as: gray = (r_coeff * R + g_coeff * G + b_coeff * B) >> 8 + * + * @param dev Peripheral instance address + * @param r_coeff Coefficient for Red channel, range 0-255 + * @param g_coeff Coefficient for Green channel, range 0-255 + * @param b_coeff Coefficient for Blue channel, range 0-255 + */ +static inline void ppa_ll_set_rgb2gray_coeff(ppa_dev_t *dev, uint8_t r_coeff, uint8_t g_coeff, uint8_t b_coeff) +{ + HAL_ASSERT((r_coeff + g_coeff + b_coeff == 256) && "Sum of RGB to GRAY coefficients must be 256"); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rgb2gray, rgb2gray_r, r_coeff); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rgb2gray, rgb2gray_g, g_coeff); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rgb2gray, rgb2gray_b, b_coeff); +} + +///////////////////////// Scaling, Rotating, Mirroring (SRM) ////////////////////////////// +/** + * @brief Reset PPA scaling-rotating-mirroring engine + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_srm_reset(ppa_dev_t *dev) +{ + dev->srm_scal_rotate.scal_rotate_rst = 1; + dev->srm_scal_rotate.scal_rotate_rst = 0; +} + +/** + * @brief Set PPA scaling coefficient in X direction + * + * @param dev Peripheral instance address + * @param x_int The integrated part of scaling coefficient in X direction, 0 - 255 + * @param x_frag The fragment part of scaling coefficient in X direction, 0 - 15. Corresponding fractional value is x_frag/16. + */ +static inline void ppa_ll_srm_set_scaling_x(ppa_dev_t *dev, uint32_t x_int, uint32_t x_frag) +{ + HAL_ASSERT(x_int <= PPA_SRM_SCAL_X_INT_V && x_frag <= PPA_SRM_SCAL_X_FRAG_V); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->srm_scal_rotate, srm_scal_x_int, x_int); + dev->srm_scal_rotate.srm_scal_x_frag = x_frag; +} + +/** + * @brief Set PPA scaling coefficient in Y direction + * + * @param dev Peripheral instance address + * @param y_int The integrated part of scaling coefficient in Y direction, 0 - 255 + * @param y_frag The fragment part of scaling coefficient in Y direction, 0 - 15. Corresponding fractional value is y_frag/16. + */ +static inline void ppa_ll_srm_set_scaling_y(ppa_dev_t *dev, uint32_t y_int, uint32_t y_frag) +{ + HAL_ASSERT(y_int <= PPA_SRM_SCAL_Y_INT_V && y_frag <= PPA_SRM_SCAL_Y_FRAG_V); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->srm_scal_rotate, srm_scal_y_int, y_int); + dev->srm_scal_rotate.srm_scal_y_frag = y_frag; +} + +/** + * @brief Set PPA rotation angle (in the counterclockwise direction) + * + * @param dev Peripheral instance address + * @param angle One of the values in ppa_srm_rotation_angle_t + */ +static inline void ppa_ll_srm_set_rotation_angle(ppa_dev_t *dev, ppa_srm_rotation_angle_t angle) +{ + uint32_t val = 0; + switch (angle) { + case PPA_SRM_ROTATION_ANGLE_0: + val = 0; + break; + case PPA_SRM_ROTATION_ANGLE_90: + val = 1; + break; + case PPA_SRM_ROTATION_ANGLE_180: + val = 2; + break; + case PPA_SRM_ROTATION_ANGLE_270: + val = 3; + break; + default: + // Unsupported rotation angle + abort(); + } + dev->srm_scal_rotate.srm_rotate_angle = val; +} + +/** + * @brief Enable PPA image mirror in X direction + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_srm_enable_mirror_x(ppa_dev_t *dev, bool enable) +{ + dev->srm_scal_rotate.srm_mirror_x = enable; +} + +/** + * @brief Enable PPA image mirror in Y direction + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_srm_enable_mirror_y(ppa_dev_t *dev, bool enable) +{ + dev->srm_scal_rotate.srm_mirror_y = enable; +} + +/** + * @brief Start PPA scaling and rotating engine to perform PPA SRM + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_srm_start(ppa_dev_t *dev) +{ + dev->srm_scal_rotate.scal_rotate_start = 1; +} + +/** + * @brief Set PPA SRM input side YUV422 data format packing order + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_srm_color_mode_t + */ +static inline void ppa_ll_srm_set_rx_yuv422_pack_order(ppa_dev_t *dev, ppa_srm_color_mode_t color_mode) +{ + switch (color_mode) { + case PPA_SRM_COLOR_MODE_YUV422_YVYU: + dev->srm_color_mode.yuv422_rx_byte_order = 3; + break; + case PPA_SRM_COLOR_MODE_YUV422_YUYV: + dev->srm_color_mode.yuv422_rx_byte_order = 2; + break; + case PPA_SRM_COLOR_MODE_YUV422_VYUY: + dev->srm_color_mode.yuv422_rx_byte_order = 1; + break; + case PPA_SRM_COLOR_MODE_YUV422_UYVY: + dev->srm_color_mode.yuv422_rx_byte_order = 0; + break; + default: + // Unsupported YUV422 pack order + abort(); + } +} + +/** + * @brief Check if the given color mode is supported by PPA SRM engine + * + * @param color_mode One of the values in ppa_srm_color_mode_t + * @return true if supported; false if not supported + */ +static inline bool ppa_ll_srm_is_color_mode_supported(ppa_srm_color_mode_t color_mode) +{ + switch (color_mode) { + case PPA_SRM_COLOR_MODE_ARGB8888: + case PPA_SRM_COLOR_MODE_RGB888: + case PPA_SRM_COLOR_MODE_RGB565: + case PPA_SRM_COLOR_MODE_YUV420: + case PPA_SRM_COLOR_MODE_YUV444: // YUV444 not supported by PPA hardware, but can be converted by 2D-DMA before PPA, and not supported as output color mode + case PPA_SRM_COLOR_MODE_YUV422_UYVY: + case PPA_SRM_COLOR_MODE_YUV422_VYUY: + case PPA_SRM_COLOR_MODE_YUV422_YUYV: + case PPA_SRM_COLOR_MODE_YUV422_YVYU: + case PPA_SRM_COLOR_MODE_GRAY8: + return true; + default: + return false; + } +} + +/** + * @brief Set the source image color mode for PPA Scaling-Rotating-Mirroring engine RX + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_srm_color_mode_t + */ +static inline void ppa_ll_srm_set_rx_color_mode(ppa_dev_t *dev, ppa_srm_color_mode_t color_mode) +{ + uint32_t val = 0; + bool is_yuv422 __attribute__((unused)) = false; + switch (color_mode) { + case PPA_SRM_COLOR_MODE_ARGB8888: + val = 0; + break; + case PPA_SRM_COLOR_MODE_RGB888: + val = 1; + break; + case PPA_SRM_COLOR_MODE_RGB565: + val = 2; + break; + case PPA_SRM_COLOR_MODE_YUV420: + val = 8; + break; + case PPA_SRM_COLOR_MODE_YUV422_UYVY: + case PPA_SRM_COLOR_MODE_YUV422_VYUY: + case PPA_SRM_COLOR_MODE_YUV422_YUYV: + case PPA_SRM_COLOR_MODE_YUV422_YVYU: + val = 9; + is_yuv422 = true; + break; + case PPA_SRM_COLOR_MODE_GRAY8: + val = 12; + break; + default: + // Unsupported SRM rx color mode + abort(); + } + dev->srm_color_mode.srm_rx_cm = val; + + // set YUV422 packing order + if (is_yuv422) { + ppa_ll_srm_set_rx_yuv422_pack_order(dev, color_mode); + } +} + +/** + * @brief Set the destination image color mode for PPA Scaling-Rotating-Mirroring engine TX + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_srm_color_mode_t + */ +static inline void ppa_ll_srm_set_tx_color_mode(ppa_dev_t *dev, ppa_srm_color_mode_t color_mode) +{ + uint32_t val = 0; + switch (color_mode) { + case PPA_SRM_COLOR_MODE_ARGB8888: + val = 0; + break; + case PPA_SRM_COLOR_MODE_RGB888: + val = 1; + break; + case PPA_SRM_COLOR_MODE_RGB565: + val = 2; + break; + case PPA_SRM_COLOR_MODE_YUV420: + val = 8; + break; + case PPA_SRM_COLOR_MODE_YUV422_UYVY: + val = 9; + break; + case PPA_SRM_COLOR_MODE_GRAY8: + val = 12; + break; + default: + // Unsupported SRM tx color mode + abort(); + } + dev->srm_color_mode.srm_tx_cm = val; +} + +/** + * @brief Set YUV to RGB protocol when PPA SRM RX pixel color space is YUV + * + * @param dev Peripheral instance address + * @param std One of the RGB-YUV conversion standards in ppa_color_conv_std_rgb_yuv_t + */ +static inline void ppa_ll_srm_set_rx_yuv2rgb_std(ppa_dev_t *dev, ppa_color_conv_std_rgb_yuv_t std) +{ + switch (std) { + case PPA_COLOR_CONV_STD_RGB_YUV_BT601: + dev->srm_color_mode.yuv2rgb_protocol = 0; + break; + case PPA_COLOR_CONV_STD_RGB_YUV_BT709: + dev->srm_color_mode.yuv2rgb_protocol = 1; + break; + default: + // Unsupported RGB-YUV conversion standard + abort(); + } +} + +/** + * @brief Set RGB to YUV protocol when PPA SRM TX pixel color space is YUV + * + * @param dev Peripheral instance address + * @param std One of the RGB-YUV conversion standards in ppa_color_conv_std_rgb_yuv_t + */ +static inline void ppa_ll_srm_set_tx_rgb2yuv_std(ppa_dev_t *dev, ppa_color_conv_std_rgb_yuv_t std) +{ + switch (std) { + case PPA_COLOR_CONV_STD_RGB_YUV_BT601: + dev->srm_color_mode.rgb2yuv_protocol = 0; + break; + case PPA_COLOR_CONV_STD_RGB_YUV_BT709: + dev->srm_color_mode.rgb2yuv_protocol = 1; + break; + default: + // Unsupported RGB-YUV conversion standard + abort(); + } +} + +/** + * @brief Set PPA SRM YUV input range + * + * @param dev Peripheral instance address + * @param range One of color range options in ppa_color_range_t + */ +static inline void ppa_ll_srm_set_rx_yuv_range(ppa_dev_t *dev, ppa_color_range_t range) +{ + switch (range) { + case PPA_COLOR_RANGE_LIMIT: + dev->srm_color_mode.yuv_rx_range = 0; + break; + case PPA_COLOR_RANGE_FULL: + dev->srm_color_mode.yuv_rx_range = 1; + break; + default: + // Unsupported color range + abort(); + } +} + +/** + * @brief Set PPA SRM YUV output range + * + * @param dev Peripheral instance address + * @param range One of color range options in ppa_color_range_t + */ +static inline void ppa_ll_srm_set_tx_yuv_range(ppa_dev_t *dev, ppa_color_range_t range) +{ + switch (range) { + case PPA_COLOR_RANGE_LIMIT: + dev->srm_color_mode.yuv_tx_range = 0; + break; + case PPA_COLOR_RANGE_FULL: + dev->srm_color_mode.yuv_tx_range = 1; + break; + default: + // Unsupported color range + abort(); + } +} + +/** + * @brief Enable PPA SRM input data swap in RGB (e.g. ARGB becomes BGRA, RGB becomes BGR) + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_srm_enable_rx_rgb_swap(ppa_dev_t *dev, bool enable) +{ + dev->srm_byte_order.srm_rx_rgb_swap_en = enable; +} + +/** + * @brief Enable PPA SRM input data swap in byte (The Byte0 and Byte1 would be swapped while byte 2 and byte 3 would be swappped) + * + * Only supported when input color mode is ARGB8888 or RGB565. + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_srm_enable_rx_byte_swap(ppa_dev_t *dev, bool enable) +{ + dev->srm_byte_order.srm_rx_byte_swap_en = enable; +} + +/** + * @brief Configure PPA SRM alpha value update mode + * + * @param dev Peripheral instance address + * @param mode Alpha value update mode, one of the values in ppa_alpha_update_mode_t + * @param val When PPA_ALPHA_FIX_VALUE mode is selected, val is the alpha value to be replaced with (output_alpha = val) + * When PPA_ALPHA_SCALE mode is selected, val/256 is the multiplier to the input alpha value (output_alpha = input_alpha * val / 256) + * When other modes are selected, this field is not used + */ +static inline void ppa_ll_srm_configure_rx_alpha(ppa_dev_t *dev, ppa_alpha_update_mode_t mode, uint32_t val) +{ + switch (mode) { + case PPA_ALPHA_NO_CHANGE: + dev->srm_fix_alpha.srm_rx_alpha_mod = 0; + dev->srm_fix_alpha.srm_rx_alpha_inv = 0; + break; + case PPA_ALPHA_FIX_VALUE: + dev->srm_fix_alpha.srm_rx_alpha_mod = 1; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->srm_fix_alpha, srm_rx_fix_alpha, val); + dev->srm_fix_alpha.srm_rx_alpha_inv = 0; + break; + case PPA_ALPHA_SCALE: + dev->srm_fix_alpha.srm_rx_alpha_mod = 2; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->srm_fix_alpha, srm_rx_fix_alpha, val); + dev->srm_fix_alpha.srm_rx_alpha_inv = 0; + break; + case PPA_ALPHA_INVERT: + dev->srm_fix_alpha.srm_rx_alpha_mod = 0; + dev->srm_fix_alpha.srm_rx_alpha_inv = 1; + break; + default: + // Unsupported alpha update mode + abort(); + } +} + +/** + * @brief Get the current configured PPA SRM macro block size + * + * @param dev Peripheral instance address + * @return The current configured macro block size, one of the values in ppa_ll_srm_mb_size_t + */ +static inline ppa_ll_srm_mb_size_t ppa_ll_srm_get_mb_size(ppa_dev_t *dev) +{ + return (dev->srm_byte_order.srm_bk_size_sel == 0) ? PPA_LL_SRM_MB_SIZE_32_32 : PPA_LL_SRM_MB_SIZE_16_16; +} + +/** + * @brief Set PPA SRM macro block size + * + * @param dev Peripheral instance address + * @param mb_size Macro block size to be set, one of the values in ppa_ll_srm_mb_size_t + */ +static inline void ppa_ll_srm_set_mb_size(ppa_dev_t *dev, ppa_ll_srm_mb_size_t mb_size) +{ + switch (mb_size) { + case PPA_LL_SRM_MB_SIZE_16_16: + dev->srm_byte_order.srm_bk_size_sel = 1; + break; + case PPA_LL_SRM_MB_SIZE_32_32: + dev->srm_byte_order.srm_bk_size_sel = 0; + break; + default: + // Unsupported SRM macro block size + abort(); + } +} + +/** + * @brief Retrieve the 2D-DMA descriptor port mode block size (in pixel) according to the PPA SRM input color mode and configured macro block size + * + * @param dev Peripheral instance address + * @param in_color_mode Input color mode, one of the values in ppa_srm_color_mode_t + * @param mb_size SRM macro block size, one of the values in ppa_ll_srm_mb_size_t + * @param[out] block_h Returned block horizontal width + * @param[out] block_v Returned block wvertical height + */ +static inline void ppa_ll_srm_get_dma_dscr_port_mode_block_size(ppa_dev_t *dev, ppa_srm_color_mode_t in_color_mode, ppa_ll_srm_mb_size_t mb_size, uint32_t *block_h, uint32_t *block_v) +{ + if (mb_size == PPA_LL_SRM_MB_SIZE_16_16) { + switch (in_color_mode) { + case PPA_SRM_COLOR_MODE_ARGB8888: + case PPA_SRM_COLOR_MODE_RGB888: + case PPA_SRM_COLOR_MODE_RGB565: + case PPA_SRM_COLOR_MODE_GRAY8: + *block_h = 18; + *block_v = 18; + break; + case PPA_SRM_COLOR_MODE_YUV420: + *block_h = 20; + *block_v = 20; + break; + case PPA_SRM_COLOR_MODE_YUV422_UYVY: + case PPA_SRM_COLOR_MODE_YUV422_VYUY: + case PPA_SRM_COLOR_MODE_YUV422_YUYV: + case PPA_SRM_COLOR_MODE_YUV422_YVYU: + *block_h = 20; + *block_v = 18; + break; + default: + // Unsupported SRM input color mode + *block_h = 0; + *block_v = 0; + } + } else if (mb_size == PPA_LL_SRM_MB_SIZE_32_32) { + switch (in_color_mode) { + case PPA_SRM_COLOR_MODE_ARGB8888: + case PPA_SRM_COLOR_MODE_RGB888: + case PPA_SRM_COLOR_MODE_RGB565: + case PPA_SRM_COLOR_MODE_GRAY8: + *block_h = 34; + *block_v = 34; + break; + case PPA_SRM_COLOR_MODE_YUV420: + *block_h = 36; + *block_v = 36; + break; + case PPA_SRM_COLOR_MODE_YUV422_UYVY: + case PPA_SRM_COLOR_MODE_YUV422_VYUY: + case PPA_SRM_COLOR_MODE_YUV422_YUYV: + case PPA_SRM_COLOR_MODE_YUV422_YVYU: + *block_h = 36; + *block_v = 34; + break; + default: + // Unsupported SRM input color mode + *block_h = 0; + *block_v = 0; + } + } else { + // Unsupported SRM macro block size + *block_h = 0; + *block_v = 0; + } +} + +/** + * @brief Whether to bypass the macro block order function in PPA SRM + * + * @param dev Peripheral instance address + * @param enable True to bypass; False to not bypass + */ +static inline void ppa_ll_srm_bypass_mb_order(ppa_dev_t *dev, bool enable) +{ + dev->srm_byte_order.srm_macro_bk_ro_bypass = enable; +} + +//////////////////////////////////// Blending //////////////////////////////////////// +/* + * Alpha Blending Calculation: + * 1. A_bg, A_fg first convert to A_bg', A_fg' according to blend_fix_alpha register configuration + * 2. Then do blending + * A_out = A_bg' + A_fg' - A_bg' * A_fg' + * C_out_r/g/b = (C_bg_r/g/b * A_bg' * (1 - A_fg') + C_fg_r/g/b * A_fg') / A_out + */ + +/** + * @brief Reset PPA blending engine + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_blend_reset(ppa_dev_t *dev) +{ + dev->blend_trans_mode.blend_rst = 1; + dev->blend_trans_mode.blend_rst = 0; +} + +/** + * @brief Start PPA blending engine to perform PPA Blending + * + * @param dev Peripheral instance address + * @param trans_mode Blending engine transfer mode, one of the values in ppa_ll_blend_trans_mode_t + */ +static inline void ppa_ll_blend_start(ppa_dev_t *dev, ppa_ll_blend_trans_mode_t trans_mode) +{ + switch (trans_mode) { + case PPA_LL_BLEND_TRANS_MODE_BLEND: + dev->blend_trans_mode.blend_bypass = 0; + dev->blend_trans_mode.blend_fix_pixel_fill_en = 0; + break; + case PPA_LL_BLEND_TRANS_MODE_FILL: + dev->blend_trans_mode.blend_bypass = 0; + dev->blend_trans_mode.blend_fix_pixel_fill_en = 1; + break; + case PPA_LL_BLEND_TRANS_MODE_BYPASS_BLEND: + dev->blend_trans_mode.blend_bypass = 1; + dev->blend_trans_mode.blend_fix_pixel_fill_en = 0; + break; + default: + // Unsupported blending trans mode + abort(); + } + dev->blend_trans_mode.blend_en = 1; + dev->blend_trans_mode.blend_trans_mode_update = 1; +} + +/** + * @brief Set PPA blending source image background YUV422 data format packing order + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_blend_color_mode_t + */ +static inline void ppa_ll_blend_set_rx_bg_yuv422_pack_order(ppa_dev_t *dev, ppa_blend_color_mode_t color_mode) +{ + switch (color_mode) { + case PPA_BLEND_COLOR_MODE_YUV422_YVYU: + dev->blend_color_mode.blend0_rx_yuv422_byte_order = 3; + break; + case PPA_BLEND_COLOR_MODE_YUV422_YUYV: + dev->blend_color_mode.blend0_rx_yuv422_byte_order = 2; + break; + case PPA_BLEND_COLOR_MODE_YUV422_VYUY: + dev->blend_color_mode.blend0_rx_yuv422_byte_order = 1; + break; + case PPA_BLEND_COLOR_MODE_YUV422_UYVY: + dev->blend_color_mode.blend0_rx_yuv422_byte_order = 0; + break; + default: + // Unsupported YUV422 pack order + abort(); + } +} + +/** + * @brief Check if the given color mode is supported by PPA blending engine + * + * @param color_mode One of the values in ppa_blend_color_mode_t + * @return true if supported (by any of rx_bg, rx_fg, tx); false if not supported + */ +static inline bool ppa_ll_blend_is_color_mode_supported(ppa_blend_color_mode_t color_mode) +{ + switch (color_mode) { + case PPA_BLEND_COLOR_MODE_ARGB8888: + case PPA_BLEND_COLOR_MODE_RGB888: + case PPA_BLEND_COLOR_MODE_RGB565: + case PPA_BLEND_COLOR_MODE_A8: + case PPA_BLEND_COLOR_MODE_A4: + // case PPA_BLEND_COLOR_MODE_L8: + // case PPA_BLEND_COLOR_MODE_L4: + case PPA_BLEND_COLOR_MODE_YUV420: + case PPA_BLEND_COLOR_MODE_YUV422_UYVY: + case PPA_BLEND_COLOR_MODE_YUV422_VYUY: + case PPA_BLEND_COLOR_MODE_YUV422_YUYV: + case PPA_BLEND_COLOR_MODE_YUV422_YVYU: + case PPA_BLEND_COLOR_MODE_GRAY8: + return true; + default: + return false; + } +} + +/** + * @brief Set the source image color mode for background for PPA blending engine RX + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_blend_color_mode_t (some color modes may not be applicable to rx bg) + */ +static inline void ppa_ll_blend_set_rx_bg_color_mode(ppa_dev_t *dev, ppa_blend_color_mode_t color_mode) +{ + uint32_t val = 0; + bool is_yuv422 __attribute__((unused)) = false; + switch (color_mode) { + case PPA_BLEND_COLOR_MODE_ARGB8888: + val = 0; + break; + case PPA_BLEND_COLOR_MODE_RGB888: + val = 1; + break; + case PPA_BLEND_COLOR_MODE_RGB565: + val = 2; + break; + // case PPA_BLEND_COLOR_MODE_L8: + // val = 4; + // break; + // case PPA_BLEND_COLOR_MODE_L4: + // val = 5; + // break; + case PPA_BLEND_COLOR_MODE_YUV420: + val = 8; + break; + case PPA_BLEND_COLOR_MODE_YUV422_UYVY: + case PPA_BLEND_COLOR_MODE_YUV422_VYUY: + case PPA_BLEND_COLOR_MODE_YUV422_YUYV: + case PPA_BLEND_COLOR_MODE_YUV422_YVYU: + val = 9; + is_yuv422 = true; + break; + case PPA_BLEND_COLOR_MODE_GRAY8: + val = 12; + break; + default: + // Unsupported blending rx background color mode + abort(); + } + dev->blend_color_mode.blend0_rx_cm = val; + + // set YUV422 packing order + if (is_yuv422) { + ppa_ll_blend_set_rx_bg_yuv422_pack_order(dev, color_mode); + } +} + +/** + * @brief Set the source image color mode for foreground for PPA blending engine RX + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_blend_color_mode_t + */ +static inline void ppa_ll_blend_set_rx_fg_color_mode(ppa_dev_t *dev, ppa_blend_color_mode_t color_mode) +{ + uint32_t val = 0; + switch (color_mode) { + case PPA_BLEND_COLOR_MODE_ARGB8888: + val = 0; + break; + case PPA_BLEND_COLOR_MODE_RGB888: + val = 1; + break; + case PPA_BLEND_COLOR_MODE_RGB565: + val = 2; + break; + // case PPA_BLEND_COLOR_MODE_L8: + // val = 4; + // break; + // case PPA_BLEND_COLOR_MODE_L4: + // val = 5; + // break; + case PPA_BLEND_COLOR_MODE_A8: + val = 6; + break; + case PPA_BLEND_COLOR_MODE_A4: + val = 7; + break; + default: + // Unsupported blending rx foreground color mode + abort(); + } + dev->blend_color_mode.blend1_rx_cm = val; +} + +/** + * @brief Set the destination image color mode for PPA blending engine TX + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_blend_color_mode_t (some color modes may not be applicable to tx) + */ +static inline void ppa_ll_blend_set_tx_color_mode(ppa_dev_t *dev, ppa_blend_color_mode_t color_mode) +{ + uint32_t val = 0; + switch (color_mode) { + case PPA_BLEND_COLOR_MODE_ARGB8888: + val = 0; + break; + case PPA_BLEND_COLOR_MODE_RGB888: + val = 1; + break; + case PPA_BLEND_COLOR_MODE_RGB565: + val = 2; + break; + case PPA_BLEND_COLOR_MODE_YUV420: + val = 8; + break; + case PPA_BLEND_COLOR_MODE_YUV422_UYVY: + val = 9; + break; + case PPA_BLEND_COLOR_MODE_GRAY8: + val = 12; + break; + default: + // Unsupported blending tx color mode + abort(); + } + dev->blend_color_mode.blend_tx_cm = val; +} + +/** + * @brief Set YUV to RGB protocol when PPA blending source image background pixel color space is YUV + * + * @param dev Peripheral instance address + * @param std One of the RGB-YUV conversion standards in ppa_color_conv_std_rgb_yuv_t + */ +static inline void ppa_ll_blend_set_rx_bg_yuv2rgb_std(ppa_dev_t *dev, ppa_color_conv_std_rgb_yuv_t std) +{ + switch (std) { + case PPA_COLOR_CONV_STD_RGB_YUV_BT601: + dev->blend_color_mode.blend0_rx_yuv2rgb_protocol = 0; + break; + case PPA_COLOR_CONV_STD_RGB_YUV_BT709: + dev->blend_color_mode.blend0_rx_yuv2rgb_protocol = 1; + break; + default: + // Unsupported RGB-YUV conversion standard + abort(); + } +} + +/** + * @brief Set RGB to YUV protocol when PPA blending destination image pixel color space is YUV + * + * @param dev Peripheral instance address + * @param std One of the RGB-YUV conversion standards in ppa_color_conv_std_rgb_yuv_t + */ +static inline void ppa_ll_blend_set_tx_rgb2yuv_std(ppa_dev_t *dev, ppa_color_conv_std_rgb_yuv_t std) +{ + switch (std) { + case PPA_COLOR_CONV_STD_RGB_YUV_BT601: + dev->blend_color_mode.blend_tx_rgb2yuv_protocol = 0; + break; + case PPA_COLOR_CONV_STD_RGB_YUV_BT709: + dev->blend_color_mode.blend_tx_rgb2yuv_protocol = 1; + break; + default: + // Unsupported RGB-YUV conversion standard + abort(); + } +} + +/** + * @brief Set PPA blending source image background YUV input range + * + * @param dev Peripheral instance address + * @param range One of color range options in ppa_color_range_t + */ +static inline void ppa_ll_blend_set_rx_bg_yuv_range(ppa_dev_t *dev, ppa_color_range_t range) +{ + switch (range) { + case PPA_COLOR_RANGE_LIMIT: + dev->blend_color_mode.blend0_rx_yuv_range = 0; + break; + case PPA_COLOR_RANGE_FULL: + dev->blend_color_mode.blend0_rx_yuv_range = 1; + break; + default: + // Unsupported color range + abort(); + } +} + +/** + * @brief Set PPA blending destination image YUV output range + * + * @param dev Peripheral instance address + * @param range One of color range options in ppa_color_range_t + */ +static inline void ppa_ll_blend_set_tx_yuv_range(ppa_dev_t *dev, ppa_color_range_t range) +{ + switch (range) { + case PPA_COLOR_RANGE_LIMIT: + dev->blend_color_mode.blend_tx_yuv_range = 0; + break; + case PPA_COLOR_RANGE_FULL: + dev->blend_color_mode.blend_tx_yuv_range = 1; + break; + default: + // Unsupported color range + abort(); + } +} + +/** + * @brief Enable PPA blending input background data wrap in RGB (e.g. ARGB becomes BGRA, RGB becomes BGR) + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_blend_enable_rx_bg_rgb_swap(ppa_dev_t *dev, bool enable) +{ + dev->blend_byte_order.blend0_rx_rgb_swap_en = enable; +} + +/** + * @brief Enable PPA blending input foreground data wrap in RGB (e.g. ARGB becomes BGRA, RGB becomes BGR) + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_blend_enable_rx_fg_rgb_swap(ppa_dev_t *dev, bool enable) +{ + dev->blend_byte_order.blend1_rx_rgb_swap_en = enable; +} + +/** + * @brief Enable PPA blending input background data swap in byte (The Byte0 and Byte1 would be swapped while byte 2 and byte 3 would be swappped) + * + * Only supported when input color mode is ARGB8888 or RGB565. + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_blend_enable_rx_bg_byte_swap(ppa_dev_t *dev, bool enable) +{ + dev->blend_byte_order.blend0_rx_byte_swap_en = enable; +} + +/** + * @brief Enable PPA blending input foreground data swap in byte (The Byte0 and Byte1 would be swapped while byte 2 and byte 3 would be swappped) + * + * Only supported when input color mode is ARGB8888 or RGB565. + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_blend_enable_rx_fg_byte_swap(ppa_dev_t *dev, bool enable) +{ + dev->blend_byte_order.blend1_rx_byte_swap_en = enable; +} + +/** + * @brief Configure PPA blending input background alpha value update mode + * + * @param dev Peripheral instance address + * @param mode Alpha value update mode, one of the values in ppa_alpha_update_mode_t + * @param val When PPA_ALPHA_FIX_VALUE mode is selected, val is the alpha value to be replaced with (output_alpha = val) + * When PPA_ALPHA_SCALE mode is selected, val/256 is the multiplier to the input alpha value (output_alpha = input_alpha * val / 256) + * When other modes are selected, this field is not used + */ +static inline void ppa_ll_blend_configure_rx_bg_alpha(ppa_dev_t *dev, ppa_alpha_update_mode_t mode, uint32_t val) +{ + switch (mode) { + case PPA_ALPHA_NO_CHANGE: + dev->blend_fix_alpha.blend0_rx_alpha_mod = 0; + dev->blend_fix_alpha.blend0_rx_alpha_inv = 0; + break; + case PPA_ALPHA_FIX_VALUE: + dev->blend_fix_alpha.blend0_rx_alpha_mod = 1; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_fix_alpha, blend0_rx_fix_alpha, val); + dev->blend_fix_alpha.blend0_rx_alpha_inv = 0; + break; + case PPA_ALPHA_SCALE: + dev->blend_fix_alpha.blend0_rx_alpha_mod = 2; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_fix_alpha, blend0_rx_fix_alpha, val); + dev->blend_fix_alpha.blend0_rx_alpha_inv = 0; + break; + case PPA_ALPHA_INVERT: + dev->blend_fix_alpha.blend0_rx_alpha_mod = 0; + dev->blend_fix_alpha.blend0_rx_alpha_inv = 1; + break; + default: + // Unsupported alpha update mode + abort(); + } +} + +/** + * @brief Configure PPA blending input foreground alpha value update mode + * + * @param dev Peripheral instance address + * @param mode Alpha value update mode, one of the values in ppa_alpha_update_mode_t + * @param val When PPA_ALPHA_FIX_VALUE mode is selected, val is the alpha value to be replaced with (output_alpha = val) + * When PPA_ALPHA_SCALE mode is selected, val/256 is the multiplier to the input alpha value (output_alpha = input_alpha * val / 256) + * When other modes are selected, this field is not used + */ +static inline void ppa_ll_blend_configure_rx_fg_alpha(ppa_dev_t *dev, ppa_alpha_update_mode_t mode, uint32_t val) +{ + switch (mode) { + case PPA_ALPHA_NO_CHANGE: + dev->blend_fix_alpha.blend1_rx_alpha_mod = 0; + dev->blend_fix_alpha.blend1_rx_alpha_inv = 0; + break; + case PPA_ALPHA_FIX_VALUE: + dev->blend_fix_alpha.blend1_rx_alpha_mod = 1; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_fix_alpha, blend1_rx_fix_alpha, val); + dev->blend_fix_alpha.blend1_rx_alpha_inv = 0; + break; + case PPA_ALPHA_SCALE: + dev->blend_fix_alpha.blend1_rx_alpha_mod = 2; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_fix_alpha, blend1_rx_fix_alpha, val); + dev->blend_fix_alpha.blend1_rx_alpha_inv = 0; + break; + case PPA_ALPHA_INVERT: + dev->blend_fix_alpha.blend1_rx_alpha_mod = 0; + dev->blend_fix_alpha.blend1_rx_alpha_inv = 1; + break; + default: + // Unsupported alpha update mode + abort(); + } +} + +/** + * @brief Configure PPA blending pixel filling image block + * + * The color to be filled is directly relying on the blend_tx_fix_pixel register field value. + * For fill operation, the data does not go through any color space conversion in the blending engine. + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_fill_color_mode_t + * @param data The point of the fix data to be filled to the image block pixels + * @param hb The horizontal width of image block that would be filled in fix pixel filling mode. The unit is pixel. + * @param vb The vertical height of image block that would be filled in fix pixel filling mode. The unit is pixel. + */ +static inline void ppa_ll_blend_configure_filling_block(ppa_dev_t *dev, ppa_fill_color_mode_t color_mode, void *data, uint32_t hb, uint32_t vb) +{ + HAL_ASSERT(hb <= PPA_BLEND_HB_V && vb <= PPA_BLEND_VB_V); + uint32_t fill_color_data = 0; + switch (color_mode) { + case PPA_FILL_COLOR_MODE_ARGB8888: + case PPA_FILL_COLOR_MODE_RGB888: + case PPA_FILL_COLOR_MODE_RGB565: + case PPA_FILL_COLOR_MODE_GRAY8: + fill_color_data = *(uint32_t *)data; + break; + case PPA_FILL_COLOR_MODE_YUV422_UYVY: { + color_macroblock_yuv_data_t *yuv_data = (color_macroblock_yuv_data_t *)data; + fill_color_data = ((yuv_data->y) << 24) | ((yuv_data->v) << 16) | ((yuv_data->y) << 8) | (yuv_data->u); + break; + } + // Non-typical YUV420, U and V components have to be the same value + // case PPA_FILL_COLOR_MODE_YUV420: { + // color_macroblock_yuv_data_t *yuv_data = (color_macroblock_yuv_data_t *)data; + // if (yuv_data->u != yuv_data->v) { + // abort(); + // } + // fill_color_data = ((yuv_data->y) << 16) | ((yuv_data->y) << 8) | (yuv_data->v); + // break; + // } + default: + // Unsupported filling color mode + abort(); + } + dev->blend_fix_pixel.blend_tx_fix_pixel = fill_color_data; + dev->blend_tx_size.blend_hb = hb; + dev->blend_tx_size.blend_vb = vb; +} + +/** + * @brief Configure PPA blending input foreground fixed RGB color for A4/A8 color mode + * + * @param dev Peripheral instance address + * @param rgb RGB color for A4/A8 mode in RGB888 format + */ +static inline void ppa_ll_blend_set_rx_fg_fix_rgb(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_rgb, blend1_rx_b, rgb->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_rgb, blend1_rx_g, rgb->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_rgb, blend1_rx_r, rgb->r); +} + +/* + * Color-key Calculation: + * 1) When FG in ck range, but BG not in ck range, then outputs BG pixel value. + * 2) When BG in ck range, but FG not in ck range, then depends on FG_BG_REVERSE value: if FG_BG_REVERSE = 0, outputs BG pixel value; otherwise, outputs FG pixel value. + * 3) When FG and BG both in their ck ranges, then outputs ck default color. + * 4) When FG and BG both not in their ck ranges, then it goes through normal Alpha Blending calculation. + */ + +/** + * @brief Configure PPA blending input background color-key threshold + * + * @param dev Peripheral instance address + * @param rgb_thres_low Color-key lower threshold of background in RGB888 format + * @param rgb_thres_high Color-key higher threshold of background in RGB888 format + */ +static inline void ppa_ll_blend_configure_rx_bg_ck_range(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb_thres_low, color_pixel_rgb888_data_t *rgb_thres_high) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_low, colorkey_bg_b_low, rgb_thres_low->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_low, colorkey_bg_g_low, rgb_thres_low->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_low, colorkey_bg_r_low, rgb_thres_low->r); + + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_high, colorkey_bg_b_high, rgb_thres_high->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_high, colorkey_bg_g_high, rgb_thres_high->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_high, colorkey_bg_r_high, rgb_thres_high->r); +} + +/** + * @brief Configure PPA blending input foreground color-key threshold + * + * @param dev Peripheral instance address + * @param rgb_thres_low Color-key lower threshold of foreground in RGB888 format + * @param rgb_thres_high Color-key higher threshold of foreground in RGB888 format + */ +static inline void ppa_ll_blend_configure_rx_fg_ck_range(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb_thres_low, color_pixel_rgb888_data_t *rgb_thres_high) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_low, colorkey_fg_b_low, rgb_thres_low->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_low, colorkey_fg_g_low, rgb_thres_low->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_low, colorkey_fg_r_low, rgb_thres_low->r); + + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_high, colorkey_fg_b_high, rgb_thres_high->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_high, colorkey_fg_g_high, rgb_thres_high->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_high, colorkey_fg_r_high, rgb_thres_high->r); +} + +/** + * @brief Configure PPA blending default RGB value when foreground and background both in color-key range + * + * @param dev Peripheral instance address + * @param rgb Default RGB value in RGB888 format + */ +static inline void ppa_ll_blend_set_ck_default_rgb(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_default, colorkey_default_b, rgb->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_default, colorkey_default_g, rgb->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_default, colorkey_default_r, rgb->r); +} + +/** + * @brief Configure whether to reverse the output when PPA blending pixel in background color-key range but not in foreground color-key range + * + * @param dev Peripheral instance address + * @param enable True then output the foreground pixel value; False then output the background pixel value + */ +static inline void ppa_ll_blend_enable_ck_fg_bg_reverse(ppa_dev_t *dev, bool enable) +{ + dev->ck_default.colorkey_fg_bg_reverse = enable; +} + +/////////////////////////// Color Look-Up Table (CLUT) /////////////////////////////// +/** + * @brief Configure PPA CLUT mem access mode + * + * @param dev Peripheral instance address + * @param fifo_mode True to access through fifo mode; False to access through memory mode + */ +static inline void ppa_ll_configure_clut_access_mode(ppa_dev_t *dev, bool fifo_mode) +{ + dev->clut_conf.apb_fifo_mask = !fifo_mode; +} + +/** + * @brief Force clock and power on for PPA blending BLEND CLUT mem + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_blend_enable_clut_mem(ppa_dev_t *dev) +{ + dev->clut_conf.blend_clut_mem_clk_ena = 1; + dev->clut_conf.blend_clut_mem_force_pu = 1; // force clut mem remain power when memory domain PD +} + +/** + * @brief Force clock and power off for PPA blending BLEND CLUT mem + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_blend_disable_clut_mem(ppa_dev_t *dev) +{ + dev->clut_conf.blend_clut_mem_clk_ena = 0; + dev->clut_conf.blend_clut_mem_force_pu = 0; +} + +/** + * @brief Reset PPA blending BLEND0 CLUT mem and read address + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_blend_reset_rx_bg_clut_mem(ppa_dev_t *dev) +{ + dev->clut_conf.blend0_clut_mem_rst = 1; + dev->clut_conf.blend0_clut_mem_rst = 0; + dev->clut_conf.blend0_clut_mem_rdaddr_rst = 1; + dev->clut_conf.blend0_clut_mem_rdaddr_rst = 0; +} + +/** + * @brief Reset PPA blending BLEND1 CLUT mem and read address + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_blend_reset_rx_fg_clut_mem(ppa_dev_t *dev) +{ + dev->clut_conf.blend1_clut_mem_rst = 1; + dev->clut_conf.blend1_clut_mem_rst = 0; + dev->clut_conf.blend1_clut_mem_rdaddr_rst = 1; + dev->clut_conf.blend1_clut_mem_rdaddr_rst = 0; +} + +/** + * @brief Write PPA blending BLEND0 CLUT mem entry through FIFO mode + * + * @param dev Peripheral instance address + * @param data The data to be written into BLEND0 CLUT entry in ARGB8888 format + */ +static inline void ppa_ll_blend_wr_rx_bg_clut_data_by_fifo(ppa_dev_t *dev, uint32_t data) +{ + dev->blend0_clut_data.rdwr_word_blend0_clut = data; +} + +/** + * @brief Write PPA blending BLEND1 CLUT mem entry through FIFO mode + * + * @param dev Peripheral instance address + * @param data The data to be written into BLEND1 CLUT entry in ARGB8888 format + */ +static inline void ppa_ll_blend_wr_rx_fg_clut_data_by_fifo(ppa_dev_t *dev, uint32_t data) +{ + dev->blend1_clut_data.rdwr_word_blend1_clut = data; +} + +/** + * @brief Write PPA blending BLEND0 CLUT mem entry through memory mode + * + * @param dev Peripheral instance address + * @param idx Entry index to the CLUT mem + * @param data The data to be written into BLEND0 CLUT entry in ARGB8888 format + */ +static inline void ppa_ll_blend_wr_rx_bg_clut_data_by_mem(ppa_dev_t *dev, uint32_t idx, uint32_t data) +{ + volatile uint32_t *blend0_clut_mem = (uint32_t *)((uint32_t)dev + PPA_LL_BLEND0_CLUT_MEM_ADDR_OFFSET); + blend0_clut_mem[idx] = data; +} + +/** + * @brief Write PPA blending BLEND1 CLUT mem entry through memory mode + * + * @param dev Peripheral instance address + * @param idx Entry index to the CLUT mem + * @param data The data to be written into BLEND1 CLUT entry in ARGB8888 format + */ +static inline void ppa_ll_blend_wr_rx_fg_clut_data_by_mem(ppa_dev_t *dev, uint32_t idx, uint32_t data) +{ + volatile uint32_t *blend1_clut_mem = (uint32_t *)((uint32_t)dev + PPA_LL_BLEND1_CLUT_MEM_ADDR_OFFSET); + blend1_clut_mem[idx] = data; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_ppa/ppa_hal.c b/components/esp_hal_ppa/ppa_hal.c index 5f057f54281..b44a2d42696 100644 --- a/components/esp_hal_ppa/ppa_hal.c +++ b/components/esp_hal_ppa/ppa_hal.c @@ -6,10 +6,13 @@ #include #include "hal/ppa_hal.h" +#include "hal/ppa_ll.h" void ppa_hal_init(ppa_hal_context_t *hal) { hal->dev = PPA_LL_GET_HW; + ppa_ll_mem_power_by_pmu(hal->dev); + ppa_ll_mem_set_low_power_mode(hal->dev, PPA_LL_MEM_LP_MODE_SHUT_DOWN); } void ppa_hal_deinit(ppa_hal_context_t *hal) diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index ff47717ee14..14800b09034 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -215,6 +215,10 @@ config SOC_TOUCH_SENSOR_SUPPORTED bool default y +config SOC_PPA_SUPPORTED + bool + default y + config SOC_MODEM_CLOCK_SUPPORTED bool default y diff --git a/components/soc/esp32s31/include/soc/soc_caps.h b/components/soc/esp32s31/include/soc/soc_caps.h index 72d2990c88e..7b45d31de55 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -96,7 +96,7 @@ #define SOC_SPI_FLASH_SUPPORTED 1 // TODO: [ESP32S31] IDF-14777 #define SOC_TOUCH_SENSOR_SUPPORTED 1 // #define SOC_RNG_SUPPORTED 1 // TODO: [ESP32S31] IDF-14632 -// #define SOC_PPA_SUPPORTED 1 // TODO: [ESP32S31] IDF-14769 +#define SOC_PPA_SUPPORTED 1 // #define SOC_LIGHT_SLEEP_SUPPORTED 1 // TODO: [ESP32S31] IDF-14645 // #define SOC_DEEP_SLEEP_SUPPORTED 1 // TODO: [ESP32S31] IDF-14643 #define SOC_MODEM_CLOCK_SUPPORTED 1 diff --git a/components/soc/esp32s31/register/soc/ppa_reg.h b/components/soc/esp32s31/register/soc/ppa_reg.h index 9e606e08383..5052c2748c7 100644 --- a/components/soc/esp32s31/register/soc/ppa_reg.h +++ b/components/soc/esp32s31/register/soc/ppa_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -272,20 +272,20 @@ extern "C" { #define PPA_YUV_TX_RANGE_M (PPA_YUV_TX_RANGE_V << PPA_YUV_TX_RANGE_S) #define PPA_YUV_TX_RANGE_V 0x00000001U #define PPA_YUV_TX_RANGE_S 9 -/** PPA_YUV2RGB_PROTOCAL : R/W; bitpos: [10]; default: 0; +/** PPA_YUV2RGB_PROTOCOL : R/W; bitpos: [10]; default: 0; * YUV to RGB protocol when reg_sr_rx_cm is 4'd8. 0: BT601. 1: BT709 */ -#define PPA_YUV2RGB_PROTOCAL (BIT(10)) -#define PPA_YUV2RGB_PROTOCAL_M (PPA_YUV2RGB_PROTOCAL_V << PPA_YUV2RGB_PROTOCAL_S) -#define PPA_YUV2RGB_PROTOCAL_V 0x00000001U -#define PPA_YUV2RGB_PROTOCAL_S 10 -/** PPA_RGB2YUV_PROTOCAL : R/W; bitpos: [11]; default: 0; +#define PPA_YUV2RGB_PROTOCOL (BIT(10)) +#define PPA_YUV2RGB_PROTOCOL_M (PPA_YUV2RGB_PROTOCOL_V << PPA_YUV2RGB_PROTOCOL_S) +#define PPA_YUV2RGB_PROTOCOL_V 0x00000001U +#define PPA_YUV2RGB_PROTOCOL_S 10 +/** PPA_RGB2YUV_PROTOCOL : R/W; bitpos: [11]; default: 0; * RGB to YUV protocol when reg_sr_tx_cm is 4'd8. 0: BT601. 1: BT709 */ -#define PPA_RGB2YUV_PROTOCAL (BIT(11)) -#define PPA_RGB2YUV_PROTOCAL_M (PPA_RGB2YUV_PROTOCAL_V << PPA_RGB2YUV_PROTOCAL_S) -#define PPA_RGB2YUV_PROTOCAL_V 0x00000001U -#define PPA_RGB2YUV_PROTOCAL_S 11 +#define PPA_RGB2YUV_PROTOCOL (BIT(11)) +#define PPA_RGB2YUV_PROTOCOL_M (PPA_RGB2YUV_PROTOCOL_V << PPA_RGB2YUV_PROTOCOL_S) +#define PPA_RGB2YUV_PROTOCOL_V 0x00000001U +#define PPA_RGB2YUV_PROTOCOL_S 11 /** PPA_YUV422_RX_BYTE_ORDER : R/W; bitpos: [13:12]; default: 0; * YUV422 input byte order when reg_sr_rx_cm is 4'd9. 0: YVYU, 1:YUYV, 2: VYUY, 3: UYVY (high addr -> low addr) */ @@ -336,20 +336,20 @@ extern "C" { #define PPA_BLEND_TX_YUV_RANGE_M (PPA_BLEND_TX_YUV_RANGE_V << PPA_BLEND_TX_YUV_RANGE_S) #define PPA_BLEND_TX_YUV_RANGE_V 0x00000001U #define PPA_BLEND_TX_YUV_RANGE_S 13 -/** PPA_BLEND0_RX_YUV2RGB_PROTOCAL : R/W; bitpos: [14]; default: 0; +/** PPA_BLEND0_RX_YUV2RGB_PROTOCOL : R/W; bitpos: [14]; default: 0; * YUV to RGB protocol when blend0 rx cm is yuv. 0: BT601. 1: BT709 */ -#define PPA_BLEND0_RX_YUV2RGB_PROTOCAL (BIT(14)) -#define PPA_BLEND0_RX_YUV2RGB_PROTOCAL_M (PPA_BLEND0_RX_YUV2RGB_PROTOCAL_V << PPA_BLEND0_RX_YUV2RGB_PROTOCAL_S) -#define PPA_BLEND0_RX_YUV2RGB_PROTOCAL_V 0x00000001U -#define PPA_BLEND0_RX_YUV2RGB_PROTOCAL_S 14 -/** PPA_BLEND_TX_RGB2YUV_PROTOCAL : R/W; bitpos: [15]; default: 0; +#define PPA_BLEND0_RX_YUV2RGB_PROTOCOL (BIT(14)) +#define PPA_BLEND0_RX_YUV2RGB_PROTOCOL_M (PPA_BLEND0_RX_YUV2RGB_PROTOCOL_V << PPA_BLEND0_RX_YUV2RGB_PROTOCOL_S) +#define PPA_BLEND0_RX_YUV2RGB_PROTOCOL_V 0x00000001U +#define PPA_BLEND0_RX_YUV2RGB_PROTOCOL_S 14 +/** PPA_BLEND_TX_RGB2YUV_PROTOCOL : R/W; bitpos: [15]; default: 0; * RGB to YUV protocol when blend tx cm is yuv. 0: BT601. 1: BT709 */ -#define PPA_BLEND_TX_RGB2YUV_PROTOCAL (BIT(15)) -#define PPA_BLEND_TX_RGB2YUV_PROTOCAL_M (PPA_BLEND_TX_RGB2YUV_PROTOCAL_V << PPA_BLEND_TX_RGB2YUV_PROTOCAL_S) -#define PPA_BLEND_TX_RGB2YUV_PROTOCAL_V 0x00000001U -#define PPA_BLEND_TX_RGB2YUV_PROTOCAL_S 15 +#define PPA_BLEND_TX_RGB2YUV_PROTOCOL (BIT(15)) +#define PPA_BLEND_TX_RGB2YUV_PROTOCOL_M (PPA_BLEND_TX_RGB2YUV_PROTOCOL_V << PPA_BLEND_TX_RGB2YUV_PROTOCOL_S) +#define PPA_BLEND_TX_RGB2YUV_PROTOCOL_V 0x00000001U +#define PPA_BLEND_TX_RGB2YUV_PROTOCOL_S 15 /** PPA_BLEND0_RX_YUV422_BYTE_ORDER : R/W; bitpos: [17:16]; default: 0; * YUV422 input byte order when reg_sr_rx_cm is 4'd9. 0: YVYU, 1:YUYV, 2: VYUY, 3: UYVY (high addr -> low addr) */ diff --git a/components/soc/esp32s31/register/soc/ppa_struct.h b/components/soc/esp32s31/register/soc/ppa_struct.h index e500ee68e02..b103ff384ed 100644 --- a/components/soc/esp32s31/register/soc/ppa_struct.h +++ b/components/soc/esp32s31/register/soc/ppa_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -108,14 +108,14 @@ typedef union { * YUV output range when reg_sr_tx_cm is 4'd8. 0: limit range. 1: full range */ uint32_t yuv_tx_range:1; - /** yuv2rgb_protocal : R/W; bitpos: [10]; default: 0; + /** yuv2rgb_protocol : R/W; bitpos: [10]; default: 0; * YUV to RGB protocol when reg_sr_rx_cm is 4'd8. 0: BT601. 1: BT709 */ - uint32_t yuv2rgb_protocal:1; - /** rgb2yuv_protocal : R/W; bitpos: [11]; default: 0; + uint32_t yuv2rgb_protocol:1; + /** rgb2yuv_protocol : R/W; bitpos: [11]; default: 0; * RGB to YUV protocol when reg_sr_tx_cm is 4'd8. 0: BT601. 1: BT709 */ - uint32_t rgb2yuv_protocal:1; + uint32_t rgb2yuv_protocol:1; /** yuv422_rx_byte_order : R/W; bitpos: [13:12]; default: 0; * YUV422 input byte order when reg_sr_rx_cm is 4'd9. 0: YVYU, 1:YUYV, 2: VYUY, 3: UYVY (high addr -> low addr) */ @@ -153,14 +153,14 @@ typedef union { * YUV output range when blend tx cm is yuv. 0: limit range. 1: full range */ uint32_t blend_tx_yuv_range:1; - /** blend0_rx_yuv2rgb_protocal : R/W; bitpos: [14]; default: 0; + /** blend0_rx_yuv2rgb_protocol : R/W; bitpos: [14]; default: 0; * YUV to RGB protocol when blend0 rx cm is yuv. 0: BT601. 1: BT709 */ - uint32_t blend0_rx_yuv2rgb_protocal:1; - /** blend_tx_rgb2yuv_protocal : R/W; bitpos: [15]; default: 0; + uint32_t blend0_rx_yuv2rgb_protocol:1; + /** blend_tx_rgb2yuv_protocol : R/W; bitpos: [15]; default: 0; * RGB to YUV protocol when blend tx cm is yuv. 0: BT601. 1: BT709 */ - uint32_t blend_tx_rgb2yuv_protocal:1; + uint32_t blend_tx_rgb2yuv_protocol:1; /** blend0_rx_yuv422_byte_order : R/W; bitpos: [17:16]; default: 0; * YUV422 input byte order when reg_sr_rx_cm is 4'd9. 0: YVYU, 1:YUYV, 2: VYUY, 3: UYVY (high addr -> low addr) */ @@ -969,7 +969,7 @@ typedef union { } ppa_date_reg_t; -typedef struct { +typedef struct ppa_dev_t { volatile ppa_blend0_clut_data_reg_t blend0_clut_data; volatile ppa_blend1_clut_data_reg_t blend1_clut_data; uint32_t reserved_008; @@ -1013,6 +1013,7 @@ typedef struct { volatile ppa_date_reg_t date; } ppa_dev_t; +extern ppa_dev_t PPA; #ifndef __cplusplus _Static_assert(sizeof(ppa_dev_t) == 0x104, "Invalid size of ppa_dev_t structure"); diff --git a/docs/doxygen/Doxyfile_esp32s31 b/docs/doxygen/Doxyfile_esp32s31 index 3dae6279e8c..6019e724bcd 100644 --- a/docs/doxygen/Doxyfile_esp32s31 +++ b/docs/doxygen/Doxyfile_esp32s31 @@ -4,6 +4,8 @@ INPUT += \ $(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_decode.h \ $(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_encode.h \ $(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_types.h \ + $(PROJECT_PATH)/components/esp_driver_ppa/include/driver/ppa.h \ + $(PROJECT_PATH)/components/esp_hal_ppa/include/hal/ppa_types.h \ $(PROJECT_PATH)/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h \ $(PROJECT_PATH)/components/esp_driver_touch_sens/include/driver/touch_sens.h \ $(PROJECT_PATH)/components/esp_driver_touch_sens/include/driver/touch_sens_types.h\ diff --git a/docs/en/api-reference/peripherals/ppa.rst b/docs/en/api-reference/peripherals/ppa.rst index 9ae45f3a9e2..6ee441c8e5e 100644 --- a/docs/en/api-reference/peripherals/ppa.rst +++ b/docs/en/api-reference/peripherals/ppa.rst @@ -139,7 +139,7 @@ The PPA requires certain buffer alignment rules to ensure memory access correctn - Cache line alignment (output buffer only): - - The ``out.buffer`` address and ``out.buffer_size`` must be aligned to the cache line size (see Kconfig option :ref:`CONFIG_CACHE_L2_CACHE_LINE_SIZE`). + - The ``out.buffer`` address and ``out.buffer_size`` must be aligned to the cache line size, if the buffer is located in a memory region that is cacheable. - Flash encryption alignment (when flash encryption is enabled and the buffers are located in external memory): @@ -175,7 +175,7 @@ The PPA operations are acted on the target block of an input picture. Therefore, Application Examples ^^^^^^^^^^^^^^^^^^^^ -* :example:`peripherals/ppa/ppa_dsi` - PPA with DSI display example. The image used in this example will be first scaled up, rotated at counter-clockwise direction and rotated back, mirrored and mirror back, and scaled down. Then the image will be blended with a whole red image with less transparency. Next the `ESP32` word will be color-keyed out. Lastly a frame will be filled around the `ESP32`. +* :example:`peripherals/ppa/ppa_rgb_lcd` - PPA with RGB LCD display example. The image used in this example will be first scaled up, rotated at counter-clockwise direction and rotated back, mirrored and mirror back, and scaled down. Then the image will be blended with a whole red image with less transparency. Next the `ESP32` word will be color-keyed out. Lastly a frame will be filled around the `ESP32`. API Reference ------------- diff --git a/docs/zh_CN/api-reference/peripherals/ppa.rst b/docs/zh_CN/api-reference/peripherals/ppa.rst index f1e2e37003e..3ab4551c0fa 100644 --- a/docs/zh_CN/api-reference/peripherals/ppa.rst +++ b/docs/zh_CN/api-reference/peripherals/ppa.rst @@ -139,7 +139,7 @@ PPA 缓存区需要满足以下对齐要求,以确保存储器访问的正确 - 缓冲行对齐(仅针对输出缓存区): - - ``out.buffer`` 地址和 ``out.buffer_size`` 大小必须与缓冲行大小对齐(请参阅 Kconfig 选项 :ref:`CONFIG_CACHE_L2_CACHE_LINE_SIZE`)。 + - 如果输出缓冲区位于一个可缓存的内存区域,则 ``out.buffer`` 地址和 ``out.buffer_size`` 大小必须与缓冲行大小对齐。 - 存储加密对齐(当存储加密启用且缓冲区位于外部存储空间时): @@ -175,7 +175,7 @@ PPA 操作作用于输入图片的目标块。因此,完成一次 PPA 事务 应用示例 ^^^^^^^^^ -* :example:`peripherals/ppa/ppa_dsi` - 使用 DSI 显示屏的 PPA 示例。首先,该示例所使用的图像会被放大、逆时针旋转后复原、镜像后复原、缩小。其次,该图像将与一个透明度较低的全红图像叠加,`ESP32` 字样将被色键移除。最后,会在 `ESP32` 周围填充一个框。 +* :example:`peripherals/ppa/ppa_rgb_lcd` - 使用 RGB LCD 显示屏的 PPA 示例。首先,该示例所使用的图像会被放大、逆时针旋转后复原、镜像后复原、缩小。其次,该图像将与一个透明度较低的全红图像叠加,`ESP32` 字样将被色键移除。最后,会在 `ESP32` 周围填充一个框。 API 参考 -------- diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 99affef3a5a..2f1573ef980 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -512,9 +512,9 @@ examples/peripherals/pcnt: - esp_driver_pcnt - soc -examples/peripherals/ppa/ppa_dsi: +examples/peripherals/ppa/ppa_rgb_lcd: disable: - - if: SOC_PPA_SUPPORTED != 1 or SOC_MIPI_DSI_SUPPORTED != 1 + - if: SOC_PPA_SUPPORTED != 1 or SOC_LCD_RGB_SUPPORTED != 1 depends_components: - esp_driver_dma - esp_driver_ppa diff --git a/examples/peripherals/lcd/rgb_panel/common_components/rgb_panel_init/CMakeLists.txt b/examples/peripherals/lcd/rgb_panel/common_components/rgb_panel_init/CMakeLists.txt new file mode 100644 index 00000000000..d91a161dff5 --- /dev/null +++ b/examples/peripherals/lcd/rgb_panel/common_components/rgb_panel_init/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "example_rgb_panel_init.c" + INCLUDE_DIRS "include" + REQUIRES esp_lcd esp_driver_gpio + ) diff --git a/examples/peripherals/lcd/rgb_panel/main/Kconfig.projbuild b/examples/peripherals/lcd/rgb_panel/common_components/rgb_panel_init/Kconfig.projbuild similarity index 98% rename from examples/peripherals/lcd/rgb_panel/main/Kconfig.projbuild rename to examples/peripherals/lcd/rgb_panel/common_components/rgb_panel_init/Kconfig.projbuild index 5dc913d6da3..df821a316f3 100644 --- a/examples/peripherals/lcd/rgb_panel/main/Kconfig.projbuild +++ b/examples/peripherals/lcd/rgb_panel/common_components/rgb_panel_init/Kconfig.projbuild @@ -1,4 +1,4 @@ -menu "Example Configuration" +menu "RGB Panel Configuration" choice EXAMPLE_LCD_BUFFER_MODE prompt "RGB LCD Buffer Mode" default EXAMPLE_USE_SINGLE_FB @@ -43,122 +43,149 @@ menu "Example Configuration" default 16 if EXAMPLE_LCD_DATA_LINES_16 default 24 if EXAMPLE_LCD_DATA_LINES_24 - menu "GPIO assignment" + menu "RGB LCD GPIO assignment" config EXAMPLE_LCD_VSYNC_GPIO int "VSYNC GPIO" help GPIO pin number for VSYNC signal. + config EXAMPLE_LCD_HSYNC_GPIO int "HSYNC GPIO" help GPIO pin number for HSYNC signal. + config EXAMPLE_LCD_DE_GPIO int "DE GPIO" help GPIO pin number for DE signal. + config EXAMPLE_LCD_PCLK_GPIO int "PCLK GPIO" help GPIO pin number for PCLK signal. + config EXAMPLE_LCD_DATA0_GPIO int "DATA0 GPIO" help GPIO pin number for data bus[0]. + config EXAMPLE_LCD_DATA1_GPIO int "DATA1 GPIO" help GPIO pin number for data bus[1]. + config EXAMPLE_LCD_DATA2_GPIO int "DATA2 GPIO" help GPIO pin number for data bus[2]. + config EXAMPLE_LCD_DATA3_GPIO int "DATA3 GPIO" help GPIO pin number for data bus[3]. + config EXAMPLE_LCD_DATA4_GPIO int "DATA4 GPIO" help GPIO pin number for data bus[4]. + config EXAMPLE_LCD_DATA5_GPIO int "DATA5 GPIO" help GPIO pin number for data bus[5]. + config EXAMPLE_LCD_DATA6_GPIO int "DATA6 GPIO" help GPIO pin number for data bus[6]. + config EXAMPLE_LCD_DATA7_GPIO int "DATA7 GPIO" help GPIO pin number for data bus[7]. + config EXAMPLE_LCD_DATA8_GPIO int "DATA8 GPIO" help GPIO pin number for data bus[8]. + config EXAMPLE_LCD_DATA9_GPIO int "DATA9 GPIO" help GPIO pin number for data bus[9]. + config EXAMPLE_LCD_DATA10_GPIO int "DATA10 GPIO" help GPIO pin number for data bus[10]. + config EXAMPLE_LCD_DATA11_GPIO int "DATA11 GPIO" help GPIO pin number for data bus[11]. + config EXAMPLE_LCD_DATA12_GPIO int "DATA12 GPIO" help GPIO pin number for data bus[12]. + config EXAMPLE_LCD_DATA13_GPIO int "DATA13 GPIO" help GPIO pin number for data bus[13]. + config EXAMPLE_LCD_DATA14_GPIO int "DATA14 GPIO" help GPIO pin number for data bus[14]. + config EXAMPLE_LCD_DATA15_GPIO int "DATA15 GPIO" help GPIO pin number for data bus[15]. + config EXAMPLE_LCD_DATA16_GPIO int "DATA16 GPIO" depends on EXAMPLE_LCD_DATA_LINES > 16 help GPIO pin number for data bus[16]. + config EXAMPLE_LCD_DATA17_GPIO int "DATA17 GPIO" depends on EXAMPLE_LCD_DATA_LINES > 16 help GPIO pin number for data bus[17]. + config EXAMPLE_LCD_DATA18_GPIO int "DATA18 GPIO" depends on EXAMPLE_LCD_DATA_LINES > 16 help GPIO pin number for data bus[18]. + config EXAMPLE_LCD_DATA19_GPIO int "DATA19 GPIO" depends on EXAMPLE_LCD_DATA_LINES > 16 help GPIO pin number for data bus[19]. + config EXAMPLE_LCD_DATA20_GPIO int "DATA20 GPIO" depends on EXAMPLE_LCD_DATA_LINES > 16 help GPIO pin number for data bus[20]. + config EXAMPLE_LCD_DATA21_GPIO int "DATA21 GPIO" depends on EXAMPLE_LCD_DATA_LINES > 16 help GPIO pin number for data bus[21]. + config EXAMPLE_LCD_DATA22_GPIO int "DATA22 GPIO" depends on EXAMPLE_LCD_DATA_LINES > 16 help GPIO pin number for data bus[22]. + config EXAMPLE_LCD_DATA23_GPIO int "DATA23 GPIO" depends on EXAMPLE_LCD_DATA_LINES > 16 diff --git a/examples/peripherals/lcd/rgb_panel/common_components/rgb_panel_init/example_rgb_panel_init.c b/examples/peripherals/lcd/rgb_panel/common_components/rgb_panel_init/example_rgb_panel_init.c new file mode 100644 index 00000000000..305e73180f8 --- /dev/null +++ b/examples/peripherals/lcd/rgb_panel/common_components/rgb_panel_init/example_rgb_panel_init.c @@ -0,0 +1,115 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "example_rgb_panel_init.h" +#include "driver/gpio.h" +#include "esp_check.h" +#include "esp_lcd_panel_rgb.h" + +static const char *TAG = "rgb_panel_init"; + +static void s_fill_data_gpio_nums(gpio_num_t data_gpio_nums[ESP_LCD_RGB_BUS_WIDTH_MAX]) +{ + data_gpio_nums[0] = EXAMPLE_PIN_NUM_DATA0; + data_gpio_nums[1] = EXAMPLE_PIN_NUM_DATA1; + data_gpio_nums[2] = EXAMPLE_PIN_NUM_DATA2; + data_gpio_nums[3] = EXAMPLE_PIN_NUM_DATA3; + data_gpio_nums[4] = EXAMPLE_PIN_NUM_DATA4; + data_gpio_nums[5] = EXAMPLE_PIN_NUM_DATA5; + data_gpio_nums[6] = EXAMPLE_PIN_NUM_DATA6; + data_gpio_nums[7] = EXAMPLE_PIN_NUM_DATA7; + data_gpio_nums[8] = EXAMPLE_PIN_NUM_DATA8; + data_gpio_nums[9] = EXAMPLE_PIN_NUM_DATA9; + data_gpio_nums[10] = EXAMPLE_PIN_NUM_DATA10; + data_gpio_nums[11] = EXAMPLE_PIN_NUM_DATA11; + data_gpio_nums[12] = EXAMPLE_PIN_NUM_DATA12; + data_gpio_nums[13] = EXAMPLE_PIN_NUM_DATA13; + data_gpio_nums[14] = EXAMPLE_PIN_NUM_DATA14; + data_gpio_nums[15] = EXAMPLE_PIN_NUM_DATA15; +#if CONFIG_EXAMPLE_LCD_DATA_LINES > 16 + data_gpio_nums[16] = EXAMPLE_PIN_NUM_DATA16; + data_gpio_nums[17] = EXAMPLE_PIN_NUM_DATA17; + data_gpio_nums[18] = EXAMPLE_PIN_NUM_DATA18; + data_gpio_nums[19] = EXAMPLE_PIN_NUM_DATA19; + data_gpio_nums[20] = EXAMPLE_PIN_NUM_DATA20; + data_gpio_nums[21] = EXAMPLE_PIN_NUM_DATA21; + data_gpio_nums[22] = EXAMPLE_PIN_NUM_DATA22; + data_gpio_nums[23] = EXAMPLE_PIN_NUM_DATA23; +#endif +} + +esp_err_t example_rgb_panel_init_backlight(void) +{ +#if EXAMPLE_PIN_NUM_BK_LIGHT >= 0 + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT, + }; + ESP_RETURN_ON_ERROR(gpio_config(&bk_gpio_config), TAG, "configure backlight gpio failed"); +#endif + + return ESP_OK; +} + +void example_rgb_panel_set_backlight(bool on) +{ + if (EXAMPLE_PIN_NUM_BK_LIGHT < 0) { + return; + } + + gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, on ? EXAMPLE_LCD_BK_LIGHT_ON_LEVEL : EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL); +} + +esp_err_t example_rgb_panel_new(esp_lcd_panel_handle_t *panel_handle) +{ + ESP_RETURN_ON_FALSE(panel_handle, ESP_ERR_INVALID_ARG, TAG, "panel handle is null"); + + esp_lcd_rgb_panel_config_t panel_config = { + .data_width = CONFIG_EXAMPLE_LCD_DATA_LINES, + .dma_burst_size = 64, + .num_fbs = EXAMPLE_RGB_PANEL_NUM_FBS, +#if CONFIG_EXAMPLE_USE_BOUNCE_BUFFER + .bounce_buffer_size_px = 20 * EXAMPLE_LCD_H_RES, +#endif + .clk_src = LCD_CLK_SRC_DEFAULT, + .disp_gpio_num = EXAMPLE_PIN_NUM_DISP_EN, + .pclk_gpio_num = EXAMPLE_PIN_NUM_PCLK, + .vsync_gpio_num = EXAMPLE_PIN_NUM_VSYNC, + .hsync_gpio_num = EXAMPLE_PIN_NUM_HSYNC, + .de_gpio_num = EXAMPLE_PIN_NUM_DE, + .timings = { + .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ, + .h_res = EXAMPLE_LCD_H_RES, + .v_res = EXAMPLE_LCD_V_RES, + .hsync_back_porch = EXAMPLE_LCD_HBP, + .hsync_front_porch = EXAMPLE_LCD_HFP, + .hsync_pulse_width = EXAMPLE_LCD_HSYNC, + .vsync_back_porch = EXAMPLE_LCD_VBP, + .vsync_front_porch = EXAMPLE_LCD_VFP, + .vsync_pulse_width = EXAMPLE_LCD_VSYNC, + .flags = { + .pclk_active_neg = true, + }, + }, + .flags.fb_in_psram = true, + }; + s_fill_data_gpio_nums(panel_config.data_gpio_nums); + return esp_lcd_new_rgb_panel(&panel_config, panel_handle); +} + +esp_err_t example_rgb_panel_init(esp_lcd_panel_handle_t panel_handle) +{ + ESP_RETURN_ON_FALSE(panel_handle, ESP_ERR_INVALID_ARG, TAG, "panel handle is null"); + ESP_RETURN_ON_ERROR(esp_lcd_panel_reset(panel_handle), TAG, "reset RGB panel failed"); + ESP_RETURN_ON_ERROR(esp_lcd_panel_init(panel_handle), TAG, "init RGB panel failed"); + return ESP_OK; +} + +esp_err_t example_rgb_panel_deinit(esp_lcd_panel_handle_t panel_handle) +{ + ESP_RETURN_ON_FALSE(panel_handle, ESP_ERR_INVALID_ARG, TAG, "panel handle is null"); + return esp_lcd_panel_del(panel_handle); +} diff --git a/examples/peripherals/lcd/rgb_panel/common_components/rgb_panel_init/include/example_rgb_panel_init.h b/examples/peripherals/lcd/rgb_panel/common_components/rgb_panel_init/include/example_rgb_panel_init.h new file mode 100644 index 00000000000..031f1319f98 --- /dev/null +++ b/examples/peripherals/lcd/rgb_panel/common_components/rgb_panel_init/include/example_rgb_panel_init.h @@ -0,0 +1,89 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "esp_err.h" +#include "esp_lcd_panel_ops.h" +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Refresh Rate = 18000000/(1+40+20+800)/(1+10+5+480) = 42Hz +#define EXAMPLE_LCD_PIXEL_CLOCK_HZ (18 * 1000 * 1000) +#define EXAMPLE_LCD_H_RES 800 +#define EXAMPLE_LCD_V_RES 480 +#define EXAMPLE_LCD_HSYNC 1 +#define EXAMPLE_LCD_HBP 40 +#define EXAMPLE_LCD_HFP 20 +#define EXAMPLE_LCD_VSYNC 1 +#define EXAMPLE_LCD_VBP 10 +#define EXAMPLE_LCD_VFP 5 + +#define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 1 +#define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL +#define EXAMPLE_PIN_NUM_BK_LIGHT -1 +#define EXAMPLE_PIN_NUM_DISP_EN -1 + +#define EXAMPLE_PIN_NUM_HSYNC CONFIG_EXAMPLE_LCD_HSYNC_GPIO +#define EXAMPLE_PIN_NUM_VSYNC CONFIG_EXAMPLE_LCD_VSYNC_GPIO +#define EXAMPLE_PIN_NUM_DE CONFIG_EXAMPLE_LCD_DE_GPIO +#define EXAMPLE_PIN_NUM_PCLK CONFIG_EXAMPLE_LCD_PCLK_GPIO + +#define EXAMPLE_PIN_NUM_DATA0 CONFIG_EXAMPLE_LCD_DATA0_GPIO +#define EXAMPLE_PIN_NUM_DATA1 CONFIG_EXAMPLE_LCD_DATA1_GPIO +#define EXAMPLE_PIN_NUM_DATA2 CONFIG_EXAMPLE_LCD_DATA2_GPIO +#define EXAMPLE_PIN_NUM_DATA3 CONFIG_EXAMPLE_LCD_DATA3_GPIO +#define EXAMPLE_PIN_NUM_DATA4 CONFIG_EXAMPLE_LCD_DATA4_GPIO +#define EXAMPLE_PIN_NUM_DATA5 CONFIG_EXAMPLE_LCD_DATA5_GPIO +#define EXAMPLE_PIN_NUM_DATA6 CONFIG_EXAMPLE_LCD_DATA6_GPIO +#define EXAMPLE_PIN_NUM_DATA7 CONFIG_EXAMPLE_LCD_DATA7_GPIO +#define EXAMPLE_PIN_NUM_DATA8 CONFIG_EXAMPLE_LCD_DATA8_GPIO +#define EXAMPLE_PIN_NUM_DATA9 CONFIG_EXAMPLE_LCD_DATA9_GPIO +#define EXAMPLE_PIN_NUM_DATA10 CONFIG_EXAMPLE_LCD_DATA10_GPIO +#define EXAMPLE_PIN_NUM_DATA11 CONFIG_EXAMPLE_LCD_DATA11_GPIO +#define EXAMPLE_PIN_NUM_DATA12 CONFIG_EXAMPLE_LCD_DATA12_GPIO +#define EXAMPLE_PIN_NUM_DATA13 CONFIG_EXAMPLE_LCD_DATA13_GPIO +#define EXAMPLE_PIN_NUM_DATA14 CONFIG_EXAMPLE_LCD_DATA14_GPIO +#define EXAMPLE_PIN_NUM_DATA15 CONFIG_EXAMPLE_LCD_DATA15_GPIO +#if CONFIG_EXAMPLE_LCD_DATA_LINES > 16 +#define EXAMPLE_PIN_NUM_DATA16 CONFIG_EXAMPLE_LCD_DATA16_GPIO +#define EXAMPLE_PIN_NUM_DATA17 CONFIG_EXAMPLE_LCD_DATA17_GPIO +#define EXAMPLE_PIN_NUM_DATA18 CONFIG_EXAMPLE_LCD_DATA18_GPIO +#define EXAMPLE_PIN_NUM_DATA19 CONFIG_EXAMPLE_LCD_DATA19_GPIO +#define EXAMPLE_PIN_NUM_DATA20 CONFIG_EXAMPLE_LCD_DATA20_GPIO +#define EXAMPLE_PIN_NUM_DATA21 CONFIG_EXAMPLE_LCD_DATA21_GPIO +#define EXAMPLE_PIN_NUM_DATA22 CONFIG_EXAMPLE_LCD_DATA22_GPIO +#define EXAMPLE_PIN_NUM_DATA23 CONFIG_EXAMPLE_LCD_DATA23_GPIO +#endif + +#if CONFIG_EXAMPLE_USE_DOUBLE_FB +#define EXAMPLE_RGB_PANEL_NUM_FBS 2 +#else +#define EXAMPLE_RGB_PANEL_NUM_FBS 1 +#endif + +#if CONFIG_EXAMPLE_LCD_DATA_LINES_16 +#define EXAMPLE_PIXEL_SIZE 2 +#elif CONFIG_EXAMPLE_LCD_DATA_LINES_24 +#define EXAMPLE_PIXEL_SIZE 3 +#endif + +esp_err_t example_rgb_panel_init_backlight(void); +void example_rgb_panel_set_backlight(bool on); +esp_err_t example_rgb_panel_new(esp_lcd_panel_handle_t *panel_handle); +esp_err_t example_rgb_panel_init(esp_lcd_panel_handle_t panel_handle); +esp_err_t example_rgb_panel_deinit(esp_lcd_panel_handle_t panel_handle); + +#ifdef __cplusplus +} +#endif diff --git a/examples/peripherals/lcd/rgb_panel/main/idf_component.yml b/examples/peripherals/lcd/rgb_panel/main/idf_component.yml index 4ca86dce7ec..9bcf75b4fe4 100644 --- a/examples/peripherals/lcd/rgb_panel/main/idf_component.yml +++ b/examples/peripherals/lcd/rgb_panel/main/idf_component.yml @@ -1,2 +1,4 @@ dependencies: lvgl/lvgl: "9.2.0" + rgb_panel_init: + path: ${IDF_PATH}/examples/peripherals/lcd/rgb_panel/common_components/rgb_panel_init diff --git a/examples/peripherals/lcd/rgb_panel/main/rgb_lcd_example_main.c b/examples/peripherals/lcd/rgb_panel/main/rgb_lcd_example_main.c index aedf4c3365f..b9d724906e5 100644 --- a/examples/peripherals/lcd/rgb_panel/main/rgb_lcd_example_main.c +++ b/examples/peripherals/lcd/rgb_panel/main/rgb_lcd_example_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: CC0-1.0 */ @@ -12,80 +12,22 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_timer.h" +#include "example_rgb_panel_init.h" #include "esp_lcd_panel_ops.h" #include "esp_lcd_panel_rgb.h" -#include "driver/gpio.h" #include "esp_err.h" #include "esp_log.h" #include "lvgl.h" static const char *TAG = "example"; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Refresh Rate = 18000000/(1+40+20+800)/(1+10+5+480) = 42Hz -#define EXAMPLE_LCD_PIXEL_CLOCK_HZ (18 * 1000 * 1000) -#define EXAMPLE_LCD_H_RES 800 -#define EXAMPLE_LCD_V_RES 480 -#define EXAMPLE_LCD_HSYNC 1 -#define EXAMPLE_LCD_HBP 40 -#define EXAMPLE_LCD_HFP 20 -#define EXAMPLE_LCD_VSYNC 1 -#define EXAMPLE_LCD_VBP 10 -#define EXAMPLE_LCD_VFP 5 - -#define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 1 -#define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL -#define EXAMPLE_PIN_NUM_BK_LIGHT -1 -#define EXAMPLE_PIN_NUM_DISP_EN -1 - -#define EXAMPLE_PIN_NUM_HSYNC CONFIG_EXAMPLE_LCD_HSYNC_GPIO -#define EXAMPLE_PIN_NUM_VSYNC CONFIG_EXAMPLE_LCD_VSYNC_GPIO -#define EXAMPLE_PIN_NUM_DE CONFIG_EXAMPLE_LCD_DE_GPIO -#define EXAMPLE_PIN_NUM_PCLK CONFIG_EXAMPLE_LCD_PCLK_GPIO - -#define EXAMPLE_PIN_NUM_DATA0 CONFIG_EXAMPLE_LCD_DATA0_GPIO -#define EXAMPLE_PIN_NUM_DATA1 CONFIG_EXAMPLE_LCD_DATA1_GPIO -#define EXAMPLE_PIN_NUM_DATA2 CONFIG_EXAMPLE_LCD_DATA2_GPIO -#define EXAMPLE_PIN_NUM_DATA3 CONFIG_EXAMPLE_LCD_DATA3_GPIO -#define EXAMPLE_PIN_NUM_DATA4 CONFIG_EXAMPLE_LCD_DATA4_GPIO -#define EXAMPLE_PIN_NUM_DATA5 CONFIG_EXAMPLE_LCD_DATA5_GPIO -#define EXAMPLE_PIN_NUM_DATA6 CONFIG_EXAMPLE_LCD_DATA6_GPIO -#define EXAMPLE_PIN_NUM_DATA7 CONFIG_EXAMPLE_LCD_DATA7_GPIO -#define EXAMPLE_PIN_NUM_DATA8 CONFIG_EXAMPLE_LCD_DATA8_GPIO -#define EXAMPLE_PIN_NUM_DATA9 CONFIG_EXAMPLE_LCD_DATA9_GPIO -#define EXAMPLE_PIN_NUM_DATA10 CONFIG_EXAMPLE_LCD_DATA10_GPIO -#define EXAMPLE_PIN_NUM_DATA11 CONFIG_EXAMPLE_LCD_DATA11_GPIO -#define EXAMPLE_PIN_NUM_DATA12 CONFIG_EXAMPLE_LCD_DATA12_GPIO -#define EXAMPLE_PIN_NUM_DATA13 CONFIG_EXAMPLE_LCD_DATA13_GPIO -#define EXAMPLE_PIN_NUM_DATA14 CONFIG_EXAMPLE_LCD_DATA14_GPIO -#define EXAMPLE_PIN_NUM_DATA15 CONFIG_EXAMPLE_LCD_DATA15_GPIO -#if CONFIG_EXAMPLE_LCD_DATA_LINES > 16 -#define EXAMPLE_PIN_NUM_DATA16 CONFIG_EXAMPLE_LCD_DATA16_GPIO -#define EXAMPLE_PIN_NUM_DATA17 CONFIG_EXAMPLE_LCD_DATA17_GPIO -#define EXAMPLE_PIN_NUM_DATA18 CONFIG_EXAMPLE_LCD_DATA18_GPIO -#define EXAMPLE_PIN_NUM_DATA19 CONFIG_EXAMPLE_LCD_DATA19_GPIO -#define EXAMPLE_PIN_NUM_DATA20 CONFIG_EXAMPLE_LCD_DATA20_GPIO -#define EXAMPLE_PIN_NUM_DATA21 CONFIG_EXAMPLE_LCD_DATA21_GPIO -#define EXAMPLE_PIN_NUM_DATA22 CONFIG_EXAMPLE_LCD_DATA22_GPIO -#define EXAMPLE_PIN_NUM_DATA23 CONFIG_EXAMPLE_LCD_DATA23_GPIO -#endif - -#if CONFIG_EXAMPLE_USE_DOUBLE_FB -#define EXAMPLE_LCD_NUM_FB 2 -#else -#define EXAMPLE_LCD_NUM_FB 1 -#endif // CONFIG_EXAMPLE_USE_DOUBLE_FB - +// Keep the LVGL draw format local to this example. The panel bus format is configured separately. #if CONFIG_EXAMPLE_LCD_DATA_LINES_16 -#define EXAMPLE_DATA_BUS_WIDTH 16 -#define EXAMPLE_PIXEL_SIZE 2 -#define EXAMPLE_LV_COLOR_FORMAT LV_COLOR_FORMAT_RGB565 +#define EXAMPLE_LV_COLOR_FORMAT LV_COLOR_FORMAT_RGB565 #elif CONFIG_EXAMPLE_LCD_DATA_LINES_24 -#define EXAMPLE_DATA_BUS_WIDTH 24 -#define EXAMPLE_PIXEL_SIZE 3 -#define EXAMPLE_LV_COLOR_FORMAT LV_COLOR_FORMAT_RGB888 +#define EXAMPLE_LV_COLOR_FORMAT LV_COLOR_FORMAT_RGB888 +#else +#error "Unsupported LVGL color format" #endif //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -144,97 +86,21 @@ static void example_lvgl_port_task(void *arg) } } -static void example_bsp_init_lcd_backlight(void) -{ -#if EXAMPLE_PIN_NUM_BK_LIGHT >= 0 - gpio_config_t bk_gpio_config = { - .mode = GPIO_MODE_OUTPUT, - .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT - }; - ESP_ERROR_CHECK(gpio_config(&bk_gpio_config)); -#endif -} - -static void example_bsp_set_lcd_backlight(uint32_t level) -{ -#if EXAMPLE_PIN_NUM_BK_LIGHT >= 0 - gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, level); -#endif -} - void app_main(void) { ESP_LOGI(TAG, "Turn off LCD backlight"); - example_bsp_init_lcd_backlight(); - example_bsp_set_lcd_backlight(EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL); + ESP_ERROR_CHECK(example_rgb_panel_init_backlight()); + example_rgb_panel_set_backlight(false); ESP_LOGI(TAG, "Install RGB LCD panel driver"); esp_lcd_panel_handle_t panel_handle = NULL; - esp_lcd_rgb_panel_config_t panel_config = { - .data_width = EXAMPLE_DATA_BUS_WIDTH, - .dma_burst_size = 64, - .num_fbs = EXAMPLE_LCD_NUM_FB, -#if CONFIG_EXAMPLE_USE_BOUNCE_BUFFER - .bounce_buffer_size_px = 20 * EXAMPLE_LCD_H_RES, -#endif - .clk_src = LCD_CLK_SRC_DEFAULT, - .disp_gpio_num = EXAMPLE_PIN_NUM_DISP_EN, - .pclk_gpio_num = EXAMPLE_PIN_NUM_PCLK, - .vsync_gpio_num = EXAMPLE_PIN_NUM_VSYNC, - .hsync_gpio_num = EXAMPLE_PIN_NUM_HSYNC, - .de_gpio_num = EXAMPLE_PIN_NUM_DE, - .data_gpio_nums = { - EXAMPLE_PIN_NUM_DATA0, - EXAMPLE_PIN_NUM_DATA1, - EXAMPLE_PIN_NUM_DATA2, - EXAMPLE_PIN_NUM_DATA3, - EXAMPLE_PIN_NUM_DATA4, - EXAMPLE_PIN_NUM_DATA5, - EXAMPLE_PIN_NUM_DATA6, - EXAMPLE_PIN_NUM_DATA7, - EXAMPLE_PIN_NUM_DATA8, - EXAMPLE_PIN_NUM_DATA9, - EXAMPLE_PIN_NUM_DATA10, - EXAMPLE_PIN_NUM_DATA11, - EXAMPLE_PIN_NUM_DATA12, - EXAMPLE_PIN_NUM_DATA13, - EXAMPLE_PIN_NUM_DATA14, - EXAMPLE_PIN_NUM_DATA15, -#if CONFIG_EXAMPLE_LCD_DATA_LINES > 16 - EXAMPLE_PIN_NUM_DATA16, - EXAMPLE_PIN_NUM_DATA17, - EXAMPLE_PIN_NUM_DATA18, - EXAMPLE_PIN_NUM_DATA19, - EXAMPLE_PIN_NUM_DATA20, - EXAMPLE_PIN_NUM_DATA21, - EXAMPLE_PIN_NUM_DATA22, - EXAMPLE_PIN_NUM_DATA23 -#endif - }, - .timings = { - .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ, - .h_res = EXAMPLE_LCD_H_RES, - .v_res = EXAMPLE_LCD_V_RES, - .hsync_back_porch = EXAMPLE_LCD_HBP, - .hsync_front_porch = EXAMPLE_LCD_HFP, - .hsync_pulse_width = EXAMPLE_LCD_HSYNC, - .vsync_back_porch = EXAMPLE_LCD_VBP, - .vsync_front_porch = EXAMPLE_LCD_VFP, - .vsync_pulse_width = EXAMPLE_LCD_VSYNC, - .flags = { - .pclk_active_neg = true, - }, - }, - .flags.fb_in_psram = true, // allocate frame buffer in PSRAM - }; - ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle)); + ESP_ERROR_CHECK(example_rgb_panel_new(&panel_handle)); ESP_LOGI(TAG, "Initialize RGB LCD panel"); - ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle)); - ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle)); + ESP_ERROR_CHECK(example_rgb_panel_init(panel_handle)); ESP_LOGI(TAG, "Turn on LCD backlight"); - example_bsp_set_lcd_backlight(EXAMPLE_LCD_BK_LIGHT_ON_LEVEL); + example_rgb_panel_set_backlight(true); ESP_LOGI(TAG, "Initialize LVGL library"); lv_init(); diff --git a/examples/peripherals/ppa/ppa_dsi/README.md b/examples/peripherals/ppa/ppa_dsi/README.md deleted file mode 100644 index c02f404be75..00000000000 --- a/examples/peripherals/ppa/ppa_dsi/README.md +++ /dev/null @@ -1,126 +0,0 @@ -| Supported Targets | ESP32-P4 | -| ----------------- | -------- | - - -# PPA DSI example - -## Overview - -This example demonstrates how to use the esp_driver_ppa component to process a given image and display it via DSI interface. - -The example used image will be first scaled up, rotated at counter-clockwise direction and rotated back, mirrored and mirror back, and scaled down. Then the image will be blended with a whole red image with less transparency. Next the `ESP32` word will be color-keyed out. Lastly a frame will be filled around the `ESP32`. - -## Usage - -The subsections below give only absolutely necessary information. For full steps to configure ESP-IDF and use it to build and run projects, see [ESP-IDF Getting Started](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html#get-started). - - -### Hardware Required - -This example requires: - -- EK79007 or ILI9881C LCD screen -- ESP32P4 devkit - -**Note:** For EK79007 you will need to connect following pins: -- 5V - 5V -- GND - GND -- RST_LCD - 3V3 - - - GND - ┌─────────────────────────────────────────────────────────┐ - │ │ - │ │ - │ │ - │ │ - │ │ - │ │ - │ │ - │ │ - ┌───────────────-─────────────┴──────────────────┐ │ - │ │ ┌──────────┴───────────┐ - │ │ DSI DATA 1P │ │ - │ ├───────────────────────────┤ │ - │ │ │ │ - │ │ DSI DATA 1N │ │ - │ ├───────────────────────────┤ │ - │ ESP32-P4 │ │ │ - │ │ DSI CLK N │ LCD Screen │ - │ ├───────────────────────────┤ │ - │ │ │ │ - │ │ DSI CLK P │ │ - │ ├───────────────────────────┤ │ - │ │ │ │ - │ │ DSI DATA 0P │ │ - │ ├───────────────────────────┤ │ - │ │ │ │ - │ │ DSI DATA 0N │ │ - │ ├───────────────────────────┤ │ - │ │ │ │ - │ │ └──────────────────────┘ - │ │ - │ │ - │ │ - │ │ - │ │ - │ │ - └────────────────────────────────────────────────┘ - - -### Set Chip Target - -First of all, your target must be supported by both: - -- **By your ESP-IDF version**: For the full list of supported targets, run: - ``` - idf.py --list-targets - ``` -- **By this example**: For the full list of supported targets, refer to the supported targets table at the top of this README. - -After you make sure that your target is supported, go to your example project directory and [set the chip target](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/tools/idf-py.html#select-the-target-chip-set-target): - -``` -idf.py set-target -``` - -For example, to set esp32-P4 as the chip target, run: - -``` -idf.py set-target esp32p4 -``` - - -### Build and Flash - -Execute the following command to build the project, flash it to your development board, and run the monitor tool to view the serial output: - -``` -idf.py build flash monitor -``` - -This command can be reduced to `idf.py flash monitor`. - -If the above command fails, check the log on the serial monitor which usually provides information on the possible cause of the issue. - -To exit the serial monitor, use `Ctrl` + `]`. - - -## Example Output - -If you see the following console output, your example should be running correctly: - -``` -I (1555) main_task: Calling app_main() -I (1555) ili9881c: ID1: 0x98, ID2: 0x81, ID3: 0x5c -I (1795) ppa_dsi: JPEG image decoded! Size of the decoded image is: 320px x 240px -start srm operations -start blend operations -start fill operations -I (10085) main_task: Returned from app_main() -``` - - -## Reference - -- [ESP-IDF: Pixel-Processing Accelerator](https://docs.espressif.com/projects/esp-idf/en/latest/esp32p4/api-reference/peripherals/ppa.html) diff --git a/examples/peripherals/ppa/ppa_dsi/main/idf_component.yml b/examples/peripherals/ppa/ppa_dsi/main/idf_component.yml deleted file mode 100644 index 4345977f95f..00000000000 --- a/examples/peripherals/ppa/ppa_dsi/main/idf_component.yml +++ /dev/null @@ -1,6 +0,0 @@ -dependencies: - idf: - version: ">=5.3.0" - dsi_init: - path: ${IDF_PATH}/examples/peripherals/camera/common_components/dsi_init - esp_jpeg: ">=1.0.2" diff --git a/examples/peripherals/ppa/ppa_dsi/pytest_ppa_dsi.py b/examples/peripherals/ppa/ppa_dsi/pytest_ppa_dsi.py deleted file mode 100644 index f8a55926c16..00000000000 --- a/examples/peripherals/ppa/ppa_dsi/pytest_ppa_dsi.py +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD -# SPDX-License-Identifier: CC0-1.0 -import pytest -from pytest_embedded import Dut -from pytest_embedded_idf.utils import idf_parametrize - - -@pytest.mark.generic -@idf_parametrize('target', ['esp32p4'], indirect=['target']) -def test_ppa_dsi(dut: Dut) -> None: - dut.expect_exact('Calling app_main()') diff --git a/examples/peripherals/ppa/ppa_dsi/CMakeLists.txt b/examples/peripherals/ppa/ppa_rgb_lcd/CMakeLists.txt similarity index 94% rename from examples/peripherals/ppa/ppa_dsi/CMakeLists.txt rename to examples/peripherals/ppa/ppa_rgb_lcd/CMakeLists.txt index ccd3fbdf81f..821828f7273 100644 --- a/examples/peripherals/ppa/ppa_dsi/CMakeLists.txt +++ b/examples/peripherals/ppa/ppa_rgb_lcd/CMakeLists.txt @@ -5,4 +5,4 @@ cmake_minimum_required(VERSION 3.22) include($ENV{IDF_PATH}/tools/cmake/project.cmake) # "Trim" the build. Include the minimal set of components, main, and anything it depends on. idf_build_set_property(MINIMAL_BUILD ON) -project(ppa_dsi) +project(ppa_rgb_lcd) diff --git a/examples/peripherals/ppa/ppa_rgb_lcd/README.md b/examples/peripherals/ppa/ppa_rgb_lcd/README.md new file mode 100644 index 00000000000..a2ec7de53ee --- /dev/null +++ b/examples/peripherals/ppa/ppa_rgb_lcd/README.md @@ -0,0 +1,54 @@ +| Supported Targets | ESP32-P4 | ESP32-S31 | +| ----------------- | -------- | --------- | + +# PPA RGB LCD Example + +## Overview + +This example demonstrates how to use `esp_driver_ppa` to process an image and display the results on a generic RGB LCD panel. + +The image is scaled, rotated, mirrored, blended, and filled by PPA, then pushed to the RGB panel with `esp_lcd_panel_draw_bitmap()`. + +## Hardware Required + +* An ESP development board, which supports the RGB LCD peripheral +* A general RGB panel, supports 16/24 bit-width, with HSYNC, VSYNC and DE signal +* An USB cable for power supply and programming + +## Configure + +Run `idf.py menuconfig` and open `Example Configuration`: + +1. Set the RGB LCD timing parameters. +2. Set the RGB LCD GPIO assignments. +3. Choose whether the source image comes from the embedded JPEG or the pre-generated `RGB565` image. + +## Build and Flash + +Run `idf.py -p PORT build flash monitor` to build, flash and monitor the project. A picture with 'ESP32' word will show up on the LCD as expected. + +The first time you run `idf.py` for the example will cost extra time as the build system needs to address the component dependencies and downloads the missing components from the ESP Component Registry into `managed_components` folder. + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +```text +I (1555) main_task: Calling app_main() +I (1565) ppa_rgb: Turn off LCD backlight +I (1575) ppa_rgb: Install RGB LCD panel driver +I (1605) ppa_rgb: Initialize RGB LCD panel +I (1615) ppa_rgb: Turn on LCD backlight +I (1795) ppa_rgb: JPEG image decoded! Size of the decoded image is: 320px x 240px +start srm operations +start blend operations +start fill operations +I (10085) main_task: Returned from app_main() +``` + +## Reference + +- [ESP-IDF: Pixel-Processing Accelerator](https://docs.espressif.com/projects/esp-idf/en/latest/esp32p4/api-reference/peripherals/ppa.html) +- [ESP-IDF: RGB LCD](https://docs.espressif.com/projects/esp-idf/en/latest/esp32p4/api-reference/peripherals/lcd/rgb_lcd.html) diff --git a/examples/peripherals/ppa/ppa_dsi/main/CMakeLists.txt b/examples/peripherals/ppa/ppa_rgb_lcd/main/CMakeLists.txt similarity index 77% rename from examples/peripherals/ppa/ppa_dsi/main/CMakeLists.txt rename to examples/peripherals/ppa/ppa_rgb_lcd/main/CMakeLists.txt index 61a29afb082..82167da14ce 100644 --- a/examples/peripherals/ppa/ppa_dsi/main/CMakeLists.txt +++ b/examples/peripherals/ppa/ppa_rgb_lcd/main/CMakeLists.txt @@ -1,4 +1,4 @@ -set(srcs "ppa_dsi_main.c") +set(srcs "ppa_rgb_lcd_main.c") if(CONFIG_EXAMPLE_SOURCE_IMAGE_FORMAT_RGB565) list(APPEND srcs "image.c") @@ -12,6 +12,6 @@ endif() idf_component_register(SRCS ${srcs} INCLUDE_DIRS "." - REQUIRES esp_mm esp_driver_ppa dsi_init + REQUIRES esp_mm esp_psram esp_driver_ppa esp_lcd EMBED_FILES ${embed_files} ) diff --git a/examples/peripherals/ppa/ppa_dsi/main/Kconfig.projbuild b/examples/peripherals/ppa/ppa_rgb_lcd/main/Kconfig.projbuild similarity index 50% rename from examples/peripherals/ppa/ppa_dsi/main/Kconfig.projbuild rename to examples/peripherals/ppa/ppa_rgb_lcd/main/Kconfig.projbuild index 2a9eb651d1e..50fa512f89a 100644 --- a/examples/peripherals/ppa/ppa_dsi/main/Kconfig.projbuild +++ b/examples/peripherals/ppa/ppa_rgb_lcd/main/Kconfig.projbuild @@ -1,17 +1,4 @@ menu "Example Configuration" - config EXAMPLE_USED_LDO_CHAN_ID - int "example used LDO channel ID" - default 3 - help - Example used LDO channel ID, you may check datasheet to know more details. - - config EXAMPLE_USED_LDO_VOLTAGE_MV - int "example used LDO voltage in mV" - default 2500 - range 0 3300 - help - Example used LDO voltage, in mV - choice EXAMPLE_SOURCE_IMAGE_FORMAT prompt "Select source image format" default EXAMPLE_SOURCE_IMAGE_FORMAT_JPEG diff --git a/examples/peripherals/ppa/ppa_rgb_lcd/main/idf_component.yml b/examples/peripherals/ppa/ppa_rgb_lcd/main/idf_component.yml new file mode 100644 index 00000000000..10787f88e8e --- /dev/null +++ b/examples/peripherals/ppa/ppa_rgb_lcd/main/idf_component.yml @@ -0,0 +1,6 @@ +dependencies: + idf: + version: ">=5.3.0" + esp_jpeg: ">=1.0.2" + rgb_panel_init: + path: ${IDF_PATH}/examples/peripherals/lcd/rgb_panel/common_components/rgb_panel_init diff --git a/examples/peripherals/ppa/ppa_dsi/main/image.c b/examples/peripherals/ppa/ppa_rgb_lcd/main/image.c similarity index 100% rename from examples/peripherals/ppa/ppa_dsi/main/image.c rename to examples/peripherals/ppa/ppa_rgb_lcd/main/image.c diff --git a/examples/peripherals/ppa/ppa_dsi/main/image.h b/examples/peripherals/ppa/ppa_rgb_lcd/main/image.h similarity index 100% rename from examples/peripherals/ppa/ppa_dsi/main/image.h rename to examples/peripherals/ppa/ppa_rgb_lcd/main/image.h diff --git a/examples/peripherals/ppa/ppa_dsi/main/image.jpg b/examples/peripherals/ppa/ppa_rgb_lcd/main/image.jpg similarity index 100% rename from examples/peripherals/ppa/ppa_dsi/main/image.jpg rename to examples/peripherals/ppa/ppa_rgb_lcd/main/image.jpg diff --git a/examples/peripherals/ppa/ppa_dsi/main/ppa_dsi_main.c b/examples/peripherals/ppa/ppa_rgb_lcd/main/ppa_rgb_lcd_main.c similarity index 65% rename from examples/peripherals/ppa/ppa_dsi/main/ppa_dsi_main.c rename to examples/peripherals/ppa/ppa_rgb_lcd/main/ppa_rgb_lcd_main.c index 04839b51a3d..aa841e70686 100644 --- a/examples/peripherals/ppa/ppa_dsi/main/ppa_dsi_main.c +++ b/examples/peripherals/ppa/ppa_rgb_lcd/main/ppa_rgb_lcd_main.c @@ -1,32 +1,37 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include -#include "esp_attr.h" -#include "esp_log.h" -#include "esp_check.h" #include "freertos/FreeRTOS.h" -#include "esp_lcd_mipi_dsi.h" -#include "esp_lcd_panel_ops.h" -#include "esp_ldo_regulator.h" #include "driver/ppa.h" -#include "example_dsi_init.h" -#include "example_dsi_init_config.h" +#include "example_rgb_panel_init.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "esp_lcd_panel_ops.h" +#include "esp_log.h" #if CONFIG_EXAMPLE_SOURCE_IMAGE_FORMAT_JPEG #include "jpeg_decoder.h" #else #include "image.h" #endif +#if CONFIG_EXAMPLE_LCD_DATA_LINES_16 +#define EXAMPLE_LCD_COLOR_FORMAT ESP_COLOR_FOURCC_RGB16 +#elif CONFIG_EXAMPLE_LCD_DATA_LINES_24 +#define EXAMPLE_LCD_COLOR_FORMAT ESP_COLOR_FOURCC_BGR24 +#else +#error "Unsupported LCD data lines" +#endif + #define EXAMPLE_IMAGE_H 240 #define EXAMPLE_IMAGE_W 320 #define EXAMPLE_BUFFER_CNT_CYCLE(buffer_cnt) (((buffer_cnt) + 1) % 2) -static const char *TAG = "ppa_dsi"; +static const char *TAG = "ppa_rgb"; #if CONFIG_EXAMPLE_SOURCE_IMAGE_FORMAT_JPEG //Reference the binary-included jpeg file @@ -78,24 +83,28 @@ esp_err_t s_get_rgb565_image(uint16_t **pixels) } #endif -void s_srm_ops(void *in_buf, void **out_buf, size_t buf_size, esp_lcd_panel_handle_t mipi_dpi_panel, ppa_client_handle_t ppa_srm_handle, void *clear_buf) +static void s_srm_ops(void *in_buf, void **out_buf, size_t buf_size, esp_lcd_panel_handle_t panel_handle, ppa_client_handle_t ppa_srm_handle, void *clear_buf) { ppa_srm_oper_config_t srm_config = { - .in.buffer = in_buf, - .in.pic_w = EXAMPLE_IMAGE_W, - .in.pic_h = EXAMPLE_IMAGE_H, - .in.block_w = EXAMPLE_IMAGE_W, - .in.block_h = EXAMPLE_IMAGE_H, - .in.block_offset_x = 0, - .in.block_offset_y = 0, - .in.srm_cm = PPA_SRM_COLOR_MODE_RGB565, - .out.buffer = out_buf[0], - .out.buffer_size = buf_size, - .out.pic_w = EXAMPLE_IMAGE_W, - .out.pic_h = EXAMPLE_IMAGE_H, - .out.block_offset_x = 0, - .out.block_offset_y = 0, - .out.srm_cm = PPA_SRM_COLOR_MODE_RGB565, + .in = { + .buffer = in_buf, + .pic_w = EXAMPLE_IMAGE_W, + .pic_h = EXAMPLE_IMAGE_H, + .block_w = EXAMPLE_IMAGE_W, + .block_h = EXAMPLE_IMAGE_H, + .block_offset_x = 0, + .block_offset_y = 0, + .srm_cm = PPA_SRM_COLOR_MODE_RGB565, + }, + .out = { + .buffer = out_buf[0], + .buffer_size = buf_size, + .pic_w = EXAMPLE_IMAGE_W, + .pic_h = EXAMPLE_IMAGE_H, + .block_offset_x = 0, + .block_offset_y = 0, + .srm_cm = (ppa_srm_color_mode_t)EXAMPLE_LCD_COLOR_FORMAT, + }, .rotation_angle = PPA_SRM_ROTATION_ANGLE_0, .scale_x = 1, .scale_y = 1, @@ -114,9 +123,10 @@ void s_srm_ops(void *in_buf, void **out_buf, size_t buf_size, esp_lcd_panel_hand srm_config.scale_x = mul[i]; srm_config.scale_y = mul[i]; ESP_ERROR_CHECK(ppa_do_scale_rotate_mirror(ppa_srm_handle, &srm_config)); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_W * size_mul[i], EXAMPLE_IMAGE_H * size_mul[i], out_buf[buffer_cnt])); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_W * size_mul[i], EXAMPLE_IMAGE_H * size_mul[i], out_buf[buffer_cnt])); vTaskDelay(800 / portTICK_PERIOD_MS); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_W * mul[i], EXAMPLE_IMAGE_H * mul[i], clear_buf)); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_W * size_mul[i], EXAMPLE_IMAGE_H * size_mul[i], clear_buf)); + srm_config.in.srm_cm = srm_config.out.srm_cm; srm_config.in.buffer = out_buf[i % 2]; srm_config.out.buffer = out_buf[1 - i % 2]; srm_config.in.pic_w = EXAMPLE_IMAGE_W * size_mul[i]; @@ -133,9 +143,9 @@ void s_srm_ops(void *in_buf, void **out_buf, size_t buf_size, esp_lcd_panel_hand srm_config.out.pic_w = EXAMPLE_IMAGE_H * 1.5; srm_config.out.pic_h = EXAMPLE_IMAGE_W * 1.5; ESP_ERROR_CHECK(ppa_do_scale_rotate_mirror(ppa_srm_handle, &srm_config)); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_H * 1.5, EXAMPLE_IMAGE_W * 1.5, out_buf[buffer_cnt])); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_H * 1.5, EXAMPLE_IMAGE_W * 1.5, out_buf[buffer_cnt])); vTaskDelay(800 / portTICK_PERIOD_MS); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_H * 1.5, EXAMPLE_IMAGE_W * 1.5, clear_buf)); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_H * 1.5, EXAMPLE_IMAGE_W * 1.5, clear_buf)); srm_config.in.buffer = out_buf[buffer_cnt]; srm_config.in.pic_w = EXAMPLE_IMAGE_H * 1.5; srm_config.in.pic_h = EXAMPLE_IMAGE_W * 1.5; @@ -149,9 +159,9 @@ void s_srm_ops(void *in_buf, void **out_buf, size_t buf_size, esp_lcd_panel_hand srm_config.out.pic_w = EXAMPLE_IMAGE_W * 1.5; srm_config.out.pic_h = EXAMPLE_IMAGE_H * 1.5; ESP_ERROR_CHECK(ppa_do_scale_rotate_mirror(ppa_srm_handle, &srm_config)); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_W * 1.5, EXAMPLE_IMAGE_H * 1.5, out_buf[buffer_cnt])); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_W * 1.5, EXAMPLE_IMAGE_H * 1.5, out_buf[buffer_cnt])); vTaskDelay(800 / portTICK_PERIOD_MS); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_W * 1.5, EXAMPLE_IMAGE_H * 1.5, clear_buf)); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_W * 1.5, EXAMPLE_IMAGE_H * 1.5, clear_buf)); srm_config.rotation_angle = PPA_SRM_ROTATION_ANGLE_0; srm_config.in.buffer = out_buf[buffer_cnt]; srm_config.in.pic_w = EXAMPLE_IMAGE_W * 1.5; @@ -166,15 +176,16 @@ void s_srm_ops(void *in_buf, void **out_buf, size_t buf_size, esp_lcd_panel_hand srm_config.mirror_x = 1; srm_config.mirror_y = 1; ESP_ERROR_CHECK(ppa_do_scale_rotate_mirror(ppa_srm_handle, &srm_config)); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_W * 1.5, EXAMPLE_IMAGE_H * 1.5, out_buf[buffer_cnt])); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_W * 1.5, EXAMPLE_IMAGE_H * 1.5, out_buf[buffer_cnt])); vTaskDelay(800 / portTICK_PERIOD_MS); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_W * 1.5, EXAMPLE_IMAGE_H * 1.5, clear_buf)); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_W * 1.5, EXAMPLE_IMAGE_H * 1.5, clear_buf)); srm_config.in.buffer = out_buf[buffer_cnt]; srm_config.out.buffer = out_buf[1 - buffer_cnt]; buffer_cnt = EXAMPLE_BUFFER_CNT_CYCLE(buffer_cnt); } //back to 1x original image + srm_config.in.srm_cm = PPA_SRM_COLOR_MODE_RGB565; srm_config.in.buffer = in_buf; srm_config.in.pic_w = EXAMPLE_IMAGE_W; srm_config.in.pic_h = EXAMPLE_IMAGE_H; @@ -189,38 +200,44 @@ void s_srm_ops(void *in_buf, void **out_buf, size_t buf_size, esp_lcd_panel_hand srm_config.mirror_x = 0; srm_config.mirror_y = 0; ESP_ERROR_CHECK(ppa_do_scale_rotate_mirror(ppa_srm_handle, &srm_config)); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, out_buf[buffer_cnt])); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, out_buf[buffer_cnt])); vTaskDelay(800 / portTICK_PERIOD_MS); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, clear_buf)); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, clear_buf)); } -void s_blend_ops(void *bg_buf, void *fg_buf, void *out_buf, size_t buf_size, esp_lcd_panel_handle_t mipi_dpi_panel, ppa_client_handle_t ppa_blend_handle, void *clear_buf) +static void s_blend_ops(void *bg_buf, void *fg_buf, void *out_buf, size_t buf_size, esp_lcd_panel_handle_t panel_handle, ppa_client_handle_t ppa_blend_handle, void *clear_buf) { //this operation will blend the bg_buf with the fg_buf ppa_blend_oper_config_t blend_config = { - .in_bg.buffer = bg_buf, - .in_bg.pic_w = EXAMPLE_IMAGE_W, - .in_bg.pic_h = EXAMPLE_IMAGE_H, - .in_bg.block_w = EXAMPLE_IMAGE_W, - .in_bg.block_h = EXAMPLE_IMAGE_H, - .in_bg.block_offset_x = 0, - .in_bg.block_offset_y = 0, - .in_bg.blend_cm = PPA_SRM_COLOR_MODE_RGB565, - .in_fg.buffer = fg_buf, - .in_fg.pic_w = EXAMPLE_IMAGE_W, - .in_fg.pic_h = EXAMPLE_IMAGE_H, - .in_fg.block_w = EXAMPLE_IMAGE_W, - .in_fg.block_h = EXAMPLE_IMAGE_H, - .in_fg.block_offset_x = 0, - .in_fg.block_offset_y = 0, - .in_fg.blend_cm = PPA_BLEND_COLOR_MODE_A8, - .out.buffer = out_buf, - .out.buffer_size = buf_size, - .out.pic_w = EXAMPLE_IMAGE_W, - .out.pic_h = EXAMPLE_IMAGE_H, - .out.block_offset_x = 0, - .out.block_offset_y = 0, - .out.blend_cm = PPA_SRM_COLOR_MODE_RGB565, + .in_bg = { + .buffer = bg_buf, + .pic_w = EXAMPLE_IMAGE_W, + .pic_h = EXAMPLE_IMAGE_H, + .block_w = EXAMPLE_IMAGE_W, + .block_h = EXAMPLE_IMAGE_H, + .block_offset_x = 0, + .block_offset_y = 0, + .blend_cm = PPA_SRM_COLOR_MODE_RGB565, + }, + .in_fg = { + .buffer = fg_buf, + .pic_w = EXAMPLE_IMAGE_W, + .pic_h = EXAMPLE_IMAGE_H, + .block_w = EXAMPLE_IMAGE_W, + .block_h = EXAMPLE_IMAGE_H, + .block_offset_x = 0, + .block_offset_y = 0, + .blend_cm = PPA_BLEND_COLOR_MODE_A8, + }, + .out = { + .buffer = out_buf, + .buffer_size = buf_size, + .pic_w = EXAMPLE_IMAGE_W, + .pic_h = EXAMPLE_IMAGE_H, + .block_offset_x = 0, + .block_offset_y = 0, + .blend_cm = (ppa_blend_color_mode_t)EXAMPLE_LCD_COLOR_FORMAT, + }, .bg_alpha_update_mode = PPA_ALPHA_SCALE, .bg_alpha_scale_ratio = 0.9, .fg_alpha_update_mode = PPA_ALPHA_SCALE, @@ -235,9 +252,9 @@ void s_blend_ops(void *bg_buf, void *fg_buf, void *out_buf, size_t buf_size, esp .mode = PPA_TRANS_MODE_BLOCKING, }; ESP_ERROR_CHECK(ppa_do_blend(ppa_blend_handle, &blend_config)); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, out_buf)); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, out_buf)); vTaskDelay(800 / portTICK_PERIOD_MS); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, clear_buf)); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, clear_buf)); //the `ESP32` in the bg_buf will be color-keyed out memset(fg_buf, 0xff, buf_size); @@ -256,21 +273,23 @@ void s_blend_ops(void *bg_buf, void *fg_buf, void *out_buf, size_t buf_size, esp .r = 0xfe, }; ESP_ERROR_CHECK(ppa_do_blend(ppa_blend_handle, &blend_config)); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, out_buf)); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, out_buf)); vTaskDelay(800 / portTICK_PERIOD_MS); } -void s_fill_ops(void *out_buf, size_t buf_size, esp_lcd_panel_handle_t mipi_dpi_panel, ppa_client_handle_t ppa_fill_handle) +static void s_fill_ops(void *out_buf, size_t buf_size, esp_lcd_panel_handle_t panel_handle, ppa_client_handle_t ppa_fill_handle) { int buffer_cnt = 0; ppa_fill_oper_config_t fill_config = { - .out.buffer = out_buf, - .out.buffer_size = buf_size, - .out.pic_w = EXAMPLE_IMAGE_W, - .out.pic_h = EXAMPLE_IMAGE_H, - .out.block_offset_x = 0, - .out.block_offset_y = 20, - .out.fill_cm = PPA_FILL_COLOR_MODE_RGB565, + .out = { + .buffer = out_buf, + .buffer_size = buf_size, + .pic_w = EXAMPLE_IMAGE_W, + .pic_h = EXAMPLE_IMAGE_H, + .block_offset_x = 0, + .block_offset_y = 20, + .fill_cm = (ppa_fill_color_mode_t)EXAMPLE_LCD_COLOR_FORMAT, + }, .fill_block_w = 10, .fill_block_h = 200, .fill_argb_color = { @@ -284,7 +303,7 @@ void s_fill_ops(void *out_buf, size_t buf_size, esp_lcd_panel_handle_t mipi_dpi_ //below ops will add a frame to the `ESP32` characters ESP_ERROR_CHECK(ppa_do_fill(ppa_fill_handle, &fill_config)); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, out_buf)); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, out_buf)); buffer_cnt = EXAMPLE_BUFFER_CNT_CYCLE(buffer_cnt); fill_config.out.block_offset_x = 0; @@ -292,7 +311,7 @@ void s_fill_ops(void *out_buf, size_t buf_size, esp_lcd_panel_handle_t mipi_dpi_ fill_config.fill_block_w = 320; fill_config.fill_block_h = 10; ESP_ERROR_CHECK(ppa_do_fill(ppa_fill_handle, &fill_config)); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, out_buf)); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, out_buf)); buffer_cnt = EXAMPLE_BUFFER_CNT_CYCLE(buffer_cnt); fill_config.out.block_offset_x = 310; @@ -300,7 +319,7 @@ void s_fill_ops(void *out_buf, size_t buf_size, esp_lcd_panel_handle_t mipi_dpi_ fill_config.fill_block_w = 10; fill_config.fill_block_h = 200; ESP_ERROR_CHECK(ppa_do_fill(ppa_fill_handle, &fill_config)); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, out_buf)); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, out_buf)); buffer_cnt = EXAMPLE_BUFFER_CNT_CYCLE(buffer_cnt); fill_config.out.block_offset_x = 0; @@ -308,7 +327,7 @@ void s_fill_ops(void *out_buf, size_t buf_size, esp_lcd_panel_handle_t mipi_dpi_ fill_config.fill_block_w = 320; fill_config.fill_block_h = 10; ESP_ERROR_CHECK(ppa_do_fill(ppa_fill_handle, &fill_config)); - ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(mipi_dpi_panel, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, out_buf)); + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, EXAMPLE_IMAGE_W, EXAMPLE_IMAGE_H, out_buf)); buffer_cnt = EXAMPLE_BUFFER_CNT_CYCLE(buffer_cnt); vTaskDelay(800 / portTICK_PERIOD_MS); } @@ -316,22 +335,20 @@ void s_fill_ops(void *out_buf, size_t buf_size, esp_lcd_panel_handle_t mipi_dpi_ void app_main(void) { uint16_t *pixels = NULL; - esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL; - esp_lcd_panel_io_handle_t mipi_dbi_io = NULL; - esp_lcd_panel_handle_t mipi_dpi_panel = NULL; + esp_lcd_panel_handle_t panel_handle = NULL; - //---------------MIPI LDO Init------------------// - esp_ldo_channel_handle_t ldo_mipi_phy = NULL; - esp_ldo_channel_config_t ldo_mipi_phy_config = { - .chan_id = CONFIG_EXAMPLE_USED_LDO_CHAN_ID, - .voltage_mv = CONFIG_EXAMPLE_USED_LDO_VOLTAGE_MV, - }; - ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy)); + ESP_LOGI(TAG, "Turn off LCD backlight"); + ESP_ERROR_CHECK(example_rgb_panel_init_backlight()); + example_rgb_panel_set_backlight(false); - //---------------DSI Init------------------// - example_dsi_resource_alloc(NULL, &mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, NULL, NULL); - example_dpi_panel_reset(mipi_dpi_panel); - example_dpi_panel_init(mipi_dpi_panel); + ESP_LOGI(TAG, "Install RGB LCD panel driver"); + ESP_ERROR_CHECK(example_rgb_panel_new(&panel_handle)); + + ESP_LOGI(TAG, "Initialize RGB LCD panel"); + ESP_ERROR_CHECK(example_rgb_panel_init(panel_handle)); + + ESP_LOGI(TAG, "Turn on LCD backlight"); + example_rgb_panel_set_backlight(true); //---------------Get Source image------------------// ESP_ERROR_CHECK(s_get_rgb565_image(&pixels)); @@ -359,7 +376,7 @@ void app_main(void) }; ESP_ERROR_CHECK(ppa_register_client(&ppa_srm_config, &ppa_srm_handle)); printf("start srm operations\n"); - s_srm_ops(pixels, (void **)out_buf, out_buf_size, mipi_dpi_panel, ppa_srm_handle, clear_buf); + s_srm_ops(pixels, (void **)out_buf, out_buf_size, panel_handle, ppa_srm_handle, clear_buf); uint8_t *fg_buf = heap_caps_calloc(out_buf_size, 1, MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM); if (!fg_buf) { @@ -376,7 +393,7 @@ void app_main(void) }; ESP_ERROR_CHECK(ppa_register_client(&ppa_blend_config, &ppa_blend_handle)); printf("start blend operations\n"); - s_blend_ops(pixels, fg_buf, out_buf[0], out_buf_size, mipi_dpi_panel, ppa_blend_handle, clear_buf); + s_blend_ops(pixels, fg_buf, out_buf[0], out_buf_size, panel_handle, ppa_blend_handle, clear_buf); //---------------FILL------------------// ppa_client_handle_t ppa_fill_handle = NULL; @@ -386,7 +403,7 @@ void app_main(void) }; ESP_ERROR_CHECK(ppa_register_client(&ppa_fill_config, &ppa_fill_handle)); printf("start fill operations\n"); - s_fill_ops(out_buf[0], out_buf_size, mipi_dpi_panel, ppa_fill_handle); + s_fill_ops(out_buf[0], out_buf_size, panel_handle, ppa_fill_handle); #if CONFIG_EXAMPLE_SOURCE_IMAGE_FORMAT_JPEG free(pixels); @@ -398,5 +415,5 @@ void app_main(void) ESP_ERROR_CHECK(ppa_unregister_client(ppa_srm_handle)); ESP_ERROR_CHECK(ppa_unregister_client(ppa_blend_handle)); ESP_ERROR_CHECK(ppa_unregister_client(ppa_fill_handle)); - example_dsi_resource_destroy(mipi_dsi_bus, mipi_dbi_io, mipi_dpi_panel); + ESP_ERROR_CHECK(example_rgb_panel_deinit(panel_handle)); } diff --git a/examples/peripherals/ppa/ppa_rgb_lcd/pytest_ppa_rgb_lcd.py b/examples/peripherals/ppa/ppa_rgb_lcd/pytest_ppa_rgb_lcd.py new file mode 100644 index 00000000000..10047ea2fb8 --- /dev/null +++ b/examples/peripherals/ppa/ppa_rgb_lcd/pytest_ppa_rgb_lcd.py @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 +import pytest +from pytest_embedded import Dut +from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets + + +@pytest.mark.generic +@idf_parametrize('target', soc_filtered_targets('SOC_PPA_SUPPORTED == 1'), indirect=['target']) +def test_ppa_rgb_lcd(dut: Dut) -> None: + dut.expect_exact('Calling app_main()') + dut.expect_exact('ppa_rgb: Install RGB LCD panel driver') + dut.expect_exact('ppa_rgb: Initialize RGB LCD panel') + # ... + dut.expect_exact('start srm operations') + dut.expect_exact('start blend operations') + dut.expect_exact('start fill operations') + dut.expect_exact('Returned from app_main()') diff --git a/examples/peripherals/ppa/ppa_rgb_lcd/sdkconfig.defaults b/examples/peripherals/ppa/ppa_rgb_lcd/sdkconfig.defaults new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/peripherals/ppa/ppa_rgb_lcd/sdkconfig.defaults.esp32p4 b/examples/peripherals/ppa/ppa_rgb_lcd/sdkconfig.defaults.esp32p4 new file mode 100644 index 00000000000..5f5cfd4f21c --- /dev/null +++ b/examples/peripherals/ppa/ppa_rgb_lcd/sdkconfig.defaults.esp32p4 @@ -0,0 +1,34 @@ +CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_HEX=y +CONFIG_SPIRAM_SPEED_200M=y + +CONFIG_EXAMPLE_LCD_DATA_LINES_16=y + +# RGB565 over 16 data lines uses B[4:0], G[5:0], R[4:0] +CONFIG_EXAMPLE_LCD_VSYNC_GPIO=41 +CONFIG_EXAMPLE_LCD_HSYNC_GPIO=39 +CONFIG_EXAMPLE_LCD_DE_GPIO=43 +CONFIG_EXAMPLE_LCD_PCLK_GPIO=33 + +# B3:B7 <=> DATA0:DATA4 +CONFIG_EXAMPLE_LCD_DATA0_GPIO=40 +CONFIG_EXAMPLE_LCD_DATA1_GPIO=42 +CONFIG_EXAMPLE_LCD_DATA2_GPIO=27 +CONFIG_EXAMPLE_LCD_DATA3_GPIO=29 +CONFIG_EXAMPLE_LCD_DATA4_GPIO=31 + +# G2:G7 <=> DATA5:DATA10 +CONFIG_EXAMPLE_LCD_DATA5_GPIO=21 +CONFIG_EXAMPLE_LCD_DATA6_GPIO=23 +CONFIG_EXAMPLE_LCD_DATA7_GPIO=26 +CONFIG_EXAMPLE_LCD_DATA8_GPIO=28 +CONFIG_EXAMPLE_LCD_DATA9_GPIO=30 +CONFIG_EXAMPLE_LCD_DATA10_GPIO=32 + +# R3:R7 <=> DATA11:DATA15 +CONFIG_EXAMPLE_LCD_DATA11_GPIO=6 +CONFIG_EXAMPLE_LCD_DATA12_GPIO=0 +CONFIG_EXAMPLE_LCD_DATA13_GPIO=15 +CONFIG_EXAMPLE_LCD_DATA14_GPIO=17 +CONFIG_EXAMPLE_LCD_DATA15_GPIO=19 diff --git a/examples/peripherals/ppa/ppa_rgb_lcd/sdkconfig.defaults.esp32s31 b/examples/peripherals/ppa/ppa_rgb_lcd/sdkconfig.defaults.esp32s31 new file mode 100644 index 00000000000..1733291dd7d --- /dev/null +++ b/examples/peripherals/ppa/ppa_rgb_lcd/sdkconfig.defaults.esp32s31 @@ -0,0 +1,42 @@ +CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_250M=y + +CONFIG_EXAMPLE_LCD_DATA_LINES_24=y + +# Default GPIO assignment +CONFIG_EXAMPLE_LCD_VSYNC_GPIO=45 +CONFIG_EXAMPLE_LCD_HSYNC_GPIO=44 +CONFIG_EXAMPLE_LCD_DE_GPIO=43 +CONFIG_EXAMPLE_LCD_PCLK_GPIO=40 + +# B0:B7 <=> DATA0:DATA7 +CONFIG_EXAMPLE_LCD_DATA0_GPIO=8 +CONFIG_EXAMPLE_LCD_DATA1_GPIO=9 +CONFIG_EXAMPLE_LCD_DATA2_GPIO=10 +CONFIG_EXAMPLE_LCD_DATA3_GPIO=11 +CONFIG_EXAMPLE_LCD_DATA4_GPIO=12 +CONFIG_EXAMPLE_LCD_DATA5_GPIO=13 +CONFIG_EXAMPLE_LCD_DATA6_GPIO=14 +CONFIG_EXAMPLE_LCD_DATA7_GPIO=15 + +# G0:G7 <=> DATA8:DATA15 +CONFIG_EXAMPLE_LCD_DATA8_GPIO=16 +CONFIG_EXAMPLE_LCD_DATA9_GPIO=17 +CONFIG_EXAMPLE_LCD_DATA10_GPIO=18 +CONFIG_EXAMPLE_LCD_DATA11_GPIO=19 +CONFIG_EXAMPLE_LCD_DATA12_GPIO=33 +CONFIG_EXAMPLE_LCD_DATA13_GPIO=34 +CONFIG_EXAMPLE_LCD_DATA14_GPIO=35 +CONFIG_EXAMPLE_LCD_DATA15_GPIO=36 + +# R0:R7 <=> DATA16:DATA23 +CONFIG_EXAMPLE_LCD_DATA16_GPIO=37 +CONFIG_EXAMPLE_LCD_DATA17_GPIO=38 +CONFIG_EXAMPLE_LCD_DATA18_GPIO=39 +CONFIG_EXAMPLE_LCD_DATA19_GPIO=2 +CONFIG_EXAMPLE_LCD_DATA20_GPIO=3 +CONFIG_EXAMPLE_LCD_DATA21_GPIO=4 +CONFIG_EXAMPLE_LCD_DATA22_GPIO=5 +CONFIG_EXAMPLE_LCD_DATA23_GPIO=7