3. SPI数据帧格式:数据位宽、MSB/LSB优先、传输字节序与数据对齐
各位同学,咱们接着聊SPI。上一节我们把SPI的四种模式(CPOL/CPHA)讲透了,这节我重点说说数据帧格式。说白了,就是数据在线上怎么排、怎么对齐、先发哪一位。这些细节,我在实际项目中踩过不少坑,今天一并分享给你们。
3.1 数据位宽:8位、16位、32位
SPI协议本身对数据位宽没有硬性规定。你可以发任意位宽的数据。但实际工程中,最常用的就是8位、16位和32位。为什么?因为大多数MCU和FPGA的寄存器、内存、总线都是这些宽度。
8位位宽:最常见。比如你读写一个8位的传感器寄存器,一次传8个bit,干净利落。我早期做的一个项目,用SPI控制一个8位ADC,每次读回来的数据就是8位,直接存进一个byte变量里,省事。
16位位宽:常用于配置寄存器较多的芯片。比如一些高精度ADC、DAC,或者带SPI接口的LCD驱动芯片。我记得有一次调试一个16位DAC,它的配置寄存器就是16位宽,我直接用16位SPI传输,一次搞定,不用拼两次8位数据。
32位位宽:多用于高速数据传输,比如SPI Flash、FPGA之间的高速通信。32位一次传完,效率高。但要注意,很多SPI从机不支持32位,你得看数据手册。
核心原则:从机支持多少位,你就发多少位。别自作主张。我曾经因为没仔细看手册,用32位去读一个只支持8位的传感器,结果读回来的数据全是乱的,排查了半天才发现是位宽不匹配。
3.2 MSB优先 vs LSB优先
这个知识点,说白了就是:你先发最高位(MSB),还是先发最低位(LSB)?
MSB优先:先发数据的最高位(bit 7、bit 15、bit 31)。这是SPI最常用的方式。绝大多数SPI从机都默认MSB优先。你想想看,我们写数字的时候,习惯从左到右写高位到低位,MSB优先符合这个直觉。
LSB优先:先发数据的最低位(bit 0)。这个用得少,但有些芯片偏偏就喜欢LSB优先。比如某些老式的SPI EEPROM,或者一些特殊的加密芯片。我遇到过一款SPI加密芯片,数据手册上写着“LSB first”,我当时没注意,按MSB发数据,结果加密结果一直不对,折腾了两天才发现是顺序反了。
我的建议:设计SPI控制器时,最好在寄存器里加一个“MSB/LSB选择位”。这样你可以灵活切换,不用改硬件。我在FPGA里就是这么做的,一个bit控制移位方向,省心。
3.3 传输字节序:大端与小端
当你的数据位宽超过8位(比如16位或32位)时,就涉及字节序的问题了。字节序,就是多字节数据在SPI线上传输时,哪个字节先发。
大端序(Big-Endian):先发高字节,再发低字节。比如0x1234,先发0x12,再发0x34。这是SPI最常用的字节序。大多数SPI Flash、ADC、DAC都采用大端序。
小端序(Little-Endian):先发低字节,再发高字节。比如0x1234,先发0x34,再发0x12。这个在SPI里用得少,但有些芯片(尤其是和ARM Cortex-M系列配合的)会采用小端序。
| 字节序 | 数据0x1234传输顺序 | 常见应用 |
|---|---|---|
| 大端序 | 0x12 → 0x34 | SPI Flash、ADC、DAC |
| 小端序 | 0x34 → 0x12 | 部分ARM外设、加密芯片 |
注意:字节序和MSB/LSB优先是两个独立的概念。MSB/LSB优先决定一个字节内部bit的发送顺序;字节序决定多个字节之间的发送顺序。别搞混了。我曾经见过一个工程师,把MSB优先和大端序当成一回事,结果数据全乱了。
3.4 数据对齐方式
数据对齐,说白了就是:当你的数据位宽和SPI控制器位宽不一致时,数据怎么放?
左对齐:数据放在高位,低位补0。比如你有一个10位的ADC数据,要放在16位的SPI帧里,那就把10位数据放在bit15~bit6,bit5~bit0补0。这样接收方拿到16位数据后,右移6位就能得到原始10位数据。
右对齐:数据放在低位,高位补0。还是那个10位ADC数据,放在16位帧里,就放在bit9~bit0,bit15~bit10补0。接收方直接取低10位即可。
居中对齐:数据放在中间,两边补0。这个用得少,但有些特殊协议会要求。比如某些音频Codec,数据是20位,放在32位帧里,就放在bit25~bit6,两边各补3个0。
实战经验:我个人习惯用左对齐。为什么?因为很多SPI从机(尤其是ADC)的数据手册里,给出的数据格式就是左对齐。你按左对齐发,直接移位就能用,省去一次乘法或除法。但如果你用的从机是右对齐,那就按右对齐来。一切以数据手册为准。
3.5 知识体系总览
下面我用一张图把SPI数据帧格式的核心逻辑串起来。你一看就明白。
这张图从上到下,就是SPI数据帧格式的决策流程。你先确定位宽,再决定MSB还是LSB优先,然后看字节序,最后考虑对齐方式。每一步都影响最终的数据传输正确性。
3.6 避坑指南
最后,我总结几个实战中容易踩的坑,你们记一下:
- 位宽不匹配:从机只支持8位,你非要用16位发,数据会错位。我曾经在调试一个SPI温度传感器时犯过这个错,浪费了半天。
- MSB/LSB搞反:有些芯片数据手册写得不清楚,你得仔细看。我建议你在设计时加一个可配置的移位方向寄存器,方便调试。
- 字节序忽略:16位或32位传输时,字节序错了,数据就全反了。尤其是和不同架构的芯片通信时(比如ARM和FPGA),一定要确认字节序。
- 对齐方式误解:左对齐和右对齐,差一个移位操作。如果你接收方没做对应的移位,数据就是错的。我习惯在SPI控制器的接收FIFO里直接做移位对齐,这样CPU读到的数据就是对齐好的,省去软件处理。
我的习惯:每次拿到一个新芯片的SPI接口,我第一件事就是画一个时序图,把位宽、MSB/LSB、字节序、对齐方式全部标出来。然后写一个简单的回环测试程序,发一个已知数据,看读回来的是不是一样的。这样能快速验证配置是否正确。
好了,SPI数据帧格式就讲到这里。这些细节看似琐碎,但每一个都直接影响通信的正确性。你们在实际项目中,一定要养成看数据手册、画时序图的好习惯。嗯,今天就到这儿。