ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ARM学习笔记(七)——LCD液晶显示

ARM学习笔记(七)——LCD液晶显示 一、主要内容今天主要学习 i.MX6ULL 的 LCD 显示系统重点包括LCD 液晶显示屏LCD 的基本显示原理RGB 数据LCD 的控制信号IOMUX 引脚复用LCD 时钟LCDIF 控制器LCD 初始化TFT LCD 参数显存和帧缓冲800×480 LCD 屏幕配置LCD 背光控制。二、什么是LCDLCDLiquid Crystal Display液晶显示器。LCD 是一种通过液晶材料控制光线透过从而显示图像的显示设备。LCD 显示的基本单位是像素 Pixel例如当前使用的 LCD 分辨率800 × 480表示水平方向800个像素 垂直方向480个像素总像素数量800 × 480 384000因此一幅完整的画面需要控制384000个像素三、LCD显示的基本原理LCD 显示图像本质上就是给每一个像素提供对应的颜色数据。例如像素1 → 红色 像素2 → 绿色 像素3 → 蓝色 像素4 → 白色 ...大量像素组合在一起就形成完整的图像。可以理解为LCD显示 │ ┌────────┴────────┐ ↓ ↓ 像素位置 像素颜色 │ │ X、Y坐标 RGB数据 │ │ └────────┬────────┘ ↓ 图像四、LCD的RGB数据LCD 通常通过 RGB 数据表示像素颜色。RGB 分别表示R → Red 红色 G → Green 绿色 B → Blue 蓝色三种颜色按照不同强度组合可以表示不同颜色。例如红色 → R较大G和B较小 绿色 → G较大 蓝色 → B较大 白色 → R、G、B都较大 黑色 → R、G、B都较小五、i.MX6ULL的LCD数据线当前使用的 LCD 接口中可以看到LCD_DATA00 LCD_DATA01 LCD_DATA02 ... LCD_DATA23即LCD_DATA00 ~ LCD_DATA23共24根数据线对应24 bit RGB数据因此 LCD 控制器可以通过这组数据线向 LCD 发送像素数据。六、LCD控制信号除了 RGB 数据线之外LCD 还需要一些控制信号。当前主要包括LCDIF_DATA00 ~ LCDIF_DATA23 LCDIF_ENABLE LCDIF_HSYNC LCDIF_VSYNC LCDIF_CLK其中1. DATA用于传输像素数据。DATA00 ~ DATA232. CLKLCD 像素时钟。LCDIF_CLK用于控制像素数据传输的时序。3. HSYNCHorizontal Synchronization行同步信号。用于表示一行显示数据的同步。4. VSYNCVertical Synchronization场同步信号。用于表示一帧图像的同步。5. ENABLE用于数据有效控制。七、LCD数据传输可以怎么理解LCD显示一幅图像时并不是一次把整个屏幕的数据全部发送出去而是按照一定的时序连续发送。基本过程可以理解为第1行 ↓ 第2行 ↓ 第3行 ↓ ... ↓ 第480行 ↓ 完成一帧 ↓ 重新开始每一行又包含像素1 ↓ 像素2 ↓ 像素3 ↓ ... ↓ 像素800因此800 × 480就是480行 × 每行800个像素八、LCD引脚复用i.MX6ULL 的引脚具有复用功能。同一个物理引脚可以根据配置承担不同功能。使用 LCD 时需要将相关引脚配置为LCDIF例如IOMUXC_SetPinMux( IOMUXC_LCD_DATA00_LCDIF_DATA00, 0 );表示将对应引脚配置为LCD_DATA00同样还需要配置LCD_DATA00 ~ LCD_DATA23 LCD_ENABLE LCD_HSYNC LCD_VSYNC LCD_CLK因此 LCD 初始化的第一步之一就是配置 LCD 引脚复用。九、LCD引脚电气属性除了配置引脚复用功能还需要配置引脚的电气属性。例如IOMUXC_SetPinConfig( IOMUXC_LCD_DATA00_LCDIF_DATA00, 0XB9 );LCD 数据线以及相关控制线都进行了类似配置。因此 LCD 引脚初始化可以分成两个步骤① 配置引脚复用功能 ↓ LCD_DATA / LCDIF ② 配置引脚电气属性 ↓ 0xB9等配置值十、LCD背光LCD 本身还需要背光。当前程序中使用GPIO1_IO08控制 LCD 背光。首先设置 GPIO1_IO08 为输出GPIO1-GDIR | (1 8);然后输出高电平GPIO1-DR | (1 8);这样可以打开背光。所以 LCD 的显示可以简单理解成两个部分LCD显示控制 LCD背光控制如果 LCD 数据和时序配置正确但是没有背光也可能看不到正常的显示效果。十一、LCD时钟LCD 要正常工作需要一个稳定的像素时钟。i.MX6ULL 中 LCD 时钟与PLL_VIDEO有关。PLL_VIDEOVideo PLL视频锁相环。LCD 时钟配置的大致过程24MHz参考时钟 ↓ PLL_VIDEO ↓ PFD/分频 ↓ LCDIF时钟 ↓ LCD显示十二、PLL_VIDEO当前 LCD 时钟初始化中使用PLL_VIDEO配置中PLL_VIDEO_NUM PLL_VIDEO_DENOM PLL_VIDEO其中设置PLL_VIDEO_NUM 0; PLL_VIDEO_DENOM 1;并配置DIV_SELECT 31得到视频 PLL 的工作频率。代码中的计算关系为PLL输出频率 24MHz × DIV_SELECT当前设置对应24MHz × 31 744MHz所以得到PLL_VIDEO 744MHz十三、LCD时钟分频PLL 输出频率比较高不能直接作为 LCD 像素时钟因此还需要经过分频。基本关系PLL_VIDEO ↓ 分频 ↓ LCDIF时钟 ↓ LCD_CLK当前程序中涉及VIDEO_DIV LCDIF1_PRE_CLK_SEL LCDIF1_PRED LCDIF1_CLK_SEL LCDIF1_PODF因此 LCD 时钟并不是简单地由 PLL 直接提供而是经过多个时钟选择和分频环节得到。十四、LCDIFLCDIFLCD Interface即LCD接口控制器。i.MX6ULL 内部提供 LCDIF 控制器用于完成 CPU 与 LCD 之间的数据和时序控制。可以理解成CPU ↓ LCDIF ↓ RGB数据 ↓ LCDLCDIF 负责像素数据传输 显示时序控制 分辨率配置 帧缓冲地址配置 LCD时钟控制十五、LCD初始化整体流程LCD 初始化可以分成几个主要步骤① LCD引脚初始化 ↓ ② LCD时钟初始化 ↓ ③ LCD复位 ↓ ④ 设置LCD分辨率 ↓ ⑤ 设置LCD时序参数 ↓ ⑥ 设置帧缓冲地址 ↓ ⑦ 配置LCDIF ↓ ⑧ 开启LCDIF ↓ ⑨ 填充显存整体流程lcd_init() │ ├── lcd_pad_init() │ ├── lcd_clk_init() │ ├── lcd_reset() │ └── LCDIF配置十六、LCD复位程序中使用LCDIF-CTRL | (1 31);进行 LCDIF 相关复位操作。之后进行一定时间的延时delay_ms(20);再释放复位LCDIF-CTRL ~(1 31);这样可以让 LCDIF 控制器进入正常工作状态。十七、LCD分辨率当前 LCD 屏幕width 800 height 480即800 × 480程序中lcd_dev.width 800; lcd_dev.height 480;因此X方向0 ~ 799 Y方向0 ~ 479总像素800 × 480 384000十八、像素大小程序中lcd_dev.pix_size 4;表示当前帧缓冲按照4 Byte / Pixel进行存储。也就是每个像素占4个字节因此整个800 × 480屏幕需要的帧缓冲空间为800 × 480 × 4计算384000 × 4 1536000 Byte约1.46MiB因此 LCD 显存需要占用一块连续的内存空间。十九、什么是帧缓冲Frame Buffer帧缓冲区。它是一块内存用于保存当前需要显示的一整帧图像数据。可以理解为CPU ↓ 写入帧缓冲 ↓ Frame Buffer ↓ LCDIF读取 ↓ LCD显示例如内存 ┌──────────────────┐ │ 像素0 │ │ 像素1 │ │ 像素2 │ │ ... │ │ 像素800 │ │ 下一行 │ │ ... │ │ 最后一行 │ └──────────────────┘LCDIF 根据帧缓冲地址读取数据并不断发送到 LCD。二十、帧缓冲地址程序中lcd.dev.frame_addr _FRAME_RAM_ADDR_;帧缓冲地址用于告诉 LCDIF图像数据存放在哪里。程序中定义的帧缓冲地址为0x89000000也就是_FRAME_RAM_ADDR_因此整个 LCD 显示系统可以理解为0x89000000 ↓ Frame Buffer ↓ LCDIF ↓ LCD二十一、LCD前景色和背景色程序中设置lcd.fore_color 0x00FF0000; lcd.back_color 0x00FFFFFF;其中fore_color → 前景色 back_color → 背景色当前背景色0x00FFFFFF对应白色。当前前景色0x00FF0000对应红色。因此后续绘制字符、图形等内容时可以使用前景色 → 显示内容 背景色 → 背景二十二、LCD时序参数LCD 不仅需要像素数据还需要严格的显示时序。程序中设置vspw 3 vfp 13 vbp 32 hspw 48 hfp 40 hbp 88其中VSPWVertical Sync Pulse Width垂直同步脉冲宽度。VFPVertical Front Porch垂直前肩。VBPVertical Back Porch垂直后肩。HSPWHorizontal Sync Pulse Width水平同步脉冲宽度。HFPHorizontal Front Porch水平前肩。HBPHorizontal Back Porch水平后肩。二十三、为什么需要LCD时序LCD不是只需要RGB数据还需要知道什么时候开始一行 什么时候结束一行 什么时候开始一帧 什么时候结束一帧因此需要HSYNC VSYNC HFP HBP VFP VBP共同确定显示时序。可以简单理解一行 ┌─────────────────────────────┐ │ HBP │ 有效显示 │ HFP │ HSPW │ └─────────────────────────────┘ 一帧 ┌─────────────────────────────┐ │ VBP │ │ 有效显示区域 │ │ │ │ │ │ VFP │ │ VSPW │ └─────────────────────────────┘二十四、LCDIF显示尺寸配置程序中LCDIF-TRANSFER_COUNT (lcd_dev.height 16) | (lcd_dev.width 0);当前height 480 width 800所以 LCDIF 被配置为800 × 480二十五、LCDIF帧缓冲地址程序中LCDIF-CUR_BUF lcd.dev.frame_addr; LCDIF-NEXT_BUF lcd.dev.frame_addr;表示当前帧缓冲地址 下一帧缓冲地址都指向当前的帧缓冲。因此 LCDIF 可以从指定的内存区域读取显示数据。二十六、VDCTRL寄存器LCDIF 中VDCTRL0 VDCTRL1 VDCTRL2 VDCTRL3 VDCTRL4用于配置 LCD 显示时序。可以简单理解为VDCTRL0 → 垂直/同步相关控制 VDCTRL1 → 垂直方向参数 VDCTRL2 → 水平方向参数 VDCTRL3 → 水平、垂直相关间隔参数 VDCTRL4 → 数据宽度等参数程序中通过这些寄存器把800 × 480以及HSPW HFP HBP VSPW VFP VBP等参数配置到 LCDIF 中。二十七、填充整个LCD背景LCDIF 开启以后程序使用二维数组指针访问帧缓冲unsigned int (*pF)[800] (unsigned int (*)[800])lcd_dev.frame_addr;然后for(i 0; i lcd_dev.height; i) { for(j 0; j lcd_dev.width; j) { pF[i][j] lcd_dev.back_color; } }其作用就是把整个 800×480 屏幕的每一个像素都设置成背景色。流程第0行 ↓ 800个像素全部填充 ↓ 第1行 ↓ 800个像素全部填充 ↓ ... ↓ 第479行 ↓ 完成整个屏幕填充当前背景色为0x00FFFFFF因此初始化后整个屏幕被填充为白色。二十八、LCD显示系统整体结构可以把今天的 LCD 系统理解为i.MX6ULL │ ┌────────┴────────┐ │ │ CPU 时钟系统 │ │ │ PLL_VIDEO │ │ │ 分频 │ │ └───────┬─────────┘ ↓ LCDIF │ ┌───────────┼───────────┐ ↓ ↓ ↓ RGB数据 HSYNC VSYNC │ LCD_CLK │ ↓ LCD屏幕 │ 800×480同时Frame Buffer │ 0x89000000 │ ↓ LCDIF │ ↓ LCD二十九、LCD初始化代码结构今天 LCD 驱动程序的整体结构可以理解为void lcd_init(void) { // 1. LCD引脚初始化 lcd_pad_init(); // 2. LCD时钟初始化 lcd_clk_init(); // 3. 设置LCD基本参数 lcd_dev.width 800; lcd_dev.height 480; lcd_dev.pix_size 4; // 4. 配置LCD时序参数 // hspw、hfp、hbp // vspw、vfp、vbp // 5. LCDIF复位 lcd_reset(); // 6. 配置LCDIF // TRANSFER_COUNT // CUR_BUF // NEXT_BUF // VDCTRL0~VDCTRL4 // 7. 开启LCDIF // 8. 填充背景 }所以以后学习 LCD 绘图函数时就是在这个基础上继续增加画点 画线 画矩形 显示字符 显示图片等功能。三十、LCD与显存的关系LCD本身并不是直接理解 C 语言中的printf()等函数。LCD最终需要的是像素数据因此程序需要先把图像数据写入Frame Buffer然后Frame Buffer ↓ LCDIF ↓ RGB数据 ↓ LCD所以LCD显示的核心就是对帧缓冲中的像素数据进行操作。例如要把坐标(x, y)位置的像素设置成红色本质上就是FrameBuffer[y][x] 红色值
返回列表