1. 项目概述与I2C核心价值
在嵌入式开发领域,芯片间的通信是构建复杂系统的基石。当你需要让主控MCU读取一个温湿度传感器的数据,或者向一块EEPROM芯片写入配置参数时,你大概率会接触到I2C总线。这条看似简单的双线制总线,其背后是一套精巧的协议和一套需要精准配置的硬件控制器。很多开发者初期接触I2C时,往往依赖于现成的库函数,这确实能快速上手,但一旦遇到通信不稳定、时序异常或者需要实现一些高级功能(如DMA传输)时,就会感到束手无策。问题的根源,通常在于对I2C控制器内部寄存器的工作机制理解不够深入。
我经历过不少因为寄存器配置不当导致的“灵异”问题,比如从机无应答、数据错位,甚至是总线锁死。这些问题的排查,最终都指向了对MSS_I2C这类控制器寄存器的每一个比特位的深刻理解。本次分享,我将以德州仪器(TI)平台常见的MSS_I2C模块为例,抛开库函数的“黑箱”,直击其寄存器配置的核心。我们将从最基础的地址设置讲起,逐步深入到中断管理、时钟配置,最终攻克DMA控制的难点。无论你是正在调试一块新的I2C传感器,还是希望优化现有通信代码的效率,这篇对ICOAR、ICMDR、ICSTR、ICIVR、ICDMAC等关键寄存器的逐位解析,都将为你提供一份清晰的“地图”和实用的“工具包”。
2. MSS_I2C寄存器全景与访问基础
在深入每个功能寄存器之前,我们必须先建立起对MSS_I2C寄存器组的整体认知和正确的访问方式。这就像在操作一台精密仪器前,必须先看懂它的控制面板布局和操作须知。
2.1 寄存器内存映射与寻址
MSS_I2C的所有控制与状态寄存器都通过内存映射(Memory-Mapped)的方式挂载在系统的地址空间上。这意味着,我们可以像读写普通内存变量一样,通过指针直接操作这些寄存器,从而控制I2C硬件的每一个行为。TI的文档中提供了一个寄存器偏移地址表,它定义了每个寄存器相对于MSS_I2C模块基地址的偏移量。
例如,ICOAR(自身地址寄存器)的偏移地址是0x00,ICMDR(模式寄存器)的偏移地址是0x24。在实际编程中,我们首先需要获取MSS_I2C模块的基地址(这通常由芯片的数据手册或头文件定义),然后加上偏移量,就得到了该寄存器的绝对内存地址。
一个关键的安全准则是:只操作文档中列出的寄存器,对于标记为“Reserved”(保留)或未在列表中出现的偏移地址,绝对不要进行写操作,甚至要谨慎读取。这些保留位可能用于芯片测试或未来功能扩展,随意写入可能导致模块行为不可预测,甚至硬件故障。
2.2 寄存器位域访问与数据类型
MSS_I2C的寄存器通常是32位宽,但并非所有位都有效。很多寄存器的高16位是保留的,读取始终为0,写入无效。因此,在定义寄存器结构体或进行位操作时,我们需要使用精确的位宽数据类型,如uint32_t,并确保操作集中在有效的低16位或低8位。
寄存器的每个有效位域都有其特定的访问类型(Access Type):
- R/W (Read/Write):最常见的类型,软件可读取当前状态,也可写入配置值。
- R (Read-Only):只读,通常用于反映硬件状态,如中断标志位。尝试写入无效。
- W (Write-Only):较少见,通常用于触发某个动作(如写入特定值以清除标志)。
理解访问类型至关重要。例如,ICSTR(状态寄存器)中的中断标志位(如AL,NACK,ARDY等)虽然是R/W类型,但写入1是为了清除该标志,而不是设置它。这是一种常见的“写1清零”(Write-1-to-Clear)机制,如果错误地写入0,将无法清除中断,导致程序误判。
2.3 基础编程模型与初始化流程
在配置任何功能寄存器之前,有一个黄金步骤:确保I2C模块处于复位状态。这是通过ICMDR寄存器中的IRS(I2C Reset Not)位控制的。IRS = 0表示模块复位,IRS = 1表示模块使能。几乎所有的配置寄存器(如时钟分频器ICCLKL/H、预分频器ICPSC)都要求在IRS=0时进行配置,配置完成后,再将IRS置1来启动模块。如果在模块活动时修改这些配置,很可能导致通信时序混乱。
一个稳健的初始化流程通常如下:
- 将
IRS位清零,使模块复位。 - 配置引脚功能(
ICPFUNC),决定使用I2C功能还是GPIO功能。 - 配置时钟(
ICPSC,ICCLKL,ICCLKH),根据系统主频和目标I2C速率计算分频值。 - 配置自身地址(
ICOAR)和模式寄存器(ICMDR)的基本位(如XA决定7/10位地址模式)。 - 根据需要配置中断掩码(
ICIMR)和DMA控制(ICDMAC)。 - 将
IRS位置1,释放复位,模块进入待命状态。
3. 核心功能寄存器深度解析
掌握了基础访问规则后,我们就可以深入MSS_I2C的几个核心功能寄存器了。它们是驱动I2C通信的“大脑”和“感官”。
3.1 ICOAR与ICSAR:身份标识与寻址握手
I2C通信始于寻址。ICOAR(I2C Own Address Register)定义了本设备作为从机时的地址。当总线上有其他主设备发送的地址帧与ICOAR中设置的地址匹配时,本设备的MSS_I2C模块会应答,并进入从机通信模式。
- 位域
A9_A0(Bits 9-0):这是地址值存储的位置。无论是7位地址模式(ICMDR.XA=0)还是10位地址模式(ICMDR.XA=1),都使用这个字段。在7位模式下,通常使用A6_A0(低7位);在10位模式下,使用全部10位。需要注意的是,I2C协议规定的地址是7位或10位,但传输时会在地址字节后跟一个读/写方向位。ICOAR寄存器存储的是纯地址,不包含方向位。 - 配置要点:必须确保系统中每个I2C从设备的地址唯一。某些地址(如广播地址
0x00)是保留的。ICOAR可以在任何时候修改,但修改后,新的地址将在下一次总线寻址周期生效。
ICSAR(I2C Slave Address Register)则是当本设备作为主设备时,用于指定目标从设备的地址。在发起一次主设备传输前,必须将要通信的从机地址写入ICSAR。
- 主从角色下的使用:
ICOAR和ICSAR清晰地划分了角色。ICOAR是“我是谁”(从机身份),ICSAR是“我要找谁”(主机目标)。在复杂的多主系统中,一个设备可能同时需要配置这两个寄存器。
3.2 ICMDR:模式控制中枢
ICMDR(I2C Mode Register)是MSS_I2C最核心的控制寄存器,它像一个总指挥,决定了每一次通信的“剧本”。
IRS(Bit 5) - I2C复位:如前所述,这是总开关。0复位,1使能。在修改关键配置前务必先复位。MST(Bit 10) 与TRX(Bit 9) - 主从与收发模式:MST=1, TRX=1:主发送模式。主机控制时钟,并向从机发送数据。MST=1, TRX=0:主接收模式。主机控制时钟,并从从机读取数据。MST=0:从机模式。此时TRX位由硬件根据接收到的地址帧后的读/写位自动设置,指示从机是发送器还是接收器。
STT(Bit 13) 与STP(Bit 11) - 启动与停止条件:STT(Start):软件写入1,硬件会在总线上产生一个起始(S)条件,并自动清零该位。仅在主机模式(MST=1)下有效。STP(Stop):软件写入1,指示主机在本次传输(由ICCNT计数)结束后产生停止(P)条件。当内部数据计数器ICCNT递减到0时,硬件会自动产生停止条件并清零STP位。- 经典操作序列:主机发送数据流程通常是:写目标地址到
ICSAR-> 配置ICMDR(MST=1, TRX=1)-> 写数据到ICDXR-> 置位STT启动传输 -> 等待传输完成(通过中断或轮询ARDY)-> 如果需要停止,则置位STP。
RM(Bit 7) - 重复模式:此模式非常有用。当RM=1时,ICCNT寄存器被忽略,数据会从ICDXR连续不断地发送出去,直到软件显式地设置STP位来产生停止条件。这适用于需要流式传输大量数据的场景,无需频繁更新数据计数。FDF(Bit 3) 与BC[2:0](Bits 2-0) - 自由数据格式与位计数:FDF=1使能自由数据格式。在此模式下,传输的每个数据字节的长度可以是2到8位(由BC[2:0]指定),而不是固定的8位。这对于连接某些非标准字节长度的旧式设备非常有用。BC[2:0]定义了在自由数据格式下,每个字节的有效数据位数(不包括ACK位)。例如,BC=011表示每个字节传输3位数据+1位ACK,共4个时钟周期。
NACKMOD(Bit 15) - NACK模式:此位仅在接收模式下有意义。通常,接收方在每个字节后发送ACK。如果NACKMOD=1,则接收方会在下一个ACK周期发送NACK信号。这在主机接收模式下用于通知从机发送结束,是主机读取多个字节后终止传输的标准方式。
3.3 ICSTR与ICIVR:状态监控与中断处理
可靠通信离不开对总线状态的实时感知。ICSTR(I2C Interrupt Status Register)提供了丰富的状态标志,而ICIVR(I2C Interrupt Vector Register)则是对中断进行高效管理的枢纽。
ICSTR关键状态位解析:
BB(Bit 12) - 总线忙:这是最重要的状态位之一。BB=1表示I2C总线正被占用(SCL或SDA为低);BB=0表示总线空闲。在主机发起传输前,必须检查BB是否为0,否则可能破坏总线上的现有通信,导致仲裁丢失。AL(Bit 0) - 仲裁丢失:在多主系统中,当两个主机同时发起传输时,硬件会进行仲裁。失败的一方会检测到AL=1,并自动切换为从机模式。软件必须检测并处理此标志,通常意味着本次传输需要重试。NACK(Bit 1) - 无应答:当主机发送地址或数据后,未收到从机的ACK应答时,此位置1。常见原因包括从机地址错误、从机设备忙或不存在。ARDY(Bit 2) - 寄存器访问就绪:这是一个非常实用的标志。当ARDY=1时,表示I2C模块已经准备好接收下一个命令或数据(例如,上一个数据已从ICDXR移入移位寄存器,可以写入新数据了)。在轮询方式编程中,经常等待此位。ICRRDY(Bit 3) 与ICXRDY(Bit 4):分别为接收数据就绪和发送数据就绪。当有数据到达ICDRR时,ICRRDY置1;当ICDXR为空可以写入新数据时,ICXRDY置1。它们是DMA和中断触发的直接源。AAS(Bit 9) - 地址匹配(作为从机):当总线上地址与ICOAR匹配时,此位置1。用于从机判断自己是否被寻址。
ICIVR中断向量管理:
ICIVR的妙处在于它将多个中断源合并为一个中断向量,并通过优先级编码给出具体的中断原因。其低3位INTCODE是一个二进制编码:
001:仲裁丢失(最高优先级)010:无应答011:寄存器访问就绪(ARDY)100:接收数据就绪(ICRRDY)101:发送数据就绪(ICXRDY)110:停止条件检测111:地址匹配(作为从机,最低优先级)
中断处理流程:
- I2C中断触发CPU。
- 在中断服务程序(ISR)中,读取
ICIVR寄存器的值。这个读取操作本身会清除INTCODE(对于ARDY,ICRRDY,ICXRDY,需要清除ICSTR中对应的状态位)以及ICSTR中对应的中断标志位(AL,NACK,SCD,AAS)。 - 根据读取到的
INTCODE值,跳转到相应的处理分支。 - 处理完毕后,如果需要清除
ARDY、ICRRDY或ICXRDY中断,需要手动清除ICSTR中的对应位(写1清零)。
注意:务必在发起新的传输(设置
STT)之前,通过读取ICIVR来清除旧的中断标志。否则,残留的中断标志可能导致ICIVR读出错误的中断代码,干扰程序逻辑。
4. 时钟配置与通信速率计算
I2C通信的稳定性很大程度上取决于精确的时钟时序。MSS_I2C通过三个寄存器协同工作来产生标准的I2C时钟(SCL):ICPSC(预分频器)、ICCLKL(时钟低电平分频)和ICCLKH(时钟高电平分频)。
4.1 时钟生成原理
I2C模块的时钟源是系统的核心时钟(例如CPU主频CLK)。时钟生成分为两步:
- 预分频:
ICPSC寄存器将CLK进行第一次分频,产生一个中间时钟I2C_CLK。其公式通常为:I2C_CLK = CLK / (IPSC + 1),其中IPSC是写入ICPSC寄存器的值。此步骤的目的是将高速的系统时钟降到适合I2C模块工作的频率范围(例如几MHz到十几MHz)。 - 高低电平分频:
ICCLKL和ICCLKH寄存器分别对I2C_CLK进行分频,以产生SCL信号的低电平时间(tLOW)和高电平时间(tHIGH)。最终的SCL频率由两者共同决定。
4.2 寄存器配置与计算实例
假设我们的系统时钟CLK = 100 MHz,目标I2C标准模式速率为100 kHz。
步骤一:配置预分频器ICPSC目标是让I2C_CLK在4-12 MHz的推荐范围内。我们选择一个中间值,例如目标I2C_CLK = 10 MHz。 计算:IPSC = CLK / I2C_CLK - 1 = 100 MHz / 10 MHz - 1 = 9。 因此,向ICPSC寄存器写入9。
步骤二:配置高低电平分频器ICCLKL和ICCLKH在标准I2C模式下,一个完整的SCL周期(tSCL)等于高电平时间加低电平时间,即tSCL = tHIGH + tLOW。通常为了产生占空比接近50%的方波,会设置ICCLKH和ICCLKL为相同的值。 已知目标SCL频率fSCL = 100 kHz,则周期tSCL = 1 / 100 kHz = 10 µs。I2C_CLK的周期tI2C_CLK = 1 / 10 MHz = 0.1 µs。 那么,每个高电平或低电平周期所需的I2C_CLK周期数N = tSCL / 2 / tI2C_CLK = (10 µs / 2) / 0.1 µs = 50。 因此,向ICCLKH和ICCLKL寄存器都写入50。
最终验证: SCL高电平时间tHIGH = (ICCLKH + 1) * tI2C_CLK = 51 * 0.1 µs = 5.1 µs。 SCL低电平时间tLOW = (ICCLKL + 1) * tI2C_CLK = 51 * 0.1 µs = 5.1 µs。 SCL周期tSCL ≈ 10.2 µs,对应频率约98 kHz,基本符合100kHz的目标。细微误差在I2C协议容限之内。
关键限制:
ICPSC、ICCLKL、ICCLKH这三个寄存器的配置必须在I2C模块复位期间(ICMDR.IRS = 0)完成。一旦IRS置1使能模块,再修改这些寄存器可能不会立即生效或导致通信错误。
5. 高级功能:DMA控制与GPIO复用
对于需要高效传输大量数据的应用,以及灵活管理I2C引脚的需求,MSS_I2C提供了DMA控制和引脚复用的高级寄存器。
5.1 ICDMAC:解放CPU的DMA传输
直接内存访问(DMA)可以允许数据在I2C缓冲器和系统内存之间自动搬运,无需CPU频繁介入处理每个字节的中断,极大提升了传输效率,并降低了CPU负载。
RXDMAEN(Bit 0) - 接收DMA使能:当此位置1时,一旦接收数据寄存器ICDRR中有新数据(ICSTR.ICRRDY置位),I2C模块就会向系统DMA控制器发出一个接收事件请求。DMA控制器随后会自动从ICDRR寄存器读取数据,并存储到预先配置好的内存缓冲区中。TXDMAEN(Bit 1) - 发送DMA使能:当此位置1时,一旦发送数据寄存器ICDXR为空(ICSTR.ICXRDY置位),I2C模块就会向系统DMA控制器发出一个发送事件请求。DMA控制器随后会自动从内存缓冲区中取出下一个数据,写入ICDXR寄存器。
DMA配置流程与注意事项:
- 系统DMA控制器配置:首先需要配置系统级的DMA通道,设置源/目标地址(内存地址或
ICDRR/ICDXR的寄存器地址)、传输数据量、地址递增模式等。这通常涉及另一组DMA相关的寄存器。 - 使能I2C DMA:在I2C初始化后期,在
IRS=1使能模块之前或之后,将ICDMAC中的RXDMAEN和/或TXDMAEN位置1。 - 启动传输:像普通模式一样,配置地址、模式,并置位
STT启动传输。随后,数据的搬移将由DMA控制器和I2C模块的硬件事件自动协同完成。 - 传输完成判断:DMA传输完成后,DMA控制器通常会产生一个完成中断。同时,I2C模块本身的
ARDY中断(当ICCNT递减到0且STP条件满足时)或SCD(停止条件检测)中断也会产生,用于通知CPU本次I2C传输事务结束。
避坑指南:DMA传输的缓冲区必须确保在物理内存中是连续且对齐的(具体对齐要求取决于芯片架构)。此外,要小心处理DMA传输完成中断和I2C传输完成中断的时序关系,避免在DMA还未搬完所有数据时,CPU就误判传输结束并修改了缓冲区。
5.2 引脚控制寄存器组:ICPFUNC, ICPDIR, ICPDIN/OUT
MSS_I2C的SCL和SDA引脚通常与通用输入/输出(GPIO)功能复用。这组寄存器提供了在软件层面切换和操控这些引脚的能力。
ICPFUNC(Pin Function Register):PFUNC0位控制SCL/SDA引脚的功能。PFUNC0=0,引脚作为I2C的SCL和SDA使用;PFUNC0=1,引脚作为普通GPIO使用。- 重要警告:在切换功能(
PFUNC0)时,必须确保I2C模块处于复位状态(IRS=0)。如果模块正在通信,切换引脚功能会导致总线冲突或信号紊乱。
ICPDIR(Pin Direction Register):- 当引脚配置为GPIO模式(
PFUNC0=1)时,PDIR0和PDIR1分别控制SCL和SDA引脚的方向。0为输入,1为输出。 - 在I2C模式(
PFUNC0=0)下,方向由硬件自动管理,此寄存器无效。
- 当引脚配置为GPIO模式(
ICPDIN(Pin Data In Register) 与ICPDOUT/ICPDSET/ICPDCLR:ICPDIN是只读寄存器,反映SCL和SDA引脚当前的实际电平,无论引脚处于I2C模式还是GPIO模式。这在调试总线冲突、检测总线状态时非常有用。ICPDOUT用于在GPIO输出模式下设置引脚输出值。ICPDSET和ICPDCLR则提供了更方便的位设置/清除操作。
一个实用的调试技巧:当I2C通信失败,怀疑总线被意外拉低时,可以先将模块复位(IRS=0),然后通过读取ICPDIN寄存器来检查SCL和SDA引脚的实际电平。如果应为高电平的引脚读出来是0,则很可能存在硬件短路或外部设备故障。
6. 实战配置流程与常见问题排查
理解了各个寄存器后,我们将它们串联起来,形成一个完整的、稳健的I2C主设备发送流程。同时,汇总那些最容易“踩坑”的地方。
6.1 完整的主设备发送配置示例
以下是一个配置MSS_I2C为主设备,向地址为0x50的从设备发送N字节数据的C语言伪代码流程,采用轮询ARDY标志的方式:
// 假设寄存器基地址已定义为 MSS_I2C_BASE #define ICOAR (*(volatile uint32_t *)(MSS_I2C_BASE + 0x00)) #define ICIMR (*(volatile uint32_t *)(MSS_I2C_BASE + 0x04)) #define ICSTR (*(volatile uint32_t *)(MSS_I2C_BASE + 0x08)) #define ICCLKL (*(volatile uint32_t *)(MSS_I2C_BASE + 0x0C)) #define ICCLKH (*(volatile uint32_t *)(MSS_I2C_BASE + 0x10)) #define ICCNT (*(volatile uint32_t *)(MSS_I2C_BASE + 0x14)) #define ICDRR (*(volatile uint32_t *)(MSS_I2C_BASE + 0x18)) #define ICSAR (*(volatile uint32_t *)(MSS_I2C_BASE + 0x1C)) #define ICDXR (*(volatile uint32_t *)(MSS_I2C_BASE + 0x20)) #define ICMDR (*(volatile uint32_t *)(MSS_I2C_BASE + 0x24)) #define ICIVR (*(volatile uint32_t *)(MSS_I2C_BASE + 0x28)) void MSS_I2C_Master_Transmit(uint8_t slaveAddr, uint8_t *data, uint32_t size) { // 1. 确保模块复位 ICMDR &= ~(1 << 5); // IRS = 0 // 2. 配置时钟 (必须在复位状态下进行) // 假设已根据系统时钟计算好分频值 ICPSC = 9; // 预分频值 ICCLKL = 50; // SCL低电平分频 ICCLKH = 50; // SCL高电平分频 // 3. 配置自身地址(如果作为从机需要)和模式寄存器基础位 ICOAR = 0x55; // 示例自身地址 ICMDR = 0; // 先清零 ICMDR |= (0 << 8); // XA=0, 7位地址模式 // 其他位如FDF, RM等根据需求设置 // 4. 配置目标从机地址和数据计数 ICSAR = slaveAddr; // 7位地址直接写入 ICCNT = size; // 要发送的字节数 // 5. 使能模块 ICMDR |= (1 << 5); // IRS = 1 // 6. 配置为主发送模式,并准备启动 ICMDR |= (1 << 10) | (1 << 9); // MST=1, TRX=1 (主发送) // 注意:此时STT和STP还是0 // 7. 写入第一个数据到发送寄存器 ICDXR = data[0]; // 8. 产生起始条件,开始传输 ICMDR |= (1 << 13); // STT = 1 (硬件会自动清零) // 9. 轮询发送剩余数据 for(uint32_t i = 1; i < size; i++) { // 等待寄存器访问就绪(前一个数据已从DXR移走) while((ICSTR & (1 << 2)) == 0); // 等待ARDY置位 // 清除ARDY标志(写1清零) ICSTR |= (1 << 2); // 写入下一个数据 ICDXR = data[i]; } // 10. 等待最后一个字节发送完成 while((ICSTR & (1 << 2)) == 0); // 等待ARDY ICSTR |= (1 << 2); // 清除ARDY // 11. 发送停止条件 // 由于ICCNT在发送最后一个字节后减为0,硬件会自动产生STP(如果STP位已设置) // 或者,我们可以手动设置STP位来确保停止条件产生 ICMDR |= (1 << 11); // STP = 1 // 等待停止条件产生(可选,通过SCD标志判断) while((ICSTR & (1 << 5)) == 0); // 等待SCD置位 ICSTR |= (1 << 5); // 清除SCD标志 }6.2 典型问题排查速查表
| 问题现象 | 可能原因 | 排查步骤与解决方法 |
|---|---|---|
| 总线死锁,SCL/SDA一直为低 | 1. 软件序列错误,未发送停止条件。 2. 从设备故障,拉低总线。 3. 仲裁丢失( AL)后未正确处理。 | 1. 检查代码是否在所有路径都正确设置了STP位或等待了停止条件完成。2. 复位I2C模块( IRS=0),读取ICPDIN检查引脚电平。若仍为低,可能是硬件问题。3. 在中断或轮询中检查 ICSTR.AL位,若置位,需执行错误恢复流程(复位模块,重新初始化)。 |
| 从机无应答(NACK) | 1. 从机地址(ICSAR)配置错误。2. 从机设备未上电或损坏。 3. 总线电平或上拉电阻问题。 4. 时钟速率过快,从机跟不上。 | 1. 核对从机设备数据手册的7位/10位地址。 2. 检查从机电源、复位信号。 3. 用示波器或逻辑分析仪观察总线波形,检查SCL/SDA上升时间是否过慢(上拉电阻过大)。 4. 降低 ICCLKL/H配置,减小SCL频率。 |
| 数据错位或丢失 | 1. 发送(ICXRDY)/接收(ICRRDY)就绪标志判断逻辑错误。2. 中断处理中未及时读取 ICIVR或清除状态位。3. DMA缓冲区溢出或下溢。 | 1. 确保在ICXRDY=1后才写入ICDXR,在ICRRDY=1后才读取ICDRR。2. 在中断服务程序中,第一件事就是读取 ICIVR值并保存,再根据其进行分支处理。3. 检查DMA配置的传输数据量是否与 ICCNT匹配,缓冲区大小是否足够。 |
| 只能发送第一个字节 | ARDY标志处理不当。在写入第一个数据并启动(STT)后,需要等待ARDY置位才能写入第二个数据。ARDY在每次ICDXR数据被移入移位寄存器后置位。 | 在发送循环中,在写入ICDXR之前,必须等待ICSTR.ARDY为1,并在写入后将其清除(写1)。 |
| 无法进入中断服务程序 | 1. 中断总使能未打开(芯片级)。 2. ICIMR中对应中断掩码位未使能(例如ICIMR.ARDY=1)。3. 中断向量表配置错误。 | 1. 确认全局中断已开启。 2. 检查 ICIMR寄存器,确保需要的中断(如ARDY,ICRRDY)的掩码位已置1。3. 核对芯片手册,确认I2C中断号,并正确配置中断控制器和向量表。 |
| 时钟频率不准 | ICPSC,ICCLKL,ICCLKH计算错误,或未在复位(IRS=0)状态下配置。 | 1. 严格按照公式计算分频值,考虑+1的偏移。2.确保在 IRS=0时配置这三个时钟寄存器,配置完成后再将IRS置1。3. 用示波器测量实际SCL频率进行校准。 |
调试I2C最有力的工具是逻辑分析仪或带有I2C解码功能的示波器。它们可以直观地展示总线上的起始、地址、数据、应答和停止信号,让你清晰地看到是哪个环节的波形不符合预期,从而快速定位是软件配置问题还是硬件连接问题。