AM64x/AM243x UART高级应用:IrDA与CIR模式配置实战指南

1. 项目概述与核心价值

在嵌入式系统开发中,串行通信是连接处理器与传感器、无线模块、调试终端乃至其他处理器的生命线。通用异步收发传输器(UART)作为最经典、最通用的串行接口,其稳定性和灵活性使其在工业控制、消费电子、通信设备等领域经久不衰。然而,当项目需求从简单的调试日志输出,升级到需要支持红外遥控(CIR)或高速红外数据传输(IrDA)时,许多开发者会发现,数据手册中那上百页的寄存器描述和零散的编程步骤,让人望而生畏,不知从何下手。

我最近在基于TI的AM64x/AM243x处理器进行一个智能家居网关项目时,就深刻体会到了这一点。项目需要同时处理传统的UART串口调试、通过IrDA与旧式PDA同步数据,并解码来自多个遥控器的CIR信号。面对AM64x/AM243x技术参考手册中庞大而复杂的UART章节,我花了大量时间梳理、实验和调试,才将这些高级功能一一跑通。这个过程让我意识到,一份将零散信息整合、并辅以实战经验的指南是多么宝贵。

因此,本文旨在为你提供一份关于AM64x/AM243x UART模块的“一站式”编程指南。我们不会停留在简单的波特率设置,而是深入其MIR/FIR模式的数据流控制、CIR模式的载波生成与调制细节,并提供一个从芯片上电复位到高级功能启用的、步骤清晰的编程模型。无论你是正在评估该平台,还是已经深陷调试泥潭,希望这篇融合了手册要点与个人踩坑经验的总结,能帮你快速构建稳定可靠的串行通信链路,特别是那些涉及红外协议的应用。

2. UART模块架构与模式概览

在深入寄存器配置之前,我们必须先理解AM64x/AM243x的UART模块不是一个简单的串口,而是一个高度集成、多模式可选的通信中心。它基于一个48MHz的系统时钟(FCLK),通过可编程的分频器产生所需的波特率时钟。模块的核心是一个发送/接收移位寄存器,并辅以深度可达64字节的独立TX/RX FIFO,这为使用DMA进行大批量数据搬运奠定了基础,能显著降低CPU中断频率。

模块最强大的特性在于其多模式支持,这通过UART_MDR1[2:0]寄存器进行选择:

  • 000: UART 16x模式(标准模式)
  • 001: SIR模式(低速IrDA,最高115.2kbps)
  • 010: UART 16x自动波特率检测模式
  • 011: UART 13x模式
  • 100: MIR模式(中速IrDA,最高1.152Mbps)
  • 101: FIR模式(高速IrDA,最高4Mbps)
  • 110: CIR模式(消费红外,用于遥控器)
  • 111: 禁用模式(默认)

为什么需要这么多模式?这源于不同的物理层需求。标准UART使用高低电平表示0和1。而IrDA(红外数据协会)标准为了适应红外发光二极管的特性,将数据“0”编码为一个窄脉冲(例如在SIR模式下为3/16或1.6µs的低电平),数据“1”则保持空闲高电平,这种“归零”编码有利于接收端的光电二极管恢复。CIR模式则更进一步,它通常使用一个高频载波(如36kHz, 38kHz, 40kHz)对基带信号进行幅度调制,以增加传输距离和抗干扰能力,这正是电视遥控器采用的原理。

注意:模式选择(UART_MDR1[2:0])必须在完成波特率除数(UART_DLL/UART_DLH)等基本配置之后进行。一旦进入IrDA或CIR模式,部分寄存器(如UART_IER,UART_LSR)的位定义会发生改变,指向模式特定的中断和状态标志。在切换模式前,最好先将模块禁用(设为111),配置好所有参数后再使能目标模式。

3. 核心细节解析:MIR/FIR与CIR模式

3.1 MIR与FIR模式的数据格式化与流控

MIR(1.152Mbps)和FIR(4Mbps)是IrDA协议中的中高速模式。它们使用更复杂的4PPM(四脉冲位置调制)编码,但幸运的是,AM64x/AM243x的硬件已经处理了这些复杂的编码/解码过程,我们只需关注数据链路层。

