Browse Source

新增gd32470z-lckfb配套LCD驱动 (#10311)

* 新增gd32470z-lckfb配套LCD驱动

* 1.使用RTT的编程规范修改注释 2.readme文件新增注意事项以及原作者信息

* Add maintainer info for gd32470z-lckfb-lcd
godmial 1 month ago
parent
commit
524ae345c1

+ 3 - 0
MAINTAINERS

@@ -75,3 +75,6 @@ tag: workflow
 path: .github
 owners: supper thomas(supperthomas)<78900636@qq.com>, Bingru Zhang(Rbb666)<751061401@qq.com>, Yuqiang Wang(kurisaW)<2053731441@qq.com>
 
+tag: gd32470z-lckfb-lcd
+path: bsp/gd32/arm/gd32470z-lckfb/board/ports
+owners: Wu Ying Xiang(godmial)<2633967641@qq.com>

+ 1 - 1
bsp/gd32/arm/gd32470z-lckfb/README.md

@@ -51,7 +51,7 @@ GD32470Z-LCKFB梁山派是立创开发板推出的一款GD32F470系列的开发
 | GPIO     | 支持       | PA0, PA1... ---> PIN: 0, 1...113 |
 | UART     | 支持       | UART0 - UART7                    |
 | **扩展模块** | **支持情况** | **备注**                           |
-| 暂无       | 暂不支持     | 暂不支持                             |
+| LCD+触摸屏      | 支持     | 暂不支持中文显示(因 Keil5 编码限制),使用方法请查看bsp\gd32\arm\gd32470z-lckfb\board\ports\README.md |
 
 ## 使用说明
 

+ 3 - 0
bsp/gd32/arm/gd32470z-lckfb/SConstruct

@@ -56,5 +56,8 @@ objs.extend(SConscript(os.path.join(libraries_path_prefix, gd32_library, 'SConsc
 # include drivers
 objs.extend(SConscript(os.path.join(libraries_path_prefix, 'gd32_drivers', 'SConscript')))
 
+# include lcd and drivers 
+objs.extend(SConscript(os.path.join(RTT_ROOT, 'bsp', 'gd32', 'arm', 'gd32470z-lckfb', 'board', 'ports', 'SConscript')))
+
 # make a building
 DoBuilding(TARGET, objs)

+ 31 - 0
bsp/gd32/arm/gd32470z-lckfb/board/Kconfig

@@ -433,6 +433,37 @@ endmenu
 
 menu "Board extended module Drivers"
 
+    menuconfig BSP_USING_LCD
+        bool "Enable LCD"
+        select RT_USING_LCD
+        default n
+        if BSP_USING_LCD
+
+            config BSP_USING_TLI
+                bool "Enable TLI"
+                default y  
+
+            config BSP_USING_SDRAM
+                bool "Enable SDRAM"
+                select RT_USING_SDRAM
+                default y
+
+            config BSP_USING_TOUCH
+                bool "Enable TOUCH"
+                select RT_USING_TOUCH
+                default n
+                
+            config BSP_USING_GPU
+                bool "Enable GPU"
+                select RT_USING_GPU
+                default y
+
+            config BSP_USING_DRAW_PANEL_EXAMPLE
+                bool "Enable DRAW PANEL EXAMPLE"
+                select RT_USING_DRAW_PANEL_EXAMPLE
+                default n
+        endif
+        
 endmenu
 
 endmenu

+ 44 - 0
bsp/gd32/arm/gd32470z-lckfb/board/ports/README.md

@@ -0,0 +1,44 @@
+#### 1. 简介
+
+用于 GD32F470 立创开发板配套 RGB LCD 屏幕的驱动,支持触摸。
+
+> **原作者:LCKFB**  
+> 本驱动最初由 LCKFB 开发,由 godmial 移植到本BSP。
+
+#### 2. 在 ENV 中的开启  
+ps:建议全部开启  
+```
+Hardware Drivers Config  --->
+      Board extended module Drivers --->
+                            Enable LCD --->
+                                - [*]Enable TLI
+                                - [*]Enable SDRAM
+                                - [*]Enable TOUCH
+                                - [*]Enable GPU
+                                - [*]Enable DRAW PANEL EXAMPLE
+```
+
+#### 3. 注意事项
+
+1. 如果屏幕出现刷新抖动,触摸屏出现连点的情况,可以尝试在 `libraries\GD32F4xx_Firmware_Library\CMSIS\GD\GD32F4xx\Source\system_gd32f4xx.c` 将时钟值修改为  
+   `#define __SYSTEM_CLOCK_240M_PLL_25M_HXTAL       (uint32_t)(240000000)`  
+   然后重新编译即可
+
+2. 由于代码格式审查原因,本驱动未包含中文显示函数。但可直接移植官方源码中的中文显示函数进行使用。
+
+3. 为避免 `scons` 命令编译不通过,代码使用了如下代码段以适配不同编译器:
+   ```
+   #if defined(__CC_ARM) || defined(__ARMCC_VERSION)
+   // Keil MDK
+   uint16_t ltdc_lcd_framebuf0[800][480] __attribute__((at(LCD_FRAME_BUF_ADDR)));
+   #elif defined(__GNUC__)
+   // GCC (RT-Thread)
+   uint16_t ltdc_lcd_framebuf0[10][10]; // 此行为避免 scons 编译错误而添加
+   #endif
+     
+
+
+#### 4. 联系方式  
+
+- 维护:godmial  
+- 主页:<https://github.com/godmial>

+ 25 - 0
bsp/gd32/arm/gd32470z-lckfb/board/ports/SConscript

@@ -0,0 +1,25 @@
+Import('RTT_ROOT')
+Import('rtconfig')
+from building import *
+
+cwd = GetCurrentDir()
+
+# add the general drivers.
+src = Split("""
+""")
+
+# add lcd drivers.
+if GetDepend('BSP_USING_LCD'):
+    src += ['drv_lcd.c']
+
+if GetDepend('BSP_USING_TOUCH'):
+    src += ['drv_touch.c']
+
+if GetDepend('BSP_USING_DRAW_PANEL_EXAMPLE'):
+    src += ['draw_panel.c']
+
+path = [cwd]
+
+group = DefineGroup('Applications', src, depend = [''], CPPPATH = path)
+
+Return('group')

+ 187 - 0
bsp/gd32/arm/gd32470z-lckfb/board/ports/draw_panel.c

@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2025-05-23     godmial      Refactor to conform to RT-Thread coding style.
+ */
+
+#include <board.h>
+#include <rthw.h>
+#include <rtthread.h>
+#include "drv_lcd.h"
+#include "drv_touch.h"
+
+#define COLOR_MAX 14
+
+/* Maximum magnification of pixels */
+#define PIXEL_SIZE_MAX 20
+
+typedef struct button_struct
+{
+    uint16_t x;
+    uint16_t y;
+    uint16_t w;
+    uint16_t h;
+    uint16_t color;
+    uint16_t value;
+} widget_object_t;
+
+uint16_t        color_buf[COLOR_MAX] = {GRAYBLUE, BLACK, BLUE, BRED, GRED, GBLUE, RED, MAGENTA, GREEN, YELLOW, CYAN, BROWN, BRRED, GRAY};
+widget_object_t button_clear, button_color, button_pixel, button_eraser;
+
+
+/**
+ * @brief    Initialize a widget button with given properties.
+ *
+ * @param    obj     Pointer to the widget object.
+ * @param    x       X coordinate of the top-left corner.
+ * @param    y       Y coordinate of the top-left corner.
+ * @param    w       Width of the widget.
+ * @param    h       Height of the widget.
+ * @param    color   Color value of the widget.
+ * @param    value   Initial value of the widget.
+ *
+ * @return   None.
+ */
+void widget_object_init(widget_object_t *obj, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color, uint16_t value)
+{
+    obj->x     = x;
+    obj->y     = y;
+    obj->h     = h;
+    obj->w     = w;
+    obj->color = color;
+    obj->value = value;
+}
+
+
+/**
+ * @brief    Initialize and display the user interface.
+ *
+ * This function draws the control buttons for clear, color,
+ * pixel size, and eraser on the screen.
+ *
+ * @return   None.
+ */
+void ui_init(void)
+{
+    char temp_buf[20] = {0};
+
+    tli_show_button(button_clear.x, button_clear.y, button_clear.w, button_clear.h, 12, button_clear.color);
+    tli_show_string(button_clear.x + 20, button_clear.y + 20, WHITE, button_clear.color, 2, "clear", 0);
+
+    tli_show_button(button_color.x, button_color.y, button_color.w, button_color.h, 12, button_color.color);
+    tli_show_string(button_color.x + 20, button_color.y + 20, WHITE, button_color.color, 2, "color", 0);
+
+    tli_show_button(button_pixel.x, button_pixel.y, button_pixel.w, button_pixel.h, 12, button_pixel.color);
+    if (button_pixel.value == 0)
+    {
+        tli_show_string(button_pixel.x + 20, button_pixel.y + 20, WHITE, button_pixel.color, 2, "pixel", 0);
+        button_pixel.value = 1;
+    }
+    else
+    {
+        sprintf(temp_buf, "%d", button_pixel.value);
+        tli_show_string(button_pixel.x + (button_pixel.w / 2) - (strlen(temp_buf) / 2 * 16), button_pixel.y + 20, WHITE, button_pixel.color, 2, (uint8_t *)temp_buf, 0);
+    }
+
+    tli_show_button(button_eraser.x, button_eraser.y, button_eraser.w, button_eraser.h, 12, button_eraser.color);
+    tli_show_string(button_eraser.x + (button_eraser.w / 2) - (strlen("eraser") / 2 * 16), button_eraser.y + 20, WHITE, button_eraser.color, 2, "eraser", 0);
+}
+
+/**
+ * @brief    Main routine to test the drawing panel with touch interaction.
+ *
+ * Initializes LCD and touch interface, sets up buttons and handles user input
+ * to draw or erase on the screen based on touch events.
+ *
+ * @return   Always returns 0.
+ */
+int draw_panel_test(void)
+{
+    int  touch_state = 0;
+    char color_num   = 0;
+    char pixel_size  = 0;
+
+    lcd_disp_config();
+    FT5206_Init();
+    tli_draw_rectangle(0, 0, 800, 480, WHITE, 1);
+
+    widget_object_init(&button_clear, 800 - 130, 480 - 80, 120, 70, BLUE, 0);
+    widget_object_init(&button_color, 10, 480 - 80, 120, 70, BLUE, 0);
+    widget_object_init(&button_pixel, 400 - 60, 480 - 80, 120, 70, BLUE, pixel_size);
+    widget_object_init(&button_eraser, 800 - 130 - 130, 480 - 80, 120, 70, BLUE, 0);
+
+    ui_init();
+
+    while (1)
+    {
+        touch_state = FT5206_Scan(0);
+        if (touch_state == 1)
+        {
+            if (tp_dev.x[0] >= button_color.x && tp_dev.x[0] <= (button_color.x + button_color.w))
+            {
+                if (tp_dev.y[0] >= button_color.y && tp_dev.y[0] <= (button_color.y + button_color.h))
+                {
+                    letgo_scan(0, button_color.x, button_color.y, (button_color.x + button_color.w), (button_color.y + button_color.h));
+                    color_num = (color_num + 1) % COLOR_MAX;
+                    widget_object_init(&button_color, button_color.x, button_color.y, button_color.w, button_color.h, color_buf[color_num], 0);
+                    ui_init();
+                }
+            }
+            if (tp_dev.x[0] >= button_clear.x && tp_dev.x[0] <= (button_clear.x + button_clear.w))
+            {
+                if (tp_dev.y[0] >= button_clear.y && tp_dev.y[0] <= (button_clear.y + button_clear.h))
+                {
+                    letgo_scan(0, button_clear.x, button_clear.y, (button_clear.x + button_clear.w), (button_clear.y + button_clear.h));
+                    tli_draw_rectangle(0, 0, 800, 480, WHITE, 1);
+                    ui_init();
+                }
+            }
+            if (tp_dev.x[0] >= button_pixel.x && tp_dev.x[0] <= (button_pixel.x + button_pixel.w))
+            {
+                if (tp_dev.y[0] >= button_pixel.y && tp_dev.y[0] <= (button_pixel.y + button_pixel.h))
+                {
+                    letgo_scan(0, button_pixel.x, button_pixel.y, (button_pixel.x + button_pixel.w), (button_pixel.y + button_pixel.h));
+                    pixel_size++;
+                    if (pixel_size > PIXEL_SIZE_MAX) pixel_size = 1;
+                    widget_object_init(&button_pixel, button_pixel.x, button_pixel.y, button_pixel.w, button_pixel.h, button_pixel.color, pixel_size);
+                    ui_init();
+                }
+            }
+
+            if (tp_dev.x[0] >= button_eraser.x && tp_dev.x[0] <= (button_eraser.x + button_eraser.w))
+            {
+                if (tp_dev.y[0] >= button_eraser.y && tp_dev.y[0] <= (button_eraser.y + button_eraser.h))
+                {
+                    letgo_scan(0, button_eraser.x, button_eraser.y, (button_eraser.x + button_eraser.w), (button_eraser.y + button_eraser.h));
+                    button_eraser.value = !button_eraser.value;
+                    if (button_eraser.value)
+                    {
+                        widget_object_init(&button_eraser, 800 - 130 - 130, 480 - 80, 120, 70, BLACK, button_eraser.value);
+                    }
+                    else
+                    {
+                        widget_object_init(&button_eraser, 800 - 130 - 130, 480 - 80, 120, 70, BLUE, button_eraser.value);
+                    }
+
+                    ui_init();
+                }
+            }
+
+
+            if (!button_eraser.value)
+            {
+                tli_point_enlarge(tp_dev.x[0], tp_dev.y[0], color_buf[color_num], button_pixel.value);
+            }
+            else
+            {
+                tli_point_enlarge(tp_dev.x[0], tp_dev.y[0], WHITE, button_pixel.value);
+            }
+        }
+    }
+}
+
+INIT_COMPONENT_EXPORT(draw_panel_test);

+ 831 - 0
bsp/gd32/arm/gd32470z-lckfb/board/ports/drv_lcd.c

@@ -0,0 +1,831 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2025-05-23     godmial      Refactor to conform to RT-Thread coding style.
+ */
+
+#include <board.h>
+#include "gd32f4xx.h"
+#include "gd32f4xx_tli.h"
+#include "drv_lcd.h"
+#include "font.h"
+
+
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION)
+/* Keil MDK Compiler */
+uint16_t ltdc_lcd_framebuf0[800][480] __attribute__((at(LCD_FRAME_BUF_ADDR)));
+#elif defined(__GNUC__)
+/* GCC Compiler (used by RT-Thread) */
+uint16_t ltdc_lcd_framebuf0[10][10];
+#endif
+
+static void tli_gpio_config(void);
+static void tli_config(void);
+static void ipa_config(void);
+static void lcd_disp_en_config(void);
+static void lcd_disp_off(void);
+static void lcd_disp_on(void);
+
+
+/**
+ * @brief    Configure and initialize the LCD display.
+ *
+ * @note     This function enables display power, initializes TLI GPIO and IPA,
+ *           and sets up TLI and its layer configuration.
+ *
+ * @param    None
+ *
+ * @return   None
+ *
+ * @warning  Should be called during system initialization phase.
+ */
+void lcd_disp_config(void)
+{
+    lcd_disp_en_config();
+    lcd_disp_off();
+
+    /* configure the GPIO of TLI */
+    tli_gpio_config();
+    lcd_disp_on();
+
+    tli_config();
+    tli_layer_enable(LAYER0);
+    tli_reload_config(TLI_FRAME_BLANK_RELOAD_EN);
+    tli_enable();
+    ipa_config();
+}
+
+/**
+ * @brief    Initialize the TLI peripheral and layer configuration.
+ *
+ * @note     This function sets up the TLI clock, background color, timing parameters,
+ *           and layer 0 settings including framebuffer and blending configuration.
+ *
+ * @param    None
+ *
+ * @return   None
+ *
+ * @warning  Must be called after clock and GPIO initialization.
+ */
+static void tli_config(void)
+{
+    tli_parameter_struct       tli_init_struct;
+    tli_layer_parameter_struct tli_layer_init_struct;
+
+    rcu_periph_clock_enable(RCU_TLI);
+    tli_gpio_config();
+    /* configure PLLSAI to generate TLI clock */
+    // if(ERROR == rcu_pllsai_config(216, 2, 3)){
+    if (ERROR == rcu_pllsai_config(192, 2, 3))
+    {
+        while (1);
+    }
+    rcu_tli_clock_div_config(RCU_PLLSAIR_DIV2);
+
+    rcu_osci_on(RCU_PLLSAI_CK);
+
+    if (ERROR == rcu_osci_stab_wait(RCU_PLLSAI_CK))
+    {
+        while (1);
+    }
+
+    /* configure TLI parameter struct */
+    tli_init_struct.signalpolarity_hs      = TLI_HSYN_ACTLIVE_LOW;
+    tli_init_struct.signalpolarity_vs      = TLI_VSYN_ACTLIVE_LOW;
+    tli_init_struct.signalpolarity_de      = TLI_DE_ACTLIVE_LOW;
+    tli_init_struct.signalpolarity_pixelck = TLI_PIXEL_CLOCK_TLI;
+    /* LCD display timing configuration */
+    tli_init_struct.synpsz_hpsz   = HORIZONTAL_SYNCHRONOUS_PULSE - 1;
+    tli_init_struct.synpsz_vpsz   = VERTICAL_SYNCHRONOUS_PULSE - 1;
+    tli_init_struct.backpsz_hbpsz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH - 1;
+    tli_init_struct.backpsz_vbpsz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH - 1;
+    tli_init_struct.activesz_hasz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH + ACTIVE_WIDTH - 1;
+    tli_init_struct.activesz_vasz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH + ACTIVE_HEIGHT - 1;
+    tli_init_struct.totalsz_htsz  = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH + ACTIVE_WIDTH + HORIZONTAL_FRONT_PORCH - 1;
+    tli_init_struct.totalsz_vtsz  = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH + ACTIVE_HEIGHT + VERTICAL_FRONT_PORCH - 1;
+    /* configure LCD background R,G,B values */
+    tli_init_struct.backcolor_red   = 0xFF;
+    tli_init_struct.backcolor_green = 0xFF;
+    tli_init_struct.backcolor_blue  = 0xFF;
+    tli_init(&tli_init_struct);
+
+#if 1
+    /* TLI layer0 configuration */
+    /* TLI window size configuration */
+    tli_layer_init_struct.layer_window_leftpos   = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH;
+    tli_layer_init_struct.layer_window_rightpos  = (ACTIVE_WIDTH + HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH - 1);
+    tli_layer_init_struct.layer_window_toppos    = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH;
+    tli_layer_init_struct.layer_window_bottompos = (ACTIVE_HEIGHT + VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH - 1);
+    /* TLI window pixel format configuration */
+    tli_layer_init_struct.layer_ppf = LAYER_PPF_RGB565;
+    /* TLI window specified alpha configuration */
+    tli_layer_init_struct.layer_sa = 255;
+    /* TLI layer default alpha R,G,B value configuration */
+    tli_layer_init_struct.layer_default_blue  = 0x00;
+    tli_layer_init_struct.layer_default_green = 0x00;
+    tli_layer_init_struct.layer_default_red   = 0x00;
+    tli_layer_init_struct.layer_default_alpha = 0x00;
+    /* TLI window blend configuration */
+    tli_layer_init_struct.layer_acf1 = LAYER_ACF1_SA;
+    tli_layer_init_struct.layer_acf2 = LAYER_ACF2_SA;
+    /* TLI layer frame buffer base address configuration */
+    tli_layer_init_struct.layer_frame_bufaddr           = (uint32_t)ltdc_lcd_framebuf0;
+    tli_layer_init_struct.layer_frame_line_length       = ((ACTIVE_WIDTH * 2) + 3);
+    tli_layer_init_struct.layer_frame_buf_stride_offset = (ACTIVE_WIDTH * 2);
+    tli_layer_init_struct.layer_frame_total_line_number = ACTIVE_HEIGHT;
+    tli_layer_init(LAYER0, &tli_layer_init_struct);
+    tli_dither_config(TLI_DITHER_ENABLE);
+#endif
+}
+
+/**
+ * @brief    Initialize the IPA peripheral.
+ *
+ * @note     Enable clock and interrupt for the IPA module.
+ *
+ * @param    None
+ *
+ * @return   None
+ */
+static void ipa_config(void)
+{
+    rcu_periph_clock_enable(RCU_IPA);
+    nvic_irq_enable(IPA_IRQn, 0, 2);
+}
+
+/**
+ * @brief    Configure the GPIO pins used for TLI display.
+ *
+ * @note     Includes alternate function mapping and output mode setup
+ *           for RGB and sync signals.
+ *
+ * @param    None
+ *
+ * @return   None
+ */
+static void tli_gpio_config(void)
+{
+    /* enable the periphral clock */
+    rcu_periph_clock_enable(RCU_GPIOA);
+    rcu_periph_clock_enable(RCU_GPIOB);
+    rcu_periph_clock_enable(RCU_GPIOC);
+    rcu_periph_clock_enable(RCU_GPIOD);
+    rcu_periph_clock_enable(RCU_GPIOF);
+    rcu_periph_clock_enable(RCU_GPIOG);
+
+    /* configure HSYNC(PC6), VSYNC(PA4), PCLK(PG7), DE(PF10) */
+    /* configure LCD_R7(PG6), LCD_R6(PA8), LCD_R5(PA12), LCD_R4(PA11), LCD_R3(PB0),
+                 LCD_G7(PD3), LCD_G6(PC7), LCD_G5(PB11), LCD_G4(PB10), LCD_G3(PG10), LCD_G2(PA6),
+                 LCD_B7(PB9), LCD_B6(PB8), LCD_B5(PA3), LCD_B4(PG12), LCD_B3(PG11) */
+    gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_3);
+    gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_4);
+    gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_6);
+    gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_8);
+    gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_11);
+    gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_12);
+
+    gpio_af_set(GPIOB, GPIO_AF_9, GPIO_PIN_0);
+    gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_8);
+    gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_9);
+    gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_10);
+    gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_11);
+
+    gpio_af_set(GPIOC, GPIO_AF_14, GPIO_PIN_6);
+    gpio_af_set(GPIOC, GPIO_AF_14, GPIO_PIN_7);
+
+    gpio_af_set(GPIOD, GPIO_AF_14, GPIO_PIN_3);
+
+    gpio_af_set(GPIOF, GPIO_AF_14, GPIO_PIN_10);
+
+    gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_6);
+    gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_7);
+    gpio_af_set(GPIOG, GPIO_AF_9, GPIO_PIN_10);
+    gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_11);
+    gpio_af_set(GPIOG, GPIO_AF_9, GPIO_PIN_12);
+
+    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_8 | GPIO_PIN_11 | GPIO_PIN_12);
+    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_8 | GPIO_PIN_11 | GPIO_PIN_12);
+
+    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11);
+    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11);
+
+    gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6 | GPIO_PIN_7);
+    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
+
+    gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
+    gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
+
+    gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10);
+    gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
+
+    gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
+    gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
+}
+
+/**
+ * @brief    Configure the GPIO pin for DISP enable control.
+ *
+ * @note     This function enables the clock for GPIOD and sets up pin 13
+ *           as push-pull output to control the display on/off signal.
+ *
+ * @param    None
+ *
+ * @return   None
+ *
+ * @warning  Must be called before attempting to control the LCD display.
+ */
+static void lcd_disp_en_config(void)
+{
+    /* enable the periphral clock */
+    rcu_periph_clock_enable(RCU_GPIOD);
+    gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_13);
+    gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
+}
+
+/**
+ * @brief    Turn off the LCD display by resetting the DISP GPIO.
+ *
+ * @note     This function clears the DISP control pin to disable
+ *           the LCD backlight or power depending on hardware design.
+ *
+ * @param    None
+ *
+ * @return   None
+ *
+ * @warning  Only valid if the DISP GPIO has been previously configured.
+ */
+static void lcd_disp_off(void)
+{
+    gpio_bit_reset(GPIOD, GPIO_PIN_13);
+}
+
+/**
+ * @brief    Turn on the LCD display by setting the DISP GPIO.
+ *
+ * @note     This function sets the DISP control pin to enable
+ *           the LCD backlight or power depending on hardware design.
+ *
+ * @param    None
+ *
+ * @return   None
+ *
+ * @warning  Only valid if the DISP GPIO has been previously configured.
+ */
+static void lcd_disp_on(void)
+{
+    gpio_bit_set(GPIOD, GPIO_PIN_13);
+}
+
+
+/**
+ * @brief    Draw a pixel on the LCD at specified coordinates.
+ *
+ * @note     This function writes a color value directly to the framebuffer.
+ *           Coordinates must be within the valid LCD dimensions.
+ *
+ * @param    x      Horizontal coordinate of the pixel.
+ * @param    y      Vertical coordinate of the pixel.
+ * @param    color  Color of the pixel in RGB565 format.
+ *
+ * @return   None
+ */
+void tli_draw_point(uint16_t x, uint16_t y, uint16_t color)
+{
+    *(ltdc_lcd_framebuf0[0] + (LCD_WIDTH * y + x)) = color;
+}
+
+/**
+ * @brief    Draw a straight line between two points.
+ *
+ * @note     Uses Bresenham's line drawing algorithm to connect two points.
+ *           Coordinates should be within LCD bounds.
+ *
+ * @param    sx      Start point X coordinate.
+ * @param    sy      Start point Y coordinate.
+ * @param    ex      End point X coordinate.
+ * @param    ey      End point Y coordinate.
+ * @param    color   Line color in RGB565 format.
+ *
+ * @return   None
+ */
+void tli_draw_line(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color)
+{
+    uint16_t t;
+    int      xerr = 0, yerr = 0, delta_x, delta_y, distance;
+    int      incx, incy, uRow, uCol;
+
+    delta_x = ex - sx;
+    delta_y = ey - sy;
+    uRow    = sx;
+    uCol    = sy;
+    if (delta_x > 0)
+        incx = 1;
+    else if (delta_x == 0)
+        incx = 0;
+    else
+    {
+        incx    = -1;
+        delta_x = -delta_x;
+    }
+    if (delta_y > 0)
+        incy = 1;
+    else if (delta_y == 0)
+        incy = 0;
+    else
+    {
+        incy    = -1;
+        delta_y = -delta_y;
+    }
+    if (delta_x > delta_y)
+        distance = delta_x;
+    else
+        distance = delta_y;
+    for (t = 0; t <= distance + 1; t++)
+    {
+        tli_draw_point(uRow, uCol, color);
+        xerr += delta_x;
+        yerr += delta_y;
+        if (xerr > distance)
+        {
+            xerr -= distance;
+            uRow += incx;
+        }
+        if (yerr > distance)
+        {
+            yerr -= distance;
+            uCol += incy;
+        }
+    }
+}
+/**
+ * @brief    Draw a rectangle on the screen, optionally filled.
+ *
+ * @note     The rectangle is defined by top-left and bottom-right corners.
+ *           If fill is set to 1, the rectangle will be filled with the color.
+ *
+ * @param    sx      X coordinate of the top-left corner.
+ * @param    sy      Y coordinate of the top-left corner.
+ * @param    ex      X coordinate of the bottom-right corner.
+ * @param    ey      Y coordinate of the bottom-right corner.
+ * @param    color   Color of the rectangle in RGB565 format.
+ * @param    fill    Fill mode: 1 = filled, 0 = only borders.
+ *
+ * @return   None
+ */
+void tli_draw_rectangle(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color, uint16_t fill)
+{
+    int i = 0, j = 0;
+    if (fill)
+    {
+        for (i = sx; i < ex; i++)
+        {
+            for (j = sy; j < ey; j++)
+            {
+                tli_draw_point(i, j, color);
+            }
+        }
+    }
+    else
+    {
+        tli_draw_line(sx, sy, ex, sy, color);
+        tli_draw_line(sx, sy, sx, ey, color);
+        tli_draw_line(sx, ey, ex, ey, color);
+        tli_draw_line(ex, sy, ex, ey, color);
+    }
+}
+
+/**
+ * @brief    Draw eight symmetric points of a circle.
+ *
+ * @note     This function is used internally to draw points in all eight
+ *           symmetrical positions around a circle center.
+ *
+ * @param    xc      X coordinate of the circle center.
+ * @param    yc      Y coordinate of the circle center.
+ * @param    x       Relative X offset from the center.
+ * @param    y       Relative Y offset from the center.
+ * @param    c       Color of the point in RGB565 format.
+ *
+ * @return   None
+ */
+
+static void _draw_circle_8(int xc, int yc, int x, int y, uint16_t c)
+{
+    tli_draw_point(xc + x, yc + y, c);
+
+    tli_draw_point(xc - x, yc + y, c);
+
+    tli_draw_point(xc + x, yc - y, c);
+
+    tli_draw_point(xc - x, yc - y, c);
+
+    tli_draw_point(xc + y, yc + x, c);
+
+    tli_draw_point(xc - y, yc + x, c);
+
+    tli_draw_point(xc + y, yc - x, c);
+
+    tli_draw_point(xc - y, yc - x, c);
+}
+
+/**
+ * @brief    Draw a circle on the screen with optional fill.
+ *
+ * @note     Uses the midpoint circle algorithm to render the circle.
+ *           When fill is enabled, the circle is drawn as a filled disk.
+ *
+ * @param    xc      X coordinate of the circle center.
+ * @param    yc      Y coordinate of the circle center.
+ * @param    c       Color of the circle in RGB565 format.
+ * @param    r       Radius of the circle.
+ * @param    fill    Fill mode: 1 = filled, 0 = outline only.
+ *
+ * @return   None
+ */
+void tli_draw_circle(int xc, int yc, uint16_t c, int r, int fill)
+{
+    int x = 0, y = r, yi, d;
+
+    d = 3 - 2 * r;
+
+    if (fill)
+    {
+        while (x <= y)
+        {
+            for (yi = x; yi <= y; yi++)
+                _draw_circle_8(xc, yc, x, yi, c);
+
+            if (d < 0)
+            {
+                d = d + 4 * x + 6;
+            }
+            else
+            {
+                d = d + 4 * (x - y) + 10;
+                y--;
+            }
+            x++;
+        }
+    }
+    else
+    {
+        while (x <= y)
+        {
+            _draw_circle_8(xc, yc, x, y, c);
+            if (d < 0)
+            {
+                d = d + 4 * x + 6;
+            }
+            else
+            {
+                d = d + 4 * (x - y) + 10;
+                y--;
+            }
+            x++;
+        }
+    }
+}
+
+/**
+ * @brief    Swap the values of two 16-bit unsigned integers.
+ *
+ * @note     This utility function is used internally to simplify sorting
+ *           or reordering logic, such as coordinate alignment.
+ *
+ * @param    a   Pointer to the first variable.
+ * @param    b   Pointer to the second variable.
+ *
+ * @return   None
+ */
+static void _swap(uint16_t *a, uint16_t *b)
+{
+    uint16_t tmp;
+    tmp = *a;
+    *a  = *b;
+    *b  = tmp;
+}
+
+/**
+ * @brief    Draw a triangle with optional fill.
+ *
+ * @note     The triangle is defined by three vertex points. When fill is set,
+ *           it is rendered as a filled triangle using scan-line rasterization.
+ *
+ * @param    x0      X coordinate of the first vertex.
+ * @param    y0      Y coordinate of the first vertex.
+ * @param    x1      X coordinate of the second vertex (typically the top).
+ * @param    y1      Y coordinate of the second vertex.
+ * @param    x2      X coordinate of the third vertex.
+ * @param    y2      Y coordinate of the third vertex.
+ * @param    color   Color of the triangle in RGB565 format.
+ * @param    fill    Fill mode: 1 = filled, 0 = outline only.
+ *
+ * @return   None
+ */
+void tli_draw_triangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color, uint16_t fill)
+{
+    uint16_t a, b, y, last;
+    int      dx01, dy01, dx02, dy02, dx12, dy12;
+    long     sa = 0;
+    long     sb = 0;
+
+    if (fill == 0)
+    {
+        tli_draw_line(x0, y0, x1, y1, color);
+        tli_draw_line(x1, y1, x2, y2, color);
+        tli_draw_line(x2, y2, x0, y0, color);
+    }
+    else
+    {
+        if (y0 > y1)
+        {
+            _swap(&y0, &y1);
+            _swap(&x0, &x1);
+        }
+        if (y1 > y2)
+        {
+            _swap(&y2, &y1);
+            _swap(&x2, &x1);
+        }
+        if (y0 > y1)
+        {
+            _swap(&y0, &y1);
+            _swap(&x0, &x1);
+        }
+        if (y0 == y2)
+        {
+            a = b = x0;
+            if (x1 < a)
+            {
+                a = x1;
+            }
+            else if (x1 > b)
+            {
+                b = x1;
+            }
+            if (x2 < a)
+            {
+                a = x2;
+            }
+            else if (x2 > b)
+            {
+                b = x2;
+            }
+            tli_draw_rectangle(a, y0, b, y0, color, 0);
+            return;
+        }
+        dx01 = x1 - x0;
+        dy01 = y1 - y0;
+        dx02 = x2 - x0;
+        dy02 = y2 - y0;
+        dx12 = x2 - x1;
+        dy12 = y2 - y1;
+
+        if (y1 == y2)
+        {
+            last = y1;
+        }
+        else
+        {
+            last = y1 - 1;
+        }
+        for (y = y0; y <= last; y++)
+        {
+            a   = x0 + sa / dy01;
+            b   = x0 + sb / dy02;
+            sa += dx01;
+            sb += dx02;
+            if (a > b)
+            {
+                _swap(&a, &b);
+            }
+            tli_draw_rectangle(a, y, b, y, color, 0);
+        }
+        sa = dx12 * (y - y1);
+        sb = dx02 * (y - y0);
+        for (; y <= y2; y++)
+        {
+            a   = x1 + sa / dy12;
+            b   = x0 + sb / dy02;
+            sa += dx12;
+            sb += dx02;
+            if (a > b)
+            {
+                _swap(&a, &b);
+            }
+
+            tli_draw_rectangle(a, y, b, y, color, 0);
+        }
+    }
+}
+
+
+/**
+ * @brief    Enlarge a single point by drawing a square block.
+ *
+ * @note     The enlarged point is drawn as a 2D cross pattern made of four
+ *           rectangles centered at (x, y) with specified magnification.
+ *
+ * @param    x         X coordinate of the center point.
+ * @param    y         Y coordinate of the center point.
+ * @param    color     Color to fill the enlarged point.
+ * @param    magnify   Enlargement factor (minimum value is 1).
+ *
+ * @return   None
+ */
+void tli_point_enlarge(uint16_t x, uint16_t y, uint16_t color, char magnify)
+{
+    tli_draw_rectangle(x - magnify, y - magnify, x, y, color, 1);
+
+    tli_draw_rectangle(x, y - magnify, x + magnify, y, color, 1);
+
+    tli_draw_rectangle(x - magnify, y, x, y + magnify, color, 1);
+
+    tli_draw_rectangle(x, y, x + magnify, y + magnify, color, 1);
+}
+
+/**
+ * @brief    Display a single ASCII character at the specified position.
+ *
+ * @note     Uses a fixed-size 16x8 font to render the character with optional
+ *           enlargement and overlay mode.
+ *
+ * @param    x      X coordinate of the character start position.
+ * @param    y      Y coordinate of the character start position.
+ * @param    fc     Foreground color.
+ * @param    bc     Background color.
+ * @param    num    ASCII character to display.
+ * @param    size   Enlargement factor (minimum 1).
+ * @param    mode   Overlay mode: 0 = non-overlay, 1 = overlay.
+ *
+ * @return   None
+ */
+void tli_show_char(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t num, uint8_t size, uint8_t mode)
+{
+    uint8_t  temp;
+    uint8_t  pos, t;
+    uint16_t x0 = 0;
+    uint16_t y0 = 0;
+    num         = num - ' ';
+
+    for (pos = 0; pos < 16; pos++)
+    {
+        temp = asc2_1608[num][pos];
+        for (t = 0; t < 16 / 2; t++)
+        {
+            if (!mode)
+            {
+                if (temp & 0x01)
+                    tli_point_enlarge(x + x0, y + y0, fc, size);
+                else
+                    tli_point_enlarge(x + x0, y + y0, bc, size);
+            }
+            else
+            {
+                if (temp & 0x01) tli_point_enlarge(x + x0, y + y0, fc, size);
+            }
+            temp >>= 1;
+            x0     = x0 + size;
+        }
+        x0 = 0;
+        y0 = y0 + size;
+    }
+}
+
+/**
+ * @brief    Display a null-terminated ASCII string on the screen.
+ *
+ * @note     Automatically handles line boundaries and skips illegal characters.
+ *
+ * @param    x      X coordinate of the start position.
+ * @param    y      Y coordinate of the start position.
+ * @param    fc     Foreground color.
+ * @param    bc     Background color.
+ * @param    size   Font enlargement factor (base size is 16x8).
+ * @param    p      Pointer to the string.
+ * @param    mode   Overlay mode: 0 = non-overlay, 1 = overlay.
+ *
+ * @return   None
+ */
+void tli_show_string(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t size, uint8_t *p, uint8_t mode)
+{
+    while ((*p <= '~') && (*p >= ' '))
+    {
+        if (x > (LCD_WIDTH - 1) || y > (LCD_HEIGHT - 1)) return;
+
+        tli_show_char(x, y, fc, bc, *p, size, mode);
+        x += 16 * size / 2;
+        p++;
+    }
+}
+
+
+/**
+ * @brief    Display a picture at a specified position on the screen.
+ *
+ * @note     The image data is expected to be in RGB565 format, with each pixel
+ *           occupying two consecutive bytes in the array.
+ *
+ * @param    x      X coordinate of the top-left corner.
+ * @param    y      Y coordinate of the top-left corner.
+ * @param    w      Width of the image in pixels.
+ * @param    h      Height of the image in pixels.
+ * @param    pic    Pointer to the image data array.
+ *
+ * @return   None
+ */
+void tli_show_picture(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const unsigned char pic[])
+{
+    uint16_t i, j;
+    uint32_t k  = 0;
+    uint16_t x0 = x, y0 = y;
+    for (i = y; i < h + y0; i++)
+    {
+        for (j = x; j < w + x0; j++)
+        {
+            tli_draw_point(j, i, pic[k * 2] << 8 | pic[k * 2 + 1]);
+            k++;
+        }
+    }
+}
+
+
+/**
+ * @brief    Draw a filled rounded rectangle button.
+ *
+ * @note     This function draws a button with four rounded corners and fills
+ *           the background. The radius must be less than half of the height.
+ *
+ * @param    x        X coordinate of the top-left corner.
+ * @param    y        Y coordinate of the top-left corner.
+ * @param    width    Width of the button.
+ * @param    height   Height of the button.
+ * @param    radius   Radius of the corners.
+ * @param    color    Fill color of the button.
+ *
+ * @return   None
+ */
+void tli_show_button(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t radius, uint16_t color)
+{
+    int i = 0;
+    int j = 0;
+
+
+    if (radius >= (height / 2)) return;
+
+
+    tli_draw_circle(x + radius, y + radius, color, radius, 1);
+    tli_draw_circle(x + width - radius - 1, y + radius, color, radius, 1);
+    tli_draw_circle(x + radius, y + height - radius - 1, color, radius, 1);
+    tli_draw_circle(x + width - radius - 1, y + height - radius - 1, color, radius, 1);
+
+    tli_draw_line(x + radius, y, x + width - radius - 1, y, color);
+    tli_draw_line(x + radius, y + height - 1, x + width - radius - 1, y + height - 1, color);
+    tli_draw_line(x, y + radius, x, y + height - radius - 1, color);
+    tli_draw_line(x + width - 1, y + radius, x + width - 1, y + height - radius - 1, color);
+
+    tli_draw_rectangle(x + radius, y + radius, x + width - radius, y + height - radius, color, 1);
+    tli_draw_rectangle(x + radius, y, x + width - radius, y + radius, color, 1);
+    tli_draw_rectangle(x, y + radius, x + width, y + height - radius, color, 1);
+    tli_draw_rectangle(x + radius, y + height - radius, x + width - radius, y + height, color, 1);
+}
+
+/**
+ * @brief    Draw a switch (toggle) component with visual state.
+ *
+ * @note     The switch has a rounded rectangle base with a circular knob
+ *           indicating on or off state. Automatically validates layout rules.
+ *
+ * @param    x           X coordinate of the top-left corner.
+ * @param    y           Y coordinate of the top-left corner.
+ * @param    width       Total width of the switch.
+ * @param    height      Total height of the switch.
+ * @param    on_color    Color of the switch when turned on.
+ * @param    off_color   Color of the switch when turned off.
+ * @param    sw          Switch state: 1 = on, 0 = off.
+ *
+ * @return   None
+ */
+void tli_show_switch(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t on_color, uint16_t off_color, char sw)
+{
+    int radius = height / 2 - 1;
+
+    if (width < 2 * (radius + 1)) return;
+
+    if (sw == 0)
+    {
+        tli_show_button(x, y, width, height, radius, off_color);
+        tli_draw_circle(x + radius, y + radius, WHITE, radius / 2, 1);
+    }
+    else
+    {
+        tli_show_button(x, y, width, height, radius, on_color);
+        tli_draw_circle(x + width - radius, y + radius, WHITE, radius / 2, 1);
+    }
+}
+
+

+ 98 - 0
bsp/gd32/arm/gd32470z-lckfb/board/ports/drv_lcd.h

@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2025-05-23     godmial      Refactor to conform to RT-Thread coding style.
+ */
+
+#ifndef __DRV_LCD_H__
+#define __DRV_LCD_H__
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#ifdef BSP_USING_SDRAM
+#include <sdram_port.h>
+#endif /* BSP_USING_SDRAM */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* LCD resolution and pixel format */
+#define LCD_WIDTH             800
+#define LCD_HEIGHT            480
+#define LCD_FB_BYTE_PER_PIXEL 1
+
+/* Timing parameters for horizontal synchronization */
+#define HORIZONTAL_SYNCHRONOUS_PULSE 10
+#define HORIZONTAL_BACK_PORCH        150
+#define ACTIVE_WIDTH                 800
+#define HORIZONTAL_FRONT_PORCH       15
+
+/* Timing parameters for vertical synchronization */
+#define VERTICAL_SYNCHRONOUS_PULSE 10
+#define VERTICAL_BACK_PORCH        140
+#define ACTIVE_HEIGHT              480
+#define VERTICAL_FRONT_PORCH       40
+
+/* Framebuffer address in SDRAM */
+#define LCD_FRAME_BUF_ADDR 0xC0000000 /* SDRAM address for LCD frame buffer */
+
+/* Pen color definitions (RGB565) */
+#define WHITE   0xFFFF /* White */
+#define BLACK   0x0000 /* Black */
+#define BLUE    0x001F /* Blue */
+#define BRED    0xF81F /* Blue-Red */
+#define GRED    0xFFE0 /* Green-Red */
+#define GBLUE   0x07FF /* Green-Blue */
+#define RED     0xF800 /* Red */
+#define MAGENTA 0xF81F /* Magenta */
+#define GREEN   0x07E0 /* Green */
+#define CYAN    0x7FFF /* Cyan */
+#define YELLOW  0xFFE0 /* Yellow */
+#define BROWN   0xBC40 /* Brown */
+#define BRRED   0xFC07 /* Brownish red */
+#define GRAY    0x8430 /* Gray */
+
+/* GUI color definitions */
+#define DARKBLUE   0x01CF /* Dark blue */
+#define LIGHTBLUE  0x7D7C /* Light blue */
+#define GRAYBLUE   0x5458 /* Grayish blue */
+#define LIGHTGREEN 0x841F /* Light green */
+#define LGRAY      0xC618 /* Light gray (panel background) */
+#define LGRAYBLUE  0xA651 /* Light gray-blue (layer color) */
+#define LBBLUE     0x2B12 /* Light brown-blue (selected item reverse color) */
+
+/* Frame buffer declaration based on compiler */
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION)
+/* Keil MDK Compiler */
+extern uint16_t ltdc_lcd_framebuf0[800][480] __attribute__((at(LCD_FRAME_BUF_ADDR)));
+#elif defined(__GNUC__)
+/* GCC Compiler (used by RT-Thread) */
+extern uint16_t ltdc_lcd_framebuf0[10][10]; /* Dummy for GCC compilation */
+#endif
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief    Configure the LCD display controller.
+ *
+ * @note     This function initializes display timing and output settings.
+ */
+void lcd_disp_config(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DRV_LCD_H__ */

+ 481 - 0
bsp/gd32/arm/gd32470z-lckfb/board/ports/drv_touch.c

@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2025-05-23     godmial      Refactor to conform to RT-Thread coding style.
+ */
+
+#include <board.h>
+#include <rthw.h>
+#include <rtthread.h>
+#include "drv_touch.h"
+#include "drv_lcd.h"
+
+#define DRV_DEBUG
+#define LOG_TAG "drv.touch"
+#include <drv_log.h>
+
+_m_tp_dev tp_dev;
+
+const uint16_t FT5206_TPX_TBL[5] = {FT_TP1_REG, FT_TP2_REG, FT_TP3_REG, FT_TP4_REG, FT_TP5_REG};
+uint8_t        g_gt_tnum         = 5; /**< Default number of supported touch points (5-point touch) */
+
+
+/**
+ * @brief Delay for a specified number of microseconds.
+ *
+ * @note This function uses the SysTick timer to implement microsecond delay by polling.
+ *
+ * @param _nus Number of microseconds to delay.
+ */
+void delay_us(uint32_t _nus)
+{
+    uint8_t  fac_us = 0;
+    uint32_t ticks;
+    uint32_t t_old, t_now, t_cnt = 0;
+    uint32_t reload = SysTick->LOAD;
+
+    fac_us = SystemCoreClock / 1000000;
+    ticks  = _nus * fac_us - fac_us * 7 / 20;
+    t_old  = SysTick->VAL;
+
+    while (1)
+    {
+        t_now = SysTick->VAL;
+
+        if (t_now < t_old)
+        {
+            t_cnt += t_old - t_now;
+        }
+        else
+        {
+            t_cnt += t_old + (reload - t_now);
+        }
+
+        if (t_cnt >= ticks)
+        {
+            break;
+        }
+
+        t_old = t_now;
+    };
+}
+
+
+/**
+ * @brief Delay function wrapper for touch operations.
+ *
+ * @param us Number of microseconds to delay.
+ */
+void touch_delay_1us(uint16_t us)
+{
+    delay_us(us);
+}
+
+/**
+ * @brief Delay to control I2C speed.
+ *
+ * @note Used between I2C signal toggles to ensure proper timing.
+ */
+void CT_Delay(void)
+{
+    touch_delay_1us(2);
+}
+
+/**
+ * @brief Initialize the I2C interface for the capacitive touch chip.
+ *
+ * @note Configures GPIO ports for SCL and SDA lines as outputs with pull-up resistors.
+ */
+void CT_IIC_Init(void)
+{
+    /* enable the led clock */
+    rcu_periph_clock_enable(SCL_RCU);
+    /* configure led GPIO port */
+    gpio_mode_set(SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, SCL_PIN);
+    gpio_output_options_set(SCL_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SCL_PIN);
+
+    rcu_periph_clock_enable(SDA_RCU);
+    gpio_mode_set(SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, SDA_PIN);
+    gpio_output_options_set(SDA_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SDA_PIN);
+}
+
+/**
+ * @brief Generate I2C start condition.
+ *
+ * @note Starts communication by pulling SDA low while SCL is high.
+ */
+void CT_IIC_Start(void)
+{
+    CT_SDA_OUT();
+    SDA_ON;
+    SCL_ON;
+    touch_delay_1us(30);
+    SDA_OFF;
+    CT_Delay();
+    SCL_OFF;
+}
+
+/**
+ * @brief Generate I2C stop condition.
+ *
+ * @note Ends communication by pulling SDA high while SCL is high.
+ */
+void CT_IIC_Stop(void)
+{
+    CT_SDA_OUT();
+    SCL_ON;
+    touch_delay_1us(30);
+    SDA_OFF;
+    CT_Delay();
+    SDA_ON;
+}
+
+/**
+ * @brief Wait for I2C ACK signal.
+ *
+ * @return 0 if ACK received successfully, 1 if timeout occurred.
+ *
+ * @warning If ACK is not received within 250 iterations, a stop condition is generated.
+ */
+uint8_t CT_IIC_Wait_Ack(void)
+{
+    uint8_t ucErrTime = 0;
+    CT_SDA_IN();
+    SDA_ON;
+    SCL_ON;
+    CT_Delay();
+    while (CT_READ_SDA)
+    {
+        ucErrTime++;
+        if (ucErrTime > 250)
+        {
+            CT_IIC_Stop();
+            return 1;
+        }
+        CT_Delay();
+    }
+    SCL_OFF;
+    return 0;
+}
+
+/**
+ * @brief Generate I2C ACK signal.
+ *
+ * @note This is used to acknowledge receipt of a byte in I2C communication.
+ */
+void CT_IIC_Ack(void)
+{
+    SCL_OFF;
+    CT_SDA_OUT();
+    CT_Delay();
+    SDA_OFF;
+    CT_Delay();
+    SCL_ON;
+    CT_Delay();
+    SCL_OFF;
+}
+
+/**
+ * @brief Generate I2C NACK signal.
+ *
+ * @note This is used to indicate the end of reading in I2C communication.
+ */
+void CT_IIC_NAck(void)
+{
+    SCL_OFF;
+    CT_SDA_OUT();
+    CT_Delay();
+    SDA_ON;
+    CT_Delay();
+    SCL_ON;
+    CT_Delay();
+    SCL_OFF;
+}
+
+
+/**
+ * @brief Send a byte over I2C.
+ *
+ * @param txd Byte to send.
+ *
+ * @note Sends 8 bits starting from the MSB over the SDA line.
+ */
+void CT_IIC_Send_Byte(uint8_t txd)
+{
+    uint8_t t;
+    CT_SDA_OUT();
+    SCL_OFF;
+    CT_Delay();
+    for (t = 0; t < 8; t++)
+    {
+        if ((txd & 0x80) >> 7)
+        {
+            gpio_bit_set(SDA_PORT, SDA_PIN);
+        }
+        else
+        {
+            gpio_bit_reset(SDA_PORT, SDA_PIN);
+        }
+
+        txd <<= 1;
+        SCL_ON;
+        CT_Delay();
+        SCL_OFF;
+        CT_Delay();
+    }
+}
+
+/**
+ * @brief Read a byte over I2C.
+ *
+ * @param ack If 1, send ACK after receiving; if 0, send NACK.
+ *
+ * @return The received byte.
+ */
+uint8_t CT_IIC_Read_Byte(unsigned char ack)
+{
+    volatile uint8_t i, receive = 0;
+    CT_SDA_IN();
+    touch_delay_1us(30);
+    for (i = 0; i < 8; i++)
+    {
+        SCL_OFF;
+        CT_Delay();
+        SCL_ON;
+        receive <<= 1;
+
+        if (CT_READ_SDA)
+            receive++;
+    }
+
+    if (!ack)
+        CT_IIC_NAck();
+    else
+        CT_IIC_Ack();
+    return receive;
+}
+
+/**
+ * @brief Write data to FT5206 register.
+ *
+ * @param reg Register address.
+ * @param buf Pointer to data buffer.
+ * @param len Length of data to write.
+ *
+ * @return 0 if successful, non-zero if any write fails.
+ */
+uint8_t FT5206_WR_Reg(uint16_t reg, uint8_t *buf, uint8_t len)
+{
+    uint8_t i;
+    uint8_t ret = 0;
+    CT_IIC_Start();
+    CT_IIC_Send_Byte(FT_CMD_WR);
+    CT_IIC_Wait_Ack();
+    CT_IIC_Send_Byte(reg & 0XFF);
+    CT_IIC_Wait_Ack();
+    for (i = 0; i < len; i++)
+    {
+        CT_IIC_Send_Byte(buf[i]);
+        ret = CT_IIC_Wait_Ack();
+        if (ret)
+            break;
+    }
+    CT_IIC_Stop();
+    return ret;
+}
+
+/**
+ * @brief Read data from FT5206 register.
+ *
+ * @param reg Register address.
+ * @param buf Pointer to buffer to store read data.
+ * @param len Number of bytes to read.
+ */
+void FT5206_RD_Reg(uint16_t reg, uint8_t *buf, uint8_t len)
+{
+    uint8_t i;
+    CT_IIC_Start();
+    CT_IIC_Send_Byte(FT_CMD_WR);
+    CT_IIC_Wait_Ack();
+    CT_IIC_Send_Byte(reg & 0XFF);
+    CT_IIC_Wait_Ack();
+    CT_IIC_Start();
+    CT_IIC_Send_Byte(FT_CMD_RD);
+    CT_IIC_Wait_Ack();
+    for (i = 0; i < len; i++)
+    {
+        buf[i] = CT_IIC_Read_Byte(i == (len - 1) ? 0 : 1);
+    }
+    CT_IIC_Stop();
+}
+
+/**
+ * @brief Initialize the FT5206 touch screen controller.
+ *
+ * @note Initializes I2C, sets operational modes and touch sensitivity.
+ *
+ * @return 0 if initialization is successful.
+ */
+uint8_t FT5206_Init(void)
+{
+    uint8_t temp[5];
+    /* enable the led clock */
+    rcu_periph_clock_enable(INT_RCU);
+    /* configure led GPIO port */
+    gpio_mode_set(INT_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, INT_PIN);
+
+
+    CT_IIC_Init();
+
+    FT5206_WR_Reg(FT_DEVIDE_MODE, temp, 1);
+    FT5206_WR_Reg(FT_ID_G_MODE, temp, 1);
+    temp[0] = 22;
+    FT5206_WR_Reg(FT_ID_G_THGROUP, temp, 1);
+    temp[0] = 12;
+    FT5206_WR_Reg(FT_ID_G_PERIODACTIVE, temp, 1);
+
+    FT5206_RD_Reg(FT_ID_G_LIB_VERSION, &temp[0], 2);
+    printf("CTP ID:%x\r\n", ((uint16_t)temp[0] << 8) + temp[1]);
+    return 0;
+}
+
+/**
+ * @brief Scan the touch screen using polling.
+ *
+ * @param mode 0 for normal scan mode.
+ *
+ * @return 1 if a touch is detected, 0 otherwise.
+ */
+uint8_t FT5206_Scan(uint8_t mode)
+{
+    uint8_t        buf[4];
+    uint8_t        i   = 0;
+    uint8_t        res = 0;
+    uint8_t        temp;
+    uint16_t       tempsta;
+    static uint8_t t = 0;
+    t++;
+    if ((t % 10) == 0 || t < 10)
+    {
+        FT5206_RD_Reg(FT_REG_NUM_FINGER, &mode, 1);
+        if ((mode & 0XF) && ((mode & 0XF) <= g_gt_tnum))
+        {
+            temp                    = 0XFF << (mode & 0XF);
+            tempsta                 = tp_dev.sta;
+            tp_dev.sta              = (~temp) | TP_PRES_DOWN | TP_CATH_PRES;
+            tp_dev.x[g_gt_tnum - 1] = tp_dev.x[0];
+            tp_dev.y[g_gt_tnum - 1] = tp_dev.y[0];
+
+            for (i = 0; i < g_gt_tnum; i++)
+            {
+                if (tp_dev.sta & (1 << i))
+                {
+                    FT5206_RD_Reg(FT5206_TPX_TBL[i], buf, 4);
+                    if (tp_dev.touchtype & 0X01)
+                    {
+                        tp_dev.y[i] = ((uint16_t)(buf[0] & 0X0F) << 8) + buf[1];
+                        tp_dev.x[i] = ((uint16_t)(buf[2] & 0X0F) << 8) + buf[3];
+                    }
+                    else
+                    {
+                        tp_dev.x[i] = (((uint16_t)(buf[0] & 0X0F) << 8) + buf[1]);
+                        tp_dev.y[i] = ((uint16_t)(buf[2] & 0X0F) << 8) + buf[3];
+                    }
+                }
+            }
+            res = 1;
+            if (tp_dev.x[0] > ACTIVE_WIDTH || tp_dev.y[0] > ACTIVE_HEIGHT)
+            {
+                if ((mode & 0XF) > 1)
+                {
+                    tp_dev.x[0] = tp_dev.x[1];
+                    tp_dev.y[0] = tp_dev.y[1];
+                    t           = 0;
+                }
+                else
+                {
+                    tp_dev.x[0] = tp_dev.x[g_gt_tnum - 1];
+                    tp_dev.y[0] = tp_dev.y[g_gt_tnum - 1];
+                    mode        = 0X80;
+                    tp_dev.sta  = tempsta;
+                }
+            }
+            else
+                t = 0;
+        }
+    }
+
+    if ((mode & 0X1F) == 0)
+    {
+        if (tp_dev.sta & TP_PRES_DOWN)
+        {
+            tp_dev.sta &= ~TP_PRES_DOWN;
+        }
+        else
+        {
+            tp_dev.x[0]  = 0xffff;
+            tp_dev.y[0]  = 0xffff;
+            tp_dev.sta  &= 0XE0;
+        }
+    }
+
+    if (t > 240)
+        t = 10;
+    return res;
+}
+
+/**
+ * @brief Detect touch release by monitoring a specific touch point.
+ *
+ * @param contact Index of touch contact to check.
+ * @param sx Start X coordinate.
+ * @param sy Start Y coordinate.
+ * @param ex End X coordinate.
+ * @param ey End Y coordinate.
+ *
+ * @note Returns when the touch point leaves the specified rectangle.
+ */
+void letgo_scan(uint16_t contact, uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey)
+{
+    while (FT5206_Scan(0))
+    {
+        if (tp_dev.x[contact] <= sx || tp_dev.x[contact] >= ex)
+        {
+            return;
+        }
+
+        if (tp_dev.y[contact] <= sy && tp_dev.y[contact] >= ey)
+        {
+            return;
+        }
+    }
+}
+
+/**
+ * @brief Example application to test the touch screen functionality.
+ *
+ * @return Always returns 0.
+ *
+ * @warning This function runs an infinite loop and is intended for manual test only.
+ */
+int touch_test(void)
+{
+    int touch_state = 0;
+    FT5206_Init();
+
+    while (1)
+    {
+        touch_state = FT5206_Scan(0);
+
+        if (touch_state == 1)
+        {
+            rt_kprintf("touch\r\n");
+        }
+        rt_thread_mdelay(10);
+    }
+}
+MSH_CMD_EXPORT(touch_test, touch test)

+ 187 - 0
bsp/gd32/arm/gd32470z-lckfb/board/ports/drv_touch.h

@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2025-05-23     godmial      Refactor to conform to RT-Thread coding style.
+ */
+
+#ifndef __TOUCH_H__
+#define __TOUCH_H__
+
+#include "stdio.h"
+#include "string.h"
+#include "gd32f4xx.h"
+
+
+#define SCL_RCU    RCU_GPIOB
+#define SCL_PORT   GPIOB
+#define SCL_PIN    GPIO_PIN_6
+#define SCL_ON     gpio_bit_set(SCL_PORT, SCL_PIN)
+#define SCL_OFF    gpio_bit_reset(SCL_PORT, SCL_PIN)
+#define SCL_TOGGLE gpio_bit_toggle(SCL_PORT, SCL_PIN)
+
+#define SDA_RCU    RCU_GPIOB
+#define SDA_PORT   GPIOB
+#define SDA_PIN    GPIO_PIN_7
+#define SDA_ON     gpio_bit_set(SDA_PORT, SDA_PIN)
+#define SDA_OFF    gpio_bit_reset(SDA_PORT, SDA_PIN)
+#define SDA_TOGGLE gpio_bit_toggle(SDA_PORT, SDA_PIN)
+
+/* IO direction settings */
+#define CT_SDA_IN()  gpio_mode_set(SCL_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, SDA_PIN);  //{GPIOF->MODER&=~(3<<(2*11));GPIOF->MODER|=0<<2*11;}	//PF11输入模式
+#define CT_SDA_OUT() gpio_mode_set(SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, SDA_PIN); //{GPIOF->MODER&=~(3<<(2*11));GPIOF->MODER|=1<<2*11;} 	//PF11输出模式
+/* IO operations */
+#define CT_IIC_SCL                                            // PBout(0) 	//SCL
+#define CT_IIC_SDA(val) ((val) == 1 ? SDA_ON : SDA_OFF)       // PFout(11) //SDA
+#define CT_READ_SDA     gpio_input_bit_get(SDA_PORT, SDA_PIN) // PFin(11)  //输入SDA
+/* Reset and interrupt pin definitions */
+#define RST_RCU    RCU_GPIOD
+#define RST_PORT   GPIOD
+#define RST_PIN    GPIO_PIN_12
+#define RST_ON     gpio_bit_set(RST_PORT, RST_PIN);
+#define RST_OFF    gpio_bit_reset(RST_PORT, RST_PIN);
+#define RST_TOGGLE gpio_bit_toggle(RST_PORT, RST_PIN);
+
+#define INT_RCU    RCU_GPIOD
+#define INT_PORT   GPIOD
+#define INT_PIN    GPIO_PIN_11
+#define INT_ON     gpio_bit_set(INT_PORT, INT_PIN);
+#define INT_OFF    gpio_bit_reset(INT_PORT, INT_PIN);
+#define INT_TOGGLE gpio_bit_toggle(INT_PORT, INT_PIN);
+
+/* I2C command definitions */
+#define FT_CMD_WR 0X70 /**< FT5206 write command */
+#define FT_CMD_RD 0X71 /**< FT5206 read command */
+/* FT5206 register definitions */
+#define FT_DEVIDE_MODE       0x00 /**< Mode control register */
+#define FT_REG_NUM_FINGER    0x02 /**< Touch status register */
+#define FT_TP1_REG           0x03 /**< Touch point 1 data */
+#define FT_TP2_REG           0x09 /**< Touch point 2 data */
+#define FT_TP3_REG           0x0F /**< Touch point 3 data */
+#define FT_TP4_REG           0x15 /**< Touch point 4 data */
+#define FT_TP5_REG           0x1B /**< Touch point 5 data */
+#define FT_ID_G_LIB_VERSION  0xA1 /**< Firmware version */
+#define FT_ID_G_MODE         0xA4 /**< Interrupt mode control */
+#define FT_ID_G_THGROUP      0x80 /**< Touch sensitivity */
+#define FT_ID_G_PERIODACTIVE 0x88 /**< Active period register */
+
+#define TP_PRES_DOWN 0x80         /**< Touch pressed flag */
+#define TP_CATH_PRES 0x40         /**< Key press detected flag */
+#define CT_MAX_TOUCH 5            /**< Maximum number of supported touch points */
+/**
+ * @brief Touch point device structure.
+ */
+typedef struct
+{
+    uint16_t x[CT_MAX_TOUCH]; /**< X coordinates of touch points */
+    uint16_t y[CT_MAX_TOUCH]; /**< Y coordinates of touch points */
+    uint8_t  sta;             /**< Touch status flag */
+    float    xfac;            /**< X axis scaling factor */
+    float    yfac;            /**< Y axis scaling factor */
+    short    xoff;            /**< X axis offset */
+    short    yoff;            /**< Y axis offset */
+    uint8_t  touchtype;       /**< Touch type flag */
+} _m_tp_dev;
+
+extern _m_tp_dev tp_dev;
+
+/**
+ * @brief Initialize I2C GPIO lines.
+ */
+void CT_IIC_Init(void);
+
+/**
+ * @brief Generate I2C start condition.
+ */
+void CT_IIC_Start(void);
+
+/**
+ * @brief Generate I2C stop condition.
+ */
+void CT_IIC_Stop(void);
+
+/**
+ * @brief Send a byte over I2C.
+ *
+ * @param txd Byte to send.
+ */
+void CT_IIC_Send_Byte(uint8_t txd);
+
+/**
+ * @brief Read a byte over I2C.
+ *
+ * @param ack 1 to send ACK after read, 0 for NACK.
+ *
+ * @return The received byte.
+ */
+uint8_t CT_IIC_Read_Byte(unsigned char ack);
+
+/**
+ * @brief Wait for I2C ACK.
+ *
+ * @return 0 on success, non-zero on timeout.
+ */
+uint8_t CT_IIC_Wait_Ack(void);
+
+/**
+ * @brief Generate I2C ACK.
+ */
+void CT_IIC_Ack(void);
+
+/**
+ * @brief Generate I2C NACK.
+ */
+void CT_IIC_NAck(void);
+
+/**
+ * @brief Write data to FT5206 register.
+ *
+ * @param reg Register address.
+ * @param buf Pointer to data.
+ * @param len Number of bytes to write.
+ *
+ * @return 0 if success, non-zero otherwise.
+ */
+uint8_t FT5206_WR_Reg(uint16_t reg, uint8_t *buf, uint8_t len);
+
+/**
+ * @brief Read data from FT5206 register.
+ *
+ * @param reg Register address.
+ * @param buf Buffer to store data.
+ * @param len Number of bytes to read.
+ */
+void FT5206_RD_Reg(uint16_t reg, uint8_t *buf, uint8_t len);
+
+/**
+ * @brief Initialize the FT5206 touch controller.
+ *
+ * @return 0 if successful.
+ */
+uint8_t FT5206_Init(void);
+
+/**
+ * @brief Poll the FT5206 for touch input.
+ *
+ * @param mode Scan mode.
+ *
+ * @return 1 if touch detected, 0 otherwise.
+ */
+uint8_t FT5206_Scan(uint8_t mode);
+
+/**
+ * @brief Wait until touch contact leaves specified area.
+ *
+ * @param contact Touch point index.
+ * @param sx Start X coordinate.
+ * @param sy Start Y coordinate.
+ * @param ex End X coordinate.
+ * @param ey End Y coordinate.
+ */
+void letgo_scan(uint16_t contact, uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey);
+
+
+#endif

+ 112 - 0
bsp/gd32/arm/gd32470z-lckfb/board/ports/font.h

@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2025-05-23     godmial      Refactor to conform to RT-Thread coding style.
+ */
+
+#ifndef __FONT_H__
+#define __FONT_H__
+
+const unsigned char asc2_1608[95][16] = {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*" ",0*/
+    {0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00}, /*"!",1*/
+    {0x00, 0x48, 0x6C, 0x24, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*""",2*/
+    {0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0x7F, 0x12, 0x12, 0x12, 0x7F, 0x12, 0x12, 0x12, 0x00, 0x00}, /*"#",3*/
+    {0x00, 0x00, 0x08, 0x1C, 0x2A, 0x2A, 0x0A, 0x0C, 0x18, 0x28, 0x28, 0x2A, 0x2A, 0x1C, 0x08, 0x08}, /*"$",4*/
+    {0x00, 0x00, 0x00, 0x22, 0x25, 0x15, 0x15, 0x15, 0x2A, 0x58, 0x54, 0x54, 0x54, 0x22, 0x00, 0x00}, /*"%",5*/
+    {0x00, 0x00, 0x00, 0x0C, 0x12, 0x12, 0x12, 0x0A, 0x76, 0x25, 0x29, 0x11, 0x91, 0x6E, 0x00, 0x00}, /*"&",6*/
+    {0x00, 0x06, 0x06, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"'",7*/
+    {0x00, 0x40, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x40, 0x00}, /*"(",8*/
+    {0x00, 0x02, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x04, 0x02, 0x00}, /*")",9*/
+    {0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x6B, 0x1C, 0x1C, 0x6B, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00}, /*"*",10*/
+    {0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x7F, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00}, /*"+",11*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x04, 0x03}, /*",",12*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"-",13*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00}, /*".",14*/
+    {0x00, 0x00, 0x80, 0x40, 0x40, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00}, /*"/",15*/
+    {0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00}, /*"0",16*/
+    {0x00, 0x00, 0x00, 0x08, 0x0E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00, 0x00}, /*"1",17*/
+    {0x00, 0x00, 0x00, 0x3C, 0x42, 0x42, 0x42, 0x20, 0x20, 0x10, 0x08, 0x04, 0x42, 0x7E, 0x00, 0x00}, /*"2",18*/
+    {0x00, 0x00, 0x00, 0x3C, 0x42, 0x42, 0x20, 0x18, 0x20, 0x40, 0x40, 0x42, 0x22, 0x1C, 0x00, 0x00}, /*"3",19*/
+    {0x00, 0x00, 0x00, 0x20, 0x30, 0x28, 0x24, 0x24, 0x22, 0x22, 0x7E, 0x20, 0x20, 0x78, 0x00, 0x00}, /*"4",20*/
+    {0x00, 0x00, 0x00, 0x7E, 0x02, 0x02, 0x02, 0x1A, 0x26, 0x40, 0x40, 0x42, 0x22, 0x1C, 0x00, 0x00}, /*"5",21*/
+    {0x00, 0x00, 0x00, 0x38, 0x24, 0x02, 0x02, 0x1A, 0x26, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00}, /*"6",22*/
+    {0x00, 0x00, 0x00, 0x7E, 0x22, 0x22, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00}, /*"7",23*/
+    {0x00, 0x00, 0x00, 0x3C, 0x42, 0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x42, 0x3C, 0x00, 0x00}, /*"8",24*/
+    {0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x64, 0x58, 0x40, 0x40, 0x24, 0x1C, 0x00, 0x00}, /*"9",25*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00}, /*":",26*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x04}, /*";",27*/
+    {0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00}, /*"<",28*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"=",29*/
+    {0x00, 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00}, /*">",30*/
+    {0x00, 0x00, 0x00, 0x3C, 0x42, 0x42, 0x46, 0x40, 0x20, 0x10, 0x10, 0x00, 0x18, 0x18, 0x00, 0x00}, /*"?",31*/
+    {0x00, 0x00, 0x00, 0x1C, 0x22, 0x5A, 0x55, 0x55, 0x55, 0x55, 0x2D, 0x42, 0x22, 0x1C, 0x00, 0x00}, /*"@",32*/
+    {0x00, 0x00, 0x00, 0x08, 0x08, 0x18, 0x14, 0x14, 0x24, 0x3C, 0x22, 0x42, 0x42, 0xE7, 0x00, 0x00}, /*"A",33*/
+    {0x00, 0x00, 0x00, 0x1F, 0x22, 0x22, 0x22, 0x1E, 0x22, 0x42, 0x42, 0x42, 0x22, 0x1F, 0x00, 0x00}, /*"B",34*/
+    {0x00, 0x00, 0x00, 0x7C, 0x42, 0x42, 0x01, 0x01, 0x01, 0x01, 0x01, 0x42, 0x22, 0x1C, 0x00, 0x00}, /*"C",35*/
+    {0x00, 0x00, 0x00, 0x1F, 0x22, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x22, 0x1F, 0x00, 0x00}, /*"D",36*/
+    {0x00, 0x00, 0x00, 0x3F, 0x42, 0x12, 0x12, 0x1E, 0x12, 0x12, 0x02, 0x42, 0x42, 0x3F, 0x00, 0x00}, /*"E",37*/
+    {0x00, 0x00, 0x00, 0x3F, 0x42, 0x12, 0x12, 0x1E, 0x12, 0x12, 0x02, 0x02, 0x02, 0x07, 0x00, 0x00}, /*"F",38*/
+    {0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x01, 0x01, 0x01, 0x71, 0x21, 0x22, 0x22, 0x1C, 0x00, 0x00}, /*"G",39*/
+    {0x00, 0x00, 0x00, 0xE7, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x42, 0xE7, 0x00, 0x00}, /*"H",40*/
+    {0x00, 0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00, 0x00}, /*"I",41*/
+    {0x00, 0x00, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x0F}, /*"J",42*/
+    {0x00, 0x00, 0x00, 0x77, 0x22, 0x12, 0x0A, 0x0E, 0x0A, 0x12, 0x12, 0x22, 0x22, 0x77, 0x00, 0x00}, /*"K",43*/
+    {0x00, 0x00, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x42, 0x7F, 0x00, 0x00}, /*"L",44*/
+    {0x00, 0x00, 0x00, 0x77, 0x36, 0x36, 0x36, 0x36, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x6B, 0x00, 0x00}, /*"M",45*/
+    {0x00, 0x00, 0x00, 0xE3, 0x46, 0x46, 0x4A, 0x4A, 0x52, 0x52, 0x52, 0x62, 0x62, 0x47, 0x00, 0x00}, /*"N",46*/
+    {0x00, 0x00, 0x00, 0x1C, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1C, 0x00, 0x00}, /*"O",47*/
+    {0x00, 0x00, 0x00, 0x3F, 0x42, 0x42, 0x42, 0x42, 0x3E, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x00}, /*"P",48*/
+    {0x00, 0x00, 0x00, 0x1C, 0x22, 0x41, 0x41, 0x41, 0x41, 0x41, 0x4D, 0x53, 0x32, 0x1C, 0x60, 0x00}, /*"Q",49*/
+    {0x00, 0x00, 0x00, 0x3F, 0x42, 0x42, 0x42, 0x3E, 0x12, 0x12, 0x22, 0x22, 0x42, 0xC7, 0x00, 0x00}, /*"R",50*/
+    {0x00, 0x00, 0x00, 0x7C, 0x42, 0x42, 0x02, 0x04, 0x18, 0x20, 0x40, 0x42, 0x42, 0x3E, 0x00, 0x00}, /*"S",51*/
+    {0x00, 0x00, 0x00, 0x7F, 0x49, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00}, /*"T",52*/
+    {0x00, 0x00, 0x00, 0xE7, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00, 0x00}, /*"U",53*/
+    {0x00, 0x00, 0x00, 0xE7, 0x42, 0x42, 0x22, 0x24, 0x24, 0x14, 0x14, 0x18, 0x08, 0x08, 0x00, 0x00}, /*"V",54*/
+    {0x00, 0x00, 0x00, 0x6B, 0x49, 0x49, 0x49, 0x49, 0x55, 0x55, 0x36, 0x22, 0x22, 0x22, 0x00, 0x00}, /*"W",55*/
+    {0x00, 0x00, 0x00, 0xE7, 0x42, 0x24, 0x24, 0x18, 0x18, 0x18, 0x24, 0x24, 0x42, 0xE7, 0x00, 0x00}, /*"X",56*/
+    {0x00, 0x00, 0x00, 0x77, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00}, /*"Y",57*/
+    {0x00, 0x00, 0x00, 0x7E, 0x21, 0x20, 0x10, 0x10, 0x08, 0x04, 0x04, 0x42, 0x42, 0x3F, 0x00, 0x00}, /*"Z",58*/
+    {0x00, 0x78, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00}, /*"[",59*/
+    {0x00, 0x00, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x20, 0x40, 0x40}, /*"\",60*/
+    {0x00, 0x1E, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1E, 0x00}, /*"]",61*/
+    {0x00, 0x38, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"^",62*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, /*"_",63*/
+    {0x00, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"`",64*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x42, 0x78, 0x44, 0x42, 0x42, 0xFC, 0x00, 0x00}, /*"a",65*/
+    {0x00, 0x00, 0x00, 0x03, 0x02, 0x02, 0x02, 0x1A, 0x26, 0x42, 0x42, 0x42, 0x26, 0x1A, 0x00, 0x00}, /*"b",66*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x02, 0x02, 0x02, 0x44, 0x38, 0x00, 0x00}, /*"c",67*/
+    {0x00, 0x00, 0x00, 0x60, 0x40, 0x40, 0x40, 0x78, 0x44, 0x42, 0x42, 0x42, 0x64, 0xD8, 0x00, 0x00}, /*"d",68*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x42, 0x7E, 0x02, 0x02, 0x42, 0x3C, 0x00, 0x00}, /*"e",69*/
+    {0x00, 0x00, 0x00, 0xF0, 0x88, 0x08, 0x08, 0x7E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00, 0x00}, /*"f",70*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x22, 0x22, 0x1C, 0x02, 0x3C, 0x42, 0x42, 0x3C}, /*"g",71*/
+    {0x00, 0x00, 0x00, 0x03, 0x02, 0x02, 0x02, 0x3A, 0x46, 0x42, 0x42, 0x42, 0x42, 0xE7, 0x00, 0x00}, /*"h",72*/
+    {0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00, 0x00}, /*"i",73*/
+    {0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x1E}, /*"j",74*/
+    {0x00, 0x00, 0x00, 0x03, 0x02, 0x02, 0x02, 0x72, 0x12, 0x0A, 0x16, 0x12, 0x22, 0x77, 0x00, 0x00}, /*"k",75*/
+    {0x00, 0x00, 0x00, 0x0E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00, 0x00}, /*"l",76*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x92, 0x92, 0x92, 0x92, 0x92, 0xB7, 0x00, 0x00}, /*"m",77*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x46, 0x42, 0x42, 0x42, 0x42, 0xE7, 0x00, 0x00}, /*"n",78*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00, 0x00}, /*"o",79*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x26, 0x42, 0x42, 0x42, 0x22, 0x1E, 0x02, 0x07}, /*"p",80*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x42, 0x44, 0x78, 0x40, 0xE0}, /*"q",81*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x4C, 0x04, 0x04, 0x04, 0x04, 0x1F, 0x00, 0x00}, /*"r",82*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x42, 0x02, 0x3C, 0x40, 0x42, 0x3E, 0x00, 0x00}, /*"s",83*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x30, 0x00, 0x00}, /*"t",84*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x42, 0x42, 0x42, 0x42, 0x62, 0xDC, 0x00, 0x00}, /*"u",85*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x42, 0x24, 0x24, 0x14, 0x08, 0x08, 0x00, 0x00}, /*"v",86*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x49, 0x49, 0x55, 0x55, 0x22, 0x22, 0x00, 0x00}, /*"w",87*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x24, 0x18, 0x18, 0x18, 0x24, 0x6E, 0x00, 0x00}, /*"x",88*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x42, 0x24, 0x24, 0x14, 0x18, 0x08, 0x08, 0x07}, /*"y",89*/
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x22, 0x10, 0x08, 0x08, 0x44, 0x7E, 0x00, 0x00}, /*"z",90*/
+    {0x00, 0xC0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xC0, 0x00}, /*"{",91*/
+    {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /*"|",92*/
+    {0x00, 0x06, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x06, 0x00}, /*"}",93*/
+    {0x0C, 0x32, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"~",94*/
+};
+
+#endif

+ 6 - 0
bsp/gd32/arm/libraries/GD32F4xx_Firmware_Library/SConscript

@@ -53,6 +53,12 @@ if GetDepend(['BSP_USING_SDRAM']):
     src += ['GD32F4xx_standard_peripheral/Source/gd32f4xx_fmc.c']
     src += ['GD32F4xx_standard_peripheral/Source/gd32f4xx_exmc.c']
 
+if GetDepend(['BSP_USING_TLI']):
+    src += ['GD32F4xx_standard_peripheral/Source/gd32f4xx_tli.c']
+
+if GetDepend(['BSP_USING_GPU']):
+    src += ['GD32F4xx_standard_peripheral/Source/gd32f4xx_ipa.c']
+    
 path = [
     cwd + '/CMSIS/GD/GD32F4xx/Include',
     cwd + '/CMSIS',