SPI通信协议深度解析:CPHA/CPOL配置、错误处理与MC68HC908MR24实战
1. 项目概述与SPI协议核心价值
搞嵌入式开发这么多年,SPI(Serial Peripheral Interface)绝对是我打交道最多的通信协议之一。它不像I2C那样需要复杂的地址寻址和应答机制,也不像UART那样对时钟同步有严格要求。SPI的魅力就在于它的“简单粗暴”——全双工、高速率、主从架构清晰,一根时钟线加两根数据线,就能在微控制器和传感器、存储器、显示屏等外设之间建立起一条高速数据通道。但正是这种表面上的简单,让很多新手在配置时钟相位(CPHA)和时钟极性(CPOL)时栽了跟头,更别提那些隐蔽的溢出错误和模式故障了。今天,我就以经典的Freescale(现NXP)MC68HC908MR24微控制器的SPI模块为例,把SPI通信里那些最核心、也最容易出错的细节掰开揉碎了讲清楚,特别是CPHA/CPOL的配置逻辑和实战中如何稳健地处理错误。
SPI本质上是一个同步的、基于移位寄存器的串行通信接口。一个典型的SPI系统包含一个主设备(Master)和一个或多个从设备(Slave)。主设备负责生成同步时钟(SPSCK),并控制通信的发起。数据通过两根线同时传输:主设备输出、从设备输入(MOSI)和主设备输入、从设备输出(MISO),从而实现全双工通信。此外,还有一个从设备选择线(SS),用于在多个从设备中选择当前通信的对象。它的高速和全双工特性使其在需要实时、大数据量交换的场景中,比如读取AD采样数据、驱动TFT屏幕、与Flash存储器通信时,成为首选方案。
然而,SPI协议本身并没有一个全球统一的严格标准,不同厂商的芯片在具体实现上会有差异,这就导致了兼容性问题。其中,CPHA和CPOL这两个寄存器的配置,是确保主从设备能够“听懂”彼此的关键。它们共同定义了时钟信号的极性(空闲状态是高还是低)以及数据采样和锁存的边沿(是时钟的第一个边沿还是第二个边沿)。配置错了,轻则数据错乱,重则通信完全失败。而像MC68HC908MR24这类老牌芯片的文档,虽然详尽,但充斥着硬件描述,对软件开发者来说不够直观。我将结合数据手册中的波形图和寄存器描述,用软件工程师的视角,重新解读这些时序,并分享我在调试中积累的配置口诀和排错心得。
2. SPI核心机制深度解析:从引脚到状态机
要玩转SPI,不能只停留在调用库函数的层面,必须理解其内部的工作机制。MC68HC908MR24的SPI模块是一个相当经典的实现,理解了它,就能触类旁通。
2.1 引脚功能与数据流
SPI模块共用5个引脚,其中4个(MISO, MOSI, SPSCK, SS)与通用I/O口复用。一旦SPI使能(SPE=1),SPI模块将接管这些引脚的方向控制,无论其数据方向寄存器(DDR)如何设置。
- MISO (Master In / Slave Out): 主设备的数据输入线,从设备的数据输出线。这是最需要理解的一点:数据总是从从设备流向主设备。当一个SPI被配置为从设备(SPMSTR=0)且其SS引脚被拉低(选中)时,它才会驱动MISO线。如果SS为高(未选中),MISO引脚将处于高阻态,防止总线冲突。在多从机系统中,这一点至关重要。
- MOSI (Master Out / Slave In): 主设备的数据输出线,从设备的数据输入线。数据从主设备流向从设备。主设备会一直驱动MOSI线。
- SPSCK (Serial Clock): 串行时钟,由主设备产生,用于同步所有数据位的传输。时钟极性(CPOL)决定了这条线在空闲时的状态。
- SS (Slave Select): 从设备选择。对于从设备,这是一个输入引脚,低电平有效(被选中)。对于主设备,这个引脚的角色比较特殊,我们后面在模式故障(MODF)错误中会详细讨论。
数据流的核心是一个8位的移位寄存器。发送时,数据从发送数据寄存器(实际是一个缓冲区)加载到移位寄存器,然后在SPSCK的驱动下,从MOSI(主设备)或MISO(从设备)引脚一位一位地移出。接收时,来自MISO(主设备)或MOSI(从设备)的数据在SPSCK的驱动下,一位一位地移入移位寄存器,满8位后,自动传输到接收数据寄存器,并置位SPRF标志。
2.2 双缓冲机制与传输队列
MC68HC908MR24的SPI采用了一个非常实用的双缓冲结构。这意味着它有一个发送数据寄存器(用于CPU写入)和一个独立的移位寄存器(用于串行移出)。这种设计带来了“队列”传输的能力。
当CPU向SPI数据寄存器(SPDR)写入一个字节时,数据实际上是进入了发送数据寄存器。此时,如果移位寄存器空闲,数据会立即被加载到移位寄存器,并开始发送,同时SPTE(发送器空)标志被置位,表示可以写入下一个字节。如果移位寄存器正在发送前一个字节,则新写入的字节会暂存在发送数据寄存器中排队,等待当前发送完成后再自动加载。这允许主设备连续写入多个字节,实现背靠背(back-to-back)传输,而无需等待每个字节发送完成再去查询和写入,极大地提高了总线利用率。
对于从设备,这个双缓冲同样重要。它允许从设备在完成当前字节的发送后,有更宽松的时间窗口来准备下一个要发送的字节,而不必在精确的时钟间隙进行写入。
注意:数据手册中特别强调,只有在SPTE标志位为1时,才能向SPDR写入数据。如果在SPTE为0时写入,数据可能丢失或导致不可预知的行为。这是一个常见的编程错误点。
2.3 时钟生成与传输启动延迟
在主设备模式下,SPI时钟(SPSCK)是由内部MCU时钟分频产生的。SPR1和SPR0两位用于选择分频系数(DIV2, DIV8, DIV32, DIV128)。这个内部SPI时钟是自由运行的(free-running)。
当CPU执行写SPDR操作来启动一次传输时,由于这个自由运行的SPI时钟与CPU操作是异步的,会存在一个“传输启动延迟”。这个延迟是不确定的,但有一个上限:最长不超过一个SPI位时间。具体来说,对于不同的分频,其最大延迟分别为2、8、32、128个MCU总线周期。这个延迟会影响你计算连续发送字节之间的最小间隔,在编写高吞吐率驱动程序时需要加以考虑。
3. CPHA与CPOL:时序配置的灵魂
这是SPI配置中最核心,也最令人困惑的部分。CPOL和CPHA共同定义了数据传输的时序模式,通常被称为SPI的“模式”(Mode 0, 1, 2, 3)。
3.1 CPOL:时钟极性
CPOL位决定了SPSCK时钟线在空闲状态(即两次传输之间)时的电平。
- CPOL = 0: 时钟空闲时为低电平。
- CPOL = 1: 时钟空闲时为高电平。
这很简单,它只是定义了时钟的初始状态。真正的玄机在于CPHA。
3.2 CPHA:时钟相位
CPHA位决定了数据是在SPSCK的哪个边沿被采样(捕获),以及在哪个边沿被改变(驱动)。这是理解SPI通信同步的关键。
CPHA = 0 模式分析
在这种模式下,数据在时钟的第一个边沿被采样,在第二个边沿发生改变。但具体是上升沿还是下降沿,要结合CPOL来看。
- 对于从设备:传输的开始信号是SS引脚的下降沿。在SS下降沿之后,从设备会立即在MISO线上驱动出要发送数据的最高位(MSB)。请注意,此时时钟可能还没有动作!数据已经就位,等待时钟来采样。
- 数据采样时刻:数据在时钟的第一个边沿被采样。如果CPOL=0(空闲低),第一个边沿是上升沿;如果CPOL=1(空闲高),第一个边沿是下降沿。
- 数据改变时刻:数据在时钟的第二个边沿发生改变,为下一个位的采样做准备。
CPHA = 1 模式分析
在这种模式下,数据在时钟的第二个边沿被采样,在第一个边沿发生改变。
- 对于从设备:传输的开始信号是SPSCK的第一个边沿。这就要求在第一个时钟边沿到来之前,SS引脚必须已经处于低电平(选中状态)。从设备在第一个时钟边沿到来时,才会在MISO线上驱动出MSB。
- 数据采样时刻:数据在时钟的第二个边沿被采样。
- 数据改变时刻:数据在时钟的第一个边沿发生改变。
3.3 模式选择与SS引脚行为差异
这两种模式最直观的差异体现在SS引脚的使用上,这也是配置时最容易出错的地方。
- 当 CPHA = 0 时:SS引脚不仅仅是一个片选信号,它直接参与了传输的启动。SS的下降沿是传输开始的标志。因此,在每个字节传输之间,SS引脚必须被拉高再拉低,以指示下一个字节传输的开始。不能在整个多字节传输过程中保持SS为低。
- 当 CPHA = 1 时:SS引脚仅作为纯粹的片选信号。传输的开始由SPSCK的第一个边沿触发。因此,SS引脚可以在连续的多个字节传输期间一直保持低电平,只要主设备持续提供时钟即可。这使得CPHA=1模式在单主单从、连续传输的场景下更为方便。
下表总结了四种SPI模式:
| 模式 | CPOL | CPHA | 时钟空闲电平 | 数据采样边沿 | 数据改变边沿 | SS引脚要求 (字节间) |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 低电平 | 上升沿 | 下降沿 | 必须翻转 |
| 1 | 0 | 1 | 低电平 | 下降沿 | 上升沿 | 可保持低 |
| 2 | 1 | 0 | 高电平 | 下降沿 | 上升沿 | 必须翻转 |
| 3 | 1 | 1 | 高电平 | 上升沿 | 下降沿 | 可保持低 |
实操心得:如何快速确定主从设备的模式?我有个笨但有效的方法——用逻辑分析仪抓取一段已知正确的通信波形。看时钟空闲时的电平,确定CPOL。再看数据线(通常是MOSI,因为主设备先发起)在时钟第一个边沿时是否稳定,如果数据已经稳定,则是CPHA=0(在第一个边沿采样);如果数据在第一个边沿发生变化,则是CPHA=1(在第二个边沿采样)。记住,主从设备的CPOL和CPHA配置必须完全一致,这是通信成功的铁律。
4. SPI错误处理机制:构建稳健通信的基石
SPI通信并非总是风平浪静,尤其是在复杂的嵌入式系统中,电源波动、信号干扰、软件响应不及时都可能导致错误。MC68HC908MR24的SPI模块提供了两种主要的错误检测机制:溢出错误(OVRF)和模式故障错误(MODF)。理解并妥善处理这些错误,是写出工业级可靠代码的关键。
4.1 溢出错误:数据丢失的隐形杀手
溢出错误(OVRF)发生在接收端。当一个新的字节已经完全移入移位寄存器,准备传输到接收数据寄存器时,如果发现接收数据寄存器里还有一个之前收到的、未被CPU读取的字节,就会发生溢出。
触发条件:当前一个字节的“捕获选通”(对应位1的采样时刻)发生时,SPRF标志位仍为1(表示上一个字节未被读取)。
后果:新移入的字节会被丢弃,无法进入接收数据寄存器。而接收数据寄存器里那个未被读取的旧字节仍然可以读取。OVRF一旦发生,就意味着有数据永久丢失了。
清除方法:OVRF标志位不能直接写0清除。必须按照特定顺序操作:先读取SPSCR寄存器(此时OVRF=1),然后再读取SPDR寄存器。这个操作顺序是硬件规定的,旨在确保软件在清除标志前,已经知晓并处理了溢出状态。
一个隐蔽的陷阱:错过溢出检测数据手册图13-8揭示了一个经典的软件漏洞。假设你只开启了SPRF中断(SPRIE=1)来处理接收完成,而没有开启错误中断(ERRIE=0)。你的中断服务程序(ISR)流程是:读SPSCR(得知SPRF=1),然后读SPDR取数据。这个操作会清除SPRF位。
问题来了:如果在“读SPSCR”和“读SPDR”这两个操作之间,恰好完成了下一个字节的接收,并且触发了OVRF,那么这个OVRF事件就会被完全错过!因为读SPDR的操作只清除了SPRF,并没有清除OVRF(清除OVRF需要先读SPSCR再读SPDR)。由于OVRF未被清除,后续的SPRF中断也无法再产生,系统会悄无声息地丢失后续所有数据,直到OVRF被意外清除。
解决方案:
- 启用错误中断(ERRIE=1):这是最推荐的做法。让OVRF也能产生中断,确保任何错误都能被及时处理。
- 双读SPSCR法:如果因故不能启用错误中断,则必须在中断服务程序中采用“读SPSCR -> 读SPDR -> 再读一次SPSCR”的流程。第二次读SPSCR就是为了检查在读取数据的过程中是否发生了OVRF。如果发现OVRF,则按流程清除它。
4.2 模式故障错误:硬件冲突的防火墙
模式故障错误(MODF)是一种硬件保护机制,用于防止因SPI主从模式配置错误而导致的引脚冲突(多个设备同时驱动同一根线,可能损坏硬件)。
触发条件:
- 对于主设备(SPMSTR=1):当MODFEN=1时,如果其SS引脚被外部拉低,则触发MODF。因为在多主系统中,SS被拉低意味着另一个设备试图成为主机,此时两个主设备同时驱动MOSI和SPSCK会导致冲突。
- 对于从设备(SPMSTR=0):当MODFEN=1时,如果在一次传输过程中(即SPSCK正在活动),其SS引脚被拉高(取消选中),则触发MODF。
MODF发生后的硬件行为(仅对主设备有特殊影响):
- 如果ERRIE=1,会产生SPI接收/错误中断。
- SPE位被自动清零,SPI模块被禁用。这是关键的保护措施!
- SPTE位被置1。
- SPI状态计数器被清零。
- 共享I/O口的数据方向寄存器重新取得对SPI引脚的控制权。
清除方法:MODF的清除流程比OVRF更严格。必须按顺序执行:先读取SPSCR寄存器(此时MODF=1),然后写入SPCR寄存器。并且,在整个清除操作执行期间,不能存在MODF条件(即SS引脚的电平必须处于正确状态),否则标志无法清除。
MODFEN位的妙用:
- 在单主系统中,可以将主设备的MODFEN位清零。这样,主设备的SS引脚就可以被重新用作通用I/O口,同时避免了因意外干扰导致MODF错误和SPI被禁用。
- 对于从设备,无论MODFEN为何值,SS引脚总是作为输入功能,无法用作通用I/O。设置MODFEN=0仅能防止SS引脚电平触发MODF错误,不影响其作为片选输入的功能。
避坑指南:在调试多机SPI通信时,如果发现主设备突然“失声”,SPI发送不出去数据了,第一件事就是去查MODF标志位。很可能是因为SS引脚受到了干扰,或者软件配置冲突,导致SPI模块被硬件自动禁用了。处理完故障源后,需要按照上述流程清除MODF标志,并重新使能SPE位。
5. 中断机制与编程实践
合理利用中断可以极大提高CPU效率,实现非阻塞的SPI通信。MC68HC908MR24的SPI提供了丰富的中断源。
5.1 中断源与使能
SPI有四个状态标志可以产生CPU中断请求,它们通过不同的使能位控制:
| 中断标志 | 含义 | 使能位 | 中断类型 |
|---|---|---|---|
| SPRF | 接收数据寄存器满(收到一个字节) | SPRIE | 接收中断 |
| SPTE | 发送数据寄存器空(可以发送下一个字节) | SPTIE | 发送中断 |
| OVRF | 接收溢出错误 | ERRIE | 接收/错误中断 |
| MODF | 模式故障错误 | ERRIE | 接收/错误中断 |
需要注意的是,OVRF和MODF共享同一个使能位ERRIE和同一个中断向量。这意味着,你的错误中断服务程序需要同时检查OVRF和MODF两个标志位来确定具体的错误类型。
5.2 典型的中断驱动编程流程
下面以一个主设备发送/接收数据的典型场景为例,说明如何编写中断服务程序。
初始化步骤:
- 配置GPIO,将SPI引脚设置为复用功能。
- 配置SPCR寄存器:设置CPOL、CPHA、SPMSTR=1(主模式)、SPE=1(使能SPI)。根据需求设置SPTIE和SPRIE。
- 配置SPSCR寄存器:设置波特率(SPR1:SPR0)。强烈建议设置ERRIE=1以启用错误中断。根据是否需要MODF保护,设置MODFEN。
- 如果需要发送数据,检查SPTE是否为1,然后写入第一个字节到SPDR,启动传输。
发送中断服务程序(SPTE):
void SPI_TX_IRQHandler(void) { if (SPSCR & SPTE_MASK) { // 确认是SPTE中断 if (tx_buffer_index < tx_buffer_length) { SPDR = tx_buffer[tx_buffer_index++]; // 写入下一个字节 } else { // 发送完成,可以关闭SPTIE中断或设置完成标志 SPCR &= ~SPTIE_MASK; transmission_complete = true; } // 清除SPTE标志:读SPSCR,然后读SPDR(对于发送中断,读SPDR是常规操作) volatile uint8_t dummy = SPSCR; dummy = SPDR; // 读SPDR以完成标志清除序列(如果关联接收的话) } }接收/错误中断服务程序(SPRF & ERRIE):
void SPI_RX_ERR_IRQHandler(void) { uint8_t status = SPSCR; // 1. 首先处理错误!顺序很重要。 if (status & OVRF_MASK) { // 发生溢出错误 handle_overflow_error(); // 清除OVRF: 读SPSCR (已读),再读SPDR volatile uint8_t dummy = SPDR; } if (status & MODF_MASK) { // 发生模式故障 handle_mode_fault_error(); // 清除MODF: 读SPSCR (已读),再写SPCR SPCR |= (1 << SPE); // 示例:重新使能SPI,同时完成清除操作 } // 2. 处理正常接收数据 if (status & SPRF_MASK) { rx_buffer[rx_buffer_index++] = SPDR; // 读取数据,同时清除SPRF // 为防止错过OVRF,遵循“双读”原则(如果ERRIE已开启则可简化) status = SPSCR; // 再次读取状态,检查在刚才读数据时是否发生了OVRF if (status & OVRF_MASK) { handle_overflow_error(); dummy = SPDR; } } }重要提示:上述代码中,清除OVRF和MODF的特定序列必须严格遵守。同时,在接收中断中采用“双读SPSCR”的策略,是构建鲁棒性代码的防御性编程技巧,即使开启了ERRIE,这样做也多了一层保护。
6. 低功耗模式与复位管理
在电池供电或低功耗应用中,SPI模块的功耗管理也不容忽视。
等待模式(WAIT):执行WAIT指令后,CPU进入低功耗待机模式,但SPI模块仍然保持活动状态。这意味着SPI可以继续收发数据,并在完成后通过中断唤醒CPU。如果不需要SPI在待机时工作,应在进入WAIT模式前清除SPE位以关闭SPI模块,降低功耗。
复位:SPI模块有两种复位方式。
- 系统复位:复位所有寄存器,包括控制位和状态标志。
- 部分复位:当SPE位被软件清零时触发。部分复位会中止当前传输、清空移位寄存器、复位状态计数器,并将引脚控制权交还给GPIO。但控制位(SPCR, SPSCR中的配置位)和错误标志(SPRF, OVRF, MODF)不会被清除。这个特性很有用,允许你在传输间隙临时禁用SPI以省电,重新使能时无需重新配置所有参数。
Break模式:在Break模式下,如果BCFE位未置位,则对SPDR的写入操作是无效的,既不会启动传输,数据也不会进入移位寄存器。这在调试时需要留意。
7. 高级应用与配置技巧
7.1 模拟I2C通信
数据手册提到,通过设置SPWOM位,可以将MOSI引脚配置为开漏输出,从而在软件的支持下,让SPI主设备具备与I2C从设备通信的有限能力。这通常需要软件精确地控制SPSCK来模拟I2C的时钟,并利用开漏输出的MOSI线实现双向数据线(需外接上拉电阻)。这是一种非常规用法,仅适用于简单的、单主机的I2C环境,对时序要求苛刻,一般不推荐在新设计中使用,但在资源极其受限或需要兼容旧设计时,可以作为一个备选方案。
7.2 多从机系统设计
设计多从机SPI系统时,需注意以下几点:
- SS片选管理:每个从设备需要独立的SS线。主设备通过GPIO控制这些SS线。确保在任何时刻,只有一条SS线处于有效(低电平)状态。
- MISO线冲突:所有从设备的MISO引脚应并联到主设备的MISO。必须确保未被选中的从设备其MISO输出为高阻态。MC68HC908MR24的SPI模块在SS为高时自动将MISO置为高阻态,符合这一要求。
- 上拉电阻:在MOSI、MISO、SPSCK线上通常不需要上拉电阻。但在SS线上,根据情况可以考虑加上拉电阻,确保在GPIO初始化完成前或异常状态下,从设备处于未选中状态。
- 布线考虑:SPSCK是高速时钟信号,布线时应尽量短,并远离模拟或高频干扰源。多个从设备应尽量靠近主设备,采用星型或菊花链拓扑(后者需设备支持)。
7.3 时序裕量与信号完整性
在高速SPI通信(例如时钟>10MHz)或长距离连接时,信号完整性成为挑战。
- 时钟抖动与偏移:SPSCK到达不同从设备的时间可能存在微小差异(时钟偏移)。这要求数据在时钟边沿必须有一段稳定的建立时间和保持时间。CPHA的配置直接决定了数据相对于时钟边沿的稳定窗口。
- PCB布局:SPI信号线应走阻抗受控的微带线,并保持等长(特别是SCK和对应的数据线),以减少信号畸变。在信号末端可考虑串联一个小电阻(如22-33欧姆)进行阻抗匹配,抑制反射。
- 用示波器调试:当通信不稳定时,最好的工具是示波器。测量SPSCK和MOSI/MISO信号,观察数据在采样边沿是否稳定。检查建立时间和保持时间是否满足从设备数据手册的要求。如果发现振铃或过冲,可能需要调整端接电阻或布线。
8. 实战问题排查与调试心法
理论最终要服务于实践。下面是我在多年调试中总结的一些常见问题场景和排查思路。
问题一:通信完全无反应,收不到任何数据。
- 检查清单:
- 电源与地:最基础也最易忽略。确保主从设备共地,电源电压正常。
- 引脚配置:确认SPI模块已使能(SPE=1),且引脚已正确配置为SPI复用功能,而非普通GPIO。
- 主从模式:确认主设备的SPMSTR=1,从设备的SPMSTR=0。
- SS引脚:
- 对于从设备,测量SS引脚是否被正确拉低。如果CPHA=0,检查SS是否在每个字节间有高低电平切换。
- 对于主设备,检查MODF标志。如果MODF=1且MODFEN=1,说明SS被拉低,SPI可能已被禁用。排查硬件短路或软件误配置。
- 时钟与模式:用逻辑分析仪或示波器抓取SPSCK、MOSI、SS波形。确认CPOL和CPHA设置与从设备要求一致。确认时钟频率是否在从设备支持的范围内。
- 软件流程:主设备是否成功写入了SPDR启动了传输?是否在等待SPTE或SPRF标志?中断是否正确使能和响应?
问题二:能收到数据,但数据错误或错位。
- 排查方向:
- CPHA/CPOL不匹配:这是最常见的原因。用逻辑分析仪对照数据手册的时序图,一个边沿一个边沿地核对。重点看数据在采样边沿是否稳定。
- 字节序(Endianness):SPI协议通常规定先传输最高位(MSB First),但有些设备可能支持或要求最低位优先(LSB First)。检查设备数据手册。
- 时钟极性干扰:在极高频率下,时钟信号的上升/下降时间过长,可能导致采样点模糊。尝试降低时钟频率。
- 软件读取时机:确保在SPRF置起后尽快读取SPDR。如果使用查询方式,循环等待SPRF的时间不能过长,以免发生溢出。
问题三:连续传输一段时间后,通信突然停止。
- 高度怀疑对象:
- 溢出错误(OVRF):检查OVRF标志。如果置位,说明接收端处理速度跟不上发送端。优化你的接收代码(如使用DMA或更高效的中断),或者降低发送速率。
- 模式故障(MODF):检查MODF标志。可能是在传输过程中SS线受到了干扰(如毛刺)。
- 缓冲区管理:在中断服务程序中,确保在写入下一个发送字节前,SPTE标志为1。在读取接收数据前,SPRF标志为1。错误的顺序会导致数据覆盖或丢失。
问题四:多从机系统中,某个从设备无法被选中。
- 排查步骤:
- 隔离测试:单独连接该从设备与主设备,测试能否通信。排除从设备本身故障。
- SS线检查:测量该从设备SS引脚上的电平。确认主设备对应的GPIO输出驱动能力足够,且在选中时能可靠拉低到GND(电压值接近0V)。
- 总线冲突:使用示波器同时观察MISO线。当选中该设备时,MISO线是否有数据波形?当选中其他设备时,该设备的MISO线是否为高阻态(表现为一条被轻微上拉的水平线)?如果发现未被选中时MISO也有驱动,说明该从设备的MISO高阻态控制可能有问题。
调试SPI,逻辑分析仪是你的最佳伙伴。它能直观地展示四根线上的每一个比特,让你清晰地看到时序关系、数据内容以及错误发生的瞬间。养成在出问题时第一时间抓波形的习惯,能节省大量盲目猜测的时间。记住,嵌入式调试,眼见为实。
