I2C控制器FIFO与DMA机制:提升嵌入式通信性能的关键

📅 2026/7/19 7:05:15
I2C控制器FIFO与DMA机制:提升嵌入式通信性能的关键
1. 项目概述I2C控制器FIFO与DMA机制深度解析在嵌入式系统开发中I2C总线是我们连接各类传感器、EEPROM、RTC等低速外设的“老熟人”。它的两根线SCL和SDA结构简单协议清晰是板上设备间通信的基石。然而当你的应用从简单的配置读写升级到需要连续、高速地搬运大量数据时——比如从图像传感器读取一帧数据或者向音频编解码器发送连续的音频流——传统的字节级中断处理方式就会立刻成为系统性能的瓶颈。CPU频繁地被每个字节的收发中断所打断大部分时间都花在了上下文切换上有效的数据吞吐率却上不去。这时I2C控制器内部集成的FIFO先进先出缓冲区和DMA直接内存访问功能就成了提升性能的关键武器。它们的设计初衷就是要把CPU从繁琐的、周期性的数据搬运工作中解放出来。FIFO充当了一个数据“蓄水池”可以暂存多个字节而DMA则是一个“自动搬运工”当“蓄水池”的水位达到我们设定的警戒线时它就自动启动将一批数据整块地搬移到内存中整个过程无需CPU干预。本文将以德州仪器TI高速I2C控制器的技术手册为蓝本结合我多年在嵌入式通信驱动开发中的实际踩坑经验为你深入拆解I2C控制器中FIFO的三种操作模式中断、轮询、DMA并重点剖析DMA请求机制的生成、释放逻辑以及那个容易让人忽略但至关重要的“排空”Draining特性。无论你是正在调试I2C驱动性能的工程师还是希望深入理解外设控制器内部机制的学习者相信这篇结合了原理、配置和实战陷阱的解析都能给你带来直接的帮助。2. 核心机制FIFO与DMA如何协同工作要理解FIFO和DMA我们得先抛开它们看看最基础的I2C数据流。在没有FIFO的简单控制器中每收发一个字节控制器就会产生一个中断XRDY或RRDYCPU必须立刻响应读写数据寄存器I2Ci.I2C_DATA然后清除中断标志。这种“来一个字节处理一个字节”的模式在低速场景下没问题但在高速或大数据量传输时中断开销巨大。FIFO的引入本质上是在数据寄存器移位寄存器和系统总线之间插入了一个缓冲区。以接收为例从SDA线移入的字节会先存入RX FIFO而不是直接触发CPU中断。这样CPU或DMA可以一次处理多个字节显著降低了事务处理的频率。2.1 FIFO的三种操作模式TI的这款高速I2C控制器为FIFO提供了三种可配置的操作模式分别适用于不同的应用场景和系统资源状况。2.1.1 中断模式Interrupt Mode这是最灵活的模式通过使能相应的中断使能位I2Ci.I2C_IE[4] XRDY_IE和I2Ci.I2C_IE[3] RRDY_IE来工作。它本身又提供了两种子策略单字节服务当FIFO非空接收或非满发送时产生中断。CPU在中断服务程序ISR中读写一个字节然后清除中断标志。控制器会持续断言中断直到FIFO状态改变例如读空RX FIFO或写满TX FIFO。这种方式给了CPU最大的控制粒度但效率较低通常只在FIFO深度很浅或数据极不规律时使用。阈值触发服务这是更高效的方式。我们通过I2Ci.I2C_BUF[5:0] XTRSH发送阈值和I2Ci.I2C_BUF[13:8] RTRSH接收阈值寄存器来设定一个触发水位。注意写入寄存器的值是阈值 - 1。发送TX当TX FIFO中的数据量小于或等于阈值时XRDY状态位置位触发中断。此时CPU应当在ISR中一次性写入XTRSH 1个字节来填充FIFO。接收RX当RX FIFO中的数据量达到或超过RTRSH 1时RRDY状态位置位触发中断。CPU应当在ISR中一次性读取RTRSH 1个字节来清空部分FIFO。关键细节与避坑指南阈值计算寄存器里存的是阈值-1。如果你希望FIFO存够8个字节再通知你那么RTRSH应该设置为70x07。这是手册里明确写着RTRSH field value 1的原因但实际编程时很容易忘记这个1导致触发点错位。中断清除在阈值模式下当你按阈值数量完成读写操作后中断条件会自动解除XRDY/RRDY位会清零无需软件额外清除中断标志位。这与单字节模式不同。从机发送模式禁忌手册用加粗的“NOTE”警告在从机发送模式MST0, TRX1下绝对不能使用“排空”Draining特性。因为从机无法预知主机何时会停止读取通过发送NACK如果使用了排空且传输结束时FIFO中还有未发送的数据这些数据会残留。此时必须通过设置I2Ci.I2C_BUF[6] TXFIFO_CLR位来手动清空TX FIFO。2.1.2 轮询模式Polling Mode当系统中断资源紧张或者对实时性要求极高、不允许任何中断延迟时可以采用轮询模式。在此模式下需要禁用中断使能位XRDY_IE和RRDY_IE和DMA使能位XDMA_EN和RDMA_EN。开发者需要在一个循环中主动查询I2Ci.I2C_STAT[4] XRDY和I2Ci.I2C_STAT[3] RRDY状态位。这两个位的逻辑与中断模式下的触发条件完全一致。例如在接收时当RRDY位为1表示RX FIFO中的数据量已经达到了设定的阈值此时程序可以执行批量读取。轮询模式的优点是确定性高没有中断上下文切换的开销。缺点则是CPU被完全占用无法执行其他任务功耗也高。它通常用于在系统初始化阶段进行简单的寄存器配置或者在一些对功耗不敏感、功能单一的裸机程序中。2.1.3 DMA模式DMA Mode这是实现高性能、低CPU占用率数据传输的终极方案。在此模式下我们需要使能DMA通道I2Ci.I2C_BUF[7] XDMA_EN和I2Ci.I2C_BUF[15] RDMA_EN并正确配置好系统DMA控制器的源/目标地址、传输长度等。接收DMA请求I2Ci_DMA_RX其行为逻辑非常清晰。当RX FIFO中累积的数据字节数超过注意是超过不是等于设定的接收阈值RTRSH 1时控制器会立即拉低I2Ci_DMA_RX信号线向DMA控制器发出请求。DMA控制器响应请求开始从I2C数据寄存器实际上是FIFO的出口读取数据。一旦DMA读取的字节数达到阈值数量I2Ci_DMA_RX请求信号便会拉高取消断言直到FIFO中数据再次累积超过阈值。这个过程是硬件自动完成的形成了“填充-请求-搬运-等待”的循环。发送DMA请求I2Ci_DMA_TX其逻辑与接收略有不同。当TX FIFO完全为空时I2Ci_DMA_TX请求信号被拉低。DMA控制器响应请求向TX FIFO写入数据。一旦写入的字节数达到设定的发送阈值XTRSH 1请求信号拉高。如果DMA写入的字节数不足阈值请求信号将保持有效拉低直到写够数量为止。这确保了FIFO在发送开始前就有足够的数据避免总线出现空闲等待。为了直观对比三种模式的核心差异与适用场景我整理了以下表格特性/模式中断模式 (单字节)中断模式 (阈值触发)轮询模式DMA模式CPU占用高每个字节一次中断中每阈值个字节一次中断极高持续查询极低仅初始化和完成中断实时性好依赖中断响应好依赖中断响应最好无中断延迟中依赖DMA响应速度数据吞吐量低中高中受限于CPU轮询速度最高编程复杂度简单中等简单较高需配置DMA适用场景极低速、零星数据中速、块数据极低功耗或对中断延迟零容忍的简单应用高速、连续、大数据量传输如摄像头、音频关键配置位XRDY_IE,RRDY_IEXRDY_IE,RRDY_IE,XTRSH,RTRSH禁用XRDY_IE,RRDY_IE,XDMA_EN,RDMA_ENXDMA_EN,RDMA_EN,XTRSH,RTRSH2.2 DMA请求的波形与阈值选择手册中的图18-24和18-25/18-26非常形象地展示了DMA请求信号与FIFO数据量的关系。理解这些图对于调试DMA传输问题至关重要。对于接收图18-24想象一个水桶RX FIFO。水数据不断流入。我们设了一个水位警戒线阈值。当水位超过警戒线警报DMA请求响起抽水机DMA开始工作每次固定抽走相当于警戒线高度的水量阈值个字节。抽完后水位下降警报解除。直到水位再次超过警戒线循环继续。关键在于警报是在“超过”时触发而不是“达到”时触发。这确保了FIFO中始终有至少一个字节的余量防止DMA响应延迟导致FIFO溢出。对于发送图18-25/18-26想象一个需要持续供水的水池TX FIFO。当池子完全空的时候警报DMA请求响起供水管DMA开始注水直到注入阈值量的水警报解除。如果供水管一次注入的水量不够阈值警报会一直响直到注满为止。图18-25高阈值和图18-26低阈值的对比展示了阈值大小如何影响DMA请求的占空比。高阈值意味着每次DMA传输的数据块更大请求频率更低有利于提升DMA传输效率减少总线仲裁开销但要求源数据缓冲区准备得更充分。低阈值则让FIFO更快地得到补充减少了总线空闲的可能但增加了DMA请求的频率。实操心得阈值设定的艺术阈值的设定没有绝对的金科玉律需要根据具体场景权衡FIFO深度阈值必须小于FIFO总深度FIFODEPTH。通常设置为FIFO深度的1/2到3/4是个不错的起点为突发数据留出缓冲空间。DMA延迟考虑你的DMA控制器从请求发出到实际开始搬运数据的最大延迟。阈值设置要保证在延迟期间FIFO不会溢出接收或下溢发送。例如如果DMA延迟可能达到10个字节传输时间那么接收阈值最好比FIFO深度小10以上。总线效率与CPU中断如果你同时使能了DMA和阈值中断用于处理最后的“排空”阈值设得太小可能导致中断过于频繁。设得太大则可能影响实时性。SCCB模式强制要求手册特别强调在SCCB相机控制总线I2C的子集模式下RX和TX阈值必须设置为1即RTRSH和XTRSH字段写0。这是因为SCCB协议通常只进行单字节读写FIFO的缓冲意义不大强制为1可以简化操作逻辑。3. 核心难点传输长度非阈值整数倍与“排空”机制这是理解该I2C控制器高级特性的关键也是实际编程中最容易出错的地方。我们理想中的数据传输长度DATACOUNT正好是FIFO阈值THRESHOLD的整数倍。但现实中数据长度往往是随意的比如要传输130个字节而阈值设为8。130除以8余2。那么最后这2个字节如何处理如果没有特殊机制在DMA模式下控制器会在传输完128个字节16个DMA周期后因为剩下的2个字节不足以触发下一次DMA请求RX FIFO未超阈值或TX FIFO未空而导致数据传输“卡住”最后2个字节永远留在FIFO里。在中断模式下CPU也会因为等待永远不会达到的阈值条件而死等。为了解决这个问题TI控制器引入了“排空”Draining特性。它的核心思想是在传输的最后阶段当剩余数据量不足一个阈值时控制器通过一个特殊的中断来通知CPU或DMA控制器“快结束了剩下的数据不够一个整块了请按实际剩余数量来处理”。3.1 排空机制的工作原理排空功能默认是关闭的需要通过设置I2Ci.I2C_IE[14] XDR_IE发送排空中断使能或I2Ci.I2C_IE[13] RDR_IE接收排空中断使能来启用。它主要服务于传输长度不是阈值整数倍的情况。接收方向的排空RDR 假设接收阈值RTRSH1 8总接收数据DATACOUNT 130。前128个字节会通过8次DMA请求或中断正常处理。当总线传输结束第129和130个字节进入RX FIFO后由于数据量2小于阈值8不会触发常规的RRDY中断或DMA请求。此时如果使能了排空控制器会立即将状态寄存器中的I2Ci.I2C_STAT[13] RDR位置1并产生中断如果使能了RDR_IE。RDR中断是一个明确的信号“传输已结束但FIFO里还有‘零头’数据快来取走”。此时软件或DMA需要去查询I2Ci.I2C_BUFSTAT[13:8] RXSTAT字段这个字段实时指示了RX FIFO中当前有效数据的字节数。在我们的例子中RXSTAT的值就是2。软件应当执行2次读I2C_DATA寄存器的操作或者重新配置DMA通道的传输长度为2来“排空”FIFO中这最后的数据。发送方向的排空XDR 对于发送逻辑类似但方向相反。假设发送阈值XTRSH1 8总发送数据DATACOUNT 130。当DMA或CPU填满了前128个字节后还剩下2个字节需要发送。此时TX FIFO是空的因为最后一个整块数据已开始发送但剩余数据量2小于阈值8不足以触发一次新的XRDY中断或DMA请求来填充FIFO。这时如果使能了排空控制器会设置I2Ci.I2C_STAT[14] XDR位并产生中断。软件需要查询I2Ci.I2C_BUFSTAT[5:0] TXSTAT字段该字段指示了还需要写入多少字节才能完成整个传输。这里TXSTAT的值是2。软件应当执行2次写I2C_DATA寄存器的操作或者重新配置DMA传输长度为2将这最后的“零头”数据送入FIFO从而完成整个发送过程。3.2 排空机制的配置与避坑要点主从模式差异在主模式下控制器知道总共要发送/接收多少数据DATACOUNT寄存器因此理论上可以通过计算DATACOUNT % THRESHOLD来提前知道剩余字节数不一定非要依赖排空中断。但在从模式下从机不知道主机要传多少数据排空机制特别是发送排空就变得至关重要用于处理传输意外终止的情况。然而正如前文强调手册明确禁止在从机发送模式下使用排空特性原因已述。DMA与排空的协同在DMA模式下使用排空流程稍显复杂。以接收为例常规DMA配置的传输长度是DATACOUNT。当排空中断RDR发生时DMA可能已经完成了预设长度的传输并停止了。此时需要软件介入读取RXSTAT值然后重新配置DMA通道修改目标地址和传输长度启动一次新的短传输来搬走剩余数据。有些更智能的DMA控制器支持“链式传输”或“重新加载”功能可以自动完成此操作。错误处理如果不使用排空功能且传输长度非阈值整数倍会发生什么控制器会产生一个访问错误Access Error将I2Ci.I2C_STAT[7] AERR位置1。这表示CPU或DMA试图进行超过实际需要的FIFO访问例如在接收时试图多读或在发送时试图多写。因此对于长度不定的传输强烈建议启用排空功能。清空FIFO在传输出错如从机发送时收到NACK需要中止时FIFO中可能残留数据。控制器提供了I2Ci.I2C_BUF[14] RXFIFO_CLR和I2Ci.I2C_BUF[6] TXFIFO_CLR位写1可以像软件复位一样清空对应的FIFO。在DMA模式下这两个位还会复位DMA状态机这在处理传输错误、重启DMA时非常有用。4. 实战配置从零搭建一个DMA驱动的I2C接收任务理论说了这么多我们来看一个具体的实战例子配置I2C1作为主机以400kbps速率使用DMA方式从某个传感器假设地址0x50连续读取200个字节数据。假设FIFO深度为8我们设置接收阈值为4即RTRSH 3。4.1 初始化与配置步骤以下是基于TI处理器常见寄存器操作的步骤分解代码风格为伪代码重点在于逻辑// 步骤1使能时钟 // 通常需要配置PRCM模块使能I2C1的功能时钟和接口时钟 PRCM-CM_FCLK_I2C1_CLKCTRL | 0x2; // 使能功能时钟 while(!(PRCM-CM_FCLK_I2C1_CLKCTRL 0x3)); // 等待时钟就绪 // 类似地使能接口时钟... // 步骤2配置引脚复用 // 将对应的GPIO引脚功能设置为I2C1的SCL和SDA CTRL_MODULE_PAD-CONTROL_PADCONF_I2C1_SCL (PIN_MODE(0) | PULL_UP_EN); // 模式0 上拉使能 CTRL_MODULE_PAD-CONTROL_PADCONF_I2C1_SDA (PIN_MODE(0) | PULL_UP_EN); // 步骤3配置I2C控制器基本参数在使能模块前 I2C1-I2C_PSC 0x07; // 假设功能时钟96MHz预分频得到~12MHz内部采样时钟 I2C1-I2C_SCLL 0x2C; // 计算得到的低电平周期值对应400kbps I2C1-I2C_SCLH 0x2C; // 计算得到的高电平周期值 // 步骤4配置FIFO与DMA I2C1-I2C_BUF 0; I2C1-I2C_BUF | (3 8); // 设置RTRSH 3即RX阈值 4 // I2C1-I2C_BUF | (x 0); // 如果需要发送设置XTRSH I2C1-I2C_BUF | (1 15); // 设置RDMA_EN 1 使能接收DMA通道 // I2C1-I2C_BUF | (1 7); // 如果需要发送DMA设置XDMA_EN // 步骤5使能I2C控制器模块 I2C1-I2C_CON | (1 15); // 设置I2C_EN 1 // 步骤6初始化I2C控制器为主机接收模式 I2C1-I2C_CON 0; I2C1-I2C_CON | (1 15); // I2C_EN保持为1 I2C1-I2C_CON | (1 10); // MST 1 主机模式 // TRX位默认为0即接收模式无需设置 // 步骤7配置从机地址和传输长度 I2C1-I2C_SA 0x50; // 7位从机地址 I2C1-I2C_CNT 200; // 要接收200个字节 // 步骤8使能排空中断处理非整数倍情况 I2C1-I2C_IE | (1 13); // 设置RDR_IE 1 使能接收排空中断 // 同时确保DMA相关中断如传输完成也在NVIC中使能 // 步骤9配置系统DMA控制器以EDMA为例简化流程 // 配置DMA通道参数源地址为I2C1数据寄存器地址目标地址为内存缓冲区传输长度为200 // 触发源选择为I2C1的接收DMA请求I2C1_DMA_RX EDMA_ConfigChannel(I2C1_RX_DMA_CH, EDMA_TRIG_I2C1_RX, my_data_buffer, (uint32_t)(I2C1-I2C_DATA), 200); EDMA_EnableChannel(I2C1_RX_DMA_CH); // 步骤10启动传输 // 首先检查总线是否繁忙 while(I2C1-I2C_STAT (1 12)); // 等待BB位为0 // 发送起始条件读命令 I2C1-I2C_CON | (1 0); // 设置STT 1启动传输 // 对于纯接收通常STP位也会在开始时设置让硬件在传输完CNT个字节后自动发送停止条件 I2C1-I2C_CON | (1 1); // 设置STP 14.2 中断服务程序处理排空当200个字节传输完成由于200是4的整数倍理论上DMA会完美处理。但为了演示排空假设我们读199个字节CNT199。前196个字节49个DMA周期由DMA处理。最后3个字节进入FIFO后由于不足阈值4会触发RDR中断。// I2C中断服务程序ISR void I2C1_IRQHandler(void) { uint32_t status I2C1-I2C_STAT; // 检查接收排空中断 if (status (1 13)) { // RDR位为1 // 1. 读取FIFO中剩余的数据量 uint8_t remaining_bytes (I2C1-I2C_BUFSTAT 8) 0x3F; // 提取RXSTAT字段 // 2. 手动读取剩余字节或者重新配置一次短DMA for(int i 0; i remaining_bytes; i) { my_data_buffer[200 - remaining_bytes i] I2C1-I2C_DATA; } // 3. 清除RDR中断标志写1清零 I2C1-I2C_STAT (1 13); // 4. 此时整个199字节的传输才算真正完成 // 可以设置一个标志位通知主程序数据就绪 g_i2c1_rx_complete true; } // 检查其他中断如AERR, NACK等并做相应处理 if (status (1 7)) { // AERR访问错误 // 处理错误可能需要清空FIFO I2C1-I2C_BUF | (1 14); // 设置RXFIFO_CLR // ... 错误恢复逻辑 I2C1-I2C_STAT (1 7); // 清除AERR标志 } // ... 处理其他状态位 }5. 调试技巧与常见问题排查在实际开发中I2C的FIFO和DMA功能虽然强大但一旦出现问题调试起来往往比简单的轮询模式更令人头疼。以下是我总结的一些常见问题点和排查思路。5.1 DMA传输卡住或数据不完整这是最常遇到的问题现象是DMA只搬运了部分数据后就停止了。检查阈值与FIFO深度首先确认你设置的XTRSH/RTRSH值是否小于FIFO深度FIFODEPTH。一个常见的错误是将阈值设得等于甚至大于深度这会导致DMA请求逻辑混乱。通过读取I2Ci.I2C_BUFSTAT[15:14] FIFODEPTH可以确认深度。检查排空中断是否使能和处理如果传输长度不是阈值的整数倍并且你没有使能或处理XDR/RDR中断那么最后几个字节就会“卡”在FIFO里。用调试器检查I2C_STAT寄存器看XDR或RDR位是否被置起。如果置起了说明排空机制已触发但你的程序没有响应。检查DMA配置确认DMA的源/目标地址、传输长度、地址递增模式是否正确。特别是传输长度它应该是你期望的总字节数。DMA控制器会在完成这个长度的传输后自动停止即使I2C这边因为排空还有数据。检查总线错误监控I2C_STAT寄存器中的NACK无应答和AL仲裁丢失位。如果从机无应答或总线冲突I2C控制器会停止传输这自然会导致DMA只进行了一部分。确保从机地址正确且从机设备上电并正常工作。使用逻辑分析仪这是最强大的工具。同时抓取I2C的SCL/SDA波形和DMA请求信号线如果芯片引脚引出。你可以清晰地看到DMA请求信号I2Ci_DMA_RX/TX是否按预期产生和释放。FIFO阈值触发点是否与理论一致。在传输末尾当数据量不足阈值时排空机制是否被触发XDR/RDR中断可能对应某个GPIO翻转来观察。5.2 数据错位或覆盖这种现象是数据读/写的位置不对比如内存中收到的数据前几个字节是0或者后一段数据覆盖了前一段。DMA地址递增问题确保DMA配置中目标地址对于接收或源地址对于发送的递增模式设置正确。对于内存缓冲区通常需要设置为递增对于外设数据寄存器地址必须设置为固定。缓冲区大小不足这是低级但常见的错误。确保你分配的内存缓冲区大小至少等于I2C_CNT寄存器设置的长度。如果DMA配置的长度超过了缓冲区大小会导致内存越界覆盖其他数据。排空处理逻辑错误在排空中断里你手动读取数并存入缓冲区的偏移地址计算错误。例如上面的例子中my_data_buffer[200 - remaining_bytes i]这个200应该是DATACOUNT如果你之前DMA已经搬了196个字节到my_data_buffer[0]到[195]那么手动读取的3个字节就应该放到[196],[197],[198]的位置。务必仔细计算这个偏移。5.3 性能未达预期即使使用了DMA发现实际带宽仍然不高。阈值设置过小如果阈值设得太小比如1或2DMA请求会非常频繁每次DMA传输的有效数据量少而总线仲裁、DMA通道切换等固定开销占比变大整体效率下降。尝试在FIFO深度允许的范围内适当增大阈值。DMA优先级检查系统中其他DMA通道或高优先级中断是否频繁抢占I2C的DMA通道。如果I2C的DMA请求被长时间阻塞会导致FIFO溢出或下溢。调整DMA通道优先级或优化其他任务。时钟配置确认I2C的功能时钟I2Ci_FCLK和内部采样时钟I2Ci_INTERNAL_CLK配置正确。错误的时钟分频会导致实际比特率远低于理论值。参考手册中的公式计算SCLL和SCLH值必要时用示波器测量SCL频率进行校准。总线负载I2C是共享总线。如果总线上有其他主设备或从设备通信频繁会导致仲裁、等待从而降低有效吞吐率。分析总线的整体活动情况。5.4 特殊模式下的注意事项SCCB模式如前所述必须将RTRSH和XTRSH设为0阈值1。同时SCCB的读写序列与标准I2C略有不同需要严格按照SCCB协议先写寄存器地址再读/写数据来操作I2C_SA、I2C_OA0和I2C_DATA寄存器。从机模式在从机模式下传输长度是未知的。对于从机接收使用DMA和阈值模式是可行的。但对于从机发送务必禁用排空特性并且通常将TX阈值设为1XTRSH0因为主机随时可能停止读取。同时要做好处理XUDF发送下溢状态的准备这表示主机还在要数据但你的TX FIFO和移位寄存器已经空了。FIFO清空在发生错误或需要重启传输时善用RXFIFO_CLR和TXFIFO_CLR位。在清除FIFO后最好也复位一下相关的状态机和DMA通道确保从一个干净的状态开始。回顾整个I2C控制器FIFO与DMA机制的设计其精髓在于通过硬件层面的缓冲与自动化将CPU从繁重的字节搬运中断中解脱出来。阈值可编程的FIFO提供了灵活性而DMA与排空机制的配合则解决了大数据量传输的效率和边界问题。理解这些机制并能在调试中熟练运用状态寄存器和逻辑分析仪进行验证是掌握高性能I2C通信的关键。在实际项目中我建议先在轮询或简单中断模式下把基本通信调通然后再逐步引入阈值中断和DMA并充分测试传输长度非整数倍、错误恢复等边界情况这样才能构建出稳定可靠的驱动。