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帧包括:
- 起始标志(BOF):至少2个(MIR)或更多个特定的起始字节(如0xC0, 0xFF),用于同步。
- 数据域:实际要发送的数据字节。
- CRC校验域:16位CRC,由硬件自动计算并添加(发送)或校验(接收)。
- 结束标志(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_SIP与UART_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,从而减少了开销。这对于需要连续发送大量小数据包的场景(如实时传感器流)能提升效率。
- 当
帧结束判定:有两种方法告诉硬件一帧数据已经发送完毕:
- 帧长度法(默认):配置好
UART_TXFLL后,当你写入FIFO的字节数达到设定长度,硬件自动认为帧结束,开始发送CRC和EOF。 - 设置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),在内存中构建一个数据缓冲区,其中每个比特都对应一个特定的脉冲-空格时间对。然后,通过以下两种方式之一控制发送时序:
- 填充TX FIFO法:将代表“0”比特的时长(换算成在特定波特率下的字节数)以0x00数据填入TX FIFO。这要求波特率(由
UART_DLL/UART_DLH设定)与CIR的位时长精确对应。例如,如果一位的时长是t,波特率应设置为1/t。这种方法将时序控制交给了硬件波特率发生器,精度高,但计算复杂。 - 外部定时器法:利用
UART_MDR1[5] SCT(存储与控制发送)位和UART_ACREG[2] SCTX_EN位。将SCT设为1,此时写入UART_THR不会立即发送。软件使用一个高精度外部定时器(如EPWM或GPT),在定时器中断中,先置位SCTX_EN启动一帧发送,然后填充下一帧数据到FIFO,等待当前帧发送完成的TX_STATUS_IT中断,再启动定时器开始下一帧的延时。这种方法更灵活,适用于变脉冲距离编码。
- 填充TX FIFO法:将代表“0”比特的时长(换算成在特定波特率下的字节数)以0x00数据填入TX FIFO。这要求波特率(由
接收:接收端的关键是判断一帧何时结束。有两种方法:
- 软件控制:使能
UART_IIR_CIR[2] RX_STOP_IT中断。当CPU检测到接收了足够多的“0”(代表帧间空格),可以手动设置UART_ACREG[5] DIS_IR_RX=1来禁用接收,处理数据后再重新使能。 - 自动停止:设置
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等位来切换访问的“模式”和“子模式”,以访问不同的寄存器集合。这是编程中最容易混淆的一步。
- 模式A(操作模式):
UART_LCR[7]=0。这是正常收发数据时的模式,读写UART_THR/UART_RHR。 - 模式B(配置模式):
UART_LCR[7:0]=0xBF。在此模式下,才能访问UART_DLL,UART_DLH(波特率)以及UART_EFR等增强功能寄存器。 - 子模式切换:在模式B下,通过设置
UART_EFR[4]和UART_MCR[6]等,可以进入TCR_TLR、MSR_SPR、XOFF等子模式,以配置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 第四阶段:协议、波特率与中断配置
这是最常配置的部分。
波特率设置:计算公式为
DLL/DLH Divisor = FCLK / (波特率 * 采样率倍数)。对于16x模式,采样率倍数为16。例如,48MHz时钟,目标波特率115200:Divisor = 48,000,000 / (115200 * 16) = 26.0416 ≈ 26。写入UART_DLL=26,UART_DLH=0。帧格式设置(
UART_LCR):CHAR_LENGTH[1:0]:数据位(5/6/7/8)。NB_STOP:停止位(1/1.5/2)。PARITY_EN,PARITY_TYPE1,PARITY_TYPE2:校验位控制(无/奇/偶/强制1/强制0)。
中断使能(
UART_IER):根据模式选择UART_IER_UART、UART_IER_IRDA或UART_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_EN和UART_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位,即奇偶校验位)与MAR在MMR非掩码位上匹配时,才会产生中断并将数据存入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,强制奇校验):
- 禁用UART模式 (
MODE_SELECT=0x7)。 - 进入模式B,设置波特率除数 (
DLL=0x1A, DLH=0x00for 48MHz)。 - 设置SIR模式 (
MODE_SELECT=0x1)。 - 退出模式B。
- 配置
UART_LCR为8数据位、2停止位、强制奇校验。 - 使能接收中断 (
UART_IER_IRDA[0] RHR_IT=1)。
- 禁用UART模式 (
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使能):
- 禁用UART模式。
- 进入模式B,设置波特率除数(对于4Mbps,需要计算。48MHz / (4Mbps * 16) = 0.75,非整数,可能需要使用13x模式或其他分频?这里需要查表或使用特定值)。实际上,FIR模式可能使用固定的分频。
- 关键一步:在模式B下,写入
UART_DLL=0和UART_DLH=0?手册表12-498中这一步是“Enable access to change UART_FCR[0]”,这是一个特殊操作。 - 使能并清除FIFO (
UART_FCR[2:0]=0x7)。 - 设置FIFO触发水平。
- 设置FIR模式 (
MODE_SELECT=0x5)。 - 退出模式B。
- 设置帧长度 (
TXFLL)。 - 使能自动SIP模式 (
UART_MDR1[6]=1) 或配置手动SIP。 - 使能发送中断 (
UART_IER_IRDA[1] THR_IT=1)。
5.3 CIR模式配置实战
假设我们要实现一个NEC协议遥控器信号的接收器。
- 系统与模块初始化:完成4.1节的全局初始化和软件复位。
- 模式与时钟配置:
- 设置
UART_MDR1[2:0]=0x6进入CIR模式。 - 根据目标载波频率(如38kHz)设置
UART_CFPS寄存器。查阅手册或计算得出CFPS=0x69。 - 设置载波占空比,NEC协议通常为1/3,即
UART_MDR2[5:4]=0x1。
- 设置
- 接收配置:
- 设置
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,如果之前被禁用)。
- 设置
- 中断服务程序:当
RX_STOP_IT中断发生时,表示一帧数据接收完毕(检测到连续40ms的低电平/无载波)。此时,从UART_RHR(或RX FIFO)中读取数据。注意:读出的数据是原始的“0”、“1”比特流,需要根据NEC协议(引导码、地址、命令、反码)进行解码。 - 发送配置���如需发射):
- 构建数据缓冲区。对于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中断中,准备下一帧数据并重启定时器。
- 构建数据缓冲区。对于NEC协议,需要将逻辑“0”(560µs脉冲+560µs空格)和逻辑“1”(560µs脉冲+1690µs空格)映射为一系列字节写入TX FIFO。这需要精确计算每个状态在CIR位时间
6. 常见问题排查与调试技巧
收不到数据/数据乱码
- 检查时钟和波特率:确认系统时钟FCLK配置正确,计算出的波特率除数准确。使用示波器测量TX引脚波形,验证实际波特率。
- 检查帧格式:数据位、停止位、校验位是否与对端设备严格匹配。常见的错误是8N1配置成了7E1。
- 检查硬件连接:TX/RX是否交叉连接?电平是否匹配(3.3V vs 5V)?IrDA/CIR模式下,红外收发器的型号和电路是否正确?
- 检查FIFO和中断:FIFO是否使能?触发水平设置是否合理?中断是否正确使能并清除了标志位?对于CIR接收,
UART_EBLR设置是否太小(过早停止)或太大(无法自动停止)?
IrDA/CIR通信距离短或不稳定
- 检查载波频率和占空比:用示波器测量红外发射管的驱动波形,确认载波频率(CIR)和脉冲宽度(SIR)符合预期且准确。
- 检查收发器对准和障碍物:红外通信对方向敏感,确保收发器之间没有遮挡,且角度偏差不大。
- 注意CIR接收器的“脉宽收缩”问题:如3.2.2节所述,尝试设置
UART_MDR3[0] DISABLE_CIR_RX_DEMOD=1,旁路内部解调,直接读取原始调制信号(需要外部解调电路或软件解码)。
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请求。
- 确认DMA模式配置:
寄存器写入无效
- 确认寄存器访问模式:这是最常见的问题。在写
UART_DLL/UART_DLH、UART_FCR[5:4]、UART_TLR等寄存器前,是否进入了正确的模式(模式B)和子模式(通过UART_EFR[4]和UART_MCR[6])?严格按照手册中的步骤表格操作。 - 检查模块是否已使能:
UART_MDR1[2:0]不能为0x7(禁用模式)。
- 确认寄存器访问模式:这是最常见的问题。在写
使用调试工具
- 利用寄存器读取:在初始化后,读取关键寄存器(如
UART_LSR、UART_IIR、UART_RXFIFO_LVL)的值,判断模块状态。 - 逻辑分析仪/示波器:是调试串行通信的终极利器。可以直观看到波形、波特率、数据内容,以及IrDA/CIR的脉冲形状和载波。
- 软件模拟:在复杂协议(如CIR编码)实现初期,可以先用GPIO模拟发送,验证解码逻辑,再移植到UART硬件上。
- 利用寄存器读取:在初始化后,读取关键寄存器(如
最后,调试AM64x/AM243x UART这类复杂外设,耐心和细致是关键。务必随身备好技术参考手册(TRM),并善用TI提供的驱动程序库(如drivers/uart),这些库函数已经封装了繁琐的寄存器访问序列,能极大提高开发效率和可靠性。但在遇到底层问题时,仍需回到寄存器层面理解其工作原理,希望这篇指南能成为你手边有用的参考。