828eco基于GD32H7mcu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

403 lines
16 KiB

/*
* Copyright (c) 2006-2025, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-11-07 RealThread the first version
*/
#include <stddef.h>
#include <rthw.h>
#include <rtthread.h>
#include "drv_lcd.h"
#ifdef RT_USING_LCD
#define DBG_TAG "drv_lcd"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
struct drv_lcd_device
{
struct rt_device parent;
struct rt_device_graphic_info lcd_info;
};
static uint16_t *frame_buffer = RT_NULL;
struct drv_lcd_device _lcd = { 0 };
RGB color_write = { 0, 0xFF, 0xFF, 0xFF };
RGB color_black = { 0, 0x00, 0x00, 0x00 };
RGB color_red = { 0, 0xFF, 0x00, 0x00 };
RGB color_blue = { 0, 0x00, 0x00, 0xFF };
RGB color_green = { 0, 0x00, 0xFF, 0x00 };
RGB color_yellow = { 0, 0xFF, 0xFF, 0x00 };
RGB color_cyan = { 0, 0x00, 0xFF, 0xFF };
RGB color_magenta = { 0, 0xFF, 0x00, 0xFF };
RGB color_orange = { 0, 0xFF, 0xA5, 0x00 };
RGB color_purple = { 0, 0x80, 0x00, 0x80 };
RGB color_gray = { 0, 0x80, 0x80, 0x80 };
RGB color_lightgray = { 0, 0xD3, 0xD3, 0xD3 };
RGB color_darkgray = { 0, 0x40, 0x40, 0x40 };
RGB color_brown = { 0, 0xA5, 0x2A, 0x2A };
RGB color_pink = { 0, 0xFF, 0xC0, 0xCB };
RGB color_gold = { 0, 0xFF, 0xD7, 0x00 };
RGB color_silver = { 0, 0xC0, 0xC0, 0xC0 };
static void framebuffer_init(void);
static void tli_config(RGB *blackground_color);
static void tli_gpio_config(void);
rt_err_t drv_lcd_init(rt_device_t dev)
{
return RT_EOK;
}
rt_err_t drv_lcd_open(rt_device_t dev, rt_uint16_t oflag)
{
return RT_EOK;
}
rt_err_t drv_lcd_close(rt_device_t dev)
{
return RT_EOK;
}
rt_ssize_t drv_lcd_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
return RT_EOK;
}
rt_ssize_t drv_lcd_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
return RT_EOK;
}
rt_err_t drv_lcd_control(struct rt_device *device, int cmd, void *args)
{
switch (cmd)
{
case RTGRAPHIC_CTRL_GET_INFO:
{
struct rt_device_graphic_info *info = (struct rt_device_graphic_info *)args;
RT_ASSERT(info != RT_NULL);
info->pixel_format = _lcd.lcd_info.pixel_format;
info->bits_per_pixel = _lcd.lcd_info.bits_per_pixel;
info->width = _lcd.lcd_info.width;
info->height = _lcd.lcd_info.height;
info->framebuffer = _lcd.lcd_info.framebuffer;
}
break;
case RTGRAPHIC_CTRL_RECT_UPDATE:
tli_reload_config(TLI_REQUEST_RELOAD_EN);
break;
default:
return RT_EOK;
}
return RT_EOK;
}
static int hw_drv_lcd_init(void)
{
// malloc frame buffer
frame_buffer = rt_malloc(ACTIVE_WIDTH * ACTIVE_HEIGHT * PRE_PIXEL_BYTES);
framebuffer_init();
_lcd.parent.type = RT_Device_Class_Graphic;
_lcd.parent.init = drv_lcd_init;
_lcd.parent.open = drv_lcd_open;
_lcd.parent.close = drv_lcd_close;
_lcd.parent.read = drv_lcd_read;
_lcd.parent.write = drv_lcd_write;
_lcd.parent.control = drv_lcd_control;
_lcd.lcd_info.framebuffer = (rt_uint8_t *)frame_buffer;
_lcd.lcd_info.width = LCD_WIGHT;
_lcd.lcd_info.height = LCD_HIGHT;
_lcd.lcd_info.bits_per_pixel = PRE_PIXEL_BYTES * 8;
_lcd.lcd_info.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565;
/* configure TLI peripheral */
tli_config(&color_write);
/* enable TLI layers */
tli_layer_enable(LAYER0);
tli_reload_config(TLI_REQUEST_RELOAD_EN);
/* enable TLI */
tli_enable();
rt_device_register(&_lcd.parent, "lcd", RT_DEVICE_FLAG_RDWR);
return RT_EOK;
}
INIT_APP_EXPORT(hw_drv_lcd_init);
static void framebuffer_init(void)
{
for (uint32_t y = 0; y < ACTIVE_HEIGHT; ++y)
{
for (uint32_t x = 0; x < ACTIVE_WIDTH; ++x)
{
frame_buffer[y * ACTIVE_WIDTH + x] = 0xFFFF;
}
}
SCB_CleanInvalidateDCache();
}
static void tli_gpio_config(void)
{
/* enable GPIO 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_GPIOE);
rcu_periph_clock_enable(RCU_GPIOF);
rcu_periph_clock_enable(RCU_GPIOH);
rcu_periph_clock_enable(RCU_GPIOG);
/* configure HSYNC(PE15), VSYNC(PA7), PCLK(PG7) */
gpio_af_set(GPIOE, GPIO_AF_10, GPIO_PIN_15);
gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_7);
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_7);
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_15);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_15);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_7);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_7);
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_7);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_7);
/* configure LCD_R7(PG6), LCD_R6(PH12), LCD_R5(PH11), LCD_R4(PA5), LCD_R3(PH9),LCD_R2(PH8),
LCD_R1(PH3), LCD_R0(PH2) */
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_6);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_12);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_11);
gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_5);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_9);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_8);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_3);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_2);
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_6);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_12);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_12);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_11);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_5);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_9);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_9);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_8);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_8);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_3);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_2);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_2);
/* configure LCD_G7(PD3), LCD_G6(PC7), LCD_G5(PC1), LCD_G4(PH15), LCD_G3(PH14), LCD_G2(PH13),LCD_G1(PB0), LCD_G0(PB1) */
gpio_af_set(GPIOD, GPIO_AF_14, GPIO_PIN_3);
gpio_af_set(GPIOC, GPIO_AF_14, GPIO_PIN_7);
gpio_af_set(GPIOC, GPIO_AF_14, GPIO_PIN_1);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_15);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_14);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_13);
gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_0);
gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_1);
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_3);
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_7);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_7);
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_1);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_15);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_15);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_14);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_13);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_0);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_1);
/* configure LCD_B7(PB9), LCD_B6(PB8), LCD_B5(PB5), LCD_B4(PC11), LCD_B3(PG11),LCD_B2(PG10), LCD_B1(PG12), LCD_B0(PG14) */
gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_9);
gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_8);
gpio_af_set(GPIOB, GPIO_AF_3, GPIO_PIN_5);
gpio_af_set(GPIOC, GPIO_AF_14, GPIO_PIN_11);
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_11);
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_10);
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_12);
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_14);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_9);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_9);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_8);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_8);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_5);
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_11);
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_11);
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_10);
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_12);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_12);
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_14);
/* configure LCD_DE(PF10) */
gpio_af_set(GPIOF, GPIO_AF_14, GPIO_PIN_10);
gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10);
gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_10);
/* LCD PWM BackLight(PG13) */
gpio_mode_set(GPIOG, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_13);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_13);
gpio_bit_set(GPIOG, GPIO_PIN_13);
}
static void tli_config(RGB *blackground_color)
{
tli_parameter_struct tli_init_struct;
tli_layer_parameter_struct tli_layer_init_struct;
rcu_periph_clock_enable(RCU_TLI);
tli_gpio_config();
rcu_pll_input_output_clock_range_config(IDX_PLL2, RCU_PLL2RNG_1M_2M, RCU_PLL2VCO_192M_836M);
if (ERROR == rcu_pll2_config(25, 192, 3, 3, 3))
{
while (1)
{
}
}
rcu_pll_clock_output_enable(RCU_PLL2R);
rcu_tli_clock_div_config(RCU_PLL2R_DIV8);
rcu_osci_on(RCU_PLL2_CK);
if (ERROR == rcu_osci_stab_wait(RCU_PLL2_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 = blackground_color->R;
tli_init_struct.backcolor_green = blackground_color->G;
tli_init_struct.backcolor_blue = blackground_color->B;
tli_init(&tli_init_struct);
/* TLI layer configuration */
tli_layer_init_struct.layer_window_leftpos = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH;
tli_layer_init_struct.layer_window_rightpos = (480 + 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 = (272 + VERTICAL_SYNCHRONOUS_PULSE +
VERTICAL_BACK_PORCH - 1);
tli_layer_init_struct.layer_ppf = LAYER_PPF_RGB565;
tli_layer_init_struct.layer_sa = 255;
tli_layer_init_struct.layer_default_blue = 0x0;
tli_layer_init_struct.layer_default_green = 0x0;
tli_layer_init_struct.layer_default_red = 0x0;
tli_layer_init_struct.layer_default_alpha = 0x00;
tli_layer_init_struct.layer_acf1 = LAYER_ACF1_SA;
tli_layer_init_struct.layer_acf2 = LAYER_ACF2_SA;
tli_layer_init_struct.layer_frame_bufaddr = (uint32_t)frame_buffer;
tli_layer_init_struct.layer_frame_line_length = ((480 * 2) + 7);
tli_layer_init_struct.layer_frame_buf_stride_offset = (480 * 2);
tli_layer_init_struct.layer_frame_total_line_number = 272;
tli_layer_init(LAYER0, &tli_layer_init_struct);
}
void lcd_draw_picture(uint32_t picture_addr, uint32_t picture_width, uint32_t picture_height, uint32_t picture_x, uint32_t picture_y)
{
ipa_destination_parameter_struct ipa_destination_init_struct;
ipa_foreground_parameter_struct ipa_fg_init_struct;
uint16_t *_address = &frame_buffer[picture_y * ACTIVE_WIDTH + picture_x];
uint32_t line_offset = ACTIVE_WIDTH - picture_width;
rcu_periph_clock_enable(RCU_IPA);
ipa_deinit();
/* configure IPA pixel format convert mode */
ipa_pixel_format_convert_mode_set(IPA_FGTODE);
/* configure destination pixel format */
ipa_destination_init_struct.destination_pf = IPA_DPF_RGB565;
/* configure destination memory base address */
ipa_destination_init_struct.destination_memaddr = (uint32_t)_address;
/* configure destination pre-defined alpha value RGB */
ipa_destination_init_struct.destination_pregreen = 0;
ipa_destination_init_struct.destination_preblue = 0;
ipa_destination_init_struct.destination_prered = 0;
ipa_destination_init_struct.destination_prealpha = 0;
/* configure destination line offset */
ipa_destination_init_struct.destination_lineoff = line_offset;
/* configure height of the image to be processed */
ipa_destination_init_struct.image_height = picture_height;
/* configure width of the image to be processed */
ipa_destination_init_struct.image_width = picture_width;
ipa_destination_init_struct.image_rotate = DESTINATION_ROTATE_0;
ipa_destination_init_struct.image_hor_decimation = DESTINATION_HORDECIMATE_DISABLE;
ipa_destination_init_struct.image_ver_decimation = DESTINATION_VERDECIMATE_DISABLE;
/* IPA destination initialization */
ipa_destination_init(&ipa_destination_init_struct);
/* configure IPA foreground */
ipa_fg_init_struct.foreground_memaddr = picture_addr;
ipa_fg_init_struct.foreground_pf = FOREGROUND_PPF_RGB565;
ipa_fg_init_struct.foreground_alpha_algorithm = IPA_FG_ALPHA_MODE_0;
ipa_fg_init_struct.foreground_prealpha = 0x0;
ipa_fg_init_struct.foreground_lineoff = 0x0;
ipa_fg_init_struct.foreground_preblue = 0x0;
ipa_fg_init_struct.foreground_pregreen = 0x0;
ipa_fg_init_struct.foreground_prered = 0x0;
/* foreground initialization */
ipa_foreground_init(&ipa_fg_init_struct);
/* start transfer */
ipa_transfer_enable();
while (RESET == ipa_interrupt_flag_get(IPA_INT_FLAG_FTF))
{
}
}
void lcd_draw_point(uint32_t point_x, uint32_t point_y, RGB *color)
{
frame_buffer[point_y * ACTIVE_WIDTH + point_x] = to_RGB565(color);
}
uint32_t to_RGB565(RGB *color)
{
uint32_t res = ((uint32_t)(color->R & 0xF8) << 8) | ((uint32_t)(color->G & 0xFC) << 3) | ((uint32_t)(color->B & 0xF8) >> 3);
return res;
}
#endif /* RT_USING_LCD */