尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

嵌入式串行通信四剑客:I2C、SPI、UART与I2S对比及调试全攻略

嵌入式串行通信四剑客:I2C、SPI、UART与I2S对比及调试全攻略 做嵌入式的朋友几乎没有谁能绕开这四种串行通信I2C、I2S、SPI、UART。传感器要I2C音频Codec要I2SFlash和ADC多半走SPI跟PC或上位机打交道基本靠UART。平时每个协议单独用都熟可真到了要在同一块板子上把它们凑齐、还要根据带宽、引脚、时序开销做取舍的时候很多人就懵了。这篇分享我把自己这些年实际调过的经验整理出来配合常见波形和踩坑记录帮你把选型逻辑和工程细节一次理清。不管你是刚入门还在啃时序图的新手还是已经写了几年驱动的老手里面应该都有点能直接拿走用的东西。1. 四种协议横向对比一张表看懂差异1.1 核心参数与信号定义对照很多新手最容易卡的地方是分不清这四种协议到底谁快谁慢、用几根线、怎么区分数据与时钟。先把最关键的参数丢到一张表里后面再逐个展开。协议信号线时钟模式传输方向典型速率通信方式UARTTXD、RXD2线异步无时钟线靠波特率对齐全双工9600bps ~ 4Mbps点对点I2CSCL、SDA2线同步主机产生SCL半双工100k/400k/1M/3.4Mbps多主多从总线广播SPISCLK、MOSI、MISO、CS4线同步主机产生SCLK和CS全双工典型1~80MHz一主多从片选区分I2SSCK、WS、SD3线同步主机产生SCK和WS全双工或分时取决于音频采样率BCLK常见1~3MHz一主多从时分复用这张表想提醒你三个点。第一UART是异步的意味着没有时钟线收发的双方靠约定好的波特率自行对齐每一位。所以波特率误差是UART调试里最隐蔽的坑。第二I2C和SPI虽然都是同步但I2C是半双工的一条数据线SDA既要发又要收通信效率天然低于SPI的全双工四条线。第三I2S其实不算通用的数据总线它是面向音频流的点对点总线参数跟着采样率和位宽走没有标准速率一说。1.2 从应用场景反推选型逻辑我自己选型时的判断顺序很简单看数据量、看引脚预算、看是否需要多设备组网。如果只是读个温度、读个编码器角度、配一下PMIC寄存器数据量小、引脚紧巴巴I2C是首选。接一颗MPU6050、一颗BMP280、一颗EEPROM两根线挂一堆从机性价比极高。但I2C不擅长跑大数据块400kbps看起来还行实际算上地址、ACK、寄存器地址这些开销有效吞吐会打很大折扣。跑连续刷屏这种活I2C会明显力不从心。如果器件本身要求高带宽或者天然是流式数据比如Nor Flash固件存储、SD卡、ADC高速采样、TFT屏幕SPI明显更合适。尤其是全双工这个特性读Flash的时候可以同时把下一笔命令写出去配合DMA吞吐能拉得很高。代价是每加一个从机就要多占一个片选四个从机就要四根CS引脚压力比I2C大不少。UART就纯粹多了只解决两个设备之间的点对点通信。工业设备、定位模块、蓝牙透传、上位机调试全都是UART的天下。它没有总线仲裁、没有ACK机制上位机只要对应好波特率就能解析开发成本最低。I2S则不用纠结选不选只要板上接了音频Codec、DAC、数字麦克风就绕不开它。音频数据是典型的同步流式数据必须保证采样点不丢不重I2S的固定帧结构和位时钟就是干这个的。1.3 容易混淆的几个概念第一有人会问I2C和SMBus/PMBus啥关系。SMBus是I2C的衍生规范时序类似但定义了更严格的超时和报警机制笔记本电脑电池、电源管理芯片上大量使用PMBus则是在SMBus之上叠加电源管理的状态命令集。遇到这类芯片能用I2C驱动框架去读但要注意SMBus的快速读写格式和PEC校验位直接套普通I2C读写函数偶尔会踩到格式不兼容的坑。第二SPI不等于四根线一定就是全双工。很多从机是半双工或者只支持单方向的例如某些SPI ADC只有MISO输出数据命令阶段MOSI写配置、数据阶段全靠MISO。这时候的时序设计和全双工Flash完全不一样读数据前得先搞清楚什么时候切方向。第三很多人会忘了I2S的时钟关系这个细节。I2S里有两层时钟位时钟SCK决定每个bit的节拍帧时钟WS决定左右声道切换很多Codec还需要主时钟MCLK而且MCLK和采样率的倍数有严格关系常见256fs。代码里配置成只要BCLK不要MCLK在某些Codec上能跑但底噪和稳定性往往不如完整时钟方案。2. UART异步串口背后的时序与工程细节2.1 帧格式与波形判读UART的帧格式是固定的空闲时TXD保持高电平发送时先拉低一个bit时间作为起始位然后从LSB到MSB依次发送数据位再根据配置发校验位最后至少拉高一个bit时间作为停止位。我经常跟新人说UART波形比I2C、SPI好认得多因为起始位的下降沿是所有判读的锚点逻辑分析仪上看到一个明显的低电平脉冲后面跟一串高低变化多半就是一帧数据。实际抓波形时要注意UART的比特率和数据位的顺序很容易让人看错。比如发送0x55二进制是01010101波形上看到的是从LSB开始也就是10101010逻辑分析仪里如果把方向看反解析出来的字节会差很大。曾经调一个串口屏一直收到0xAA而不是0x55后来发现是逻辑分析仪通道接反了把TXD和RXD调换后立刻正常。这种低级问题在UART调试里出现频率极高。波特率误差也是个经典难点。两个设备波特率不一致时短帧可能看不出问题长帧或高速率下就开始随机乱码。像115200波特率下如果接收方波特率有2%的偏差时间长了采样点就会滑移到比特边界出现稳定的每帧都错、但偶尔对的现象。我给自己定的经验值是时钟误差尽量控制在1%以内特别是用外部晶振的MCU内部RC振荡器在温度变化时偏差会超出容忍范围。2.2 16550标准与USB转串口芯片聊UART不能不提16550。这是PC时代定义下来的标杆UART控制器它把寄存器布局、FIFO深度、中断结构都定了标准后来的USB转串口芯片FT231X、FT232R、CP2102、CH340在Linux和Windows下的驱动本质上都是兼容16550这套编程模型的。FT232R能实现即插即用就是因为它把16550的寄存器映射和FIFO行为都模拟得足够好上位机软件不用关心底层是不是USB。实际项目中用FT231X和FT232R比较多因为它们内置EEPROM可以改写VID/PID和串口名称量产出货很方便。但也因为这点二手模块的驱动问题会很多Windows下装官方驱动时报该设备找不到足够资源代码12多半是USB控制器枚举问题或者模块的EEPROM被刷坏用FT_Prog重新烧写一次出厂配置基本能救回来。Linux下走ftdi_sio内核驱动一般插上就识别成/dev/ttyUSBx速度上限取决于USB端点实测FT232R跑到3Mbps没有问题再高就要换FT2232H这类高速芯片了。2.3 打样时常见的UART翻车点最典型的翻车是把TXD和RXD直连接反。板子上丝印TXD的引脚接到对端TXD结果完全无数据。判断方法很简单拿示波器量空闲电平TXD应该一直是高电平如果量出来是低说明被对端拉住了或者根本没配置成推挽输出。还有个容易忽视的是地线。UART是单端信号两边的地必须连在一起只接三根线不接地会看到偶发的乱码和电压飘动。特别是两个设备用不同电源适配器供电时不共地几乎是必出问题。另外收发芯片MAX3232这类的电荷泵电容没焊好也会导致信号电平不对用万用表量电压时看似正常一接示波器就发现波形塌陷。3. I2C开漏总线上的主从博弈3.1 从物理层理解开漏和上拉电阻I2C的物理层设计了开漏输出也就是说芯片只能把SCL和SDA拉低不能主动拉高高电平靠外部上拉电阻实现。这个设计的意义在于支持多主多从和线或逻辑任何一个设备都可以拉低总线不需要额外的方向仲裁电路。上拉电阻的取值直接影响通信质量我经常遇到新人直接抄一个4.7kΩ就上了在400kbps快速模式下偶尔通信失败。上拉电阻的选择逻辑是总线电容越大、速率越高需要的上拉电阻越小。阻值太大上升沿太缓设备可能采样到错误的逻辑电平阻值太小灌电流过大低电平时输出电压会超标。常规低速100kbps可以用4.7k到10k400kbps建议1k到4.7k1Mbps以上最好用1k出头上拉。板子上总线走线长、挂的设备多的时候可以在两端各放一组上拉而不是只在主机侧放一颗。我曾经调过一块挂了8颗I2C从机的板子总线上电容大用10k上拉在快速模式下怎么都读不对换4.7k稍微好点最后改成1k才稳定。从那以后我习惯在原理图阶段就把上拉电阻的封装留成双排焊盘实际测试时方便换阻值。3.2 时序细节起始停止、ACK和数据格式I2C的核心时序其实是三个动作起始条件、数据位、停止条件。起始条件是SCL保持高电平时SDA产生下降沿停止条件是SCL保持高电平时SDA产生上升沿数据在SCL低电平期间改变在SCL高电平期间保持稳定。理解这三句话基本就理解了所有I2C时序图。传输一个字节的流程是主机发出起始条件然后发送7位设备地址加1位读写位被寻址的从机在第九个时钟拉低SDA应答主机再逐字节发送寄存器地址和数据每字节后都要等待从机ACK。如果主机想读数据则需要从机在每字节后等主机给出ACK最后读最后一字节时主机回一个NACK再发停止条件。这些细节在i2c时序图里看着复杂实际逻辑分析仪抓出来就是一组规律的方波配合协议解析器能直接看到ACK和NACK。真正折磨人的是NACK。从机收到地址后不拉低SDA通常是地址错误或者写位/读位搞反。之前调RDA5807收音机芯片时它的设备地址手册里写0x11但那是7位地址实际总线上的字节是0x22左移一位不熟悉这点的直接发0x11怎么都收不到ACK。这个坑特别普遍因为很多器件手册用8位地址表示法有些用7位同一个芯片在不同手册里会差一倍。3.3 自由数据模式与特殊器件调试有些器件不按常规的寄存器地址数据格式来需要在I2C总线上直接塞入自定义格式的字节流这就是大家常说的I2C自由数据模式或者叫裸数据模式。典型场景是GT911触摸屏控制器和部分RF芯片。它们寄存器配置复杂有些配置是流式写入的不能简单套用读寄存器地址A、写数据B的流程。我调GT911时就踩过这个坑。芯片手册给的初始化流程是先写软复位命令然后等待一段时间再连续写入一长串配置数据。乍看是标准I2C但有一步要求在无应答状态下也可以继续写入也就是说从机NACK了主机也要把后续字节送完这在标准I2C驱动库里是没有这个选项的。解决方法是把I2C驱动底层的检测到NACK立即停止关掉或者直接用GPIO模拟I2C自己控制每个字节的时序。软件模拟I2C虽然慢但自由度最高遇到非标准器件时反而是最可靠的调试手段。从机主动更新主机寄存器这个问题也经常有人问。I2C是主机主导的协议标准机制下从机没有主动发言权它不能自己把数据推到主机寄存器里。常规做法有三条路第一从机通过中断引脚拉高通知主机主机收到中断后主动去读第二简化成主机快速轮询把读取周期压到足够短第三用SMBus的Alert Response机制从机靠拉低SDA触发一个SMBALERT事件主机通过特定的Alert Response地址去处理。第一条路在实际工程里最常用因为不依赖特殊硬件只要从机多一根GPIO就行。3.4 多从机与地址扩展I2C从机地址是7位的有10位扩展模式但用得少7位地址空间有限实际还要排除保留地址所以同一条总线上能挂的独立设备地址是有限的。遇到好几颗芯片地址冲突时常规解法是I2C多路复用器典型的是TCA9548A把一路I2C分成8路各路挂不同地址范围的设备主机先选通道再访问从机。另一个常用思路是地址扩展引脚比如PCF8574这类的GPIO扩展芯片有A0/A1/A2三个引脚通过接高低电平最多分出8个地址。除了地址多从机通信还要注意ACK时序和总线挂死。设备上电时序异常时从机可能把SDA拉死不放主机端看总线一直低电平、发什么都失败。这种问题多数要靠硬件复位对应器件或者断电重启来解决软件层面可以加一个总线复位流程主机手动翻转SCL九次以上让卡死的从机跳出异常状态。这个技巧在项目现场排查时救过我好几次。4. SPI高速全双工的四个模式与片选学问4.1 CPOL和CPHA四个模式的本质SPI的误用率在我见过的项目里排第一因为它的四种模式太容易配错。SPI定义了时钟极性CPOL和时钟相位CPHA两个参数CPOL决定空闲时SCLK是高还是低CPHA决定数据是在SCLK的第一个边沿采样还是第二个边沿采样。组合出来就是模式0、1、2、3分别对应(CPOL0CPHA0)、(01)、(10)、(11)。我调试时最怕的就是芯片手册只在某个不起眼的地方写了一句SPI Mode 1结果我默认用了Mode 0数据读出来全是错位或者丢一位。判断模式的实操技巧是看时序图里的采样沿标注如果数据在上升沿稳定、下降沿变化通常是Mode 0如果反过来了就要考虑Mode 1。实在不确定就用逻辑分析仪抓从机返回的数据对比已知寄存器的期望值来反推模式。注意MCU的SPI外设和FPGA的软件模拟SPI对模式的定义是等价的但在FPGA里实现时更要小心。FPGA实现SPI模式0一般做法是在SCLK上升沿采样MISO、下降沿更新MOSI这一个上升沿采样、下降沿输出的约定要写进状态机注释里不然过俩月自己都忘了当时为什么这么写。4.2 硬件片选与软件片选的抉择SPI的多从机架构靠CS片选来区分片选有两种做法硬件片选和软件片选也叫GPIO片选。硬件片选就是MCU的SPI外设自带NSS引脚配置好之后外设自己拉低片选软件不用操心软件片选就是随便拿一个普通GPIO来控制CS发送前手动拉低、结束后手动拉高。硬件片选省心但在多从机高速传输时有个坑它往往和数据的传输时序绑定得太紧比如某些MCU会在发送完最后一个字节的瞬间自动拉高CS而外部Flash可能还需要一点额外的保持时间。相比之下软件片选最灵活可以自己控制CS拉低的建立时间和拉高的释放时机适合调试奇怪的从机。片选时序里还有个细节很多从机手册会标注CS拉高的最小保持时间以及CS拉低到SCLK第一个沿之间的建立时间。有人问CS最小能做到多少微秒这个没有固定答案完全看从机手册里的参数。比如某颗Nor Flash要求CS高电平时间至少30ns两笔连续操作之间如果CS释放太短Flash会认为交易没有结束导致命令丢失。我曾经为了压速度把CS低到高的间隔缩短到几十纳秒结果下一笔操作偶尔失败最后老老实实按手册加了延时才稳定。4.3 STM32CubeMX下的SPIDMA配置手写SPI寄存器太容易错用CubeMX生成代码是当前主流做法。配置SPI外设时先选好SCLK/MOSI/MISO/NSS引脚设置预分频得到目标SCLK频率最重要的是在外设配置里把数据大小设为8位或16位以及确认CPOL/CPHA。需要DMA吞吐时在CubeMX里把SPI的发送和接收分别挂到DMA通道上优先级建议设成Medium以上。生成代码后实际使用多用HAL_SPI_Transmit_DMA和HAL_SPI_Receive_DMA。有一个特别容易踩的坑DMA模式下如果发送和接收都开启就要保证DMA通道的中断优先级合适否则回调没执行完下一笔请求又到了。还有一个坑是HAL库的DMA传输结束后SPI的句柄状态不会自动回到Ready下次调用前要手动处理或者干脆重新Init。现场出问题时先用查询模式跑通再切换到DMA能大幅缩小排查范围。4.4 FPGA侧SPI读ADC的时序设计FPGA和SPI ADC之间是经典搭配比如ADS8361、AD7606这些。SPI ADC的读取流程一般分两步先发转换命令等待转换完成再从MISO读数据。但在硬件上转换时间t_CONV往往比数据读取时间长很多FPGA状态机里必须按等待转换完成标志来设计而不是简单的一发一收。常见设计是把状态机分成IDLE、START、CONV_WAIT、READ、DONE几个状态用CS信号的下降沿触发转换WAIT期间SCLK保持空闲等转换完成引脚或者固定延时到了以后再拉低CS并输出SCLK读取数据。调试时最容易出问题的是时序余量ADC的SCLK最大频率往往低于普通Flash如果FPGA把SCLK跑得太快ADC的MISO在采样点还没稳定读回来的数据就是乱的。稳妥的做法是先按ADC手册建议的SCLK上限的一半来跑抓MISO波形确认建立时间足够再把频率提上去。关于python调用usb模拟spi接口这类玩法在实验室验证时特别好用。用FT232H搭配pyftdi电脑就能直接当SPI主机代码里指定片选、设置频率、写读同一事务非常适合在没有MCU的情况下单测一颗SPI从机。实测下来pyftdi的时序对低速器件足够但高速Flash调试还是老老实实用MCU或FPGA。5. I2S专为音频而生的同步总线5.1 I2S引脚与音频帧结构I2S是Philips为数字音频定义的串行总线它的引脚和SPI有点像但功能完全不同。SCK是位时钟每个时钟对应一个数据位WS是左/右声道选择通常低电平表示左声道、高电平表示右声道数据在WS跳变后的第一个时钟开始传输SD是串行数据线从MSB开始逐位发送。很多Codec还额外需要MCLK主时钟MCLK一般是采样率的256倍或512倍像44.1kHz采样率配256倍MCLK就是11.2896MHz。理解了这三根线I2S波形就很好判读了。用逻辑分析仪抓I2S时先看WS的跳变边界每个声道周期内SCK的个数等于位宽比如16bit音频一个声道16个SCK、SD上从MSB开始那16个bit才是有效数据。很多人把I2S和SPI搞混误以为SCK等于SPI的SCLK、WS当成CS其实I2S没有地址寻址概念WS只是纯声道标志数据永远线上排队。5.2 I2S时钟的倍数关系与Codec兼容I2S的时钟配置是音频调试里的重灾区。常见音源是16bit/44100Hz双声道BCLK应当是44100×16×21.4112MHzMCLK则按Codec的接口要求选择128fs、256fs、512fs之一。如果BCLK的配置和采样率不匹配播放速度会变成0.5倍或者1.5倍听感上就是慢放或快进而且这种问题示波器看不出来只能靠计算确认。我踩过的一个大坑某颗Codec要求MCLK是BCLK的整数倍我用ESP32-C3的I2S外设直接输出BCLK和WSMCLK从别的引脚分频出来结果相位关系对不上Codec初始化失败。后来把时钟树改成由MCLK作为时钟源、在内部生成BCLK和WS才恢复正常。所以拿到Codec手册先看它的时钟树要求别省事。5.3 ESP32-C3的I2S输出实操ESP32-C3只有一个I2S外设新版本ESP-IDF把接口改成了i2s_std模式。初始化一段输出16bit/44100Hz双声道音频大致要做这些事配置i2s_std_config_t的CLK、WS、数据引脚设置slot_cfg里的数据和位宽调用i2s_channel_init_std_mode和i2s_channel_enable之后就能用i2s_channel_write把PCM数据写进去。GPIO上注意C3可用的I2S引脚和JTAG口有冲突不用的调试口记得复用成GPIO。C3的I2S在性能和噪声上都能满足普通音频应用但它的I2S只有标准的时分模式不支持TDM多通道接多麦克风阵列就得换C6或者外部Codec做通道合并。还有一点音量控制最好在I2S写入端做数字增益别在Codec端乱加模拟增益实测C3输出到Codec时数字增益过大容易削波发破音。6. 高频场景实战记录从踩坑到抄作业6.1 GT911 I2C通信失败排查全过程触摸屏调不通是I2C问题的高发区。GT911的I2C通信失败按照我排查的优先级排序是先查硬件地址对不对GT911的7位地址是0x5D或0x14看INT引脚的上拉电阻再查上电时序GT911要求复位时序比较严格拉高复位引脚后要等待一段时间才能访问最后查寄存器写入方式GT911的配置数据是流式写入的不能简单当标准寄存器。我修过一块板子上电时序没做好芯片一直处于复位状态SDA被拉低所有I2C命令都得不到ACK重新整理复位流程后立刻恢复。还有个细节GT911在部分固件版本下要先把软复位命令写进去等待200ms左右后再次访问才有ACK。如果代码里写完复位立即读读到的一直是NACK。这类时序敏感型芯片排查时强烈建议加调试打印把每个步骤的时间戳打出来对照芯片手册的时序要求逐项核对。6.2 FPGA通过软件I2C读写EEPROMFPGA里用状态机读EEPROM新手常卡在读流程的写寄存器地址再改读方向这一步。完整读流程是发起始条件、写设备地址写位、写EEPROM寄存器地址、再发一次起始条件、写设备地址读位、连续读两个字节、最后一个字节回NACK、发停止条件。中间那个重启不是停止再加起始而是直接发第二次起始条件时序图上是一个经典的重启符号。用Verilog实现时建议把I2C时序拆成发送字节、接收字节、发送ACK三个通用模块主状态机只管组织这些模块的调用顺序。这样读写EEPROM的代码结构会非常清晰也方便复用。编这一步时序时SCL的频率和SDA的变化时机必须对齐数据只能在SCL低电平期间切换高电平期间要保持稳定。逻辑分析仪上要是看到SDA在SCL高电平时跳变那一定是状态机时序写错了。6.3 RK3588 SPI接口与设备树调整RK3588的SPI接口复用选项很多同一个物理引脚组可以配置成SPI也可以配置成其它外设改设备树时最要注意的是pinctrl配置。通常在dts里找到SPI节点设置pinctrl-0指向对应的引脚组比如spi0 pins再设置spi-max-frequency片选要么用外设内置CS要么cs-gpios指定普通GPIO。我遇到过最诡异的问题GPIO模拟片选在设备树里配了active-high结果驱动初始化时片选一直是高的访问Flash全部失败。改成active-low并把GPIO默认输出高问题立刻消失。RK3588的SPI控制器支持的最高频率可以达到几十MHz但实际能跑到多少取决于PCB走线和从机的负载。板卡上如果SPI走线较长就算芯片手册标称支持50MHz实际在20MHz下波形已经开始振铃。这类问题看逻辑分析仪最直观SCLK边沿有无过冲、MISO数据眼有没有闭合一眼就知道降不降频。6.4 Python调用USB模拟SPI与串口转GPIB实验室自动化场景里用Python调USB模拟SPI几乎成了标配。用pyftdi控制FT232H作为SPI主机一个典型读写序列是初始化Ftdi、配置SPI频率和模式、拉低片选、写命令字节、读响应字节、拉高片选。做批量测试的时候把片选拉高拉低和字节发送封装成独立函数测试脚本会清爽很多。需要注意FT232H的时序不是毫秒级实时性很强的跑高速Flash回环测试时偶尔会在高频下丢位建议测试时把SPI频率降到目标值的一半做等价验证。串口转GPIB这种需求一般出现在仪器控制场景。有些老式示波器、源表只有GPIB口PC串口又没有GPIB硬件中间加一个协议转换器本质上是在串口上跑GPIB命令流底层把读写指令翻译成IEEE 488总线时序。这类设备协议不统一买之前务必确认它支持的是SCPI命令还是厂商私有协议。7. 调试工具与常见问题速查7.1 逻辑分析仪选型和抓波形的关键参数调试串行协议逻辑分析仪是我排在示波器前面的工具。原因很简单协议调试需要长时间抓取大量数据示波器只能看片段逻辑分析仪却能连续录几十万条采样点配合协议解析器直接把I2C的ACK、SPI的字节、UART的帧还原出来。选逻辑分析仪时采样率和通道数是最重要的参数。抓I2C快速模式的1Mbps采样率最低也要4Msps抓I2S的BCLK常见1~3MHz至少8Msps起步否则窄脉冲会被漏掉波形上看到一堆假的毛刺。通道数不一定要多16通道对大多数场景足够关键看协议解析支持哪些协议。我常用的流程是接好线、打开协议解析器、触发条件设为起始条件或CS下降沿然后照着时序图对比解析结果问题基本十分钟内定位。7.2 高频问题速查表我把自己遇到的和身边同事遇到的高频问题整理成一张速查表每个问题后面都附了最直接的检查顺序。问题现象常见原因优先排查项I2C地址写对但无ACK地址表示法搞混/从机未上电确认7位还是8位地址量从机供电SPI数据全为0x00或0xFF模式配错/方向接反确认CPOL/CPHA检查MOSI/MISO接线UART乱码只在数据量大时出现波特率误差或地线问题量两侧波特率检查共地I2S有波形但无声音MCLK倍数不对/左右声道反核对Codec时钟树交换WS极性USB转串口驱动报代码12EEPROM损坏或USB枚举异常用厂家工具重写配置换USB口SPI偶尔丢字节CS释放时间太短或DMA竞争加长CS高电平时间检查DMA优先级这张表不是让你照着逐条试而是从最可能的物理层开始逐步往中间件排查。串行通信问题绝大多数出在物理连接和时序配置上寄存器配置错误反而占比小。7.3 两条个人调试经验第一条遇到诡异通信问题先别改代码先抓波形。我曾经在SPI上花了一整天改软件最后发现是板子上MOSI和MISO的丝印被画反了。波形一抓就看到主机发的命令根本没出现在从机的MISO上问题瞬间定位。第二条尽量把协议操作封装成统一的读写函数并且在每个函数入口和出口留日志钩子。项目越复杂、接手的人越多这个习惯的价值越大。很多偶发无法复现的问题最后都是靠日志里的时间戳硬推出来的。调试串行通信耐心比技巧重要思路比工具重要。我个人这几年最大的体会是不要被协议的名字唬住底层全是高低电平加时钟的配合把一张时序图看懂比背一百个寄存器都管用。真到了现场逻辑分析仪永远是你最靠谱的伙伴遇到非标器件软件模拟总线永远比硬调外设寄存器省时间。如果你们以后在项目里把这四种协议用出了新花样欢迎回来聊聊各自的坑。
返回列表