diff --git a/.devcontainer/__lv_conf.h__ b/.devcontainer/__lv_conf.h__ index 1f87f3e785..7961819730 100644 --- a/.devcontainer/__lv_conf.h__ +++ b/.devcontainer/__lv_conf.h__ @@ -886,6 +886,9 @@ #define LV_USE_GENERIC_MIPI (LV_USE_ST7735 | LV_USE_ST7789 | LV_USE_ST7796 | LV_USE_ILI9341) +/*Driver for Renesas GLCD*/ +#define LV_USE_RENESAS_GLCDC 0 + /* LVGL Windows backend */ #define LV_USE_WINDOWS 0 diff --git a/Kconfig b/Kconfig index 37931f2df1..5361fc6ae5 100644 --- a/Kconfig +++ b/Kconfig @@ -1625,6 +1625,10 @@ menu "LVGL configuration" bool "Generic MIPI driver" default y if LV_USE_ST7735 || LV_USE_ST7789 || LV_USE_ST7796 || LV_USE_ILI9341 + config LV_USE_RENESAS_GLCDC + bool "Use Renesas GLCDC driver" + default n + config LV_USE_WINDOWS bool "Use LVGL Windows backend" default n diff --git a/docs/integration/chip/renesas.rst b/docs/integration/chip/renesas.rst index fc42b89a3c..fb15d30594 100644 --- a/docs/integration/chip/renesas.rst +++ b/docs/integration/chip/renesas.rst @@ -1,3 +1,5 @@ +.. _renesas: + ======= Renesas ======= @@ -19,6 +21,14 @@ Dave2D is capable of accelerating most of the drawing operations of LVGL: As Dave2D works in the background, the CPU is free for other tasks. In practice, during rendering, Dave2D can reduce the CPU usage by half or to one-third, depending on the application. +GLCDC +----- + +GLCDC is a multi-stage graphics output peripheral available in several Renesas MCUs. +It is able to drive LCD panles via a higly configurable RGB interface. + +More info can be found at the :ref:`dirver's page`. + Certified boards ---------------- @@ -35,6 +45,8 @@ The official IDE of Renesas is called `e² studio `__ repository: +**Setting up the project** -.. code:: shell - git clone https://github.com/lvgl/lv_renesas.git --recurse-submodules +- First, clone the ready-to-use `lv_port_renesas_ek-ra8d1 `__ repository: -After that, *Import* ``lv_ek_ra8d1`` into e² studio, build the project, and flash it. + .. code-block:: shell + + git clone https://github.com/lvgl/lv_port_renesas_ek-ra8d1.git --recurse-submodules + +- Open e² studio, go to ``File`` -> ``Import project`` and select ``General`` / ``Exsisting projects into workspace`` + + .. image:: /misc/renesas/import.png + :alt: Importing the project + + +- Browse the cloned folder and press ``Finish`` + +- Double click on ``configuration.xml``. This will activate the configuration window. + + Renesas' Flexible Software Package (FSP) incudes BSP and HAL layer support extended with multiple RTOS variants and other middleware stacks. + The components will be available via code generation, incuding the entry point of *"main.c"*. + + Press ``Generate Project Content`` in the top right corner. + + .. image:: /misc/renesas/generate.png + :alt: Code generation with FSP + +- Build the project by pressing ``Ctrl`` + ``Alt`` + ``B`` + +- Click the Debug button. When prompted select the `J-Link ARM` Debugger and the `R7FA8D1BH` MCU. Note that on the ``SW1`` DIP switch (middle of the board) 7 should be ON, all others are OFF. @@ -61,7 +96,7 @@ Modify the project Open a demo ~~~~~~~~~~~ -In `LVGL_thread_entry `__, the demos are automatically enabled based on the settings in `lv_conf.h `__. +In `LVGL_thread_entry `__, the demos are automatically enabled based on the settings in `lv_conf.h `__. You can disable all demos (or just comment them out) and call some ``lv_example_...()`` functions, or add your custom code. @@ -81,4 +116,4 @@ Configuration Support ------- -In case of an problems or questions open an issue in the `lv_renesas `__ repository. +In case of an problems or questions open an issue in the `lv_port_renesas_ek-ra8d1 `__ repository. diff --git a/docs/integration/driver/display/index.rst b/docs/integration/driver/display/index.rst index 060f49cdfb..07e87259b7 100644 --- a/docs/integration/driver/display/index.rst +++ b/docs/integration/driver/display/index.rst @@ -12,3 +12,4 @@ Display st7735 st7789 st7796 + renesas_glcdc diff --git a/docs/integration/driver/display/renesas_glcdc.rst b/docs/integration/driver/display/renesas_glcdc.rst new file mode 100644 index 0000000000..6f082a1f48 --- /dev/null +++ b/docs/integration/driver/display/renesas_glcdc.rst @@ -0,0 +1,58 @@ +.. _renesas_glcdc: + +============= +Renesas GLCDC +============= + +Overview +-------- + +.. image:: /misc/renesas/glcdc.png + :alt: Architectural overview of Renesas GLCDC + :align: center + +| + +GLCDC is a multi-stage graphics output peripheral used in Renesas MCUs. +It is designed to automatically generate timing and data signals for different LCD panels. + +- Supports LCD panels with RGB interface (up to 24 bits) and sync signals (HSYNC, VSYNC and Data Enable optional) +- Supports various color formats for input graphics planes (RGB888, ARGB8888, RGB565, ARGB1555, ARGB4444, CLUT8, CLUT4, CLUT1) +- Supports the Color Look-Up Table (CLUT) usage for input graphics planes (ARGB8888) with 512 words (32 bits/word) +- Supports various color formats for output (RGB888, RGB666, RGB565, Serial RGB888) +- Can input two graphics planes on top of the background plane and blend them on the screen +- Generates a dot clock to the panel. The clock source is selectable from internal or external (LCD_EXTCLK) +- Supports brightness adjustment, contrast adjustment, and gamma correction +- Supports GLCDC interrupts to handle frame-buffer switching or underflow detection + +| Setting up a project and further integration with Renesas' ecosystem is described in detail on :ref:`page Renesas `. +| Check out the `EK-RA8D1 example repository `__ for a ready-to-use example. + +Prerequisites +------------- + +- This diver relies on FSP generated code. Missing the step while setting up the project will cause a compilation error. +- Activate the diver by setting :c:macro:`LV_USE_DRAW_PXP` to ``1`` in your *"lv_conf.h"*. + +Usage +----- + +There is no need to implement any platform-specific functions. + +The following code demonstrates using the diver in :cpp:enumerator:`LV_DISPLAY_RENDER_MODE_DIRECT` mode. + +.. code:: c + + lv_display_t * disp = lv_renesas_glcdc_direct_create(); + lv_display_set_default(disp); + +To use the driver in :cpp:enumerator:`LV_DISPLAY_RENDER_MODE_PARTIAL` mode, an extra buffer must be allocated, +desireably in the fastest available memory region. +Buffer swapping can be activated by passing a second buffer of same size insted of the :cpp:expr:`NULL` argument. + +.. code:: c + + static lv_color_t partial_draw_buf[DISPLAY_HSIZE_INPUT0 * DISPLAY_VSIZE_INPUT0 / 10] BSP_PLACE_IN_SECTION(".sdram") BSP_ALIGN_VARIABLE(1024); + + lv_display_t * disp = lv_renesas_glcdc_partial_create(partial_draw_buf, NULL, sizeof(partial_draw_buf)); + lv_display_set_default(disp); diff --git a/docs/misc/renesas/generate.png b/docs/misc/renesas/generate.png new file mode 100644 index 0000000000..b123e56582 Binary files /dev/null and b/docs/misc/renesas/generate.png differ diff --git a/docs/misc/renesas/glcdc.png b/docs/misc/renesas/glcdc.png new file mode 100644 index 0000000000..fcb7d40fc9 Binary files /dev/null and b/docs/misc/renesas/glcdc.png differ diff --git a/docs/misc/renesas/import.png b/docs/misc/renesas/import.png new file mode 100644 index 0000000000..5364b2eb09 Binary files /dev/null and b/docs/misc/renesas/import.png differ diff --git a/env_support/cmsis-pack/README.md b/env_support/cmsis-pack/README.md index 1461d2c679..0f2c67ebed 100644 --- a/env_support/cmsis-pack/README.md +++ b/env_support/cmsis-pack/README.md @@ -103,6 +103,7 @@ remove the misleading guide above this code segment. - LV_USE_ILI9341 + - LV_USE_RENESAS_GLCDC 5. Update `LV_LOG_PRINTF` to `1` and `LV_LOG_LEVEL` to `LV_LOG_LEVEL_USER` diff --git a/lv_conf_template.h b/lv_conf_template.h index d25bf1878f..9b54b5cfeb 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -967,6 +967,9 @@ #define LV_USE_GENERIC_MIPI (LV_USE_ST7735 | LV_USE_ST7789 | LV_USE_ST7796 | LV_USE_ILI9341) +/*Driver for Renesas GLCD*/ +#define LV_USE_RENESAS_GLCDC 0 + /* LVGL Windows backend */ #define LV_USE_WINDOWS 0 diff --git a/src/drivers/display/renesas_glcdc/lv_renesas_glcdc.c b/src/drivers/display/renesas_glcdc/lv_renesas_glcdc.c new file mode 100644 index 0000000000..3874cfc7d8 --- /dev/null +++ b/src/drivers/display/renesas_glcdc/lv_renesas_glcdc.c @@ -0,0 +1,192 @@ +/** + * @file lv_renesas_glcdc.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_renesas_glcdc.h" + +#if LV_USE_RENESAS_GLCDC + +#include "LVGL_thread.h" +#include +#include "../../../display/lv_display_private.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void glcdc_init(void); +static void flush_direct(lv_display_t * display, const lv_area_t * area, uint8_t * px_map); +static void flush_partial(lv_display_t * display, const lv_area_t * area, uint8_t * px_map); +static void flush_wait_direct(lv_display_t * display); +static void flush_wait_partial(lv_display_t * display); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_display_t * lv_renesas_glcdc_direct_create(void) +{ + glcdc_init(); + + lv_display_t * display = lv_display_create(DISPLAY_HSIZE_INPUT0, DISPLAY_VSIZE_INPUT0); + lv_display_set_flush_cb(display, flush_direct); + lv_display_set_flush_wait_cb(display, flush_wait_direct); + lv_display_set_buffers(display, &fb_background[0][0], &fb_background[1][0], sizeof(fb_background[0]), + LV_DISPLAY_RENDER_MODE_DIRECT); + + return display; +} + +lv_display_t * lv_renesas_glcdc_partial_create(void * buf1, void * buf2, size_t buf_size) +{ + glcdc_init(); + + lv_display_t * display = lv_display_create(DISPLAY_HSIZE_INPUT0, DISPLAY_VSIZE_INPUT0); + lv_display_set_flush_cb(display, flush_partial); + lv_display_set_flush_wait_cb(display, flush_wait_partial); + lv_display_set_buffers(display, buf1, buf2, buf_size, LV_DISPLAY_RENDER_MODE_PARTIAL); + + return display; +} + +/*This function is declared in and being used by FSP generated code modules*/ +void glcdc_callback(display_callback_args_t * p_args) +{ + if(DISPLAY_EVENT_LINE_DETECTION == p_args->event) { +#if BSP_CFG_RTOS == 2 /*FreeRTOS*/ + BaseType_t context_switch; + + /*Set Vsync semaphore*/ + xSemaphoreGiveFromISR(_SemaphoreVsync, &context_switch); + + /*Return to the highest priority available task*/ + portYIELD_FROM_ISR(context_switch); +#else +#endif + } + else if(DISPLAY_EVENT_GR1_UNDERFLOW == p_args->event) { + __BKPT(0); /*Layer 1 Underrun*/ + } + else if(DISPLAY_EVENT_GR2_UNDERFLOW == p_args->event) { + __BKPT(0); /*Layer 2 Underrun*/ + } + else { /*DISPLAY_EVENT_FRAME_END*/ + __BKPT(0); + } + +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void glcdc_init(void) +{ + /* Fill the Frame buffer with black colour (0x0000 in RGB565), for a clean start after previous runs */ + lv_memzero(fb_background, sizeof(fb_background)); + + /* Initalize GLCDC driver */ + uint8_t * p_fb = &fb_background[1][0]; + fsp_err_t err; + + err = R_GLCDC_Open(&g_display0_ctrl, &g_display0_cfg); + if(FSP_SUCCESS != err) { + __BKPT(0); + } + + err = R_GLCDC_Start(&g_display0_ctrl); + if(FSP_SUCCESS != err) { + __BKPT(0); + } + + do { + err = + R_GLCDC_BufferChange(&g_display0_ctrl, + (uint8_t *) p_fb, + (display_frame_layer_t) 0); + } while(FSP_ERR_INVALID_UPDATE_TIMING == err); +} + +static void flush_direct(lv_display_t * display, const lv_area_t * area, uint8_t * px_map) +{ + FSP_PARAMETER_NOT_USED(area); + /*Display the frame buffer pointed by px_map*/ + + if(!lv_display_flush_is_last(display)) return; + +#if defined(RENESAS_CORTEX_M85) && (BSP_CFG_DCACHE_ENABLED) + /* Invalidate cache - so the HW can access any data written by the CPU */ + SCB_CleanInvalidateDCache_by_Addr(px_map, sizeof(fb_background[0])); +#endif + + R_GLCDC_BufferChange(&g_display0_ctrl, + (uint8_t *) px_map, + (display_frame_layer_t) 0); +} + +static void flush_wait_direct(lv_display_t * display) +{ + if(!lv_display_flush_is_last(display)) return; + +#if BSP_CFG_RTOS == 2 /*FreeRTOS*/ + /*If Vsync semaphore has already been set, clear it then wait to avoid tearing*/ + if(uxSemaphoreGetCount(_SemaphoreVsync)) { + xSemaphoreTake(_SemaphoreVsync, 10); + } + + xSemaphoreTake(_SemaphoreVsync, portMAX_DELAY); +#endif + +} + +static void flush_partial(lv_display_t * display, const lv_area_t * area, uint8_t * px_map) +{ + LV_UNUSED(display); + + int32_t w = lv_area_get_width(area); + int32_t h = lv_area_get_height(area); + + uint16_t * fb = (uint16_t *)fb_background[1]; + uint16_t * img = (uint16_t *)px_map; + + fb = fb + area->y1 * DISPLAY_HSIZE_INPUT0; + fb = fb + area->x1; + + int32_t i; + for(i = 0; i < h; i++) { + lv_memcpy(fb, img, w * 2); +#if defined(RENESAS_CORTEX_M85) && (BSP_CFG_DCACHE_ENABLED) + SCB_CleanInvalidateDCache_by_Addr(fb, w * 2); +#endif + fb += DISPLAY_HSIZE_INPUT0; + img += w; + } +} + +static void flush_wait_partial(lv_display_t * display) +{ + LV_UNUSED(display); + + return; +} + +#endif /*LV_USE_RENESAS_GLCDC*/ diff --git a/src/drivers/display/renesas_glcdc/lv_renesas_glcdc.h b/src/drivers/display/renesas_glcdc/lv_renesas_glcdc.h new file mode 100644 index 0000000000..0558614e53 --- /dev/null +++ b/src/drivers/display/renesas_glcdc/lv_renesas_glcdc.h @@ -0,0 +1,57 @@ +/** + * @file lv_renesas_glcdc.h + * + */ + +#ifndef LV_RENESAS_GLCDC_H +#define LV_RENESAS_GLCDC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../../../display/lv_display.h" + +#if LV_USE_RENESAS_GLCDC + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a display using Renesas' GLCDC peripherial in DIRECT render mode + * @return pointer to the created display + */ +lv_display_t * lv_renesas_glcdc_direct_create(void); + +/** + * Create a display using Renesas' GLCDC peripherial in PARTIAL render mode + * @param buf1 first buffer + * @param buf2 second buffer (can be `NULL`) + * @param buf_size buffer size in byte + * @return pointer to the created display + */ +lv_display_t * lv_renesas_glcdc_partial_create(void * buf1, void * buf2, size_t buf_size); + +/********************** + * MACROS + **********************/ + +#endif /* LV_USE_RENESAS_GLCDC */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LV_RENESAS_GLCDC_H */ diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 32ebee4547..bdc6409a95 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -3156,6 +3156,15 @@ #endif #endif +/*Driver for Renesas GLCD*/ +#ifndef LV_USE_RENESAS_GLCDC + #ifdef CONFIG_LV_USE_RENESAS_GLCDC + #define LV_USE_RENESAS_GLCDC CONFIG_LV_USE_RENESAS_GLCDC + #else + #define LV_USE_RENESAS_GLCDC 0 + #endif +#endif + /* LVGL Windows backend */ #ifndef LV_USE_WINDOWS #ifdef CONFIG_LV_USE_WINDOWS