2. SPI数据帧格式:8位/16位数据帧、MSB/LSB先行、时钟极性与相位对数据采样的影响
好,咱们接着聊SPI。上一章我们把SPI的四根线讲清楚了,这一章我重点说说数据到底怎么在线上跑。说白了,就是数据帧的格式问题。很多新手调SPI,调不通的原因往往不是硬件接错了,而是主从设备的帧格式没对上。我当年刚入行时就吃过这个亏,折腾了一整天,最后发现是MSB/LSB顺序搞反了。
2.1 数据帧长度:8位还是16位?
SPI协议本身没有规定一次必须传多少位。最常见的当然是8位,也就是一个字节。但很多MCU的SPI外设也支持16位帧格式。你想想看,如果你的传感器输出的是12位或16位数据,用8位帧就得传两次,还得拼数据,多麻烦。
核心要点:8位帧兼容性最好,16位帧效率更高。选择取决于外设的数据宽度。
我个人习惯是:如果从设备的数据寄存器是16位的,我优先用16位帧。比如一些高精度ADC、DAC、陀螺仪,它们的数据手册里明确写了“16-bit data word”,那就别硬拆成两个8位去传。
| 帧格式 | 典型应用场景 | 优点 | 缺点 |
|---|---|---|---|
| 8位 | Flash存储器、温度传感器、通用外设 | 兼容性极广,几乎所有SPI设备都支持 | 传16位数据需两次传输,软件拼接麻烦 |
| 16位 | 音频Codec、高精度ADC/DAC、陀螺仪 | 一次传输完成16位数据,效率高 | 部分低端MCU不支持,或需特殊配置 |
小技巧:配置寄存器时,注意看SPI_CR1或SPI_CR2里的DFF位(Data Frame Format)。置1选16位,清0选8位。切换帧格式时,最好先把SPI外设禁能,改完再使能,否则容易出乱子。
2.2 位序:MSB先行还是LSB先行?
这个问题看似简单,但坑不少。SPI默认是MSB先行,也就是最高位先传。大多数设备都遵循这个约定。但有些奇葩外设,比如某些LED驱动芯片、LCD控制器,偏偏要用LSB先行。
为什么会这样?有些芯片内部的数据移位寄存器是从低位开始处理的,所以它们希望LSB先到。嗯,这里要注意:如果你主设备用MSB,从设备用LSB,那收到的数据就是反的。比如你想发0x80(二进制1000 0000),结果从设备收到的是0x01(0000 0001)。
避坑指南:我曾经在一个项目里,用STM32的SPI驱动一个LED点阵屏。屏幕怎么点都不亮,逻辑分析仪抓波形发现数据完全反了。查了三天手册,才发现那个LED驱动芯片要求LSB先行。把SPI的LSBFIRST位置1,问题立刻解决。
配置位序的寄存器位通常叫LSBFIRST或类似的名称。置1表示LSB先行,清0表示MSB先行。我建议你养成一个习惯:拿到一个新外设,第一件事就是看数据手册里关于数据格式的章节,确认位序。
2.3 时钟极性与相位:数据采样的关键
这部分是SPI协议里最容易让人晕的地方。时钟极性(CPOL)和时钟相位(CPHA)组合出四种模式。很多工程师把这四种模式背得滚瓜烂熟,但一到实际调试还是抓瞎。我换个角度给你讲,保证你听完就懂。
2.3.1 时钟极性(CPOL)
CPOL决定的是时钟空闲时的电平。说白了就是:没有数据传输时,SCK线是高电平还是低电平?
- CPOL = 0:空闲时SCK为低电平。时钟脉冲是一个从低到高再回低的波形。
- CPOL = 1:空闲时SCK为高电平。时钟脉冲是一个从高到低再回高的波形。
这个很好理解,对吧?
2.3.2 时钟相位(CPHA)
CPHA才是真正的难点。它决定的是数据在时钟的哪个边沿被采样。注意,是采样,不是输出。
- CPHA = 0:数据在时钟的第一个边沿被采样。第一个边沿可能是上升沿(CPOL=0时),也可能是下降沿(CPOL=1时)。
- CPHA = 1:数据在时钟的第二个边沿被采样。
你想想看,第一个边沿和第二个边沿,差了一个时钟周期。如果主从设备的CPHA没对上,数据就会错位一个时钟周期,结果就是全乱套。
记住这个口诀:CPHA=0,第一个边沿采样;CPHA=1,第二个边沿采样。采样边沿和CPOL无关,只和CPHA有关。
2.3.3 四种模式组合
| 模式 | CPOL | CPHA | 空闲时钟电平 | 数据采样边沿 | 数据输出边沿 |
|---|---|---|---|---|---|
| 模式0 | 0 | 0 | 低 | 上升沿(第一个边沿) | 下降沿 |
| 模式1 | 0 | 1 | 低 | 下降沿(第二个边沿) | 上升沿 |
| 模式2 | 1 | 0 | 高 | 下降沿(第一个边沿) | 上升沿 |
| 模式3 | 1 | 1 | 高 | 上升沿(第二个边沿) | 下降沿 |
最常用的模式是模式0和模式3。很多Flash芯片、SD卡都默认用模式0。但别想当然,一定要看数据手册。
2.4 实际配置中的注意事项
配置SPI数据帧格式时,我建议你按这个顺序来检查:
- 先看从设备数据手册,找到SPI时序图。图上会明确标出CPOL和CPHA的值。
- 确认数据帧长度,是8位还是16位。
- 确认位序,MSB还是LSB先行。
- 配置MCU的SPI寄存器,让主从设备完全一致。
- 用逻辑分析仪抓波形验证,别光靠眼睛看代码。
重要提醒:有些MCU的SPI外设,在改变CPOL或CPHA后,必须重新初始化才能生效。我遇到过的情况是:改了寄存器但没重新使能SPI,结果波形还是老样子。调试了半天才发现是这个问题。