TI UART核心寄存器LSR/MSR/TCR深度解析与驱动编程实战
2026/7/22 15:56:00 网站建设 项目流程

1. 项目概述:从芯片手册到驱动代码的桥梁

搞嵌入式开发,特别是涉及到串口通信,芯片手册里那一堆寄存器描述是不是经常让你看得头大?我当年也是,尤其是面对像TI这种大厂的UART模块手册,动辄几十个寄存器,每个寄存器又有七八个位域,每个位域还分UART模式、IrDA模式、CIR模式,感觉像在读天书。但后来我明白了,手册不是用来“读”的,是用来“用”的。你不需要记住每一个比特,但你必须理解那几个核心寄存器是如何串联起整个数据收发、状态监控和错误处理流程的。今天,我就以TI的UART模块为例,结合我踩过的坑和调通的经验,带你彻底搞懂LSR(线路状态寄存器)、MSR(调制解调器状态寄存器)、TCR(传输控制寄存器)这几个关键角色。这不是一篇翻译手册的文章,而是一份“解码”指南,告诉你这些寄存器位在真实的代码里如何被查询、如何影响程序逻辑,以及如何利用它们写出健壮、高效的驱动。

串口通信看似简单,就TX、RX两根线,但其底层硬件状态机却相当复杂。数据从你的应用程序写入,到最终变成电平信号发送出去,中间经历了FIFO缓冲、并串转换、起始/停止位添加、奇偶校验等环节。任何一个环节出错,数据就可能丢失或畸变。而LSR、MSR这些寄存器,就是硬件提供给软件的一扇“观察窗”和“控制面板”。通过它们,你可以知道发送缓冲区是否空了(能不能继续写数据)、接收缓冲区是否有数据(该不该去读)、线上有没有发生帧错误或奇偶校验错误(数据是否可信)、对方的设备(如Modem)是否准备好了(CTS信号是否有效)。不理解这些,你的串口驱动就只能跑在“能用”的层面,一旦遇到复杂的流控、高波特率或恶劣的电磁环境,各种灵异问题就会接踵而至。

2. 核心寄存器功能深度解析与设计逻辑

2.1 线路状态寄存器(LSR):通信状态的“仪表盘”

LSR是你在调试串口时最需要频繁打交道的寄存器,没有之一。它实时反映了数据链路层的健康状况。手册里那张位域图(RXFIFOE, RXOE, RXPE, RXFE, RXBI, TXFIFOE, TXSRE, RXFIFOSTS)就是你的诊断工具集。我们别光看定义,来点实际的。

2.1.1 接收状态位组(Bit 0-4, 7):你的数据质检员

  • Bit 0 - RXFIFOE (Receive FIFO Empty):这是你轮询或中断驱动的起点。为0表示RX FIFO里有数据,软件该去读了。这里有个关键细节:读取LSR本身不会移动FIFO的读指针,只有读RHR(接收保持寄存器)才会。所以你可以安全地先读LSR检查状态,再决定是否读数据。
  • Bit 1 - RXOE (Overrun Error):溢出错,这是新手常踩的坑。当RX FIFO已满,而移位寄存器又收到一个新字符时,这个新字符就会丢失,并置位此位。这意味着你读数据不够快。解决方法通常是:1) 提高读取优先级或使用DMA;2) 增大FIFO深度(如果支持);3) 检查是否有长时间关中断的操作阻塞了接收。
  • Bit 2 - RXPE (Parity Error) & Bit 3 - RXFE (Framing Error):奇偶校验错和帧错误。它们指示接收到的字符本身有问题。帧错误通常意味着波特率不匹配或线路干扰导致停止位没检测到。这里手册强调了一个重要机制:LSR[4:2](BI, FE, PE)反映的是RX FIFO最顶部那个字符(即下一个将被RHR读出的字符)的错误状态。所以正确的错误处理流程是:读LSR -> 如果错误位被置位 -> 读RHR取出这个带错误的字符(同时错误位被更新)-> 根据错误类型做日志记录或丢弃。如果你不读RHR,这个错误状态会一直挂着。
  • Bit 4 - RXBI (Break Indicator):中断指示。当RX线被拉低超过一个完整字符传输时间(字符长度+停止位),硬件会认为是一个“Break”信号,用于协议帧分隔或设备复位。收到Break后,你需要清空RX FIFO并可能重置接收状态机。
  • Bit 7 - RXFIFOSTS:这是一个“全局错误标志”。只要RX FIFO中任何位置存在一个带有PE/FE/BI错误的字符,此位就为1。它给你一个快速判断“是否有错”的方法,而不用遍历整个FIFO。只有当所有错误字符都被读出后,此位才清零。

