2017-09-12 17:57:14 +08:00
|
|
|
/*
|
2018-10-16 13:00:37 +08:00
|
|
|
* Copyright (c) 2006-2018, RT-Thread Development Team
|
2017-09-12 17:57:14 +08:00
|
|
|
*
|
2018-10-16 13:00:37 +08:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2017-09-12 17:57:14 +08:00
|
|
|
*
|
|
|
|
* Change Logs:
|
|
|
|
* Date Author Notes
|
|
|
|
* 2017-08-17 Tanek first implementation
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <rtthread.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "stm32f4xx_hal.h"
|
|
|
|
|
|
|
|
#define RT_HW_LCD_WIDTH ((uint16_t)800) /* LCD PIXEL WIDTH */
|
|
|
|
#define RT_HW_LCD_HEIGHT ((uint16_t)480) /* LCD PIXEL HEIGHT */
|
|
|
|
#define LCD_800_480_HSYNC ((uint16_t)96) /* Horizontal synchronization */
|
|
|
|
#define LCD_800_480_HBP ((uint16_t)10) /* Horizontal back porch */
|
|
|
|
#define LCD_800_480_HFP ((uint16_t)10) /* Horizontal front porch */
|
|
|
|
#define LCD_800_480_VSYNC ((uint16_t)2) /* Vertical synchronization */
|
|
|
|
#define LCD_800_480_VBP ((uint16_t)10) /* Vertical back porch */
|
|
|
|
#define LCD_800_480_VFP ((uint16_t)10) /* Vertical front porch */
|
|
|
|
|
|
|
|
#define LCD_BITS_PER_PIXEL 16
|
|
|
|
|
|
|
|
|
|
|
|
static LTDC_HandleTypeDef hltdc;
|
|
|
|
static DMA2D_HandleTypeDef hdma2d;
|
|
|
|
|
|
|
|
static rt_uint16_t *lcd_framebuffer = RT_NULL;
|
|
|
|
static rt_uint16_t *_rt_framebuffer = RT_NULL;
|
|
|
|
|
|
|
|
static struct rt_device_graphic_info _lcd_info;
|
|
|
|
static struct rt_device lcd;
|
|
|
|
|
|
|
|
void HAL_LTDC_MspInit(LTDC_HandleTypeDef* hltdc)
|
|
|
|
{
|
|
|
|
GPIO_InitTypeDef GPIO_InitStruct;
|
|
|
|
if(hltdc->Instance==LTDC)
|
|
|
|
{
|
|
|
|
/* Peripheral clock enable */
|
|
|
|
__HAL_RCC_LTDC_CLK_ENABLE();
|
|
|
|
__HAL_RCC_DMA2D_CLK_ENABLE();
|
|
|
|
__HAL_RCC_GPIOE_CLK_ENABLE();
|
|
|
|
__HAL_RCC_GPIOI_CLK_ENABLE();
|
|
|
|
__HAL_RCC_GPIOJ_CLK_ENABLE();
|
|
|
|
__HAL_RCC_GPIOK_CLK_ENABLE();
|
|
|
|
|
|
|
|
/**LTDC GPIO Configuration
|
|
|
|
PI12 ------> LTDC_HSYNC
|
|
|
|
PI13 ------> LTDC_VSYNC
|
|
|
|
PI14 ------> LTDC_CLK
|
|
|
|
PI15 ------> LTDC_R0
|
|
|
|
PJ0 ------> LTDC_R1
|
|
|
|
PJ2 ------> LTDC_R3
|
|
|
|
PJ3 ------> LTDC_R4
|
|
|
|
PJ4 ------> LTDC_R5
|
|
|
|
PJ5 ------> LTDC_R6
|
|
|
|
PJ6 ------> LTDC_R7
|
|
|
|
PJ9 ------> LTDC_G2
|
|
|
|
PJ10 ------> LTDC_G3
|
|
|
|
PJ11 ------> LTDC_G4
|
|
|
|
PK0 ------> LTDC_G5
|
|
|
|
PK1 ------> LTDC_G6
|
|
|
|
PK2 ------> LTDC_G7
|
|
|
|
PJ15 ------> LTDC_B3
|
|
|
|
PK3 ------> LTDC_B4
|
|
|
|
PK4 ------> LTDC_B5
|
|
|
|
PK5 ------> LTDC_B6
|
|
|
|
PK6 ------> LTDC_B7
|
|
|
|
PK7 ------> LTDC_DE
|
|
|
|
*/
|
|
|
|
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
|
|
|
|
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
|
|
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
|
|
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
|
|
|
GPIO_InitStruct.Alternate = GPIO_AF14_LTDC;
|
|
|
|
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
|
|
|
|
|
|
|
|
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4
|
|
|
|
|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_9|GPIO_PIN_10
|
|
|
|
|GPIO_PIN_11|GPIO_PIN_15;
|
|
|
|
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
|
|
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
|
|
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
|
|
|
GPIO_InitStruct.Alternate = GPIO_AF14_LTDC;
|
|
|
|
HAL_GPIO_Init(GPIOJ, &GPIO_InitStruct);
|
|
|
|
|
|
|
|
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
|
|
|
|
|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
|
|
|
|
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
|
|
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
|
|
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
|
|
|
GPIO_InitStruct.Alternate = GPIO_AF14_LTDC;
|
|
|
|
HAL_GPIO_Init(GPIOK, &GPIO_InitStruct);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void HAL_LTDC_MspDeInit(LTDC_HandleTypeDef* hltdc)
|
|
|
|
{
|
|
|
|
if(hltdc->Instance==LTDC)
|
|
|
|
{
|
|
|
|
/* Peripheral clock disable */
|
|
|
|
__HAL_RCC_LTDC_CLK_DISABLE();
|
|
|
|
|
|
|
|
/**LTDC GPIO Configuration
|
|
|
|
PE5 ------> LTDC_G0
|
|
|
|
PE6 ------> LTDC_G1
|
|
|
|
PI12 ------> LTDC_HSYNC
|
|
|
|
PI13 ------> LTDC_VSYNC
|
|
|
|
PI14 ------> LTDC_CLK
|
|
|
|
PI15 ------> LTDC_R0
|
|
|
|
PJ0 ------> LTDC_R1
|
|
|
|
PJ1 ------> LTDC_R2
|
|
|
|
PJ2 ------> LTDC_R3
|
|
|
|
PJ3 ------> LTDC_R4
|
|
|
|
PJ4 ------> LTDC_R5
|
|
|
|
PJ5 ------> LTDC_R6
|
|
|
|
PJ6 ------> LTDC_R7
|
|
|
|
PJ9 ------> LTDC_G2
|
|
|
|
PJ10 ------> LTDC_G3
|
|
|
|
PJ11 ------> LTDC_G4
|
|
|
|
PK0 ------> LTDC_G5
|
|
|
|
PK1 ------> LTDC_G6
|
|
|
|
PK2 ------> LTDC_G7
|
|
|
|
PJ12 ------> LTDC_B0
|
|
|
|
PJ13 ------> LTDC_B1
|
|
|
|
PJ14 ------> LTDC_B2
|
|
|
|
PJ15 ------> LTDC_B3
|
|
|
|
PK3 ------> LTDC_B4
|
|
|
|
PK4 ------> LTDC_B5
|
|
|
|
PK5 ------> LTDC_B6
|
|
|
|
PK6 ------> LTDC_B7
|
|
|
|
PK7 ------> LTDC_DE
|
|
|
|
*/
|
|
|
|
HAL_GPIO_DeInit(GPIOE, GPIO_PIN_5|GPIO_PIN_6);
|
|
|
|
|
|
|
|
HAL_GPIO_DeInit(GPIOI, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15);
|
|
|
|
|
|
|
|
HAL_GPIO_DeInit(GPIOJ, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
|
|
|
|
|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_9
|
|
|
|
|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13
|
|
|
|
|GPIO_PIN_14|GPIO_PIN_15);
|
|
|
|
|
|
|
|
HAL_GPIO_DeInit(GPIOK, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
|
|
|
|
|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void LTDC_CLK_Config(void)
|
|
|
|
{
|
|
|
|
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
|
|
|
|
|
|
|
|
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
|
|
|
|
PeriphClkInitStruct.PLLSAI.PLLSAIN = 100;
|
|
|
|
PeriphClkInitStruct.PLLSAI.PLLSAIR = 2;
|
|
|
|
PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_2;
|
|
|
|
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
|
|
|
|
{
|
|
|
|
RT_ASSERT(RT_NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* LTDC init function */
|
|
|
|
static void MX_LTDC_Init(void)
|
|
|
|
{
|
|
|
|
LTDC_LayerCfgTypeDef pLayerCfg;
|
|
|
|
|
|
|
|
hltdc.Instance = LTDC;
|
|
|
|
hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
|
|
|
|
hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
|
|
|
|
hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
|
|
|
|
hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
|
|
|
|
|
|
|
|
hltdc.Init.Backcolor.Blue = 0;
|
|
|
|
hltdc.Init.Backcolor.Green = 0;
|
|
|
|
hltdc.Init.Backcolor.Red = 0;
|
|
|
|
|
|
|
|
hltdc.Init.HorizontalSync = LCD_800_480_HSYNC;
|
|
|
|
hltdc.Init.VerticalSync = LCD_800_480_VSYNC;
|
|
|
|
hltdc.Init.AccumulatedHBP = LCD_800_480_HSYNC + LCD_800_480_HBP;
|
|
|
|
hltdc.Init.AccumulatedVBP = LCD_800_480_VSYNC + LCD_800_480_VBP;
|
|
|
|
hltdc.Init.AccumulatedActiveW = RT_HW_LCD_WIDTH + LCD_800_480_HSYNC + LCD_800_480_HBP;
|
|
|
|
hltdc.Init.AccumulatedActiveH = RT_HW_LCD_HEIGHT + LCD_800_480_VSYNC + LCD_800_480_VBP;
|
|
|
|
hltdc.Init.TotalWidth = RT_HW_LCD_WIDTH + LCD_800_480_HSYNC + LCD_800_480_HBP + LCD_800_480_HFP;
|
|
|
|
hltdc.Init.TotalHeigh = RT_HW_LCD_HEIGHT + LCD_800_480_VSYNC + LCD_800_480_VBP + LCD_800_480_VFP;
|
|
|
|
|
|
|
|
hltdc.LayerCfg->ImageHeight = RT_HW_LCD_HEIGHT;
|
|
|
|
hltdc.LayerCfg->ImageWidth = RT_HW_LCD_WIDTH;
|
|
|
|
|
|
|
|
if (HAL_LTDC_Init(&hltdc) != HAL_OK)
|
|
|
|
{
|
|
|
|
RT_ASSERT(RT_NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
lcd_framebuffer = rt_malloc_align(sizeof(rt_uint16_t) * RT_HW_LCD_WIDTH * RT_HW_LCD_HEIGHT, 32);
|
|
|
|
RT_ASSERT(lcd_framebuffer != RT_NULL);
|
|
|
|
rt_memset(lcd_framebuffer, 0, sizeof(rt_uint16_t) * RT_HW_LCD_WIDTH * RT_HW_LCD_HEIGHT);
|
|
|
|
|
|
|
|
pLayerCfg.WindowX0 = 0;
|
|
|
|
pLayerCfg.WindowX1 = RT_HW_LCD_WIDTH;
|
|
|
|
pLayerCfg.WindowY0 = 0;
|
|
|
|
pLayerCfg.WindowY1 = RT_HW_LCD_HEIGHT;
|
|
|
|
pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
|
|
|
|
pLayerCfg.Alpha = 0xFF;
|
|
|
|
pLayerCfg.Alpha0 = 0xFF;
|
|
|
|
pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
|
|
|
|
pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR1_CA;
|
|
|
|
pLayerCfg.FBStartAdress = (uint32_t)lcd_framebuffer;
|
|
|
|
pLayerCfg.ImageWidth = RT_HW_LCD_WIDTH;
|
|
|
|
pLayerCfg.ImageHeight = RT_HW_LCD_HEIGHT;
|
|
|
|
pLayerCfg.Backcolor.Blue = 0;
|
|
|
|
pLayerCfg.Backcolor.Green = 0;
|
|
|
|
pLayerCfg.Backcolor.Red = 0;
|
|
|
|
if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
|
|
|
|
{
|
|
|
|
RT_ASSERT(RT_NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* DMA2D init function */
|
|
|
|
static void MX_DMA2D_Init(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
hdma2d.Instance = DMA2D;
|
|
|
|
hdma2d.Init.Mode = DMA2D_M2M;
|
|
|
|
hdma2d.Init.ColorMode = DMA2D_OUTPUT_RGB565;
|
|
|
|
hdma2d.Init.OutputOffset = 0;
|
|
|
|
hdma2d.LayerCfg[0].InputOffset = 0;
|
|
|
|
hdma2d.LayerCfg[0].InputColorMode = DMA2D_INPUT_RGB565;
|
|
|
|
hdma2d.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA;
|
|
|
|
hdma2d.LayerCfg[0].InputAlpha = 0;
|
|
|
|
if (HAL_DMA2D_Init(&hdma2d) != HAL_OK)
|
|
|
|
{
|
|
|
|
RT_ASSERT(RT_NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HAL_DMA2D_ConfigLayer(&hdma2d, 0) != HAL_OK)
|
|
|
|
{
|
|
|
|
RT_ASSERT(RT_NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void lcd_backlight_init(void)
|
|
|
|
{
|
|
|
|
GPIO_InitTypeDef GPIO_InitStruct;
|
|
|
|
|
|
|
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
|
|
|
|
|
|
|
GPIO_InitStruct.Pin = GPIO_PIN_0;
|
|
|
|
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
|
|
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
|
|
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
|
|
|
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
|
|
|
|
|
|
|
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
|
|
|
|
}
|
|
|
|
|
|
|
|
static rt_err_t rt_lcd_init(rt_device_t dev)
|
|
|
|
{
|
|
|
|
return RT_EOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static rt_err_t rt_lcd_open(rt_device_t dev, rt_uint16_t oflag)
|
|
|
|
{
|
|
|
|
return RT_EOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static rt_err_t rt_lcd_close(rt_device_t dev)
|
|
|
|
{
|
|
|
|
return RT_EOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static rt_err_t rt_lcd_control(rt_device_t dev, rt_uint8_t cmd, void *args)
|
|
|
|
{
|
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case RTGRAPHIC_CTRL_RECT_UPDATE:
|
|
|
|
{
|
|
|
|
memcpy((void *)lcd_framebuffer, _rt_framebuffer, sizeof(rt_uint16_t)*RT_HW_LCD_HEIGHT * RT_HW_LCD_WIDTH);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RTGRAPHIC_CTRL_POWERON:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RTGRAPHIC_CTRL_POWEROFF:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RTGRAPHIC_CTRL_GET_INFO:
|
|
|
|
memcpy(args, &_lcd_info, sizeof(_lcd_info));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RTGRAPHIC_CTRL_SET_MODE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return RT_EOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int stm32_hw_lcd_init(void)
|
|
|
|
{
|
|
|
|
_rt_framebuffer = rt_malloc_align(sizeof(rt_uint16_t) * RT_HW_LCD_WIDTH * RT_HW_LCD_HEIGHT, 32);
|
|
|
|
if (_rt_framebuffer == RT_NULL)
|
|
|
|
return -1; /* no memory yet */
|
|
|
|
|
|
|
|
LTDC_CLK_Config();
|
|
|
|
MX_LTDC_Init();
|
|
|
|
lcd_backlight_init();
|
|
|
|
MX_DMA2D_Init();
|
|
|
|
|
|
|
|
_lcd_info.bits_per_pixel = LCD_BITS_PER_PIXEL;
|
|
|
|
_lcd_info.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565; // RTGRAPHIC_PIXEL_FORMAT_ARGB888
|
|
|
|
_lcd_info.framebuffer = (void *)_rt_framebuffer;
|
|
|
|
_lcd_info.width = RT_HW_LCD_WIDTH;
|
|
|
|
_lcd_info.height = RT_HW_LCD_HEIGHT;
|
|
|
|
|
|
|
|
/* init device structure */
|
|
|
|
lcd.type = RT_Device_Class_Graphic;
|
|
|
|
lcd.init = rt_lcd_init;
|
|
|
|
lcd.open = rt_lcd_open;
|
|
|
|
lcd.close = rt_lcd_close;
|
|
|
|
lcd.read = NULL;
|
|
|
|
lcd.write = NULL;
|
|
|
|
lcd.control = rt_lcd_control;
|
|
|
|
lcd.user_data = (void *)&_lcd_info;
|
|
|
|
|
|
|
|
/* register lcd device to RT-Thread */
|
|
|
|
rt_device_register(&lcd, "lcd", RT_DEVICE_FLAG_RDWR);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
INIT_APP_EXPORT(stm32_hw_lcd_init);
|