深入解析TI TM4C129 LCD控制器:从Raster/LIDD模式到DMA与中断实战
1. 项目概述与核心价值
在嵌入式系统开发中,图形用户界面(GUI)的实现往往是一个既关键又复杂的环节。它直接关系到产品的用户体验,而其底层驱动,尤其是LCD控制器的配置,则是整个显示系统的基石。今天,我想和大家深入聊聊德州仪器(TI)Tiva™ TM4C129系列微控制器内置的LCD控制器。这个模块功能强大,但官方数据手册动辄上百页的寄存器描述,常常让开发者望而生畏。很多人可能只是从库函数或示例代码中拷贝配置,知其然而不知其所以然,一旦遇到非标准面板或者需要性能调优,就束手无策。
这个LCD控制器的技术价值在于,它不仅仅是一个简单的“数据搬运工”。它集成了对光栅扫描(Raster)和LCD接口显示驱动(LIDD)两种主流模式的支持,内置了灵活的DMA引擎,并提供了丰富的可编程时序参数与中断机制。这意味着,从简单的字符型LCD到复杂的TFT真彩屏,我们都可以通过精细的寄存器配置来驱动,无需外部分立控制器,极大地简化了硬件设计,降低了BOM成本。然而,要真正驾驭它,我们必须深入理解其寄存器配置的逻辑、DMA搬运数据的机制以及如何利用中断实现高效、稳定的帧同步。这不仅仅是“配通了就行”,而是关乎显示是否流畅、有无撕裂、功耗是否最优的核心问题。接下来,我将结合手册内容和实际调试经验,为你拆解其中的关键细节。
2. 核心工作模式解析:Raster vs. LIDD
在深入寄存器之前,我们必须先厘清LCD控制器最根本的两种工作模式,这是所有配置的出发点。选择哪种模式,取决于你要驱动的显示面板类型。
2.1 光栅扫描模式(Raster Mode)
这是驱动现代TFT-LCD、OLED等主动矩阵面板的标准模式。想象一下老式电视的电子枪扫描,Raster模式的工作方式与之类似:控制器会按行、按像素地顺序将帧缓冲区(Frame Buffer)中的颜色数据发送出去,同时生成严格同步的时序信号。
核心信号线包括:
- LCDCLK/LCDCP (像素时钟):每个时钟周期输出一个像素数据。
- LCDHSYNC (水平同步):指示一扫描行的开始。
- LCDVSYNC (垂直同步):指示一帧图像的开始。
- LCDDATA[15:0] (数据总线):传输像素数据,宽度可以是8/16/24位等。
- LCDAC (输出使能):在有效像素数据期间有效。
模式特点与适用场景:
- 连续数据流:一旦启动,控制器会以固定的像素时钟速率,持续不断地从DMA获取数据并输出,形成稳定的视频流。这非常适合需要连续刷新、显示动态内容的图形界面。
- 时序高度可配:通过
LCDRASTRTIM0、LCDRASTRTIM1、LCDRASTRTIM2等寄存器,你可以精确配置前沿(Front Porch)、后沿(Back Porch)、同步脉冲宽度(Sync Width)以及有效像素行数/列数。这些参数必须与你的液晶面板 datasheet 完全匹配,否则会出现显示位置偏移、图像抖动甚至无法显示的问题。 - 依赖DMA:由于数据流是连续的,CPU不可能实时喂数据。因此,Raster模式几乎总是与DMA深度绑定,由DMA自动从内存中的帧缓冲区搬运数据到LCD控制器的FIFO。
关键寄存器LCDCTL中的模式选择:模式选择由LCDCTL寄存器的LCDMODE位决定。在Raster模式下,你需要将其设置为1。同时,该寄存器的CLKDIV字段用于生成像素时钟LCDCP,计算公式为f_LCDCP = f_SYSCLK / CLKDIV。这里有个重要坑点:手册明确指出,当CLKDIV配置为0x0或0x1时,对于Raster模式是不允许的。这意味着像素时钟最快只能是系统时钟的1/2。在计算时务必注意,例如系统时钟为120MHz,想要得到30MHz的像素时钟,CLKDIV应设置为4。
2.2 LCD接口显示驱动模式(LIDD Mode)
LIDD模式则是为了驱动那些古老的、但至今仍在大量使用的字符型LCD模块(比如1602、12864等)而设计的。这类面板通常内部有一个显示RAM和控制器(如HD44780),MCU需要通过并口以“命令/数据”的形式与之通信,而不是直接流式发送像素数据。
核心信号线(以Intel 8080模式为例):
- LCDD[7:0] (数据/命令总线):复用的数据总线。
- LCDCS (片选):选择目标LCD芯片。
- LCDRS (寄存器选择):区分当前操作是命令(低电平)还是数据(高电平)。
- LCDWR (写使能)/LCDRD (读使能):读写控制信号。
- LCDALE (地址锁存使能,某些模式):用于锁存地址。
模式特点与适用场景:
- 事务型通信:每次显示更新都是一次独立的“写命令”或“写数据”总线事务,而不是连续流。通信速率相对较慢。
- 模拟总线时序:LIDD控制器本质上是一个可编程的并行总线接口发生器。通过配置
LIDDCS0CFG等寄存器,你可以精确设定建立时间(Setup)、保持时间(Hold)和脉冲宽度(Duration),以满足不同厂家LCD模块的苛刻时序要求。这是驱动成功的关键。 - CPU或DMA驱动:你可以通过CPU直接读写
LIDDCS0DATA等寄存器来操作LCD,也可以启用DMA模式(LCDLIDDCTL.DMAEN=1),让DMA自动将一段内存中的数据(如要显示的字符串编码)通过LIDD接口发送出去,解放CPU。
模式选择与引脚复用:在LCDLIDDCTL寄存器中,MODE字段(bits 2:0)用于选择具体的LIDD子模式:同步/异步 Motorola 6800、同步/异步 Intel 8080 或 Hitachi 模式。不同的模式会改变引脚的功能定义。例如,在Intel 8080异步模式下,LCDCP引脚用作读使能RD,LCDLP用作写使能WR,LCDFP用作地址锁存ALE。配置时务必对照手册中的引脚功能表,并与硬件连接核对,一个配置错误就可能导致通信全无。
实操心得:在项目初期,务必用逻辑分析仪或示波器抓取LIDD接口的时序波形。即使寄存器配置“看起来”正确,实际波形中的建立/保持时间也可能因布线、负载等原因不满足要求。我曾遇到一个12864屏偶尔乱码的问题,最后发现是
WR信号的保持时间(WRHOLD)比屏要求的最小值少了5ns,微调寄存器后问题解决。永远不要完全相信计算值,要相信仪器看到的波形。
3. 寄存器配置详解:从使能到时序
理解了模式,我们就可以开始动手配置了。配置流程有严格的顺序,乱序操作可能导致模块无法启动或行为异常。
3.1 基础使能与时钟配置
这是所有操作的第一步,在接触任何LCD专用寄存器前必须完成。
- 系统级使能:通过系统控制模块的
RCGCLCD寄存器使能LCD控制器的时钟。没有时钟,后续所有寄存器读写都可能失败。 - 模块时钟使能:配置
LCDCLKEN寄存器,使能LCD控制器内部所需的DMA时钟、核心时钟,如果使用LIDD模式,还需使能LIDD控制器时钟。 - 模式与主时钟配置:在
LCDCTL寄存器中:- 设置
LCDMODE位,选择 Raster (1) 或 LIDD (0) 模式。 - 根据目标像素时钟或接口时钟(MCLK)频率,计算并设置
CLKDIV分频值。再次强调:Raster模式下CLKDIV必须大于等于2。
- 设置
3.2 Raster模式核心寄存器配置
如果你驱动的是TFT屏,以下是必须关注的寄存器组:
LCDRASTRCTL(光栅控制寄存器):这是Raster模式的总控制开关。LCDEN(Bit 0):Raster模式总使能位。务必在所有时序、DMA参数��置完成后再置位。LCDTFT(Bit 7):选择主动矩阵(TFT)还是被动矩阵(STN)。驱动TFT屏必须设为1。LCDBW(Bit 1):单色/彩色选择。彩色TFT设为0。PALMODE(Bits 21:20):调色板加载模式。对于16位色(RGB565)或24位色(RGB888)的“原始数据”帧缓冲区,应设置为0x2(仅数据加载)。如果使用8位色+调色板,则需配置为0x0或0x1。TFT24和TFT24UPCK(Bits 25, 26):用于控制24位色数据的存储格式(打包或未打包),这需要与你在内存中组织像素数据的方式严格对应,否则颜色会完全错乱。
LCDRASTRTIM0/1/2(光栅时序寄存器):这三个寄存器定义了屏幕的“物理特性”。- 你需要根据液晶面板手册,填写以下参数:
PPL(Pixels Per Line):每行有效像素数。LPP(Lines Per Panel):每帧有效行数。HSW(Horizontal Sync Width):行同步脉冲宽度。HFP/HBP(Horizontal Front/Back Porch):行前沿/后沿。VSW(Vertical Sync Width):场同步脉冲宽度。VFP/VBP(Vertical Front/Back Porch):场前沿/后沿。
- 计算示例:假设一个800x480的屏幕,其手册要求时序为:
HBP=46,HFP=210,HSW=1,VBP=23,VFP=22,VSW=1。那么:LCDRASTRTIM0:HBP=46,HFP=210,HSW=1。LCDRASTRTIM1:PPL=800。LCDRASTRTIM2:VBP=23,VFP=22,VSW=1,LPP=480。
- 一个常见的错误是混淆了前沿和后沿的顺序,或者把单位弄错(是像素时钟数还是行数)。务必仔细核对。
- 你需要根据液晶面板手册,填写以下参数:
LCDRASTRSUBPn(子画面显示寄存器):这是一个高级功能,允许你在主画面上叠加一个子画面区域。通过设置SPEN位使能,并用LPPT定义子画面区域的行数。HOLS位则控制子画面显示在屏幕顶部还是底部。这在实现状态栏、OSD(屏幕显示)菜单时非常有用,可以独立于主画面更新。
3.3 LIDD模式核心寄存器配置
如果驱动字符型LCD,配置重心则完全不同:
LCDLIDDCTL(LIDD控制寄存器):MODE(Bits 2:0):选择6800/8080等具体接口协议。CS0E0,CS1E1,WRDIRINV,RDEN,ALE:这些位用于控制各控制信号的极性(高有效或低有效)。必须严格对照你所用LCD模块的数据手册。通常,CS(片选)低有效,WR(写)低有效,RD(读)低有效。DMAEN(Bit 8):是否启用DMA模式。如果只是初始化或发送少量命令,可以用CPU轮询;如果需要连续发送大量显示数据(如清屏、绘制图形),启用DMA效率更高。
LIDDCS0CFG/LIDDCS1CFG(片选时序配置寄存器):这是LIDD模式的灵魂。它定义了总线读/写操作中,各信号之间的时序关系,单位是LCDMCLK周期。WRSU/RDSU:写/读建立时间。在WR或RD信号有效前,地址/数据总线需要稳定多少个时钟周期。WRDUR/RDDUR:写/读脉冲宽度。WR或RD信号需要保持有效的时钟周期数。这个值通常有最小值要求。WRHOLD/RDHOLD:写/读保持时间。在WR或RD信号无效后,地址/数据总线需要继续保持稳定的时钟周期数。GAP:两次访问之间的间隔周期(除非两次都是读操作)。- 配置方法:从LCD模块手册中找到时序图,读出
t_{AS},t_{DSW},t_{H},t_{CYC}等参数。然后根据你配置的LCDMCLK频率(由CLKDIV决定),计算出对应的时钟周期数。例如,t_{DSW}(数据建立时间)要求至少12ns,LCDMCLK周期为20ns(50MHz),则WRSU至少需要设置为ceil(12ns / 20ns) = 1(即1个周期,但通常为了保险会设大一点,如2)。
LIDDCS0ADDR和LIDDCS0DATA:在CPU模式下,向LIDDCS0ADDR写入值会触发一次地址总线写周期(如果A/D复用);向LIDDCS0DATA写入值会触发一次数据总线写周期。读取则触发读周期。这是CPU直接控制LCD的基础。
4. DMA帧缓冲区管理与数据传输机制
无论是Raster的连续流还是LIDD的批量发送,高效的数据搬运都离不开DMA。LCD控制器的DMA引擎设计精巧,通过双帧缓冲区(Frame Buffer)和一系列控制寄存器,实现了无撕裂(Tear-Free)显示的可能。
4.1 帧缓冲区概念与寄存器配置
帧缓冲区就是内存中一片存储了整屏像素数据的区域。LCD控制器的DMA会自动从这片区域读取数据并发送给面板。
缓冲区基地址与上限地址:
LCDDMABAFB0/LCDDMABAFB1:帧缓冲区0和1的起始地址。必须对齐到32位边界。LCDDMACAFB0/LCDDMACAFB1:帧缓冲区0和1的结束地址的后一个字节地址。即CAFBn = BAFBn + 缓冲区大小。- 缓冲区大小计算:这取决于你的显示分辨率、色深和像素存储格式。
- 例如,800x480分辨率,RGB565格式(16位/像素),则一帧数据大小为
800 * 480 * 2 bytes = 768,000 bytes。 - 如果使用24位打包格式(
TFT24UPCK=0),则每3个32位字存储4个像素,计算稍复杂:总像素数 = 800*480 = 384,000,需要(384,000 / 4) * 3 * 4 bytes = 1,152,000 bytes。
- 例如,800x480分辨率,RGB565格式(16位/像素),则一帧数据大小为
- 双缓冲区机制:DMA引擎可以在两个缓冲区之间切换。当它正在从缓冲区0读取数据显示当前帧时,你的应用程序可以更新缓冲区1的内容。在合适的时机(如垂直消隐期)切换缓冲区,就能实现平滑的帧更新,避免画面撕裂。这是流畅动画的基础。
LCDDMACTL(DMA控制寄存器):这个寄存器控制DMA的搬运行为。BURSTSZ:DMA突发传输大小。通常设置为与系统内存总线宽度匹配的值(如16字),以获得最高的传输效率。FB:当前活动的帧缓冲区选择位。指示DMA当前正在使用哪个缓冲区(0或1)。注意:在DMA运行时,软件不应直接修改此位来切换缓冲区,而应通过配置PALMODE或利用中断机制来触发切换。PALMODE:如前所述,它影响DMA的数据加载行为。对于原始数据模式,DMA只搬运像素数据;对于调色板模式,DMA会先搬运调色板数据到内部Palette RAM,再搬运像素数据。
4.2 DMA工作流程与数据流
以Raster模式为例,DMA的工作流程是一个持续的循环:
- 初始化与启动:配置好所有时序、缓冲区地址后,置位
LCDRASTRCTL.LCDEN。 - DMA请求:LCD控制器的内部FIFO需要数据时,会向DMA引擎发出请求。
- 突发传输:DMA引擎根据
BURSTSZ的设置,从当前活动帧缓冲区中一次性读取一连串数据(如16个32位字),通过系统总线填充到LCD控制器的FIFO中。 - 像素输出:LCD控制器从FIFO中取出数据,根据配置的色深、格式(如RGB565),将其转换为连续的像素流,配合
HSYNC、VSYNC等信号输出到引脚。 - 缓冲区边界与切换:当DMA读取到当前帧缓冲区的上限地址(
CAFBn)时,表示一帧数据发送完毕。此时,如果使能了相应的中断(如EOF0),则会触发。在中断服务程序(ISR)中,是切换活动缓冲区(通过更新LCDDMACTL.FB或重新配置基地址)的最佳时机。同时,DMA���擎会自动回绕到当前活动缓冲区的基地址,开始下一帧的读取。
注意事项:确保你的帧缓冲区位于DMA可以访问的内存区域。对于TM4C129,内部SRAM和通过EPI接口连接的外部SDRAM都可以。如果使用外部内存,务必正确配置EPI模块,并如手册 Note 部分强调的,将
EPIADDRMAP寄存器的ECADR字段设置为0x1,以映射到正确的地址空间(0x1000.0000)。我曾花费数小时调试一个“显示全黑”的问题,最终发现是DMA无法访问我分配在错误地址的外部帧缓冲区。
5. 中断机制详解与应用实践
中断是协调LCD显示与应用程序的关键。它让CPU从轮询DMA状态的苦差事中解脱出来,只在关键时刻(如一帧结束)被唤醒进行处理,极大地提高了系统效率。
5.1 中断类型与触发条件
LCD控制器提供了丰富的中断源,在LCDIM(中断掩码)寄存器中使能,状态在LCDRIS(原始中断状态)和LCDMIS(屏蔽后中断状态)寄存器中查询。
DMA帧结束中断(EOF0 / EOF1):这是最常用、最重要的中断。当DMA完成对帧缓冲区0(或1)的整帧数据传输时触发。这正是执行双缓冲区交换的理想时刻。在ISR中,你可以:
- 检查当前显示的是哪个缓冲区(
LCDDMACTL.FB)。 - 将新的图像内容绘制到“后台”缓冲区。
- 在下一帧开始前,通过修改
LCDDMACTL.FB位或重新配置BAFBn/CAFBn来切换显示缓冲区。 - 关键技巧:为了避免在切换瞬间DMA读到不完整的数据,最好在垂直消隐期(VSYNC后沿期间)进行切换。许多LCD控制器(包括TM4C129)的DMA设计保证了在帧边界进行切换是安全的,但为了绝对可靠,可以在EOF中断中稍作延迟,或结合VSYNC信号进行处理。
- 检查当前显示的是哪个缓冲区(
DMA调色板加载完成中断:当
PALMODE设置为调色板模式,且DMA完成将调色板数据从内存加载到内部Palette RAM时触发。如果你需要动态更新调色板(比如实现颜色渐变效果),可以在该中断中安全地更新下一组调色板数据。FIFO下溢中断(FIFOU):当LCD控制器实时输出需要像素数据,但内部FIFO为空时触发。这通常是一个严重错误,意味着DMA供给数据的速度跟不上像素时钟消耗的速度。原因可能是:
- 系统总线带宽不足(被其他高优先级DMA占用)。
- 帧缓冲区位于非常慢的内存中。
- DMA突发大小或优先级配置不当。
- 像素时钟
LCDCP配置得过快。 发生下溢时,屏幕会出现撕裂、闪烁或水平线条。LCDCTL.UFLOWRST位可以配置为让硬件自动在下一帧重启模块,但这只是治标。根本解决方法是优化DMA和内存访问。
同步丢失中断(SYNCS):当从FIFO中读取数据时,在新帧的开始处没有找到预期的帧开始标识符时触发。这通常意味着DMA传输的数据流结构出现了问题,可能是帧缓冲区地址或大小配置错误。
光栅模式帧完成中断(RRASTRDONE):在Raster模式下,每发送完一整帧数据到引脚时触发。这与EOF中断类似,但触发点更靠后(在数据已物理输出后)。可用于精确的帧率统计或与外设同步。
LIDD模式帧完成中断(DONE):在LIDD DMA模式下,当DMA完成发送一个帧缓冲区数据时触发。用于通知CPU可以准备下一批要发送的数据。
5.2 中断服务程序(ISR)编写要点
编写LCD中断服务程序时,有几个原则必须遵守:
- 高效快速:ISR中只做最必要的操作,如设置标志位、切换缓冲区指针。复杂的图像渲染计算应放在主循环中基于这些标志进行。
- 清除中断标志:在退出ISR前,必须通过向
LCDISC(中断状态清除)寄存器的对应位写1来清除已处理的中断标志。否则,该中断会持续触发,导致系统瘫痪。 - 原子操作:在更新帧缓冲区基地址或切换活动缓冲区时,如果可能,应确保操作的原子性,或者在一个不会被中断打断的临界区内进行,防止出现显示错乱。
- 优先级设置:根据系统需求,合理设置LCD中断的优先级。通常,FIFO下溢这种错误中断可以设高优先级,而帧结束中断可以设中等优先级,确保系统能及时响应但又不会阻塞更关键的任务。
一个典型的双缓冲区更新伪代码流程如下:
// 全局变量 volatile uint32_t front_buffer = 0; // 当前显示缓冲区索引 volatile uint32_t back_buffer = 1; // 当前绘制缓冲区索引 volatile bool buffer_ready = false; // 后台缓冲区已更新标志 // EOF0 中断服务程序 void LCD_EOF0_ISR(void) { // 1. 清除中断标志 LCDISC = INT_EOF0; // 2. 切换显示到后台缓冲区 front_buffer = back_buffer; LCDDMACTL = (LCDDMACTL & ~0x1) | front_buffer; // 更新FB位 // 3. 通知主循环可以开始绘制下一帧到另一个缓冲区 buffer_ready = true; } // 主循环 while(1) { if(buffer_ready) { buffer_ready = false; // 在“新的”后台缓冲区上绘制图形 draw_graphics(back_buffer); // 交换绘制缓冲区索引 back_buffer = 1 - back_buffer; } // ... 执行其他任务 }6. 常见问题排查与调试技巧
即使按照手册一步步配置,在实际硬件上也可能遇到各种显示问题。以下是一些常见故障的排查思路和调试技巧。
6.1 问题排查速查表
| 现象 | 可能原因 | 排查步骤 |
|---|---|---|
| 屏幕全白/全黑/无任何显示 | 1. 电源或背光未开启。 2. LCD控制器未使能( RCGCLCD,LCDCLKEN,LCDEN)。3. 像素时钟 LCDCP无输出或频率极错。4. 时序参数( PPL,LPP, Porch等)与面板严重不符。 | 1. 检查硬件电源、背光电路。 2. 用调试器确认上述使能位已置位。 3. 用示波器测量 LCDCP引脚是否有波形,频率是否匹配计算值。4. 逐项核对时序寄存器值与面板手册要求。 |
| 图像偏移、滚动、撕裂 | 1. 水平/垂直同步脉宽、前后沿参数不准确。 2. DMA缓冲区切换时机不对,在有效显示期间切换。 | 1. 用示波器同时抓取HSYNC,VSYNC,DATA信号,与手册时序图对比,微调HFP/HBP/VFP/VBP。2. 确保只在EOF中断或垂直消隐期切换缓冲区。 |
| 颜色错乱(红蓝互换等) | 1. 数据线连接顺序错误(RGB位序)。 2. 色深或像素格式配置错误(如 TFT24,TFT24UPCK,FRMBUFSZ)。3. 帧缓冲区中像素数据的存储格式与寄存器配置不匹配。 | 1. 检查硬件连接,确认LCDDATA总线各比特位对应关系。2. 仔细检查 LCDRASTRCTL中与格式相关的位。3. 在内存中查看帧缓冲区数据,确认其排列是否符合预期(如RGB565是R[15:11], G[10:5], B[4:0])。 |
| 显示闪烁、有杂点 | 1. FIFO下溢(FIFOU中断触发)。2. 系统总线带宽不足,DMA抢不到总线。 3. 内存访问延迟太大(如使用了未优化的外部内存)。 | 1. 检查是否使能并触发了FIFOU中断。2. 降低像素时钟频率 LCDCP试试。3. 优化DMA突发大小 BURSTSZ(通常设为最大)。4. 提高LCD DMA的仲裁优先级(在系统控制模块中配置)。 5. 将帧缓冲区放在内部SRAM(如果大小允许)以获取最快访问速度。 |
| LIDD模式无法通信 | 1. 控制信号极性(CS0E0,WRDIRINV等)配置反了。2. 时序参数( WRSU,WRDUR等)不满足LCD模块要求。3. 初始化序列未正确发送(如复位、功能设置等命令)。 | 1. 用逻辑分析仪抓取CS,RS,WR,DATA信号,对照LCD模块手册看波形是否正常。2. 根据模块手册的AC特性表,重新计算并调整时序寄存器值,尤其关注最小脉宽和保持时间。 3. 确保在DMA模式前,已通过CPU模式正确完成了LCD模块的初始化序列。 |
6.2 高级调试技巧
使用内部调色板进行诊断:即使你使用RGB565原始数据模式,也可以临时启用一个简单的调色板。例如,配置为8位色模式(使用256色调色板),然后在调色板RAM中填充一组明显渐变的颜色(如从黑到白的灰度)。如果你的帧缓冲区数据是简单的递增索引,屏幕上应该显示一个平滑的灰度渐变。如果显示异常,可以快速定位是数据通路问题还是时序问题。
利用“子画面”功能隔离问题:如果你怀疑是主画面区域的数据或时序有问题,可以尝试启用子画面功能。配置一个小的、单色的子画面区域(比如屏幕底部10行,填充为红色)。如果子画面能正常显示,而主画面不能,那么问题很可能出在主画面的帧缓冲区数据或相关的DMA配置上。
监控DMA活动:TM4C129的DMA控制器有丰富的状态寄存器。你可以监控LCD DMA通道的传输状态、剩余数据量等,判断其是否在持续工作,以及传输速率是否匹配像素时钟的消耗速率。
逐步逼近法配置时序:对于一块全新的、时序参数不确定的屏幕,不要试图一次配对所有参数。可以尝试:
- 先使用一个非常保守的低像素时钟。
- 将前后沿(Porch)和同步宽度(Sync Width)设置得大一些。
- 先让屏幕显示出东西(哪怕位置不对),再逐步调整参数,向面板手册推荐值靠拢。
调试LCD驱动是一个需要耐心和细致观察的过程。从电源、时钟、基础使能,到时序、数据格式,再到DMA和中断,层层递进,利用好工具(万用表、示波器、逻辑分析仪、调试器),大部分问题都能被定位和解决。最让我印象深刻的一次调试,是屏幕上半部分正常,下半部分花屏。最终发现是计算帧缓冲区大小时,错误地将行数当成了字节数,导致DMA在传输下半帧时超出了缓冲区边界,读到了非法内存数据。这个教训告诉我,对于任何涉及内存地址和大小的计算,都必须反复验算,最好让编译器通过sizeof或类似机制来确保正确性。