2.1.2 发送状态位组(Bit 5-6):你的发送流程“阀门”

  • Bit 5 - TXFIFOE (Transmit FIFO Empty):为1表示发送保持寄存器(TX FIFO)空了。注意手册的警告:“传输不一定完成”。这是因为数据从TX FIFO到发送移位寄存器还需要时间。此位仅表示软件可以写入新数据了,不代表线上的数据已经发完。
  • Bit 6 - TXSRE (Transmitter Shift Register Empty):为1表示发送移位寄存器也空了。这意味着最后一个比特也已经送到了TX引脚上。如果你需要精确知道一帧数据何时完全发送完毕(例如在切换RS-485收发器方向前),应该查询此位,而不是TXFIFOE

实操心得:在查询式发送中,我的习惯是检查TXFIFOE来决定能否写入下一个字节;而在需要严格时序控制时(如半双工RS-485),我会在发送完最后一个字节后,持续查询TXSRE位,直到其为1,再延迟几个比特时间(确保停止位也已发出)后才切换方向,这样可以极大避免数据帧被截断。

2.2 调制解调器状态寄存器(MSR):硬件握手信号的“监听器”

在需要硬件流控(RTS/CTS)或连接调制解调器的场景,MSR至关重要。它反映了CTS、DSR、RI、DCD这四条Modem控制线的当前状态及其变化。

2.2.1 当前状态位(Bit 0-3)与取反状态位(Bit 4-7)

MSR的设计很巧妙,它提供了两套信息:

  • Bit 0-3 (CTS_STS, DSR_STS, RI_STS, DCD_STS):这四位是变化标志。当对应的输入引脚状态发生改变时,硬件会将其置1。该位在读MSR后会自动清零。这是用来检测“事件”的,比如CTS线从高变低(对方要求暂停发送)。
  • Bit 4-7 (NCTS_STS, NDSR_STS, NRI_STS, NCD_STS):这四位是当前状态的取反值。例如,如果CTS引脚输入为低电平(有效),NCTS_STS位就是1。它们不会自动清零,实时反映引脚电平。

2.2.2 环回模式(Loopback Mode)下的特殊行为

手册提到,在环回模式下,Bit 4-7的状态等同于MCR(Modem控制寄存器)中相应控制位的值。这是用于芯片自检的。当你将MCR的环回位打开后,TX和RX在内部短接,同时CTS、DSR等输入信号也由MCR对应的输出位模拟产生。此时读MSR,就是在检查你通过MCR设置的值是否被正确“环回”了,这是验证UART内部通路是否正常的重要手段。

注意事项:在实现硬件流控时,常见的做法是:在发送数据前,检查NCTS_STS(即CTS信号)是否有效(为1)。如果无效,则应暂停发送,等待其变有效。同时,你可以使能MSR的变化中断,这样当CTS状态改变时,你会收到中断,从而及时恢复或暂停发送,实现高效的流量控制,避免因缓冲区满导致数据丢失。

2.3 传输控制寄存器(TCR)与流控触发阈值

TCR是硬件流控(自动RTS/CTS)的核心配置寄存器。它不直接控制引脚,而是定义了何时激活/取消RTS信号(请求发送)的内部阈值。

2.3.1 核心字段:HALT与RESTORE阈值

  • RXFIFOTRIGHALT (Bit 3-0):当接收方的RX FIFO中数据量达到或超过这个阈值时,接收方UART会拉高RTS信号(即RTS=1,对于低电平有效的硬件,这意味着“请求发送”无效),通知发送方“我快满���,请暂停发送”。
  • RXFIFOTRIGSTART (Bit 7-4):当接收方的RX FIFO中数据量低于或等于这个阈值时,接收方UART会拉低RTS信号(RTS=0,即“请求发送”有效),通知发送方“我有空间了,可以继续发送”。

