1 前言
RT1052 系列芯片内部自带一个增强型液晶Parallel RGB接口外设eLCDIF(Enhanced LCD Interface),配合使用内部SRAM或外部的SDRAM作为显存,可直接控制液晶面板,无需额外增加液晶控制器芯片。RT1052 的eLCDIF 液晶控制器最高支持1366x768 分辨率的屏幕;可支持多种颜色格式,包括RGB888、RGB565、ARGB8888 等(其中的“A”是指透明像素)。下面我们就来介绍一下这个外设。(对LCD不熟悉的小伙伴可以先参考文章《小猫爪:嵌入式小知识09-LCD Parallel RGB接口(转载)》)
2 结构
eLCDIF功能结构如下图显示:
- LCD Pins
eLCDIF 的通讯引脚与液晶显示面板控制信号一一对应,包含有HSYNC、VSYNC、DE、CLK 以及RGB 数据线。 - Panel Interface Generator
eLCDIF 外设提供了一个面板接口生成器的功能,也称为Pigeon Mode 模式。使用该模式时,可以通过每个eLCDIF 信号线独有的计数器进行控制,计数器的起始条件和递增条件可以自由定制,从而可以使各个信号线实现延迟、翻转等功能。 - LUT
在eLCDIF 外设中LUT 表是个256x24位的空间,共有2 个LUT 表,在每个表的空间中可以缓存256 种24 位的颜色,颜色的格式是RGB888。利用颜色查找表显示,实际的图像只能使用这256 种颜色,这可以使用8位数据来表示24位的显示效果。比如对于色彩要求不高的场合,可以在RAM中定义8位数据宽度来表示像素点,但是可以通过LUT表将8位像素数据转变成24像素数,然后再通过IO输出给LCD。 - LCD Interface
LCD Interface是eLCDIF 外设的主要功能部件,受控制总线(Control Bus)的寄存器控制,从系统总线(System Bus)获得输入像素数据,经过一系列转换后通过eLCDIF 的通讯引脚发送至外接的液晶面板。 - Display clock和Bus clock
Bus clock是eLCDIF外设时钟, Display clock则是RGB接口的像素时钟。在这里得重点说一下像素时钟,像素时钟是LCD发出的时钟,虽然我们口头经常说我们将显存数据输送给LCD,其实这种说法是不正确的,LCD控制器其实是主机,RT1050是从机,它发送像素时钟信号给RT1050,然后从显存中取数据。
3 初始化结构体
可以直接使用NXP的SDK 库中的LCD初始化结构体对其进行初始化,下面贴出LCD初始化结构体:
typedef struct _elcdif_rgb_mode_config
{
uint16_t panelWidth; /*!< Display panel width, pixels per line. */
uint16_t panelHeight; /*!< Display panel height, how many lines per panel. */
uint8_t hsw; /*!< HSYNC pulse width. */
uint8_t hfp; /*!< Horizontal front porch. */
uint8_t hbp; /*!< Horizontal back porch. */
uint8_t vsw; /*!< VSYNC pulse width. */
uint8_t vfp; /*!< Vrtical front porch. */
uint8_t vbp; /*!< Vertical back porch. */
uint32_t polarityFlags; /*!< OR'ed value of @ref _elcdif_polarity_flags, used to contol the signal polarity. */
uint32_t bufferAddr; /*!< Frame buffer address. */
elcdif_pixel_format_t pixelFormat; /*!< Pixel format. */
elcdif_lcd_data_bus_t dataBus; /*!< LCD data bus. */
} elcdif_rgb_mode_config_t;
每一个参数都是那么显而易见的:
名称 | 描述 |
---|---|
panelWidth | 配置要控制的液晶面板的分辨率,分别指定宽和高,即每行有多少个像素点、一共有多少行。 |
panelHeight | 配置要控制的液晶面板的分辨率,分别指定宽和高,即每行有多少个像素点、一共有多少行。 |
hsw | HSYNC 信号的宽度像素时钟数 |
hfp | HSYNC 前的无效像素时钟数 |
hbp | HSYNC 后的无效像素时钟数 |
vsw | VSYNC 信号的宽度时钟数 |
vfp | VSYNC 前的无效行数时钟数 |
vbp | VSYNC 后的无效行数时钟数 |
polarityFlags | 设置各个信号的极性,对这个结构体成员赋值时可使用枚举类型_elcdif_polarity_flags |
bufferAddr | 配置显存的基地址,eLCDIF 外设会从该地址中搬运数据到液晶面板,显存的位置可根据需要定义到内部SRAM 或扩展的SDRAM 空间中,该地址要求8 字节对齐(double-word aligned) |
pixelFormat | 配置eLCDIF 的输入源像素数据格式,它是一个_elcdif_pixel_format 枚举类型变量 |
dataBus | 配置eLCDIF 要使用的数据信号线宽度,它是一个elcdif_lcd_data_bus_t 枚举类型 |
4 开启一次简单的传输过程
其实传输过程很简单,取出NXP的demo来看(已经去除其他的部分):
/*初始化LCD相关的引脚*/
BOARD_InitPins();
/*初始化LCD像素时钟*/
BOARD_InitLcdifPixelClock();
/*打开LCD背光*/
BOARD_InitLcd();
/*初始化LCDIF控制器*/
APP_ELCDIF_Init();
/*使能LCD中断*/
BOARD_EnableLcdInterrupt();
/* Clear the frame buffer. */
memset(s_frameBuffer, 0, sizeof(s_frameBuffer));
/*填充显存1*/
APP_FillFrameBuffer(s_frameBuffer[frameBufferIndex]);
/*使能LCD传输完成中断源*/
ELCDIF_EnableInterrupts(APP_ELCDIF, kELCDIF_CurFrameDoneInterruptEnable);
/*开启eLCDIF的RGB模式*/
ELCDIF_RgbModeStart(APP_ELCDIF);
/*填充显存2*/
APP_FillFrameBuffer(s_frameBuffer[frameBufferIndex]);
/*设置显存地址,开始一次传输*/
ELCDIF_SetNextBufferAddr(APP_ELCDIF, (uint32_t)s_frameBuffer[frameBufferIndex]);
5 PXP
PXP全称pixel pipeline,这是RT1050的一个图形处理硬件加速引擎。举个简单的例子,如果我想将一幅图片缩小后在显示在LCD屏幕上,这就需要通过软件对源图片数据进行处理后然后再输出给LCD显存,这中间则是造成了CPU和RAM 资源的大量使用,但是有了PXP,则是可以将这部分的处理工作交给PXP去完成,再将PXP处理后的数据输出给LCD显存,这不仅增加了速度,还节省了CPU和RAM资源,除了缩放,PXP可以完成叠加以及旋转等操作,在这里我就不说具体实现过程了,感兴趣的小伙伴可以参照官方和SDK的PXP例程学习。
这里提一嘴,现在市场上常见的嵌入式UI设计,有Emwin、LVGL、Embeded Wizard以及Crank等,如果我们将这些UI移植进我们的开发板中,其中间的复杂的UI操作默认都是靠软件变换去实现的,并没有用到PXP,如果想在这些UI中使用PXP,这个时候则需要针对UI的底层进行优化,不过这是一个非常考验软件功底的操作,对于开源UI一般都是需要大牛或者芯片产商去做无私的奉献,而对于收费的UI,如Embeded Wizard则就需要money去解决了。