帧结构:一个完整的IrDA帧包括:

  1. 起始标志(BOF):至少2个(MIR)或更多个特定的起始字节(如0xC0, 0xFF),用于同步。
  2. 数据域:实际要发送的数据字节。
  3. CRC校验域:16位CRC,由硬件自动计算并添加(发送)或校验(接收)。
  4. 结束标志(EOF):特定的结束序列。

关键配置寄存器

  • UART_TXFLL/UART_TXFLH:定义发送帧的数据域长度(字节数)。硬件会自动加上CRC和EOF。
  • UART_RXFLL/UART_RXFLH:定义接收帧的最大长度(包括数据域和CRC等)。如果接收到的帧超过此长度,会触发FRAME_TOO_LONG错误。
  • UART_EBLR:在SIR模式下,用于定义额外的起始标志(xBOF)数量。在MIR/FIR模式下,它定义了附加的起始标志数量(MIR协议要求至少2个起始标志)。
  • UART_ACREG[3] SEND_SIPUART_MDR1[6] SIP_MODE:SIP(Serial Infrared Interaction Pulse)是帧结束后发送的一个特殊脉冲,用于某些流控或协议交互。
    • SIP_MODE=1时,每帧传输结束后硬件都会自动发送一个SIP。
    • SIP_MODE=0时,SIP的发送由软件通过置位SEND_SIP位来控制。手册中提到,CPU可以至少每500ms置位一次SEND_SIP。这种方式的好处是,TX状态机不必在每帧末尾都发送SIP,从而减少了开销。这对于需要连续发送大量小数据包的场景(如实时传感器流)能提升效率。

帧结束判定:有两种方法告诉硬件一帧数据已经发送完毕:

  1. 帧长度法(默认):配置好UART_TXFLL后,当你写入FIFO的字节数达到设定长度,硬件自动认为帧结束,开始发送CRC和EOF。
  2. 设置EOT位法:将UART_MDR1[7] FRAME_END_MODE设为1。在发送最后一字节数据之前,先设置UART_ACREG[0] EOT_EN位,然后再写入最后一个数据字节。这给了软件更灵活的控制权,适用于变长帧。

错误处理:接收完成后,应读取UART_LSR_IRDA寄存器检查FRAME_TOO_LONG,ABORT,CRC等错误位。更详细每帧的错误信息存储在状态FIFO中,可以通过依次读取UART_SFREGL/UART_SFREGH(帧长度)和UART_SFLSR(帧状态)来获取。

3.2 CIR模式详解:从时钟生成到数据收发

CIR模式用于解码诸如电视、空调遥控器发出的红外信号。这些信号通常使用脉宽调制脉冲距离调制。AM64x/AM243x的CIR模块实现了接收端的解调功能和发送端的载波生成功能。

3.2.1 CIR时钟与载波生成

这是CIR模式最核心的部分。CIR发射器需要产生一个高频载波(例如38kHz)来调制基带信号。载波频率由UART_CFPS(载波频率预分频器)寄存器控制。

其计算公式为:载波频率 = (FCLK / 12) / (CFPS + 1)其中 FCLK = 48 MHz。

例如,要产生36kHz的载波:CFPS = (48,000,000 / 12) / 36,000 - 1 = 4,000,000 / 36,000 - 1 ≈ 111.11 - 1 ≈ 110但手册示例给出的是0x7(十进制7),这似乎对不上?这里需要特别注意:手册中的公式Dividing value = (FCLK / 12) / MODfreq可能描述有歧义。根据典型值和示例(目标36.04kHz,CFPS=7),更合理的解释是载波频率 = FCLK / (12 * (CFPS + 1))。 验证:48,000,000 / (12 * (7+1)) = 48,000,000 / 96 = 500,000 Hz。这500kHz再经过后续的16分频(见下图中的/16)得到31.25kHz?这仍然不对。

实际上,结合图12-273的框图,信号路径是:48MHz时钟 -> RCTX分频 -> 移位寄存器 -> CFPS分频 -> 16分频 -> 输出脉冲。CFPS寄存器控制的是“载波频率预分频器”(Carrier frequency prescaler)。手册���格12-475下的示例才是准确的:对于36kHz目标频率,CFPS应设置为0x7(十进制7)。因此,在编程时,最可靠的方法是直接参考手册提供的示例值表格,或者通过实验(如用逻辑分析仪测量)来校准。