2.3.2 配置的精髓与陷阱

手册的NOTE部分给出了黄金法则:必须确保TCR[7:4](START) >TCR[3:0](HALT)。举个例子,你设置HALT阈值为56字节(即FIFO快满时暂停),START阈值为8字节(即腾出一些空间后恢复)。这样设计是为了避免RTS信号在临界点附近频繁跳变,形成“震荡”。

更关键的是下面这句话:在FIFO中断模式下使用流控时,还必须确保HALT阈值大于或等于接收FIFO的中断触发水平(由TLR或FCR设置)。为什么?假设你的RX FIFO中断触发水平是56字节(数据量>=56就产生中断),而HALT阈值是48字节。可能出现这种情况:FIFO数据达到48字节,RTS被拉高暂停对方发送,但你的中断(56字节)还没产生,导致你的软件没有及时来读数据。FIFO数据量卡在48-56之间,对方一直等待,你的中断一直不产生,系统就“饿死”了。所以,HALT阈值必须 >= 中断触发水平,确保“请求暂停”事件发生时,你的中断服务程序已经被触发并开始处理数据了。

而在DMA模式下,由于每个字节到达都可能产生DMA请求,不存在“中断触发水平”的概念,因此这个限制就不存在了。

3. 关键寄存器联动与驱动编程实战

理解了单个寄存器后,我们来看看它们如何在驱动程序中协同工作。这里我以一个典型的“中断+ FIFO”模式的UART接收驱动为例,拆解编程流程和注意事项。

3.1 初始化配置流程

  1. 确定工作模式(MDR1):首先通过MDR1[2:0]选择UART 16x模式、IrDA或CIR。必须在配置波特率除数(DLL/DLH)和线路控制(LCR)之后,最后设置此寄存器,且模式一旦设定,在正常操作中不应更改。
  2. 配置FIFO与触发(FCR, TLR):使能FIFO(FCR[0]),根据应用场景设置TX/RX FIFO的复位位。通过TLR寄存器或FCRRXFIFOTLTXFIFOTL位设置中断触发阈值。如果需要1字节的粒度,需配置SCR寄存器的RXTRIGGRANU1TXTRIGGRANU1位。
  3. 配置中断(IER):使能所需的中断源。对于接收,通常使能“接收数据可用”中断(对应LSR的RXFIFOE状态)和“接收线路状态”中断(对应LSR的错误位,如OE, PE, FE, BI)。不要忘记使能MSR的“Modem状态变化”中断,如果你用了硬件流控
  4. 配置硬件流控(TCR, MCR):如果使用自动RTS/CTS,需按照前述规则配置TCR的HALT和START阈值,并在MCR寄存器中使能自动流控功能(通常涉及MCR[1]MCR[5]等位,具体需查手册)。

3.2 中断服务程序(ISR)处理逻辑

当UART中断发生时,首先应读取IIR(中断标识寄存器)来确定中断源。IIR会告诉你当前最高优先级的中断是什么。

3.2.1 处理“接收线路状态”中断(最高优先级之一)

此中断由LSR中的OE、PE、FE、BI错误触发。ISR中必须:

  1. 读取LSR寄存器,并将错误状态位保存到驱动程序的上下文变量中。
  2. 必须紧接着读取RHR寄存器,即使你不关心这个错误数据。因为只有读RHR,才能将FIFO顶部的这个错误字符移走,并更新LSR中的错误状态。否则,该错误状态会一直存在,可能阻塞后续正常数据的接收。
  3. 根据保存的错误类型,进行相应的错误计数、日志记录或协议层处理(如丢弃错误帧)。
// 伪代码示例 if (iir & IIR_RLS_INT) { // 接收线路状态中断 uint16_t lsr = READ_REG(UART_LSR); uint8_t error_data = READ_REG(UART_RHR); // 关键!必须读RHR来清除错误状态 if (lsr & LSR_OE) { uart_ctx.overrun_err_cnt++; } if (lsr & LSR_PE) { uart_ctx.parity_err_cnt++; /* 可能丢弃该字节 */ } if (lsr & LSR_FE) { uart_ctx.frame_err_cnt++; /* 可能丢弃该字节 */ } if (lsr & LSR_BI) { uart_ctx.break_detected = true; /* 可能需要清空FIFO并重置 */ } }

