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传输。我画了一张图,帮你理清它们的关系:

SPI控制器核心寄存器协同工作图 控制寄存器 (CR) 模式选择 · 使能控制 状态寄存器 (SR) 忙标志 · 空/满标志 数据寄存器 (DR) 发送/接收数据 时钟分频 (CKDIV) SCK频率控制 配置状态 触发读写 分频配置 产生SCK 配置流程:CR设置模式 → CKDIV设置速率 → 查询SR状态 → 读写DR数据 配置路径 数据路径 时钟路径

从这张图可以看出,CR是总指挥,决定了SPI的工作模式;CKDIV是速度调节器,决定了SCK的快慢;SR是状态反馈,告诉你什么时候可以读写;DR是数据通道,负责数据的进出。四个寄存器环环相扣,缺一不可。

好了,这一章的内容就到这里。记住这四个寄存器,SPI控制器的核心你就掌握了。下一章我们会结合PLL时钟,讲讲如何配置时钟分频来匹配不同的外设需求。


可可精品资料库