目录
一 通过STM32CubeMX配置LTDC
二 配置SDRAM与DMA2D
三 通过STM32CubeMX配置STemWin(推荐)
四 添加STemWin代码(手动移植STemWin)
五 编写RGB LCD驱动文件(手动移植STemWin)
六 关联TFTLCD驱动函数与STemWin(手动移植STemWin)
开发板: 正点原子STM32F767
LCD型号: 正点原子4.3寸、分辨率为480×272的RGB屏
STM32CubeMX : Version 5.2.1
一 通过STM32CubeMX配置LTDC
1.Parameter Setting配置
RGB LCD几个重要的参数配置如下所示:
通过上表可以得出以下关键信息:
- LCD频率可配置为9MHz
- VSYNC width:垂直同步脉宽, 取值1
- VBP:垂直后廊,表示垂直同步信号后,无效行的个数,取值8
- VFP:垂直前廊,表示一帧数据输出结束后,到下一个垂直同步信号开始之前的无效行数,取值8
- Active Height:有效高度,横屏取值272,竖屏取值480
- HSYNC width:水平同步脉宽,取值1
- HBP:水平后廊,,表示水平同步信号开始到行有效数据开始之间的相素时钟(CLK)个数,取值40
- HFP:水平前廊,表示行有效数据结束到下一个水平有效信号开始之前的相素时钟(CLK)个数,取值5
- Active width:有效宽度,横屏取值480,竖屏取值272
通过以上说明配置Parameter Setting如下所示:
2 Layer Setting配置
RGB LCD可以配置两层,一般情况下Layer1作为前景层,Layer0作为背景层,需要知道的是这里的两层是软件层面上的,硬件上LCD只有一层,最终显示时,是将两层数据进行混合形成一层数据,再发送给LCD进行显示。
例如下图有一副前景图片,该图片含有透明因子,该图片存放在Layer1对应的buff1中;另有一副背景图片,该图片存放在Layer0对应的buff0中。stm32通过混合运算,将buff1与buff0中的数据进行合并后再发送给RGB LCD显示。
3. GPIO Setting配置如下:
4. 配置像素时钟
通过数据手册得知时钟范围为5~12MHz,典型为9MHz,所以LCD-TFT时钟配置如下:
二 配置SDRAM与DMA2D
LCD采用RGB565的方式,所以每一个点的颜色占用2字节, LCD共有480×272个点
所以LCD一层的显示至少需要 480×272×2 = 261120 byte = 255 kb
一般情况下RGBLCD有两层,如果需要两层显示则需要 255 ×2 = 510 kb
而stm32f767内置flash只有512kb, 明显是不够用的,所以需要使用外扩SDRAM.
1. 通过STM32CubeMX配置SDRAM可参考博客:
2. 配置DMA2D
Chrom-Art Accelerator™ (DMA2D) 是专用于图像处理的专业 DMA。由前面介绍可知,显示的图形是通过一定格式存储在内存中,要改变显示的内容,只需将新的数据存储在对应的显存中即可,可以通过DMA传输数据。DMA2D和普通的DMA通道不一样是,它是专用于图像处理的专用DMA,他可以执行下列操作。
- 用特定颜色填充目标图像的一部分或全部
- 将源图像的一部分(或全部)复制到目标图像的一部分(或全部)中
- 通过像素格式转换将源图像的一部分或全部复制到目标图像的一部分或全部中
- 将像素格式不同的两个源图像部分和 / 或全部混合,再将结果复制到颜色格式不同的部分或整个目标图像中。
DMA2D的Parameter Setting配置如下所示:
需要特别注意的是,这里必须要配置DMA2D中断,否则在使用DMA2D传输数据是会一直等待传输完成。
三 通过STM32CubeMX配置STemWin(推荐)
配置好LTDC后StemWin才是可选择的:
至此,已经可以生成代码,在开发板上运行程序了。
四 添加STemWin代码(手动移植STemWin)
1. 使用STemWin必须打开CRC,否则图形库运行不起来
2.添加的代码如下:
3. 头文件路径如下:
五 编写RGB LCD驱动文件(手动移植STemWin)
主要实现画点, 读点,填充函数, 这里填充函数使用了DMA2D
#define LTDC_WIDTH 480
#define LTDC_HEIGHT 272
uint16_t ltdc_layer0[LTDC_HEIGHT][LTDC_WIDTH] __attribute__((at(LAYER0_ADDR))); //定义最大屏分辨率时,LCD所需的帧缓存数组大小
uint16_t ltdc_layer1[LTDC_WIDTH][LTDC_HEIGHT] __attribute__((at(LAYER1_ADDR))); //定义最大屏分辨率时,LCD所需的帧缓存数组大小
/***************************************************************************************
* @brief 读取个某点的颜色值
* @input x,y:坐标
* @return 返回值:此点的颜色
***************************************************************************************/
uint32_t LCD_ReadPoint(uint16_t x, uint16_t y)
{
return *(uint16_t*)((uint32_t)ltdc_layer0[0] + 2 * (LTDC_WIDTH * y + x));
}
/***************************************************************************************
* @brief 画点
* @input x,y:坐标 color:颜色
* @return
***************************************************************************************/
void LCD_DrawPoint(uint16_t x, uint16_t y, uint32_t color)
{
*(uint16_t*)((uint32_t)ltdc_layer0[0] + 2 * (LTDC_WIDTH * y + x)) = color;
}
/***************************************************************************************
* @brief 在指定区域内填充单个颜色
* @input (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
* @input color:要填充的颜色
* @return
***************************************************************************************/
void LCD_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t color)
{
uint32_t timeout = 0;
uint32_t addr = ((uint32_t)ltdc_layer0[0] + 2 * (LTDC_WIDTH * sy + sx));//输出存储器地址
uint16_t offline = LTDC_WIDTH - (ex - sx + 1); //设置行偏移
RCC->AHB1ENR |= RCC_AHB1LPENR_DMA2DLPEN; //使能DM2D时钟
DMA2D->CR = DMA2D_CR_MODE; //寄存器到存储器模式
DMA2D->OPFCCR = LTDC_PIXEL_FORMAT_RGB565;//设置颜色格式
DMA2D->OOR = offline;
DMA2D->CR &= ~(DMA2D_CR_START); //先停止DMA2D
DMA2D->OMAR = addr;
DMA2D->NLR = (ey - sy + 1) | ((ex - sx + 1)<<16);//设定行数寄存器
DMA2D->OCOLR = color; //设定输出颜色寄存器
DMA2D->CR |= DMA2D_CR_START; //启动DMA2D
while((DMA2D->ISR & DMA2D_ISR_TCIF) == 0) //等待传输完成
{
timeout++;
if(timeout>0X1FFFFF)
break; //超时退出
}
DMA2D->IFCR |= DMA2D_IFCR_CTCIF; //清除传输完成标志
}
六 关联TFTLCD驱动函数与STemWin(手动移植STemWin)
1. 注释掉LCD_ConfDefaults.h和LCD_Private.h文件中的#include "LCDConf.h"
2. GUIConf.h 文件中添加 #define OS_SUPPORT 启用OS
3. 从STemWin库中复制STemWin_Library_V1.2.0\Project\STM32469I-EVAL\RTOS\Config\GUI_X_FreeRTOS.c文件
替代GUI_X_OS.c文件中的内容. (stm32cubemx官方下载地址)
4. 修改LCDConf_FlexColor_Template.c文件
在这个文件中我们要完成 STemWin 的打点(_SetPixelIndex())、读点(_GetPixelIndex())、填充(_FillRect())等函数的实现
static void _SetPixelIndex(GUI_DEVICE * pDevice, int x, int y, int PixelIndex) {
......
GUI_USE_PARA(PixelIndex);
{
LCD_DrawPoint(x,y,PixelIndex); //此处调用画点函数
}
......
}
static unsigned int _GetPixelIndex(GUI_DEVICE * pDevice, int x, int y) {
......
GUI_USE_PARA(y);
{
PixelIndex = LCD_ReadPoint(x,y); //次处调用读点函数
}
......
}
static void _FillRect(GUI_DEVICE * pDevice, int x0, int y0, int x1, int y1) {
......
if (GUI_pContext->DrawMode & LCD_DRAWMODE_XOR) {
......
} else {
LCD_Fill(x0,y0,x1,y1,LCD_COLORINDEX);//此处修改为画矩形函数
}
}
5.修改LCDConf_FlexColor_Template.c
该文件主要修改LCD_X_Config函数 与XSIZE_PHYS /YSIZE_PHYS 两个宏,
有一点需要注意:GUI_DEVICE_CreateAndLink(&GUIDRV_Template_API, GUICC_M565, 0, 0);
该函数的第一个参数是有修改的,表示我们使用的驱动函数是GUIDRV_Template_API数组中的函数
#define XSIZE_PHYS 480// To be adapted to x-screen size
#define YSIZE_PHYS 272// To be adapted to y-screen size
void LCD_X_Config(void) {
// Set display driver and color conversion
//
GUI_DEVICE_CreateAndLink(&GUIDRV_Template_API, GUICC_M565, 0, 0);
//
// Display driver configuration, required for Lin-driver
//
LCD_SetSizeEx (0, XSIZE_PHYS , YSIZE_PHYS);
LCD_SetVSizeEx(0, XSIZE_PHYS, YSIZE_PHYS);
}