3.2.2 处理“接收数据可用”中断

此中断由RX FIFO达到触发阈值(或非空,取决于配置)产生。ISR中应:

  1. 循环读取LSR的RXFIFOE位,只要为0(表示有数据),就持续从RHR读取数据到你的软件缓冲区。
  2. 注意缓冲区管理,防止软件缓冲区溢出。
  3. 如果使能了硬件流控,当你的软件缓冲区也快满时,可能需要手动控制RTS信号(通过MCR)来提前暂停对方发送,这比依赖硬件FIFO的阈值更灵活。

3.2.3 处理“Modem状态变化”中断

此中断由MSR的Bit 0-3(变化标志)置位引发。ISR中应:

  1. 读取MSR寄存器,该操作会自动清除变化标志位。
  2. 检查CTS_STS等位,判断是CTS、DSR、RI还是DCD发生了变化。
  3. 根据变化调整发送逻辑。例如,如果CTS_STS为1(表示CTS信号从有效变为无效),应立即暂停发送。

3.3 发送过程中的状态查询与流控配合

对于发送,尤其是在查询方式或中断方式下配合硬件流控:

  1. 发送前检查:在写入THR(发送保持寄存器)前,除了检查TXFIFOE(或THR空中断),还必须检查MSR中的NCTS_STS位(或等待CTS变化中断),确保对方设备可以接收数据。
  2. 发送完成判断:如果需要确保一帧数据完全发出(如RS-485切换),在写入最后一个字节后,应轮询TXSRE位,而非TXFIFOE位。TXSRE为1意味着移位寄存器也空了,数据已全部推到TX引脚。

4. 高级功能与疑难杂症排查

4.1 多种工作模式下的寄存器差异

TI的这个UART模块集成了UART、IrDA和CIR(消费电子红外)模式。同一个LSR寄存器,在不同模式下位域含义完全不同,这是最容易混淆的地方。

  • UART模式:LSR关注字节级的错误(PE, FE, BI)和FIFO状态。
  • IrDA模式:LSR关注帧级错误(CRC, ABORT, FRAME_TOO_LONG)和帧状态(RX_LAST_BYTE用于判断帧边界)。此外,IrDA模式引入了状态FIFO (SFLSR, SFREGL/H)来存放每个数据帧的附加信息(如帧长度、错误状态),这与UART模式有本质区别。读取IrDA数据时,需要先读状态FIFO获取帧信息,再读数据FIFO。
  • CIR模式:LSR更简单,主要关注RXSTOP(接收完成)和RXFIFOE

切换模式时务必小心:通过MDR1切换模式前,最好先禁用模块或进行复位操作,避免残留状态导致异常。模式切换后,所有寄存器的含义都可能改变,驱动程序需要根据当前模式重新解释这些寄存器。

4.2 错误排查速查表

现象可能原因排查步骤与寄存器关注点
能发送,不能接收1. RX引脚配置错误
2. 波特率不匹配
3. 接收未使能(IER)
4. 外部线路问题
1. 检查引脚复用配置。
2. 用示波器测量RX引脚波形,计算实际波特率,与DLL/DLH配置值核对。
3. 检查IER寄存器是否使能了接收中断或查询LSR的RXFIFOE
4. 检查LSR的RXFE位是否频繁置位(帧错误)。
接收数据乱码1. 波特率轻微偏差
2. 奇偶校验设置不匹配
3. 数据位/停止位设置不匹配
4. 电磁干扰
1. 核对双方设备的时钟精度及波特率除数。
2. 检查LCR的奇偶校验位设置,并观察LSR的RXPE位是否置位。
3. 核对LCR的数据位长度和停止位数量。
4. 检查硬件滤波、屏蔽是否良好。
高波特率下丢失数据1. 接收溢出(Overrun)
2. 软件处理不及时
3. 未使用流控,对方发送过快
1.首先检查LSR的RXOE,如果为1,则是典型的溢出。
2. 优化ISR,减少处理时间;或改用DMA传输(配置SCRTLR寄存器)。
3. 启用硬件流控(配置TCR,MCR),或使用XON/XOFF软件流控。
硬件流控失效1. TCR阈值设置不合理
2. RTS/CTS引脚未正确连接或配置
3. MCR中自动流控未使能
1.重点检查TCR的HALT/START阈值,确保START > HALT,且HALT阈值 >= RX FIFO中断触发水平。
2. 用万用表或示波器检查RTS/CTS引脚电平是否随FIFO状态变化。
3. 检查MCR寄存器中自动RTS/CTS使能位。
发送最后一字节丢失1. 判断发送完成的条件错误
2. 在RS-485中方向切换过早
1. 发送完成后,应查询LSR[6] TXSRE位,而非LSR[5] TXFIFOE位,确保移位寄存器也已空。
2. 查询TXSRE为1后,再延迟1-2个字符时间,确保停止位也已发出,再切换RS-485方向控制引脚。
进入中断后无法退出1. 中断标志未清除
2. 共享中断向量下,未处理完所有中断源
1.对于LSR错误中断,必须读RHR;对于MSR变化中断,必须读MSR。这些操作会清除中断源。
2. 在ISR中,应使用while循环检查IIR,直到其指示为“无中断”状态,确保处理完所有挂起的中断。

