2. SPI控制器核心寄存器详解
各位同学,今天我们来聊聊SPI控制器里最核心的几个寄存器。说实话,我刚入行那会儿,面对一堆寄存器也是头大。但后来我发现,只要搞懂了四个关键寄存器——控制寄存器、状态寄存器、数据寄存器和时钟分频寄存器,SPI这块基本就通了八成。
2.1 控制寄存器(CR)—— 指挥中心
控制寄存器,说白了就是SPI模块的「总开关」和「模式选择器」。你想想看,一个SPI设备要工作,总得告诉它:你是主机还是从机?数据是从高位传还是低位传?时钟极性怎么设?这些都由CR来决定。
CR寄存器典型位域定义(32位为例):
| 位域 | 名称 | 功能描述 |
|---|---|---|
| [0] | SPI_EN | SPI使能位,1使能,0关闭 |
| [1] | MST_SLV | 主从选择,1为主机,0为从机 |
| [2] | CPOL | 时钟极性,0空闲低电平,1空闲高电平 |
| [3] | CPHA | 时钟相位,0第一个边沿采样,1第二个边沿采样 |
| [4] | LSB_FIRST | 数据顺序,0 MSB先传,1 LSB先传 |
| [7:5] | DATA_WIDTH | 数据宽度,000=8位,001=16位,010=32位 |
我个人习惯,配置CR时先关掉SPI_EN,把所有参数设好,最后再使能。为什么?因为如果在配置过程中SPI已经在工作,可能会产生错误的传输。我在项目中遇到过,有同事在SPI正在传输时改了CPOL,结果从机直接罢工,排查了半天才发现是这个问题。
小技巧:配置CR时,建议用读-改-写的方式,不要直接写死整个寄存器。比如只改CPOL位,其他位保持不变。这样能避免误操作。
2.2 状态寄存器(SR)—— 实时反馈
状态寄存器就像SPI模块的「仪表盘」,告诉你当前工作状态。你发了一个数据,到底发完没有?接收缓冲区有没有数据?有没有发生错误?这些信息都在SR里。
常用的状态位有这么几个:
- BUSY位:SPI正在传输中。我建议你在发送数据前先检查这个位,确保前一次传输已完成。
- TX_EMPTY位:发送缓冲区为空。可以往数据寄存器写新数据了。
- RX_FULL位:接收缓冲区有数据。赶紧读走,不然下一个数据来了会覆盖。
- OVR_ERR位:溢出错误。接收缓冲区满了,新数据又来了。嗯,这个要特别注意。
避坑指南:我曾经在一个高速数据采集项目中,因为没及时读RX_FULL标志,导致连续两次溢出错误,丢了一整帧数据。后来我养成了习惯:每次传输完成后,强制检查OVR_ERR位,如果有错误就重新发起传输。
状态寄存器通常是只读的,你只能看,不能写。但有些芯片设计会允许写某些位来清除中断标志,这个要看具体的数据手册。
2.3 数据寄存器(DR)—— 数据通道
数据寄存器是SPI模块的「数据窗口」。你要发送的数据写进去,接收到的数据从里面读出来。就这么简单。
但这里有个坑:很多芯片的发送寄存器和接收寄存器是同一个地址。你写它就是发送,你读它就是接收。为什么会这样?因为SPI是同步传输,你发一个字节的同时,也会收到一个字节。所以用一个寄存器就够了。
// 典型的数据收发流程
void spi_transfer(uint8_t tx_data, uint8_t *rx_data) {
// 等待发送缓冲区空
while (!(SPI_SR & TX_EMPTY_MASK));
// 写入发送数据
SPI_DR = tx_data;
// 等待接收缓冲区满
while (!(SPI_SR & RX_FULL_MASK));
// 读取接收数据
*rx_data = SPI_DR;
}
你看这段代码,先等发送空,再写数据,再等接收满,最后读数据。这个流程我用了十年,基本没出过问题。但要注意,有些芯片的TX_EMPTY和RX_FULL是同一个位,读和写要区分清楚。
2.4 时钟分频寄存器(CKDIV)—— 速度控制
时钟分频寄存器决定了SPI的通信速率。SPI的时钟源通常来自系统时钟或PLL输出,经过分频后得到SCK信号。
公式很简单:
SCK频率 = 时钟源频率 / (2 * (CKDIV + 1))
举个例子,如果时钟源是100MHz,CKDIV设为9,那么SCK频率就是:
SCK = 100MHz / (2 * (9 + 1)) = 100MHz / 20 = 5MHz
配置CKDIV时要注意几点:
- 不要超过从机支持的最大频率。我见过有人把SCK设到50MHz,结果从机是10MHz的旧芯片,通信全是乱码。
- 考虑PCB走线长度。频率越高,信号完整性越差。如果走线超过10cm,建议SCK不要超过20MHz。
- 和PLL时钟配合。如果PLL输出频率变了,CKDIV也要相应调整,否则SCK频率会漂移。
实战经验:我在调试一个ADC采集板时,SPI时钟设到了30MHz,结果数据偶尔出错。用示波器一看,SCK信号上升沿有回勾,是阻抗不匹配导致的。后来把CKDIV调到15MHz,问题就解决了。有时候,慢一点反而更可靠。
2.5 四个寄存器的协同工作
这四个寄存器不是孤立的,它们配合起来才能完成一次完整的SPI传输。我画了一张图,帮你理清它们的关系:
从这张图可以看出,CR是总指挥,决定了SPI的工作模式;CKDIV是速度调节器,决定了SCK的快慢;SR是状态反馈,告诉你什么时候可以读写;DR是数据通道,负责数据的进出。四个寄存器环环相扣,缺一不可。
好了,这一章的内容就到这里。记住这四个寄存器,SPI控制器的核心你就掌握了。下一章我们会结合PLL时钟,讲讲如何配置时钟分频来匹配不同的外设需求。
可可精品资料库