载波占空比:通过UART_MDR2[5:4] CIR_PULSE_MODE设置,可选1/4, 1/3, 5/12, 1/2。通常遥控器使用1/3或1/2占空比。

3.2.2 CIR数据格式化与收发控制

CIR模式的数据格式与IrDA不同,它不包含标准的起始位、停止位,而是由一系列代表“0”和“1”的脉冲-空格组合构成。例如,NEC协议用560µs脉冲+560µs空格表示“0”,用560µs脉冲+1690µs空格表示“1”。

  • 发送:CPU需要根据目标协议(如NEC、RC5),在内存中构建一个数据缓冲区,其中每个比特都对应一个特定的脉冲-空格时间对。然后,通过以下两种方式之一控制发送时序:

    1. 填充TX FIFO法:将代表“0”比特的时长(换算成在特定波特率下的字节数)以0x00数据填入TX FIFO。这要求波特率(由UART_DLL/UART_DLH设定)与CIR的位时长精确对应。例如,如果一位的时长是t,波特率应设置为1/t。这种方法将时序控制交给了硬件波特率发生器,精度高,但计算复杂。
    2. 外部定时器法:利用UART_MDR1[5] SCT(存储与控制发送)位和UART_ACREG[2] SCTX_EN位。将SCT设为1,此时写入UART_THR不会立即发送。软件使用一个高精度外部定时器(如EPWM或GPT),在定时器中断中,先置位SCTX_EN启动一帧发送,然后填充下一帧数据到FIFO,等待当前帧发送完成的TX_STATUS_IT中断,再启动定时器开始下一帧的延时。这种方法更灵活,适用于变脉冲距离编码。
  • 接收:接收端的关键是判断一帧何时结束。有两种方法:

    1. 软件控制:使能UART_IIR_CIR[2] RX_STOP_IT中断。当CPU检测到接收了足够多的“0”(代表帧间空格),可以手动设置UART_ACREG[5] DIS_IR_RX=1来禁用接收,处理数据后再重新使能。
    2. 自动停止:设置UART_EBLR为一个非零值(例如,对应一段空白时间的比特数)。接收硬件会计数连续收到的“0”比特,当计数达到UART_EBLR设定值时,自动产生RX_STOP_IT中断并停止接收。当RX引脚再次检测到“1”(脉冲)时,自动重新开始接收。这是最常用、最可靠的方式

一个重要限制:手册指出,某些市售IrDA收发器在接收时会导致调制脉冲的保持时间缩短。例如,发送条件是:移位寄存器周期0.9µs,调制频率36kHz,占空比1/4,会产生7µs的脉冲(在28µs周期内)。但某些接收器可能只输出2µs的脉冲。UART CIR接收滤波机制基于与发送相同的编码,这2µs的脉冲可能被过滤掉,导致RX FIFO收不到数据。这仅影响接收,不影响发送。解决方案是尝试调整UART_MDR3[0] DISABLE_CIR_RX_DEMOD位,旁路接收解调,或者更换更符合标准的红外接收头。

4. 完整编程模型与实操步骤

下面我将以“从零开始”的顺序,梳理UART模块的初始化、配置到收发数据的完整流程。这个流程基于手册第12.1.5.5节的编程模型,并融入了我的实践理解。

4.1 第一阶段:全局初始化与软件复位

在操作任何外设之前,必须确保其所在的电源和时钟域已经就绪。对于AM64x/AM243x的UART模块,这涉及到PLL、时钟控制器、电源管理以及系统互联的配置。手册中的“Surrounding Modules Global Initialization”表格(表12-476)列出了相关模块,但在实际的SDK(如MCU+ SDK)中,这些通常由Board_init()或类似的系统初始化函数完成。我们开发者更关注的是模块本身的软件复位。

// 假设 UART0 的基地址为 0x02800000 #define UART0_BASE 0x02800000 #define UART_SYSC (*(volatile uint32_t *)(UART0_BASE + 0x54)) #define UART_SYSS (*(volatile uint32_t *)(UART0_BASE + 0x58)) void UART_softReset(void) { // 步骤1: 发起软件复位 UART_SYSC |= (1 << 1); // 设置 SOFTRESET 位为1 // 步骤2: 等待复位完成 while((UART_SYSS & 0x1) == 0) { // 等待 RESETDONE 位变为1 // 建议加入超时机制,防止死循环 } }