4.3 DMA配置与SCR寄存器的使用

对于高速数据流,使用DMA是必须的。TI UART的DMA模式通过SCR寄存器进行精细控制。

  • DMA模式选择(SCR[2:1] DMAMODE2:当SCR[0] DMAMODECTL=1时,DMA模式由此字段决定。模式1/2/3分别对应TX请求、RX请求或独立请求的不同引脚映射,需要与你的DMA控制器配置匹配。
  • DMA计数器复位(SSR[2] DMACOUNTERRST:这个位非常有用。当它为1时,如果你通过FCR[1]FCR[2]复位了TX或RX FIFO,对应的DMA传输计数器也会被重置。这可以确保在软件复位FIFO后,DMA能重新从起点开始传输,保持同步。
  • TX空中断控制(SCR[3] TXEMPTYCTLIT:通常的THR空中断在TX FIFO空时就触发。但如果你将此位置1,则中断会在TX FIFO和TX移位寄存器都空时才触发。这为你提供了更精确的“发送完全结束”中断事件,特别适合需要严格帧间隔或关闭发送器的场景。

5. 从寄存器理解到稳健驱动设计

折腾了这么多寄存器位,最终目的是为了写出靠谱的驱动。我的体会是,不要试图去记忆,而是去理解其设计模式。状态寄存器(LSR, MSR)是给你“读”的,用于了解硬件发生了什么;控制寄存器(TCR, MCR, FCR)是给你“写”的,用于告诉硬件你想要它怎么做;而配置寄存器(LCR, DLL, DLH, MDR1)则是设定通信的基本规则。

一个稳健的UART驱动应该具备以下层次:

  1. 硬件抽象层:直接操作寄存器,但将位域定义成有意义的宏或枚举,并提供初始化、读、写、中断处理等基础函数。这一层必须严格处理清除中断标志的序列。
  2. 缓冲区管理层:在ISR和应用程序之间构建环形缓冲区(Ring Buffer)。ISR只负责快速从RHR搬数据到环形缓冲区,或从环形缓冲区搬数据到THR。应用程序则从环形缓冲区取数据。
  3. 流控管理层:集成硬件流控(通过MSR和TCR)和软件流控逻辑。当接收环形缓冲区快满时,能自动通过硬件或软件信号通知对方暂停。
  4. 错误处理与统计层:在ISR中记录LSR报告的各种错误计数,并提供查询接口。这对于现场调试和监控通信质量至关重要。
  5. 阻塞/非阻塞接口层:向上层应用提供read(),write(),ioctl()等标准或类标准的接口,支持轮询、中断和DMA多种后台工作方式。

最后,手册永远是第一参考。但希望这篇解读能帮你打通从手册上冰冷的位描述,到代码里鲜活的状态判断和控制流之间的任督二脉。下次再看到LSR、MSR、TCR这些缩写时,你能立刻在脑海里勾勒出数据流如何被监控、控制流如何被调节的完整图景,这才是真正掌握了UART的核心。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询