3、SPI数据帧格式:MSB/LSB先行、数据位宽与连续传输
SPI通信,说白了就是主从设备之间互相倒腾数据。但怎么倒腾、先倒腾哪一位、一次倒腾多少位,这些细节决定了你的驱动能不能正常工作。我见过不少工程师,时序调了半天,最后发现是数据帧格式配错了——这种坑,踩一次就记住了。
3.1 MSB先行 vs LSB先行:谁先谁后?
SPI协议本身没规定数据必须从哪一位开始传。但大多数设备默认MSB先行(Most Significant Bit First),也就是先传最高位。比如你要传0x53(二进制0101 0011),MSB模式下先传bit7(0),再传bit6(1),以此类推。
LSB先行则反过来,先传bit0(1),再传bit1(1)……最后传bit7(0)。
我在项目中遇到过一款温湿度传感器,数据手册里写着“Data is transmitted MSB first”,结果我按LSB配了,读回来的温度值一直在乱跳。排查了两天才发现是位序问题。嗯,从那以后我拿到新芯片第一件事就是确认位序配置。
MCU中的配置方式
以STM32为例,SPI_CR1寄存器里的LSBFIRST位控制这个:
// MSB先行(默认)
SPI1->CR1 &= ~SPI_CR1_LSBFIRST;
// LSB先行
SPI1->CR1 |= SPI_CR1_LSBFIRST;
其他MCU也大同小异,无非是寄存器名不同。配置前一定去翻数据手册的SPI章节,别凭经验猜。
| 位序模式 | 发送0x53(0101 0011) | 典型应用 |
|---|---|---|
| MSB先行 | 0 → 1 → 0 → 1 → 0 → 0 → 1 → 1 | 大多数SPI设备、Flash、ADC |
| LSB先行 | 1 → 1 → 0 → 0 → 1 → 0 → 1 → 0 | 部分LCD驱动、某些传感器 |
3.2 数据位宽:8位、16位还是32位?
SPI帧的数据位宽决定了每次传输交换多少位数据。常见的有8位、16位,部分MCU支持32位甚至可编程位宽。
你想想看,如果从设备寄存器是16位的,你用8位帧去读,就得读两次再拼起来。麻烦不说,还容易出错。
配置示例(STM32)
// 8位数据帧
SPI1->CR1 &= ~SPI_CR1_DFF; // DFF=0
// 16位数据帧
SPI1->CR1 |= SPI_CR1_DFF; // DFF=1
对于支持32位的MCU(比如NXP的LPC系列),配置方式类似,但寄存器名可能叫DSS(Data Size Select)。
3.3 连续传输与片选控制
连续传输,也叫多字节传输,指的是在片选信号持续有效的情况下,连续发送多个数据帧。这在访问Flash、SD卡等需要批量读写的场景下特别常见。
片选信号(CS/SS)的作用是告诉从设备:“我要跟你说话了”。正常情况下,每次传输开始前拉低CS,传输结束后拉高CS。
但在连续传输模式下,CS在整个传输过程中保持低电平,直到所有数据传完才释放。
为什么需要连续传输?
- 效率高:省去了每次传输都重新拉低CS的开销
- 原子操作:某些命令(如Flash的Page Program)要求CS在整个命令+地址+数据期间不能拉高
- 时序要求:部分从设备在CS拉高后会立即复位内部状态机
MCU中的实现方式
大多数MCU的SPI外设支持连续传输。以STM32为例,只要在TXE(发送缓冲区空)标志置位时及时写入新数据,SPI就会自动连续发送,CS由硬件自动控制(如果开启了硬件CS管理)。
// 连续发送3个字节
SPI1->CR1 |= SPI_CR1_SPE; // 使能SPI
// 发送第一个字节
while(!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = 0x01;
// 发送第二个字节(CS保持低)
while(!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = 0x02;
// 发送第三个字节
while(!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = 0x03;
// 等待传输完成
while(SPI1->SR & SPI_SR_BSY);
// 此时硬件自动拉高CS(如果配置了硬件CS)
3.4 知识结构图
下面这张图把SPI数据帧格式的核心要素串起来了,方便你对照理解:
3.5 常见配置组合速查表
实际项目中,不同外设对数据帧格式的要求差异很大。我整理了一张速查表,方便你快速对照:
| 外设类型 | 位序 | 位宽 | 传输模式 | CS控制 |
|---|---|---|---|---|
| W25Qxx Flash | MSB | 8位 | 连续 | 硬件CS |
| ADXL345 加速度计 | MSB | 8位 | 单次/连续 | 软件CS |
| MAX7219 LED驱动 | MSB | 16位 | 单次 | 软件CS |
| SD卡(SPI模式) | MSB | 8位 | 连续 | 硬件CS |
| 某些LCD驱动 | LSB | 8位/16位 | 单次 | 软件CS |
好了,SPI数据帧格式的核心内容就这些。记住三个关键点:位序要匹配、位宽要对齐、CS控制要符合从设备要求。这三样配对了,SPI通信就成功了一大半。