/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2025-12-06 Administrator the first version * 2025-12-07 Qwen 使用 RT-Thread 内存池替代静态帧缓存,修复 rt_mp_create 参数错误 */ /* ltdc.c */ #include "ltdc.h" #include "lcd.h" #include #include #include LTDC_HandleTypeDef g_ltdc_handle; /* LTDC句柄 */ DMA2D_HandleTypeDef g_dma2d_handle; /* DMA2D句柄 */ #define MAX_FRAME_WIDTH 1024 #define MAX_FRAME_HEIGHT 600 #if LTDC_PIXFORMAT == LTDC_PIXFORMAT_ARGB8888 || LTDC_PIXFORMAT == LTDC_PIXFORMAT_RGB888 #define BYTES_PER_PIXEL 4 #else #define BYTES_PER_PIXEL 2 #endif #define FRAME_BUF_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * BYTES_PER_PIXEL) #define FRAME_ALIGN 64 /* LTDC 推荐对齐到 64 字节 */ static rt_mp_t frame_mp = RT_NULL; uint32_t *g_ltdc_framebuf[2] = {RT_NULL, RT_NULL}; /* 初始化为 NULL */ _ltdc_dev lcdltdc; /* 管理LCD LTDC的重要参数 */ /** * @brief 从内存池分配对齐内存 */ static void* alloc_aligned_frame_buffer(rt_mp_t mp, rt_size_t size, rt_size_t align) { void *raw, *aligned; rt_size_t offset; /* 分配足够空间以保证能对齐 */ raw = rt_mp_alloc(mp, size + align - 1); if (raw == RT_NULL) return RT_NULL; offset = (rt_ubase_t)raw & (align - 1); if (offset != 0) aligned = (void *)((rt_ubase_t)raw + align - offset); else aligned = raw; return aligned; } /** * @brief LTDC开关 * @param sw : 1,打开; 0,关闭; * @retval 无 */ void ltdc_switch(uint8_t sw) { if (sw) { __HAL_LTDC_ENABLE(&g_ltdc_handle); /* 打开LTDC */ } else { __HAL_LTDC_DISABLE(&g_ltdc_handle); /* 关闭LTDC */ } } /** * @brief LTDC开关指定层 * @param layerx : 0,第一层; 1,第二层; * @param sw : 1,打开; 0,关闭; * @retval 无 */ void ltdc_layer_switch(uint8_t layerx, uint8_t sw) { if (sw) { __HAL_LTDC_LAYER_ENABLE(&g_ltdc_handle, layerx); /* 开启layerx */ } else { __HAL_LTDC_LAYER_DISABLE(&g_ltdc_handle, layerx); /* 关闭layerx */ } __HAL_LTDC_RELOAD_CONFIG(&g_ltdc_handle); /* 立即重新加载配置 */ } /** * @brief LTDC选择层 * @param layerx : 层号:0,第一层; 1,第二层; * @retval 无 */ void ltdc_select_layer(uint8_t layerx) { lcdltdc.activelayer = layerx; } /** * @brief LTDC显示方向设置 * @param dir : 0,竖屏; 1,横屏; * @retval 无 */ void ltdc_display_dir(uint8_t dir) { lcdltdc.dir = dir; /* 显示方向 */ if (dir == 0) /* 竖屏 */ { lcdltdc.width = lcdltdc.pheight; lcdltdc.height = lcdltdc.pwidth; } else if (dir == 1) /* 横屏 */ { lcdltdc.width = lcdltdc.pwidth; lcdltdc.height = lcdltdc.pheight; } } /** * @brief LTDC画点函数 * @param x,y : 写入坐标 * @param color : 颜色值 * @retval 无 */ void ltdc_draw_point(uint16_t x, uint16_t y, uint32_t color) { #if LTDC_PIXFORMAT == LTDC_PIXFORMAT_ARGB8888 if (lcdltdc.dir) /* 横屏 */ { *(uint32_t *)((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * y + x)) = color; } else /* 竖屏 */ { *(uint32_t *)((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * (lcdltdc.pheight - x - 1) + y)) = color; } #elif LTDC_PIXFORMAT == LTDC_PIXFORMAT_RGB888 if (lcdltdc.dir) /* 横屏 */ { *(uint16_t *)((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * y + x)) = color; *(uint8_t *)((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * y + x) + 2) = color >> 16; } else /* 竖屏 */ { *(uint16_t *)((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * (lcdltdc.pheight - x - 1) + y)) = color; *(uint8_t *)((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * (lcdltdc.pheight - x - 1) + y) + 2) = color >> 16; } #else if (lcdltdc.dir) /* 横屏 */ { *(uint16_t *)((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * y + x)) = color; } else /* 竖屏 */ { *(uint16_t *)((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * (lcdltdc.pheight - x - 1) + y)) = color; } #endif } /** * @brief LTDC读点函数 * @param x,y : 读取点的坐标 * @retval 颜色值 */ uint32_t ltdc_read_point(uint16_t x, uint16_t y) { #if LTDC_PIXFORMAT == LTDC_PIXFORMAT_ARGB8888 if (lcdltdc.dir) /* 横屏 */ { return *(uint32_t *)((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * y + x)); } else /* 竖屏 */ { return *(uint32_t *)((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * (lcdltdc.pheight - x - 1) + y)); } #elif LTDC_PIXFORMAT == LTDC_PIXFORMAT_RGB888 if (lcdltdc.dir) /* 横屏 */ { return *(uint32_t *)((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * y + x)) & 0XFFFFFF; } else /* 竖屏 */ { return *(uint32_t *)((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * (lcdltdc.pheight - x - 1) + y)) & 0XFFFFFF; } #else if (lcdltdc.dir) /* 横屏 */ { return *(uint16_t *)((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * y + x)); } else /* 竖屏 */ { return *(uint16_t *)((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * (lcdltdc.pheight - x - 1) + y)); } #endif } /** * @brief LTDC填充矩形, DMA2D填充 */ void ltdc_fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t color) { uint32_t psx, psy, pex, pey; uint32_t timeout = 0; uint16_t offline; uint32_t addr; if (lcdltdc.dir) { psx = sx; psy = sy; pex = ex; pey = ey; } else { if (ex >= lcdltdc.pheight) { ex = lcdltdc.pheight - 1; } if (sx >= lcdltdc.pheight) { sx = lcdltdc.pheight - 1; } psx = sy; psy = lcdltdc.pheight - ex - 1; pex = ey; pey = lcdltdc.pheight - sx - 1; } offline = lcdltdc.pwidth - (pex - psx + 1); addr = ((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * psy + psx)); __HAL_RCC_DMA2D_CLK_ENABLE(); DMA2D->CR &= ~(DMA2D_CR_START); DMA2D->CR = DMA2D_R2M; DMA2D->OPFCCR = LTDC_PIXFORMAT; DMA2D->OOR = offline; DMA2D->OMAR = addr; DMA2D->NLR = (pey - psy + 1) | ((pex - psx + 1) << 16); DMA2D->OCOLR = color; DMA2D->CR |= DMA2D_CR_START; while ((DMA2D->ISR & (DMA2D_FLAG_TC)) == 0) { timeout++; if (timeout > 0X1FFFFF) break; } DMA2D->IFCR |= DMA2D_FLAG_TC; } /** * @brief 在指定区域内填充指定颜色块, DMA2D填充 */ void ltdc_color_fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *color) { uint32_t psx, psy, pex, pey; uint32_t timeout = 0; uint16_t offline; uint32_t addr; if (lcdltdc.dir) { psx = sx; psy = sy; pex = ex; pey = ey; } else { psx = sy; psy = lcdltdc.pheight - ex - 1; pex = ey; pey = lcdltdc.pheight - sx - 1; } offline = lcdltdc.pwidth - (pex - psx + 1); addr = ((uint32_t)g_ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize * (lcdltdc.pwidth * psy + psx)); __HAL_RCC_DMA2D_CLK_ENABLE(); DMA2D->CR &= ~(DMA2D_CR_START); DMA2D->CR = DMA2D_M2M; DMA2D->FGPFCCR = LTDC_PIXFORMAT; DMA2D->FGOR = 0; DMA2D->OOR = offline; DMA2D->FGMAR = (uint32_t)color; DMA2D->OMAR = addr; DMA2D->NLR = (pey - psy + 1) | ((pex - psx + 1) << 16); DMA2D->CR |= DMA2D_CR_START; while((DMA2D->ISR & (DMA2D_FLAG_TC)) == 0) { timeout++; if (timeout > 0X1FFFFF) break; } DMA2D->IFCR |= DMA2D_FLAG_TC; } /** * @brief LTDC清屏 */ void ltdc_clear(uint32_t color) { ltdc_fill(0, 0, lcdltdc.width - 1, lcdltdc.height - 1, color); } /** * @brief LTDC时钟(Fdclk)设置函数 */ uint8_t ltdc_clk_set(uint32_t pll3n, uint32_t pll3m, uint32_t pll3r) { RCC_PeriphCLKInitTypeDef periphclk_initure; periphclk_initure.PeriphClockSelection = RCC_PERIPHCLK_LTDC; periphclk_initure.PLL3.PLL3M = pll3m; periphclk_initure.PLL3.PLL3N = pll3n; periphclk_initure.PLL3.PLL3P = 2; periphclk_initure.PLL3.PLL3Q = 2; periphclk_initure.PLL3.PLL3R = pll3r; if (HAL_RCCEx_PeriphCLKConfig(&periphclk_initure) == HAL_OK) { return 0; } else { return 1; } } /** * @brief LTDC层窗口设置 */ void ltdc_layer_window_config(uint8_t layerx, uint16_t sx, uint16_t sy, uint16_t width, uint16_t height) { HAL_LTDC_SetWindowPosition(&g_ltdc_handle, sx, sy, layerx); HAL_LTDC_SetWindowSize(&g_ltdc_handle, width, height, layerx); if (lcdltdc.pheight == 1280 && layerx == 0) { LTDC_Layer1->CFBLR = (width * 4 << 16) | (width * 4 + 7); } } /** * @brief LTDC层基本参数设置 */ void ltdc_layer_parameter_config(uint8_t layerx, uint32_t bufaddr, uint8_t pixformat, uint8_t alpha, uint8_t alpha0, uint8_t bfac1, uint8_t bfac2, uint32_t bkcolor) { LTDC_LayerCfgTypeDef playercfg; playercfg.WindowX0 = 0; playercfg.WindowY0 = 0; playercfg.WindowX1 = lcdltdc.pwidth; playercfg.WindowY1 = lcdltdc.pheight; playercfg.PixelFormat = pixformat; playercfg.Alpha = alpha; playercfg.Alpha0 = alpha0; playercfg.BlendingFactor1 = (uint32_t)bfac1 << 8; playercfg.BlendingFactor2 = (uint32_t)bfac2; playercfg.FBStartAdress = bufaddr; playercfg.ImageWidth = lcdltdc.pwidth; playercfg.ImageHeight = lcdltdc.pheight; playercfg.Backcolor.Red = (uint8_t)(bkcolor & 0X00FF0000) >> 16; playercfg.Backcolor.Green = (uint8_t)(bkcolor & 0X0000FF00) >> 8; playercfg.Backcolor.Blue = (uint8_t)bkcolor & 0X000000FF; HAL_LTDC_ConfigLayer(&g_ltdc_handle, &playercfg, layerx); } /** * @brief LTDC读取面板ID */ uint16_t ltdc_panelid_read(void) { uint8_t idx = 0; GPIO_InitTypeDef gpio_init_struct; __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_GPIOI_CLK_ENABLE(); gpio_init_struct.Pin = GPIO_PIN_6; gpio_init_struct.Mode = GPIO_MODE_INPUT; gpio_init_struct.Pull = GPIO_PULLUP; gpio_init_struct.Speed = GPIO_SPEED_HIGH; HAL_GPIO_Init(GPIOG, &gpio_init_struct); gpio_init_struct.Pin = GPIO_PIN_2 | GPIO_PIN_7; HAL_GPIO_Init(GPIOI, &gpio_init_struct); rt_thread_mdelay(1); idx = (uint8_t)HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_6); idx |= (uint8_t)HAL_GPIO_ReadPin(GPIOI, GPIO_PIN_2) << 1; idx |= (uint8_t)HAL_GPIO_ReadPin(GPIOI, GPIO_PIN_7) << 2; switch (idx) { case 0: return 0X4342; case 1: return 0X7084; case 2: return 0X7016; case 3: return 0X7018; case 4: return 0X4384; case 5: return 0X1018; default: return 0; } } /** * @brief LTDC初始化函数 */ int ltdc_init(void) { uint16_t lcdid = 0; lcdid = ltdc_panelid_read(); #if RGB_80_8001280 lcdid = 0X8081; #endif if (lcdid == 0X4342) { lcdltdc.pwidth = 480; lcdltdc.pheight = 272; lcdltdc.hsw = 1; lcdltdc.hbp = 40; lcdltdc.hfp = 5; lcdltdc.vsw = 1; lcdltdc.vbp = 8; lcdltdc.vfp = 8; ltdc_clk_set(300, 25, 33); } else if (lcdid == 0X7084) { lcdltdc.pwidth = 800; lcdltdc.pheight = 480; lcdltdc.hsw = 1; lcdltdc.hbp = 46; lcdltdc.hfp = 210; lcdltdc.vsw = 1; lcdltdc.vbp = 23; lcdltdc.vfp = 22; ltdc_clk_set(300, 25, 9); } else if (lcdid == 0X7016) { lcdltdc.pwidth = 1024; lcdltdc.pheight = 600; lcdltdc.hsw = 20; lcdltdc.hbp = 160; lcdltdc.hfp = 160; lcdltdc.vsw = 3; lcdltdc.vbp = 23; lcdltdc.vfp = 12; ltdc_clk_set(128, 40, 5); } else if (lcdid == 0X7018) { lcdltdc.pwidth = 1280; lcdltdc.pheight = 800; } else if (lcdid == 0X4384) { lcdltdc.pwidth = 800; lcdltdc.pheight = 480; lcdltdc.hsw = 48; lcdltdc.hbp = 88; lcdltdc.hfp = 40; lcdltdc.vsw = 3; lcdltdc.vbp = 32; lcdltdc.vfp = 13; ltdc_clk_set(300, 25, 9); } else if (lcdid == 0X8081) { lcdltdc.pwidth = 800; lcdltdc.pheight = 1280; lcdltdc.hsw = 5; lcdltdc.hbp = 20; lcdltdc.hfp = 40; lcdltdc.vsw = 3; lcdltdc.vbp = 20; lcdltdc.vfp = 30; ltdc_clk_set(300, 25, 5); } else if (lcdid == 0X1018) { lcdltdc.pwidth = 1280; lcdltdc.pheight = 800; lcdltdc.hsw = 10; lcdltdc.hbp = 140; lcdltdc.hfp = 10; lcdltdc.vsw = 3; lcdltdc.vbp = 10; lcdltdc.vfp = 10; ltdc_clk_set(300, 25, 5); } lcddev.width = lcdltdc.pwidth; lcddev.height = lcdltdc.pheight; lcdltdc.pixformat = LTDC_PIXFORMAT; lcdltdc.pixsize = BYTES_PER_PIXEL; /* === 使用 RT-Thread 内存池分配帧缓存(双缓冲)=== */ if (frame_mp == RT_NULL) { rt_size_t block_size = FRAME_BUF_SIZE + FRAME_ALIGN; /* 每块大小 */ rt_size_t block_count = 2; /* 双缓冲 */ frame_mp = rt_mp_create("ltdc_mp", block_count, block_size); if (frame_mp == RT_NULL) { rt_kprintf("LTDC: Failed to create memory pool!\n"); return -1; } rt_kprintf("LTDC: Memory pool created (%d blocks, %d bytes each)\n", block_count, block_size); } /* 分配帧缓冲 0 */ if (g_ltdc_framebuf[0] == RT_NULL) { void *aligned_buf = alloc_aligned_frame_buffer(frame_mp, FRAME_BUF_SIZE, FRAME_ALIGN); if (aligned_buf == RT_NULL) { rt_kprintf("LTDC: Failed to allocate frame buffer 0!\n"); return -1; } g_ltdc_framebuf[0] = (uint32_t *)aligned_buf; } /* 分配帧缓冲 1(双缓冲) */ if (g_ltdc_framebuf[1] == RT_NULL) { void *aligned_buf = alloc_aligned_frame_buffer(frame_mp, FRAME_BUF_SIZE, FRAME_ALIGN); if (aligned_buf == RT_NULL) { rt_kprintf("LTDC: Warning: only single buffer available.\n"); // 可选:回退到单缓冲 g_ltdc_framebuf[1] = g_ltdc_framebuf[0]; } else { g_ltdc_framebuf[1] = (uint32_t *)aligned_buf; } } /* LTDC配置 */ g_ltdc_handle.Instance = LTDC; if (lcdid == 0X8081) { g_ltdc_handle.Init.HSPolarity = LTDC_HSPOLARITY_AH; } else { g_ltdc_handle.Init.HSPolarity = LTDC_HSPOLARITY_AL; } g_ltdc_handle.Init.VSPolarity = LTDC_VSPOLARITY_AL; g_ltdc_handle.Init.DEPolarity = LTDC_DEPOLARITY_AL; g_ltdc_handle.State = HAL_LTDC_STATE_RESET; if (lcdid == 0X1018 || lcdid == 0X8081) { g_ltdc_handle.Init.PCPolarity = LTDC_PCPOLARITY_IIPC; } else { g_ltdc_handle.Init.PCPolarity = LTDC_PCPOLARITY_IPC; } g_ltdc_handle.Init.HorizontalSync = lcdltdc.hsw - 1; g_ltdc_handle.Init.VerticalSync = lcdltdc.vsw - 1; g_ltdc_handle.Init.AccumulatedHBP = lcdltdc.hsw + lcdltdc.hbp - 1; g_ltdc_handle.Init.AccumulatedVBP = lcdltdc.vsw + lcdltdc.vbp - 1; g_ltdc_handle.Init.AccumulatedActiveW = lcdltdc.hsw + lcdltdc.hbp + lcdltdc.pwidth - 1; g_ltdc_handle.Init.AccumulatedActiveH = lcdltdc.vsw + lcdltdc.vbp + lcdltdc.pheight - 1; g_ltdc_handle.Init.TotalWidth = lcdltdc.hsw + lcdltdc.hbp + lcdltdc.pwidth + lcdltdc.hfp - 1; g_ltdc_handle.Init.TotalHeigh = lcdltdc.vsw + lcdltdc.vbp + lcdltdc.pheight + lcdltdc.vfp - 1; g_ltdc_handle.Init.Backcolor.Red = 0; g_ltdc_handle.Init.Backcolor.Green = 0; g_ltdc_handle.Init.Backcolor.Blue = 0; HAL_LTDC_Init(&g_ltdc_handle); /* 层配置 */ ltdc_layer_parameter_config(0, (uint32_t)g_ltdc_framebuf[0], LTDC_PIXFORMAT, 255, 0, 6, 7, 0X000000); ltdc_layer_window_config(0, 0, 0, lcdltdc.pwidth, lcdltdc.pheight); ltdc_select_layer(0); /* LTDC LCD复位 */ LTDC_RST(1); rt_thread_mdelay(10); LTDC_RST(0); rt_thread_mdelay(50); LTDC_RST(1); rt_thread_mdelay(200); LTDC_BL(1); ltdc_clear(0XFFFFFFFF); return 0; } /** * @brief LTDC底层IO初始化和时钟使能 */ void HAL_LTDC_MspInit(LTDC_HandleTypeDef *hltdc) { GPIO_InitTypeDef gpio_init_struct; __HAL_RCC_LTDC_CLK_ENABLE(); __HAL_RCC_DMA2D_CLK_ENABLE(); /* 控制引脚 */ LTDC_BL_GPIO_CLK_ENABLE(); LTDC_RST_GPIO_CLK_ENABLE(); LTDC_DE_GPIO_CLK_ENABLE(); LTDC_VSYNC_GPIO_CLK_ENABLE(); LTDC_HSYNC_GPIO_CLK_ENABLE(); LTDC_CLK_GPIO_CLK_ENABLE(); gpio_init_struct.Pin = LTDC_BL_GPIO_PIN; gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; gpio_init_struct.Pull = GPIO_PULLUP; gpio_init_struct.Speed = GPIO_SPEED_HIGH; HAL_GPIO_Init(LTDC_BL_GPIO_PORT, &gpio_init_struct); gpio_init_struct.Pin = LTDC_RST_GPIO_PIN; HAL_GPIO_Init(LTDC_RST_GPIO_PORT, &gpio_init_struct); gpio_init_struct.Pin = LTDC_DE_GPIO_PIN; gpio_init_struct.Mode = GPIO_MODE_AF_PP; gpio_init_struct.Pull = GPIO_NOPULL; gpio_init_struct.Speed = GPIO_SPEED_HIGH; gpio_init_struct.Alternate = GPIO_AF14_LTDC; HAL_GPIO_Init(LTDC_DE_GPIO_PORT, &gpio_init_struct); gpio_init_struct.Pin = LTDC_VSYNC_GPIO_PIN; HAL_GPIO_Init(LTDC_VSYNC_GPIO_PORT, &gpio_init_struct); gpio_init_struct.Pin = LTDC_HSYNC_GPIO_PIN; HAL_GPIO_Init(LTDC_HSYNC_GPIO_PORT, &gpio_init_struct); gpio_init_struct.Pin = LTDC_CLK_GPIO_PIN; HAL_GPIO_Init(LTDC_CLK_GPIO_PORT, &gpio_init_struct); /* 数据引脚 */ __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOI_CLK_ENABLE(); gpio_init_struct.Pin = GPIO_PIN_8; gpio_init_struct.Alternate = GPIO_AF13_LTDC; HAL_GPIO_Init(GPIOA, &gpio_init_struct); gpio_init_struct.Pin = GPIO_PIN_2; gpio_init_struct.Alternate = GPIO_AF14_LTDC; HAL_GPIO_Init(GPIOA, &gpio_init_struct); gpio_init_struct.Pin = GPIO_PIN_6; HAL_GPIO_Init(GPIOD, &gpio_init_struct); gpio_init_struct.Pin = GPIO_PIN_5 | GPIO_PIN_6; HAL_GPIO_Init(GPIOE, &gpio_init_struct); gpio_init_struct.Pin = GPIO_PIN_6 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14; HAL_GPIO_Init(GPIOG, &gpio_init_struct); gpio_init_struct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; HAL_GPIO_Init(GPIOH, &gpio_init_struct); gpio_init_struct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7; HAL_GPIO_Init(GPIOI, &gpio_init_struct); } INIT_DEVICE_EXPORT(ltdc_init);