实操心得:软件复位后,几乎所有寄存器都会恢复为默认值。因此,完整的配置流程必须在软件复位之后进行。在调试时,如果遇到通信异常,尝试执行一次软件复位并重新配置,往往能解决一些状态机卡住的问题。

4.2 第二阶段:寄存器访问模式与子模式切换

AM64x/AM243x的UART寄存器地址是重叠的,通过UART_LCR[7] DIV_EN(即DLAB位)和UART_EFR[4] ENHANCED_EN等位来切换访问的“模式”和“子模式”,以访问不同的寄存器集合。这是编程中最容易混淆的一步。

  1. 模式A(操作模式)UART_LCR[7]=0。这是正常收发数据时的模式,读写UART_THR/UART_RHR
  2. 模式B(配置模式)UART_LCR[7:0]=0xBF。在此模式下,才能访问UART_DLL,UART_DLH(波特率)以及UART_EFR等增强功能寄存器。
  3. 子模式切换:在模式B下,通过设置UART_EFR[4]UART_MCR[6]等,可以进入TCR_TLRMSR_SPRXOFF等子模式,以配置FIFO触发级别(UART_TLR)、软件流控字符(UART_XON1/XOFF1)等。

一个标准的配置流程片段如下

void UART_configureBaudRate(uint32_t base, uint32_t baudDivisor) { volatile uint32_t *lcr = (volatile uint32_t *)(base + 0x0C); volatile uint32_t *dll = (volatile uint32_t *)(base + 0x00); volatile uint32_t *dlh = (volatile uint32_t *)(base + 0x04); uint32_t lcr_backup = *lcr; // 1. 进入模式B以访问DLL/DLH *lcr = 0xBF; // 进入模式B (DIV_EN=1, 且LCR[6:0]特定值) // 2. 写入波特率除数 *dll = baudDivisor & 0xFF; // 低8位 *dlh = (baudDivisor >> 8) & 0x3F; // 高6位,注意AM64x是14位分频器 // 3. 退出模式B,回到操作模式(或进行其他配置) *lcr = lcr_backup & ~(1 << 7); // 清除DIV_EN位,保持其他LCR设置(如数据位、停止位) }

4.3 第三阶段:FIFO、DMA与中断配置

为了高效处理数据,必须合理配置FIFO和中断/DMA。

4.3.1 FIFO触发级别设置

FIFO触发级别决定了何时产生中断或DMA请求。可以通过UART_FCR寄存器或UART_TLR寄存器设置,具体取决于UART_SCR[7:6]位的配置。

  • UART_SCR[7]=0:RX FIFO触发级别由UART_FCR[7:6]UART_TLR[7:4]决定。如果UART_TLR[7:4]不为0,则优先使用UART_TLR的值。
  • UART_SCR[7]=1:RX FIFO触发级别是UART_TLR[7:4]UART_FCR[7:6]的级联组合,提供1-63的精细粒度。 TX FIFO触发级别(UART_SCR[6]UART_FCR[5:4]UART_TLR[3:0])同理。

配置示例(使用TCR_TLR子模式设置TLR)

void UART_setFifoTrigger(uint32_t base, uint8_t rxTrigger, uint8_t txTrigger) { // rxTrigger, txTrigger 范围 0-60(步进4)或 1-63(当SCR[7]=1时) volatile uint32_t *lcr = (volatile uint32_t *)(base + 0x0C); volatile uint32_t *efr = (volatile uint32_t *)(base + 0x08); volatile uint32_t *mcr = (volatile uint32_t *)(base + 0x10); volatile uint32_t *tlr = (volatile uint32_t *)(base + 0x1C); // 进入模式B *lcr = 0xBF; // 使能对MCR[7:5]的写访问 *efr |= (1 << 4); // 回到模式A(使能DLL/DLH访问) *lcr = 0x80; // 假设此时只需访问DLL/DLH,实际需根据情况 // 但为了设置TLR,我们需要进入TCR_TLR子模式,这通常在模式B下设置MCR[6] // 更清晰的流程应遵循手册表格12-479 *lcr = 0xBF; // 确保在模式B *efr |= (1 << 4); // 使能增强功能 *lcr = 0x80; // 切换到模式A?这里容易出错。 // 正确的做法是严格遵循手册的步骤表格! }

由于步骤繁琐,强烈建议直接参考手册中的“表12-483 通过FCR定义加载FIFO触发级别”或“表12-484 通过TLR定义加载FIFO触发级别”,并封装成函数。

4.3.2 DMA模式选择

DMA模式通过UART_SCR[0] DMA_MODE_CTL选择配置源:

  • DMA_MODE_CTL=0:DMA模式由UART_FCR[3]选择。
    • 0:无DMA。
    • 1:DMA模式1。UART_nDMA_REQ[0]用于TX,UART_nDMA_REQ[1]用于RX。
  • DMA_MODE_CTL=1:DMA模式由UART_SCR[2:1] DMA_MODE_2选择。
    • 00:模式0(无DMA)。
    • 01:模式1(同上)。
    • 10:模式2(仅RX DMA)。
    • 11:模式3(仅TX DMA)。

配置建议:对于高速或大数据量传输,启用DMA。根据你的DMA控制器通道分配情况选择合适的模式。例如,如果只有一条DMA请求线连接到UART,则选择模式2或3。

4.4 第四阶段:协议、波特率与中断配置

这是最常配置的部分。

  1. 波特率设置:计算公式为DLL/DLH Divisor = FCLK / (波特率 * 采样率倍数)。对于16x模式,采样率倍数为16。例如,48MHz时钟,目标波特率115200:Divisor = 48,000,000 / (115200 * 16) = 26.0416 ≈ 26。写入UART_DLL=26,UART_DLH=0

  2. 帧格式设置(UART_LCR

    • CHAR_LENGTH[1:0]:数据位(5/6/7/8)。
    • NB_STOP:停止位(1/1.5/2)。
    • PARITY_EN,PARITY_TYPE1,PARITY_TYPE2:校验位控制(无/奇/偶/强制1/强制0)。
  3. 中断使能(UART_IER:根据模式选择UART_IER_UARTUART_IER_IRDAUART_IER_CIR。常见使能位:

    • RHR_IT:接收FIFO达到触发水平,或有数据且超时。
    • THR_IT:发送FIFO为空或低于触发水平。
    • LINE_STS_IT:接收线路错误(帧错误、奇偶校验错误、溢出错误、BREAK)。
    • 在IrDA/CIR模式下,还有TX_STATUS_IT(发送状态)、RX_STOP_IT(CIR接收停止)等。

一个典型的UART模式初始化函数骨架

void UART_init(uint32_t base, uint32_t baudDivisor, uint8_t dataBits, uint8_t stopBits, uint8_t parity) { // 1. 软件复位 UART_softReset(base); // 2. 配置波特率 (需要切换寄存器访问模式) UART_enterModeB(base); UART_setBaudDivisor(base, baudDivisor); UART_exitModeB(base); // 3. 配置帧格式 uint8_t lcrValue = 0; lcrValue |= ((dataBits - 5) & 0x03); // CHAR_LENGTH if(stopBits == 2) lcrValue |= (1 << 2); // NB_STOP // ... 设置 parity UART_setLCR(base, lcrValue); // 4. 使能FIFO并设置触发级别 UART_enableFifo(base, rxTriggerLevel, txTriggerLevel); // 5. 使能所需中断 UART_enableInterrupt(base, UART_IER_RHR_IT | UART_IER_LINE_STS_IT); // 6. 最后,确保模块处于UART 16x模式 UART_setMode(base, UART_MODE_UART_16X); }

4.5 第五阶段:高级功能配置(流控、多播地址匹配)

硬件流控(RTS/CTS):配置UART_EFR[7] AUTO_CTS_ENUART_EFR[6] AUTO_RTS_EN,并设置UART_TCR中的RX_FIFO_TRIG_START(恢复电平)和RX_FIFO_TRIG_HALT(暂停电平)。注意硬件流控和软件流控不能同时使用。

多播地址匹配模式:用于RS-485等多设备总线。使能UART_EFR2[2] MULTIDROP,设置本机地址UART_MAR和地址掩码UART_MMR。当接收到的字节的地址位(通常为第9位,即奇偶校验位)与MARMMR非掩码位上匹配时,才会产生中断并将数据存入FIFO。广播地址UART_MBR可以单独设置。

5. IrDA (SIR/MIR/FIR) 与 CIR 模式专项配置

手册12.1.5.5.7节提供了非常具体的编程模型表格。这里我提炼出关键步骤和注意事项。

5.1 SIR模式配置要点

SIR(低速红外)是兼容最广的IrDA模式,最高115.2kbps。

  • 脉冲宽度:通过UART_ACREG[7] PULSE_TYPE选择。0为3/16位周期,1为固定1.6µs。必须与对端设备匹配。大多数现代设备支持自动检测,但固定1.6µs是更通用的选择。
  • BOF数量:通过UART_EBLR设置。如果需要N个起始标志,则EBLR = N(注意:手册指出,设置为0表示1个BOF加255个xBOF)。通常设置为1即可。
  • 示例(接收配置,115.2kbps,8N2,强制奇校验)
    1. 禁用UART模式 (MODE_SELECT=0x7)。
    2. 进入模式B,设置波特率除数 (DLL=0x1A, DLH=0x00for 48MHz)。
    3. 设置SIR模式 (MODE_SELECT=0x1)。
    4. 退出模式B。
    5. 配置UART_LCR为8数据位、2停止位、强制奇校验。
    6. 使能接收中断 (UART_IER_IRDA[0] RHR_IT=1)。

5.2 MIR/FIR模式配置要点

MIR和FIR模式使用硬件CRC和更复杂的帧结构。

  • 帧长度寄存器必须正确设置UART_TXFLL/UART_TXFLH(发送)和UART_RXFLL/UART_RXFLH(接收)。长度仅指数据域字节数,CRC和帧头尾由硬件管理。
  • SIP控制:如3.1节所述,根据需求选择自动或手动SIP模式。
  • FIFO使用:在FIR模式(4Mbps)下,强烈建议使能FIFO(UART_FCR[0]=1),并设置合理的触发水平,以应对高速数据流。
  • 示例(FIR模式发送,4Mbps,无校验,FIFO使能)
    1. 禁用UART模式。
    2. 进入模式B,设置波特率除数(对于4Mbps,需要计算。48MHz / (4Mbps * 16) = 0.75,非整数,可能需要使用13x模式或其他分频?这里需要查表或使用特定值)。实际上,FIR模式可能使用固定的分频。
    3. 关键一步:在模式B下,写入UART_DLL=0UART_DLH=0?手册表12-498中这一步是“Enable access to change UART_FCR[0]”,这是一个特殊操作。
    4. 使能并清除FIFO (UART_FCR[2:0]=0x7)。
    5. 设置FIFO触发水平。
    6. 设置FIR模式 (MODE_SELECT=0x5)。
    7. 退出模式B。
    8. 设置帧长度 (TXFLL)。
    9. 使能自动SIP模式 (UART_MDR1[6]=1) 或配置手动SIP。
    10. 使能发送中断 (UART_IER_IRDA[1] THR_IT=1)。

5.3 CIR模式配置实战

假设我们要实现一个NEC协议遥控器信号的接收器。

  1. 系统与模块初始化:完成4.1节的全局初始化和软件复位。
  2. 模式与时钟配置
    • 设置UART_MDR1[2:0]=0x6进入CIR模式。
    • 根据目标载波频率(如38kHz)设置UART_CFPS寄存器。查阅手册或计算得出CFPS=0x69
    • 设置载波占空比,NEC协议通常为1/3,即UART_MDR2[5:4]=0x1
  3. 接收配置
    • 设置UART_EBLR。NEC协议中,一个重复帧之间的空闲时间大约为40ms以上。我们需要将这个时间转换为在CIR位速率下的“0”比特数量。首先需确定CIR的位时间(t)。位时间由波特率决定(UART_DLL/UART_DLH)。CIR模式下,波特率决定了“0”和“1”的基准时间单位。例如,设置波特率对应位时间t=1ms。那么40ms对应40个“0”比特。设置EBLR=40(十进制)。
    • 使能RX_STOP_IT中断 (UART_IER_CIR[2]=1)。
    • 使能接收 (UART_ECR[3] RX_EN=1,如果之前被禁用)。
  4. 中断服务程序:当RX_STOP_IT中断发生时,表示一帧数据接收完毕(检测到连续40ms的低电平/无载波)。此时,从UART_RHR(或RX FIFO)中读取数据。注意:读出的数据是原始的“0”、“1”比特流,需要根据NEC协议(引导码、地址、命令、反码)进行解码。
  5. 发送配置���如需发射)
    • 构建数据缓冲区。对于NEC协议,需要将逻辑“0”(560µs脉冲+560µs空格)和逻辑“1”(560µs脉冲+1690µs空格)映射为一系列字节写入TX FIFO。这需要精确计算每个状态在CIR位时间t下的持续时间所对应的字节数。通常采用外部定时器法(SCT控制)更易实现。
    • 设置UART_MDR1[5] SCT=1
    • 填充第一帧数据到TX FIFO。
    • 启动外部定时器,在定时器中断中置位UART_ACREG[2] SCTX_EN开始发送。
    • TX_STATUS_IT中断中,准备下一帧数据并重启定时器。

6. 常见问题排查与调试技巧

  1. 收不到数据/数据乱码

    • 检查时钟和波特率:确认系统时钟FCLK配置正确,计算出的波特率除数准确。使用示波器测量TX引脚波形,验证实际波特率。
    • 检查帧格式:数据位、停止位、校验位是否与对端设备严格匹配。常见的错误是8N1配置成了7E1。
    • 检查硬件连接:TX/RX是否交叉连接?电平是否匹配(3.3V vs 5V)?IrDA/CIR模式下,红外收发器的型号和电路是否正确?
    • 检查FIFO和中断:FIFO是否使能?触发水平设置是否合理?中断是否正确使能并清除了标志位?对于CIR接收,UART_EBLR设置是否太小(过早停止)或太大(无法自动停止)?
  2. IrDA/CIR通信距离短或不稳定

    • 检查载波频率和占空比:用示波器测量红外发射管的驱动波形,确认载波频率(CIR)和脉冲宽度(SIR)符合预期且准确。
    • 检查收发器对准和障碍物:红外通信对方向敏感,确保收发器之间没有遮挡,且角度偏差不大。
    • 注意CIR接收器的“脉宽收缩”问题:如3.2.2节所述,尝试设置UART_MDR3[0] DISABLE_CIR_RX_DEMOD=1,旁路内部解调,直接读取原始调制信号(需要外部解调电路或软件解码)。
  3. DMA不工作或数据丢失

    • 确认DMA模式配置UART_SCR[0]UART_FCR[3](或UART_SCR[2:1])是否设置正确?
    • 检查DMA请求映射:确认UART的DMA请求线(UARTi_DREQ_TX/RX)是否正确连接到DMA控制器的相应通道。
    • 检查FIFO触发水平与DMA传输量:确保DMA传输的数据量大于或等于FIFO触发水平,否则可能无法触发DMA请求。
  4. 寄存器写入无效

    • 确认寄存器访问模式:这是最常见的问题。在写UART_DLL/UART_DLHUART_FCR[5:4]UART_TLR等寄存器前,是否进入了正确的模式(模式B)和子模式(通过UART_EFR[4]UART_MCR[6])?严格按照手册中的步骤表格操作。
    • 检查模块是否已使能UART_MDR1[2:0]不能为0x7(禁用模式)。
  5. 使用调试工具

    • 利用寄存器读取:在初始化后,读取关键寄存器(如UART_LSRUART_IIRUART_RXFIFO_LVL)的值,判断模块状态。
    • 逻辑分析仪/示波器:是调试串行通信的终极利器。可以直观看到波形、波特率、数据内容,以及IrDA/CIR的脉冲形状和载波。
    • 软件模拟:在复杂协议(如CIR编码)实现初期,可以先用GPIO模拟发送,验证解码逻辑,再移植到UART硬件上。

最后,调试AM64x/AM243x UART这类复杂外设,耐心和细致是关键。务必随身备好技术参考手册(TRM),并善用TI提供的驱动程序库(如drivers/uart),这些库函数已经封装了繁琐的寄存器访问序列,能极大提高开发效率和可靠性。但在遇到底层问题时,仍需回到寄存器层面理解其工作原理,希望这篇指南能成为你手边有用的参考。