简介:这份资源面向FPGA初学者与显示驱动开发者,聚焦用Altera FPGA驱动RGB接口液晶屏并输出彩条测试画面的完整工程。包内共126个文件,约3.43MB,以Quartus工程文件为主:cdb、hdb、ddb等综合与布局布线中间数据库,v源码文件承载Verilog逻辑,qpf、qsf工程配置,sof下载文件可直接烧录验证,另有rpt、summary报告与readme说明,便于复现与排查。已有1722人学习下载。读者可从中获得RGB时序生成(像素时钟、HSync、VSync)、并行数据传输、帧缓冲与颜色空间转换等关键环节的可运行参考,并借助编译报告与工程结构理解Altera开发流程,适合作为显示驱动入门的对照样例与调试起点。
1. tft_rgb_colorbar.rar:一个压缩包名背后,藏着屏幕点亮的全部基本功
第一次看到tft_rgb_colorbar.rar这个标题,很多人会以为它只是某个工程打包后的压缩文件,解压出来跑一下就能看到彩条。真正做过屏驱的人知道,彩条(colorbar)是 TFT 屏点亮流程里最朴素也最诚实的自检画面:红、绿、蓝、白、黑几条竖带铺满整屏,颜色对不对、位置偏不偏、有没有撕裂和闪烁,一眼就能看出来。它解决的不是“显示好看”的问题,而是“RGB 时序、数据位序、像素时钟到底通没通”的问题。适合正在调 MCU 或 FPGA 驱动 TFT 屏、手里有 RGB 接口屏但画面还出不来的从业者,也适合刚接手一块屏、需要先建立可信基准画面的新手。下面按“先立时序、再出彩条、最后排坑”的顺序讲透。
2. 先把 RGB 时序立住:彩条不是画出来的,是时序喂出来的
彩条之所以能当基准,是因为它把“像素数据”和“扫描时序”这两件事同时暴露出来。TFT 屏的 RGB 接口本质是一台按行扫描的机器:每个像素时钟(PCLK)推一个像素进来,一行推满 HSYNC 个时钟,其中前肩、有效像素、后肩三段组成;一帧推满 VSYNC 行,同样分前肩、有效行、后肩。彩条只改有效区里的像素值,不改时序参数,所以画面能出来,说明时序骨架是对的;画面出不来或错位,问题多半在时序而不是颜色。
2.1 为什么先做彩条而不是先显示图片
图片会掩盖问题。一张照片里颜色过渡柔和,数据位序接反了、某个颜色通道丢了,肉眼未必立刻发现;彩条是纯色块,R/G/B 三通道各自独立成条,哪条颜色不对、哪条位置偏移,直接对应到接线或寄存器。常见做法是先把彩条跑通,再换渐变图验证灰阶,最后才上真实图像。这个顺序不是仪式感,是排错成本最低的路径:彩条阶段的问题几乎都能定位到“时序参数”或“数据位序”两类,范围窄。
2.2 RGB 接口的五个关键信号与参数含义
不管驱动是 MCU 的 LTDC 外设还是 FPGA 手写时序,绕不开这几组信号:PCLK(像素时钟)、HSYNC(行同步)、VSYNC(帧同步)、DE(数据有效使能,部分屏用)、以及 R/G/B 数据总线。参数上要盯住四个数:水平前肩 HFP、水平后肩 HBP、水平同步宽度 HSW;垂直前肩 VFP、垂直后肩 VBP、垂直同步宽度 VSW。有效分辨率 HACT/VACT 由屏的规格决定,不能改。PCLK 频率则由“一帧总时钟数 × 帧率”反推,算错就会花屏或黑屏。
| 参数 | 含义 | 典型取值来源 | 改错的后果 |
|---|---|---|---|
| HACT / VACT | 有效像素宽高 | 屏规格书固定 | 画面裁切或不满屏 |
| HSW / VSW | 同步脉冲宽度 | 屏规格书给范围 | 同步不稳、画面抖动 |
| HFP / HBP | 水平前后肩 | 规格书给最小值 | 图像左右偏移 |
| VFP / VBP | 垂直前后肩 | 规格书给最小值 | 图像上下滚动 |
| PCLK | 像素时钟 | 总时钟数×帧率反算 | 花屏、闪烁、无显示 |
提示:规格书里的前后肩常给“最小值”,实际取值要留余量。按最小值卡死,换一批屏或温度变化就可能翻车。
2.3 用一段最小配置把时序参数落到寄存器
下面这段是常见 MCU LTDC 风格的配置骨架,参数用占位常量表示,实际值从屏规格书抄。重点看结构:先定时序,再定极性,最后开层。
/* 最小 LTDC 时序配置骨架,参数需按屏规格书替换 */ ltdc_timing_t timing = { .hact = 480, /* 有效宽,屏规格书固定 */ .hsw = 41, /* 行同步宽度 */ .hbp = 13, /* 行后肩 */ .hfp = 32, /* 行前肩 */ .vact = 272, /* 有效高 */ .vsw = 10, /* 帧同步宽度 */ .vbp = 2, /* 帧后肩 */ .vfp = 2, /* 帧前肩 */ .pclk_hz = 9000000, /* 像素时钟,按总时钟数×帧率反算 */ .hsync_pol = 0, /* 极性:0 低有效,1 高有效,按屏定 */ .vsync_pol = 0, .de_pol = 1, .pclk_pol = 0 }; ltdc_init(&timing); /* 写时序寄存器 */ ltdc_layer_enable(0, true); /* 使能第一层,先不配图像 */逻辑说明:ltdc_init把上面八个时序量和四个极性写进控制器;极性错了,同步信号反相,屏会认为“一直在消隐”,表现就是黑屏但有背光。pclk_hz不是随便填,算法是(HACT+HFP+HSW+HBP) × (VACT+VFP+VSW+VBP) × 帧率,算出来偏大屏会花,偏小会闪。参数说明里最容易被忽略的是极性,规格书通常在时序图角落标注,抄漏了就是几小时的黑屏排查。
3. 彩条数据怎么生成:位序、缓存与三种落地写法
时序通了,接下来是往有效区里填颜色。彩条看着简单,真正容易翻车的是数据位序和缓存组织:RGB565 里 R 占高 5 位、G 占中间 6 位、B 占低 5 位,接反一位,红条变蓝条;用显存还是逐行实时生成,决定了 RAM 够不够、画面稳不稳。
3.1 RGB565 位序:红绿蓝各占哪几位
以 16 位 RGB565 为例,一个像素打包成RRRRRGGGGGGBBBBB。纯红是0xF800,纯绿是0x07E0,纯蓝是0x001F,白是0xFFFF,黑是0x0000。这五个值就是彩条的全部素材。位序错误的典型现象:发红色收到蓝色,说明 R 和 B 的高低段接反;发白色正常但单色不对,说明某通道位宽错位。排查时不要猜,直接把五个常量逐个发满全屏,能对上三个以上,位序基本就对了。
3.2 用显存画彩条的完整函数
如果控制器带显存(framebuffer),最稳的做法是启动时把彩条一次性写进显存,之后只做扫描输出。下面函数按竖条划分,每条宽度用bar_w控制,颜色循环使用五个基准色。
/* 向 RGB565 显存写入竖彩条,fb 为显存基址,w/h 为有效分辨率 */ void draw_colorbar(uint16_t *fb, int w, int h, int bar_w) { const uint16_t colors[5] = {0xF800, 0x07E0, 0x001F, 0xFFFF, 0x0000}; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { int idx = (x / bar_w) % 5; /* 每 bar_w 像素换一色 */ fb[y * w + x] = colors[idx]; /* 行优先写入显存 */ } } }逻辑说明:外层按行、内层按列,y * w + x是行优先显存的线性下标,和大多数控制器的扫描顺序一致;如果屏是列优先或做了 90 度旋转,这个下标要换。参数说明:bar_w取w/5能让五条等宽铺满,取小了会重复循环,取大了会截断;colors顺序决定彩条排列,调试时故意打乱顺序能快速确认“颜色映射”和“位置映射”是不是同一套。写完显存后要确保控制器层已使能且显存地址配对上,否则屏上仍是黑屏。
3.3 没有显存时逐行实时生成
小 RAM 的 MCU 常常没有足够显存,只能按行缓冲。做法是准备一行大小的缓冲,在行中断或 DMA 行事件里按当前行号填色,再推给接口。关键点是“行号从有效区第一行算起”,把前肩行也算进去会导致彩条整体下移。逐行生成的代码结构和上面类似,只是把y换成当前有效行计数,缓冲只保留w个像素。这种写法对时序抖动更敏感,PCLK 偏高时容易出现行内撕裂,需要把填色放在行消隐期完成。
3.4 FPGA 侧用计数器直接出彩条
FPGA 手写时序时,彩条可以完全不占存储:用x_cnt、y_cnt两个计数器,在 DE 有效期间按x_cnt / bar_w查颜色表输出。好处是零 BRAM、时序确定;坏处是颜色表要写成组合逻辑或小 LUT,改颜色得改代码。常见做法是把五个常量放进 case 语句,综合后就是几个多路选择器,资源几乎可以忽略。验证时先看 DE 是否在有效区拉高,再看x_cnt是否从 0 数到 HACT-1,两个都对,彩条一定出得来。
4. 避坑与排查:彩条出不来时先看这五处
彩条阶段的问题高度集中,下面五条是按出现频率排的踩坑记录,每条都按“现象 → 原因 → 解决”写,照着顺序查能省掉大量盲试。
4.1 背光亮但全黑:先查极性和使能
现象:背光已开,屏上纯黑无任何条纹。原因通常是同步极性配反,控制器认为一直处于消隐期,或者层使能没打开、显存地址没配对。解决:先把 HSYNC/VSYNC/DE 极性按规格书逐个翻转试一遍,再确认层使能位和显存基址寄存器;用示波器看 HSYNC 是否有脉冲,没有脉冲就是控制器根本没在输出。
4.2 彩条颜色整体错位:位序或字节序反了
现象:红条显示成蓝条,绿条位置也偏。原因多为 RGB565 的高低字节接反,或 R/B 通道在 PCB 上对调。解决:先发纯红0xF800满屏,若显示蓝则交换 R/B 段;若显示暗红或偏色,检查 16 位数据线高低字节顺序。血泪经验是不要一次改多个变量,每次只动一处,否则改对了也不知道是哪次改对的。
4.3 画面左右偏移或右边有黑边:前后肩不对
现象:彩条整体偏左或偏右,右侧出现固定宽度黑边。原因是 HBP/HFP 与屏实际要求不符,有效区起点错位。解决:固定 HSW 和 HACT,只微调 HBP,每次加减几个时钟看黑边变化方向;黑边在左说明 HBP 偏大,在右说明偏小。垂直方向同理调 VBP/VFP。
4.4 画面闪烁或行内撕裂:PCLK 与刷新不匹配
现象:彩条边缘抖动,或某几行内容错位。原因是 PCLK 频率超出屏规格,或逐行生成时填色没赶在消隐期完成。解决:按公式重算 PCLK,先降帧率验证是否消失;逐行方案要把填色逻辑挪到行消隐窗口内,必要时加一行缓冲做乒乓。
4.5 换一块同型号屏就不亮:参数卡在最小值
现象:同一套配置在一块屏上正常,换同型号另一块就黑屏或抖动。原因是前后肩按规格书最小值卡死,个体差异或温度变化越界。解决:前后肩各留 10% 到 20% 余量,同步宽度取规格书推荐值而非最小值;把时序参数做成可配置表,换屏只改表不改代码。
5. 从彩条到可信画面:用渐变图和棋盘格做二次验证
彩条跑通只证明“时序骨架 + 五色映射”对了,还不能证明灰阶和整屏一致性没问题。我一般会再加两步验证,成本很低但能提前暴露后面调图像时才发现的坑。
第一步是渐变图。水平方向从 0 到 255 线性递增灰阶,垂直方向保持常数,生成一张 256 级灰阶带。人眼能看出明显断层,说明数据位宽被截断或 Gamma 没配;渐变出现规律性竖纹,多半是显存写入步长和扫描步长不一致。第二步是棋盘格,黑白相间 8×8 或 16×16,用来查整屏是否有局部死区、行列驱动是否有固定位置的异常。这两张图都不需要外部素材,用和彩条同一套写显存函数改几行就能生成。
/* 生成 256 级水平灰阶带,RGB565 下 R/G/B 取相同高位近似 */ void draw_gray_ramp(uint16_t *fb, int w, int h) { for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { uint8_t g = (uint8_t)((x * 255) / (w - 1)); /* 0..255 线性 */ uint16_t r5 = g >> 3, g6 = g >> 2, b5 = g >> 3; fb[y * w + x] = (r5 << 11) | (g6 << 5) | b5; } } }这段的关键在(x * 255) / (w - 1):分母用w-1才能让最后一个像素正好到 255,用w会永远差一级,渐变末端出现一条暗带,容易被误判成驱动问题。RGB565 下灰阶只有 32/64/32 级,渐变本来就会有台阶,判断标准是“台阶均匀”而不是“完全平滑”;要更细的灰阶得换 RGB888 或做抖动。
验证顺序上,我的习惯是彩条 → 灰阶 → 棋盘格 → 真实图像,每步都留一张能复现的截图或照片,后面出问题可以快速回退到“上一次正常”的状态。这套流程不依赖任何特定工具链,MCU 和 FPGA 都适用,区别只在写显存的函数名。真正值得投入的不是彩条本身,而是这套“先建立可信基准、再逐层加复杂度”的调试习惯——它能让你在换屏、换主控、换分辨率时,始终有一个五分钟内能确认“底层还活着”的手段。希望帮到你。
本文还有配套的精品资源,点击获取