1. 项目概述与核心价值
在嵌入式系统开发,尤其是工业控制、电机驱动和数字电源这些对实时性和可靠性要求极高的领域,TMS320F2802x系列DSP是当之无愧的主力芯片。在这些应用中,芯片与外部传感器、上位机、其他微控制器之间的数据交换是系统正常工作的生命线。串行通信接口(SCI)和I2C总线,就是承载这条生命线的两根核心血管。
SCI,也就是我们常说的UART,负责的是点对点的异步通信。它不依赖时钟线,只需要两根线(TX和RX)就能工作,结构简单,协议直接,是打印调试信息、与PC机通信、连接GPS/蓝牙模块的标配。而I2C则是一种同步、多主从的通信总线,凭借其简洁的两线制(SDA数据线和SCL时钟线)和寻址机制,在连接EEPROM、传感器、IO扩展芯片等低速外设时,能极大地节省宝贵的GPIO资源,简化PCB布线。
然而,很多工程师在初次接触F2802x的SCI和I2C时,往往会被其数据手册中密密麻麻的寄存器描述所困扰。配置起来要么是照抄例程,知其然不知其所以然;要么是调试时通信不通,面对一堆状态标志位无从下手。比如,为什么发送数据后程序会卡住?为什么FIFO中断不触发?为什么I2C总线上会丢数据?这些问题,根源大多在于对寄存器每一位功能的深入理解不够。
本文将从一线开发者的实战视角出发,彻底拆解TMS320F2802x中SCI与I2C模块的关键寄存器。我们不止步于翻译数据手册,而是结合真实的调试场景,深入探讨诸如SCIRXEMU寄存器在CCS调试中的妙用、SCIFFTX/RX中FIFO中断水位线的精确计算、以及I2CCLKL/H寄存器配置如何影响总线时序和可靠性等核心问题。目标是让你在配置这些通信外设时,不仅能“配得通”,更能“配得优”,写出稳定、高效的驱动代码,从容应对各种复杂的现场应用。
2. SCI模块核心寄存器深度解析与实战配置
SCI模块的寄存器看似繁多,但核心逻辑围绕“数据缓冲”、“状态标志”和“流程控制”展开。理解这几组寄存器的协同工作方式,是掌握SCI通信的关键。
2.1 数据缓冲寄存器组:数据流转的核心枢纽
数据在SCI模块内部的流动,可以想象成一个精心设计的流水线。发送数据时,CPU将数据写入SCITXBUF(发送数据缓冲寄存器),然后硬件自动将其加载到TXSHF(发送移位寄存器)中,一位一位地串行发出。接收过程则相反,数据从RX引脚进入RXSHF(接收移位寄存器),凑满一个字节后,自动转移到SCIRXBUF(接收数据缓冲寄存器)中,等待CPU读取。
2.1.1 SCITXBUF与TXRDY标志的“握手”协议
SCITXBUF(偏移地址9h)是CPU放置待发送数据的“码头”。其低8位TXDT是有效数据区。这里有一个至关重要的细节:数据必须右对齐写入。也就是说,如果你配置为8位数据模式,数据就写在bit7-0;如果是7位模式,数据应写在bit6-0,高位忽略。如果写错了位置,发送出去的数据将是错误的。
当数据从SCITXBUF被搬运到TXSHF寄存器后,TXRDY(发送就绪)标志位(位于SCICTL2.7)会被硬件自动置1。这就像码头工人告诉你:“码头(SCITXBUF)已经空了,可以卸下一批货(写下一个数据)了。”如果你使能了发送中断(TXINTENA,SCICTL2.0 = 1),这个搬运动作还会触发一个中断,让你可以在中断服务程序里及时补充数据,实现连续发送。
实操心得:在查询方式发送时,务必在写
SCITXBUF之前,先检查TXRDY是否为1。盲目写入会导致数据被覆盖,造成发送错误。一个可靠的发送函数片段如下:void SCI_SendByte(uint16_t base, uint16_t data) { // 等待发送缓冲区空闲 while(SCI_getTxReadyStatus(base) == 0); // 查询TXRDY标志 // 将数据写入发送缓冲区 SCI_writeDataBlockingNonFIFO(base, data); }
2.1.2 SCIRXBUF、RXRDY与SCIRXEMU的调试艺术
SCIRXBUF(偏移地址7h)是CPU获取接收数据的“仓库”。当RXSHF收满一个字符后,数据会自动存入SCIRXBUF,同时RXRDY(接收就绪)标志位被置1。这里有一个关键动作:一旦CPU读取了SCIRXBUF,RXRDY标志位会被硬件自动清零。这个机制在查询方式下很直观,但在调试时却会带来麻烦。
想象一下,你在Code Composer Studio (CCS)的Watch窗口中添加了SCIRXBUF来观察接收到的数据。每次你手动点击“刷新”或程序暂停时,CCS都会去读取这个寄存器的值。这个读取操作会意外地清除RXRDY标志!这可能导致你的接收中断逻辑紊乱,或者让你无法判断是否真的有新数据到来。
这就是SCIRXEMU(接收仿真缓冲寄存器,偏移地址6h)存在的意义。数据手册说得很清楚,它并非一个物理上独立的寄存器,而只是SCIRXBUF的一个“镜像”地址。但通过这个特殊地址去读数据,不会触发RXRDY标志的清除。你可以把它理解为一个仅供“观察”的窗口。
调试技巧:在CCS中调试SCI接收程序时,强烈建议将
SCIRXEMU而非SCIRXBUF添加到Watch窗口。这样,你可以随时查看接收缓冲区内的最新数据,而完全不会干扰程序的正常运行状态和中断标志位。这对于诊断偶发的数据丢失、解析数据帧格式异常等问题至关重要。
SCIRXBUF寄存器的高位(bit15, bit14)还包含了FIFO模式下的帧错误(SCIFFFE)和奇偶校验错误(SCIFFPE)标志,这对于通信可靠性的判断非常有价值。
2.2 FIFO控制寄存器组:提升效率的关键武器
对于高速或大数据量的通信,频繁的中断会消耗大量CPU资源。SCI模块内置的16级深度的FIFO(先入先出缓冲区)就是为了解决这个问题。而配置FIFO的核心,就在于SCIFFTX、SCIFFRX和SCIFFCT这三个寄存器。
2.2.1 SCIFFTX:发送FIFO的“指挥官”
SCIFFTX寄存器控制发送FIFO的使能、复位和中断。
SCIFFENA(bit14):FIFO功能总开关。必须置1才能使用FIFO增强功能。TXFIFORESET(bit13):发送FIFO复位。写0复位FIFO指针并保持复位,写1重新使能FIFO操作。在初始化或需要清空发送FIFO时,应先写0再写1。TXFFST(bit12-8):只读状态位,实时指示发送FIFO中存有多少个字(0-16)。这是你判断FIFO空满状态的依据。TXFFINT(bit7):发送FIFO中断标志。当TXFFST小于或等于TXFFIL设定的水位线时,此标志置1。TXFFINTCLR(bit6):写1清除TXFFINT标志。TXFFIENA(bit5):发送FIFO中断使能。TXFFIL(bit4-0):发送FIFO中断触发水位线。这是配置的精髓所在。
如何设置TXFFIL?这需要在CPU中断开销和总线利用率之间做权衡。假设你的发送FIFO深度为16。
- 如果设置
TXFFIL = 0:那么FIFO一空(TXFFST=0)就立即触发中断。这能保证数据一旦发送完就立刻补充,总线利用率最高,但中断也最频繁,CPU负担重。 - 如果设置
TXFFIL = 8:那么当FIFO中剩余数据小于等于8个时(即已发送出去8个以上)才触发中断。此时你一次补满16个数据,中断频率降低了一半,但存在FIFO完全清空、总线等待的风险。 - 常见策略:对于实时性要求高的系统,可以设低水位线(如2或4),快速响应。对于吞吐量大但实时性要求稍低的场景,可以设高水位线(如12),减少中断次数。初始调试时可设为8(半满)作为折中。
2.2.2 SCIFFRX:接收FIFO的“守门���”
SCIFFRX寄存器控制接收FIFO,其位定义与SCIFFTX类似但方向相反。
RXFFOVF(bit15):接收FIFO溢出标志。当FIFO已满(16个字)且又收到第17个字时,此位置1,且最早的数据会被覆盖丢失。这是一个严重错误标志,必须在中断服务程序中检查并处理。RXFFOVRCLR(bit14):写1清除溢出标志。RXFFIL(bit4-0):接收FIFO中断触发水位线。注意逻辑与发送相反:当RXFFST(接收FIFO状态)大于或等于RXFFIL时,触发中断。
如何设置RXFFIL?默认值为1Fh(即31,大于FIFO深度16),意味着默认情况下接收FIFO中断是被禁用的(因为状态永远不可能大于等于31)。你必须根据应用修改它。
- 如果设置
RXFFIL = 1:那么只要FIFO收到1个数据就触发中断。响应最快,但中断频繁。 - 如果设置
RXFFIL = 16:那么FIFO完全满时才触发中断。中断次数最少,但CPU一次要处理16个数据,可能造成处理延迟,且如果数据持续高速涌入,有溢出风险。 - 推荐配置:通常设置为半满或3/4满,例如8或12。这样既能积累一定数据量再处理,提高效率,又能留出缓冲空间,避免溢出。同时,务必使能
RXFFIENA并编写相应的中断服务程序,及时从FIFO中读取数据。
2.2.3 SCIFFCT:自动波特率与传输延迟
SCIFFCT寄存器有两个重要功能。
- 自动波特率检测(ABD):通过
ABD位和ABDCLR位,配合CDC位,可以实现自动检测对方波特率的功能。这在需要与不同设备自适应通信的场景下有用,但多数固定波特率的应用可以不使用。 - FFTXDLY(bit7-0):FIFO传输延迟。这是最容易被忽略但影响巨大的一个配置。它定义了从FIFO传输缓冲区(TXBUF)到发送移位寄存器(TXSHF)之间,每个字符传输的延迟,单位是SCI波特率时钟周期。
为什么需要这个延迟?在FIFO模式下,数据是自动、连续地从FIFO加载到发送移位寄存器的。如果没有延迟,一个字符的停止位刚发完,下一个字符的起始位立刻开始,帧与帧之间紧密相连。这在某些老旧的或响应慢的接收设备上,可能导致其来不及处理而丢失数据。FFTXDLY就是在两帧之间插入一个可控的“空闲时间”。
- 计算与配置:假设波特率为115200,则每个位的时间约为8.68us。如果你想在两帧之间插入2个位时间的延迟,则
FFTXDLY应设置为2。延迟时间 =FFTXDLY* (1 / 波特率)。手册特别指出,当配置为2个停止位时,实际延迟会减1。 - 实战建议:在标准UART通信中,如果接收端是稳定的MCU,通常可以设置为0。但如果通信对象是某些古老的打印机、调制解调器或通过电平转换芯片连接的长线,适当增加
FFTXDLY(如1-2个周期)可以显著提高通信稳定性。这是一个需要通过实际测试来优化的参数。
2.3 优先级控制寄存器(SCIPRI):仿真调试时的“定心丸”
SCIPRI寄存器主要关注FREESOFT位(bit4-3)。它决定了当你在CCS中遇到断点、单步执行等仿真挂起事件时,SCI模块的行为。
00:立即停止。SCI模块立刻冻结,当前正在发送或接收的字符可能被截断。01:完成当前接收/发送序列后停止。这是最安全、最推荐的调试模式。确保当前正在传输的一个完整字节(包括起始位、数据位、停止位)完成后,模块再暂停,避免产生错误的、不完整的帧干扰总线上的其他设备。10或11:自由运行。仿真挂起不影响SCI操作。这可能导致你在查看变量时,SCI仍在后台收发数据,使得系统状态难以捕捉。
避坑指南:在开发阶段,务必将
FREESOFT设置为01。这能保证你在打断点调试时,不会因为一个残缺的字节而把与之通信的传感器或执行器搞“懵”,从而引发一系列难以排查的异常问题。在产品量产代码中,此位通常保持默认值或设置为自由运行。
3. I2C模块核心机制与寄存器配置实战
I2C协议的精妙之处在于其用两根线实现了多主多从的通信。TMS320F2802x的I2C模块完整支持标准模式(最高100kbps)和快速模式(最高400kbps),理解其时钟生成、状态机和FIFO机制是稳定通信的基础。
3.1 I2C时钟系统配置:通信速率的基石
I2C总线的时钟(SCL)由主机产生,其频率的精确配置是通信成功的首要条件。配置涉及两个步骤:生成模块时钟,再分频得到总线时钟。
3.1.1 模块时钟配置(I2CPSC寄存器)
模块时钟是I2C模块内部工作的时钟源,由系统时钟(SYSCLK)分频而来。公式为:I2C模块时钟频率 = SYSCLK / (I2CPSC.IPSC + 1)。 这里有一个硬性约束:为了满足I2C协议严格的时序要求,模块时钟频率必须在7-12 MHz之间。不满足此条件,通信可能极不稳定。
例如,系统时钟SYSCLK = 60MHz。要得到10MHz的模块时钟,则IPSC = (60/10) - 1 = 5。关键步骤:I2CPSC寄存器的配置必须在I2C模块复位期间(即I2CMDR.IRS = 0时)进行。一旦将IRS置1使能模块,再修改IPSC是无效的。
3.1.2 总线时钟配置(I2CCLKL与I2CCLKH寄存器)
模块时钟进一步被分频,以产生最终出现在SCL引脚上的总线时钟。这里的分频器比较特殊,它分别控制SCL低电平时间(通过I2CCLKL.ICCL)和高电平时间(通过I2CCLKH.ICCH)。
总线时钟周期Tmst的计算公式为:Tmst = Tmod * [(ICCH + d) + (ICCL + d)]其中,Tmod是模块时钟周期,d是一个由IPSC决定的延迟因子(见数据手册表10-1)。通常d为5(当IPSC>1时)。
配置实例:目标总线时钟频率为100kHz(标准模式),周期Tmst = 10us。假设模块时钟Fmod = 10MHz,Tmod = 0.1us,且d=5。 则(ICCH + d) + (ICCL + d) = Tmst / Tmod = 10us / 0.1us = 100。 令高、低电平时间相等(占空比50%),则ICCH = ICCL = (100 / 2) - d = 50 - 5 = 45。 因此,设置I2CCLKH = 45,I2CCLKL = 45。
注意事项:
ICCH和ICCL的值必须至少为d(通常为5)。计算出的值需要是整数,否则实际频率会有偏差。建议使用TI提供的I2C_calcClockDivider之类的工具函数或在线计算器进行辅助计算,并最终用示波器测量SCL频率进行验证。
3.2 工作模式与核心控制寄存器(I2CMDR)
I2CMDR(I2C模式寄存器)是I2C模块的“大脑”,它决定了模块作为主机还是从机、启动或停止条件、数据传输模式等。
3.2.1 主/从模式与启停控制
MST位:主模式使能。1为主机,0为从机。STT位:产生START条件。在主机模式下,软件置1此位,模块将在总线上产生一个START(或Repeated START)信号。STP位:产生STOP条件。在主机模式下,传输结束后,软件置1此位,模块将产生STOP信号。主机必须在传输序列的最后生成STP,否则总线将无法释放。RM位:重复模式。0为非重复模式(标准模式),传输字节数由I2CCNT寄存器指定;1为重复模式,持续传输数据直到软件产生STOP或新的START。
3.2.2 关键操作流程
- 主机发送流程:配置为主机(
MST=1),写从机地址(含读写位)到I2CSAR,写数据到I2CDXR,然后置STT=1启动传输。模块会自动发送地址帧,并在收到从机应答后,发送I2CDXR中的数据。在非重复模式下,每发送一个字节,需要等待XRDY标志置1(或FIFO中断)再写下一个数据。 - 主机接收流程:前几步同发送流程,但地址中的读写位应为读(1)。启动传输后,主机将释放SDA线并产生时钟。每接收完一个字节,数据会存入
I2CDRR(或RX FIFO),并置位RRDY标志。主机需要在发送最后一个字节的NACK和STOP前,读取数据。 - 从机响应流程:从机需设置自身的地址
I2COAR。当总线上的地址与自身匹配时,模块会置位AAS(被寻址为从机)标志,并可触发中断。在中断中,根据地址帧中的读写位,从机需要软件配置I2CMDR为从发送器或从接收器模式,然后进行数据读写。
3.3 数据寄存器与FIFO:高效数据搬运
与SCI类似,I2C也通过数据寄存器和FIFO来缓冲数据。
I2CDXR:I2C数据发送寄存器。CPU将待发送的数据写入此处。I2CDRR:I2C数据接收寄存器。CPU从此处读取接收到的数据。I2CFFTX/I2CFFRX:I2C的发送/接收FIFO控制寄存器,其功能与SCI的FIFO寄存器高度相似,包括使能、复位、中断水位线(TXFFIL/RXFFIL)配置等。
I2C FIFO配置要点:
- 使能顺序:先配置FIFO参数(如水位线),最后再置位
I2CFFTX. SCIFFENA(注意,此位名称在I2C模块中可能仍沿用SCI前缀,具体见寄存器定义)来使能FIFO功能。 - 中断处理:在FIFO中断服务程序中,必须检查
TXFFST或RXFFST状态,一次性读取或写入多个数据,以充分发挥FIFO的批处理优势,减少中断次数。 - 错误处理:务必在接收FIFO中断中检查
RXFFOVF(溢出标志),一旦发生溢出,意味着数据丢失,需要执行错误恢复流程,如复位FIFO、重新启动传输等。
3.4 状态寄存器(I2CSTR)与错误处理
I2CSTR寄存器是诊断I2C通信问题的“仪表盘”。以下几个标志位至关重要:
BB(Bus Busy):总线忙标志。在发起通信(置STT)前,必须检查此位是否为0。ARDY(寄存器访问就绪):当I2CMDR寄存器可被访问时置1。在写入I2CMDR启动一次传输后,应等待ARDY置1,再写入下一次传输的命令。NACK(无应答):当发送地址或数据后,未收到从机的ACK应答时置1。这是一个错误标志,通常意味着从机地址错误、从机设备不存在或忙、或总线故障。主机程序必须检测并处理此情况,通常的做法是产生STOP条件,终止本次传输。ARBL(仲裁丢失):在多主系统中,当本机与其他主机同时发起传输并竞争总线失败时置1。模块会自动切换到从机模式并监听总线。RSFULL(接收移位寄存器满):在从接收模式下,如果I2CDRR尚未被读取,而新的数据已准备从I2CRSR移入,此位置1,模块会拉低SCL时钟线(时钟延展),直到CPU读取I2CDRR释放空间。XSMT(发送器空):在从发送模式下,如果I2CDXR为空,没有新数据可发送,此位置0,模块也会拉低SCL时钟线,直到CPU写入新数据。
排查技巧:当I2C通信卡住,SCL线被持续拉低时,首先检查
I2CSTR寄存器。如果RSFULL=1,说明接收缓冲区满,需要去读I2CDRR;如果XSMT=0,说明发送缓冲区空,需要去写I2CDXR。这是从机模式下最常见的通信“挂死”原因。
4. 典型配置流程与调试问题实录
理解了单个寄存器后,我们需要将其串联起来,形成可靠的配置和操作流程。
4.1 SCI模块初始化与通信流程
一个完整的SCI初始化配置流程如下,以115200波特率、8位数据位、1位停止位、无校验、使能FIFO为例:
- 使能时钟与配置GPIO:首先使能SCI模块所在的外设时钟,并将对应的GPIO引脚复用为SCI功能(TX和RX),通常需要配置GPxMUX和GPxPUD寄存器。
- 软件复位与基本配置:
- 将
SCICCR寄存器写0,实现软件复位。 - 配置
SCICCR:选择通信格式(8位数据,无校验,1停止位)。 - 配置
SCICTL1:使能接收/发送器,退出复位状态。
- 将
- 配置波特率:根据系统时钟频率,计算并写入
SCIHBAUD和SCILBAUD寄存器。计算公式为:BRR = (LSPCLK / (波特率 * 8)) - 1。其中LSPCLK是低速外设时钟。 - 配置FIFO与中断(如果使用):
- 写
SCIFFTX:先写TXFIFORESET=0,再写TXFIFORESET=1来复位发送FIFO。设置TXFFIL(如4),使能TXFFIENA和SCIFFENA。 - 写
SCIFFRX:同样复位接收FIFO(RXFIFORESET)。设置RXFFIL(如8),使能RXFFIENA。 - 写
SCIFFCT:根据需求设置FFTXDLY(通常为0)。
- 写
- 使能中断:如果需要,在PIE(外设中断扩展)模块中使能对应的SCI中断向量,并配置好中断服务程序。
- 启动通信:将
SCICTL2中的TXINTENA或RXINTENA等位使能,模块即开始工作。
4.2 I2C主机模式通信流程
以下是一个I2C作为主机,向从机设备(地址0x50)写入3个字节数据的标准流程:
- 引脚与时钟初始化:
- 配置SDA和SCL对应的GPIO为I2C功能,通常为开漏模式,需要外部上拉电阻。
- 确保
I2CMDR.IRS = 0(模块复位)。配置I2CPSC得到7-12MHz的模块时钟。 - 配置
I2CCLKL和I2CCLKH,得到目标总线时钟(如100kHz)。
- 配置自身地址与模式:写入
I2COAR(自身地址,主机模式下可任意设置,但需避开冲突)。写入I2CMDR,配置为主机模式、非重复模式等。 - 配置从机地址与数据计数:将目标从机地址0x50写入
I2CSAR。将待发送字节数3写入I2CCNT。 - 启动传输:
- 检查
I2CSTR.BB,确保总线空闲。 - 将第一个待发送数据写入
I2CDXR。 - 配置
I2CMDR寄存器(包含MST=1,STT=1,TRX=1(发送),RM=0等),并写入。此操作会启动START条件并发送从机地址(写模式)。
- 检查
- 等待与发送后续数据:
- 等待
I2CSTR.XRDY置1(或FIFO中断),表示I2CDXR已空,可以写入下一个数据。 - 写入第二个数据到
I2CDXR。 - 再次等待
XRDY,写入第三个数据。
- 等待
- 结束传输:
- 等待最后一个数据的
XRDY标志。 - 此时,因为
I2CCNT已递减到0,模块会自动在最后一个字节后发送NACK?注意:对于主机写入,最后一个字节后应由主机发送ACK,然后主机产生STOP。实际上,在非重复模式下,当I2CCNT减为0时,模块会自动在最后一个字节后产生STOP条件(前提是I2CMDR.STP位在传输开始前已置1,或者通过检查ARDY后在传输结束时软件置位STP)。更稳妥的做法是,在发送完最后一个数据后,等待I2CSTR.ARDY置1,然后软件置位I2CMDR.STP来产生STOP条件。
- 等待最后一个数据的
- 错误处理:在整个过程中,应持续监控
I2CSTR.NACK。如果置1,说明从机无应答,应立即置位STP终止传输,并进行错误重试或上报。
4.3 常见调试问题与解决方案实录
在实际开发中,通信失败是常态。下面记录几个最典型的故障场景和排查思路。
问题一:SCI发送少量数据正常,连续发送大量数据时丢失后半部分。
- 现象:发送一个短字符串没问题,发送一段长数据,后面的字符就没了。
- 排查:
- 首先检查
TXRDY标志或FIFO中断的处理。是不是在查询方式下,没有等待TXRDY就写入了下一个数据?这会导致数据被覆盖。 - 如果使用了FIFO,检查
TXFFIL中断水位线是否设置过高?例如设为15,那么要等到FIFO几乎全空才触发中断,中断服务程序需要一次性补充16个数据。如果你的中断服务程序写得慢,或者被更高优先级中断打断,就可能出现FIFO和发送移位寄存器都空了,但新数据还没填进去,造成总线空闲,表现为数据发送��断。 - 检查
SCIFFCT中的FFTXDLY。如果设置过大,帧与帧之间的空闲时间过长,在高速发送时可能造成整体吞吐量下降,但通常不会丢数据。
- 首先检查
- 解决:
- 确保遵循“先查标志,再写数据”的原则。
- 优化FIFO中断水位线。对于连续发送,将
TXFFIL设为一个中等值(如4),并确保中断服务程序能高效地将数据从应用缓冲区搬入FIFO。 - 在中断服务程序中,根据
TXFFST的值一次性写入多个数据,填满或接近填满FIFO。
问题二:I2C通信完全无响应,SCL线被持续拉低。
- 现象:逻辑分析仪或示波器显示,START条件后,SCL线被拉低且不再释放,通信卡死。
- 排查:
- 检查从机设备:这是最常见的原因。确认从机设备地址是否正确,电源是否正常,是否处于复位或休眠状态。
- 检查
I2CSTR寄存器:读取I2CSTR的值。如果RSFULL=1,表明模块(作为从机时)接收寄存器已满,正在通过时钟延展(拉低SCL)等待主机读取数据。如果XSMT=0,表明模块(作为从机时)发送寄存器空,无数据可发,也在拉低SCL等待。 - 检查多主竞争:如果
ARBL=1,说明发生了仲裁丢失,本机已转为从机。需要检查总线上是否有其他主机设备。 - 检查硬件:测量SDA和SCL线的电压,确认上拉电阻已正确连接,电压电平符合要求。检查线路是否有短路或对地短路。
- 解决:
- 如果是
RSFULL或XSMT问题,检查你的从机程序是否正确、及时地读取了I2CDRR或写入了I2CDXR。 - 确保主机在通信结束时正确发送了STOP条件。
- 在程序中加入超时机制。如果检测到SCL被拉低超过一定时间(如10ms),强制执行一个软件复位(
IRS=0再IRS=1)来释放总线,并重新初始化I2C模块。
- 如果是
问题三:SCI或I2C在仿真器单步调试时工作正常,全速运行则出错。
- 现象:这是嵌入式调试中的经典问题。
- 排查与解决:
- 时序竞争:单步执行极大地降低了代码速度,掩盖了某些时序问题。例如,全速运行时,CPU写入配置寄存器的速度远快于外设响应速度。确保在关键操作后插入必要的延迟或状态检查。例如,在使能I2C模块(
IRS=1)后,等待几个时钟周期再进行后续操作。 - 中断冲突:全速运行时中断频繁发生,可能引发重入、优先级倒置等问题。检查中断服务程序是否保护了共享变量,中断处理是否过于耗时。
- FIFO配置:检查FIFO中断的水位线设置。单步时,你有充足的时间响应中断;全速时,如果中断服务程序处理不够快,可能导致FIFO溢出或下溢。尝试调整水位线,或优化中断服务程序代码。
- SCIPRI寄存器:确认
SCIPRI.FREESOFT位是否设置为01(完成当前字节后停止)。如果设置为00,全速运行遇到断点,会立刻中止传输,产生不完整的帧,可能干扰总线。
- 时序竞争:单步执行极大地降低了代码速度,掩盖了某些时序问题。例如,全速运行时,CPU写入配置寄存器的速度远快于外设响应速度。确保在关键操作后插入必要的延迟或状态检查。例如,在使能I2C模块(
问题四:I2C通信速率达不到理论值(如400kbps)。
- 现象:配置为快速模式,但实际测量SCL频率远低于400kHz。
- 排查:
- 计算错误:重新核算
I2CPSC、I2CCLKL、I2CCLKH的值。确保模块时钟在7-12MHz范围内。 - 软件开销:在查询方式下,检查
XRDY/RRDY标志和读写数据寄存器的代码是否在循环中,这本身会消耗CPU时间。对于高速I2C,必须使用FIFO和中断驱动,才能接近理论速率。 - 总线负载:总线上挂载的设备过多,或者总线电容过大(线太长、分支太多),会导致上升沿变缓,SCL频率被硬件限制。I2C规范对总线电容有要求(通常<400pF)。可以通过减小上拉电阻阻值来加快上升时间,但会增加功耗。
- 从机速度:确认所有从机设备都支持快速模式。只要有一个只支持标准模式的设备挂在总线上,整个总线就必须以降速模式运行。
- 计算错误:重新核算
通过以上对TMS320F2802x的SCI和I2C模块寄存器从原理到配置、从流程到调试的层层剖析,我们可以看到,稳定的通信驱动建立在对其内部状态机、缓冲机制和异常处理机制的深刻理解之上。寄存器配置不是简单的填数字,而是根据应用场景(速率、数据量、实时性)进行精心权衡的结果。调试时,善用SCIRXEMU这样的仿真工具,以及I2CSTR这样的状态寄存器,能够快速定位问题根源。记住,通信调试,三分靠配置,七分靠分析和验证。