SPI协议高级应用:主从模式、FIFO管理与Turbo模式配置详解
2026/7/22 1:51:07 网站建设 项目流程

1. SPI协议核心与高级模式概览

在嵌入式开发领域,串行外设接口(SPI)几乎是工程师的“瑞士军刀”。它不像I2C那样需要复杂的地址协议,也不像UART那样依赖精确的波特率匹配。SPI以其简单、高速、全双工的特性,成为连接Flash、传感器、显示屏、音频编解码器等外设的首选。但很多人对SPI的理解可能还停留在“四根线(SCLK, MOSI, MISO, CS)和模式(CPOL, CPHA)”的层面,实际上,现代微控制器(MCU)中的SPI控制器,尤其是像TI这类厂商提供的,其功能深度远超基础应用。今天,我们就深入聊聊SPI的主从模式、内置FIFO的管理艺术,以及能显著提升性能的Turbo模式配置。这些高级功能,是你在处理高速数据流、优化CPU负载或设计复杂多从机系统时必须掌握的利器。

简单来说,SPI通信就像一场由主设备(Master)指挥的“数据舞会”。主设备通过产生时钟(SCLK)来控制节奏,并通过片选信号(CS)邀请特定的从设备(Slave)共舞。数据在MOSI(主出从入)和MISO(主入从出)线上同步交换。然而,在实际项目中,你可能会遇到各种复杂场景:比如主设备只需要监听传感器数据而无需发送命令(接收模式);或者需要以最高效率连续传输一大块数据到LCD屏(Turbo模式配合FIFO);又或者需要连接多个从设备但希望简化硬件布线(3线模式)。这些场景,都需要你深入SPI控制器的寄存器配置层面,而不仅仅是调用HAL库的HAL_SPI_TransmitReceive函数。

2. 主设备工作模式深度解析

2.1 主设备接收模式(Master Receive-Only Mode)

当你只需要从从设备(比如一个只输出的ADC或温度传感器)读取数据,而不需要发送任何命令时,主设备接收模式就是为优化这种场景而生的。它的核心价值在于最小化CPU干预和数据搬运

在标准的主设备收发模式下,即使你只想接收,通常也需要向发送寄存器(TX)写入一个虚拟数据(如0xFF或0x00)来产生时钟,从而驱动从设备输出数据。这会导致不必要的CPU写操作和潜在的数据总线占用。接收模式通过配置通道配置寄存器MCSPI_CH(i)CONF中的TRM位来启用。

在此模式下,调度器(决定哪个通道能使用移位寄存器)的规则发生了变化。它只关心接收寄存器(RX)是否为空。一旦接收寄存器为空,该通道就有资格被调度,从而启动一次数据传输。此时,发送寄存器(TX)的内容(可能是上次写入的旧数据或未定义值)会被加载到移位寄存器并发送出去,但这纯粹是为了产生时钟信号,其数据内容通常被忽略。

注意:启用接收模式后,发送寄存器状态位TX_EMPTYTX_UNDERFLOW在首次加载后永远不会被置位。因为控制器认为发送寄存器始终是“满”的(内容被锁定用于产生时钟),所以不会产生发送空或下溢中断。你需要通过接收寄存器状态位RX_FULL或移位完成标志EOT来判断一次传输的完成。

实操心得:这个模式在读取只读设备时非常高效。但务必注意,你仍然需要预先向发送寄存器写入一次数据(任何值均可),以提供首次传输的时钟源。之后,控制器会自动维持这个发送数据用于后续传输。如果你的从设备需要在每次传输前接收一个特定的命令字(例如读取特定寄存器的指令),那么这个模式就不适用了,你需要使用标准的收发模式。

2.2 单通道主模式与片选保持(Single-Channel Master & Keep CS Active)

当SPI总线上只有一个从设备,或者某一时刻只与一个从设备通信时,可以启用单通道主模式(设置MCSPI_MODULCTRL[SINGLE] = 1)。这不仅仅是简化操作,它解锁了一个强大功能:手动控制片选(CS)信号,实现连续传输而无须在字与字之间反复拉高、拉低CS。

这有什么用呢?想象一下向一个图形显示器的GRAM连续写入像素数据,或者向一个DAC发送连续的音频采样流。如果每传输一个16位字都切换一次CS,会产生大量无用的时间开销(CS建立和保持时间)。保持CS持续有效,可以最大化总线利用率。

启用此功能需在4线模式(PIN34=0)下,并将MCSPI_CHxCONF[FORCE]位用于控制CS线电平。例如,设置FORCE=1EPOL=0,会使对应的SPI_SCS[n]线输出高电平(有效)。一旦使能该通道(EN=1),CS线就会按照设定的极性激活。此后,只要发送寄存器或FIFO非空,数据传输就会一个接一个地进行,CS线始终保持有效,直到你手动禁用通道或将FORCE位清零。

关键配置步骤与陷阱

  1. 配置先行:必须在使能通道之前,完成所有传输参数的配置,包括字长(WL)、时钟极性与相位(POL, PHA)、以及FORCEEPOL。通道使能后,修改这些关键参数可能导致当前传输损坏。
  2. 动态修改限制:文档明确指出,当CS信号处于激活状态时,绝对不能修改EPOL(CS极性)、POL(时钟极性)和PHA(时钟相位)。TRM(传输模式)也只能在通道禁用时修改。但你可以安全地禁用再重新使能通道,而CS线会保持激活状态。
  3. 软件责任:如果你需要在一次CS有效期间切换传输模式(例如,先发一个命令字,紧接着发数据字),你必须在两个字传输之间的空闲时间里,通过软件禁用通道、修改TRM模式、再使能通道。这个时间窗口的把握是你的责任,需要确保大于从设备所需的最短CS无效时间(如果设备有要求)。

2.3 吞吐量加速器:Turbo模式解析

Turbo模式是提升SPI接口吞吐量的“性能模式”。在普通的多通道轮询模式下,一个通道只有在它的接收寄存器为空且发送寄存器为满时,才有机会被调度使用共享的移位寄存器。这就像只有一个收银台(移位寄存器),多个顾客(通道)必须排队,且每次只能结算一件商品(一个SPI字)。

Turbo模式改变了游戏规则。当仅使能单个通道并开启Turbo模式(Turbo=1)后,调度规则变为:只要接收寄存器未满,该通道就可以持续被调度。这意味着,一旦开始传输,只要CPU或DMA能及时提供发送数据并取走接收数据,移位寄存器就可以被这个通道独占,实现近乎背靠背的连续传输,消除了通道轮询带来的空闲时钟周期。

核心机制:在Turbo模式下,规则3(关于接收寄存器状态的调度限制)不再适用。只要接收寄存器(或接收FIFO)还没满,并且发送寄存器有数据,传输就可以持续进行。这直接带来了两个好处:第一,减少了传输间隙,提高了总线时钟利用率;第二,由于接收寄存器不会被覆盖(规则保证了这一点),RX_OVERFLOW中断永远不会发生,简化了错误处理。

适用场景与限制

  • 场景:非常适合需要高速、连续、大批量数据流传输的应用,如驱动高分辨率显示屏、读写大容量SPI Flash、高速ADC数据流采集。
  • 限制:Turbo模式仅在单通道使能时有效。如果使能了多个通道,Turbo位会被忽略,系统退回标准的轮询仲裁模式。此外,它也可以和“保持CS有效”模式结合使用,实现极致的连续传输性能。

3. FIFO缓冲区管理实战指南

内置FIFO是解放CPU、提升系统效率的关键。它本质上是一个位于APB/AHB总线域与SPI时钟域之间的异步缓冲区,允许CPU或DMA一次性写入/读取多个数据字,而不是每个��都产生一次中断或请求。

3.1 FIFO基础配置与拆分模式

FIFO的深度由芯片设计时的参数FFNBYTE决定(例如64字节)。通过设置MCSPI_CH(i)CONF寄存器中的FFER(接收FIFO使能)和FFEW(发送FIFO使能)位来为特定通道启用FIFO。重要原则:一次只能有一个通道使用FIFO。如果错误地使能了多个通道的FIFO位,控制器将禁用FIFO功能,需要驱动软件来保证配置正确。

最有趣的是拆分模式。当通道配置为收发模式(TRM=0)且同时使能了FFERFFEW时,总的FFNBYTE深度的FIFO会被平均分成两半,一半专用于发送路径,另一半专用于接收路径。这为全双工通信提供了平衡的缓冲能力。

不同模式下的FIFO配置

传输模式 (TRM)FFER(接收FIFO)FFEW(发送FIFO)FIFO使用方式
0 (收发)00禁用FIFO,使用单独的TX/RX寄存器
0 (收发)10仅接收路径使用完整深度FIFO
0 (收发)01仅发送路径使用完整深度FIFO
0 (收发)11拆分模式,发送和接收各用一半深度
1 (仅接收)1X接收路径使用完整深度FIFO
2 (仅发送)X1发送路径使用完整深度FIFO

3.2 水位线设置与中断/DMA触发

FIFO管理的精髓在于两个水位线寄存器MCSPI_XFERLEVEL[AEL](几乎空)和MCSPI_XFERLEVEL[AFL](几乎满)。它们的单位是字节,而不是SPI字长。这是第一个容易踩坑的地方。

你必须确保AEL+1AFL+1的值是你当前SPI字长(WL)的整数倍。例如,SPI字长为16位(2字节),那么AEL可以设置为1、3、5...(使得AEL+1为2、4、6...)。如果设置错误,可能导致DMA传输计数错误或数据错位。

  • 发送场景(AEL):当发送FIFO中的数据量低于或等于AEL设定的字节阈值时,会触发TX_EMPTY中断或DMA发送请求,通知系统需要填充更多数据。系统必须写入AEL+1字节的数据后,该请求才会解除,防止频繁中断。
  • 接收场景(AFL):当接收FIFO中的数据量达到或超过AFL设定的字节阈值时,会触发RX_FULL中断或DMA接收请求,通知系统需要取走数据。系统必须读取AFL+1字节的数据后,请求才会解除。

这种机制实现了“块操作”而非“字节操作”,极大降低了CPU中断频率。在DMA模式下,你可以设置DMA的传输宽度(字节、半字、字)和数量,与FIFO水位线配合,实现高效的大数据块搬运。

3.3 字计数与传输结束管理

这是FIFO使用中另一个关键且易错的功能:字计数(WCNT)。通过设置MCSPI_XFERLEVEL[WCNT],你可以预先定义好要通过FIFO传输的SPI字数量(注意,是字数量,不是字节数)。

启用WCNT后,控制器会在传输完指定数量的SPI字后,自动停止(通常会产生一个中断)。这对于需要精确控制传输长度的应用(如读取特定长度的传感器数据包)非常有用,避免了软件计数的开销和误差。

致命陷阱:如果你使能了FIFO,使用了WCNT功能,并且使用TX_EMPTY中断来填充数据,那么你必须保证WCNT的值是AEL(几乎空水位线)的整数倍。为什么?因为TX_EMPTY中断是根据AEL触发的。假设AEL=3(意味着FIFO剩3字节时请求填充4字节),而WCNT=10(传输10个字,即20字节)。如果最后一次触发中断时,需要填充的数据量加上已传输的数据量可能无法精确匹配总字计数,会导致控制器无法准确在最后一个字后停止,可能引发不可预知的行为。文档明确要求WCNT必须是AEL的倍数,就是为了确保中断触发边界与传输结束边界对齐。

操作流程建议

  1. 配置SPI参数(字长、模式等)。
  2. 配置FIFO:使能FFER/FFEW,设置AELAFL水位线(确保是字长的整数倍)。
  3. 如果使用自动停止,设置WCNT(确保是AEL的整数倍)。
  4. 使能通道,开始传输。
  5. 传输完成后(WCNT计数完成产生中断),先禁用通道,然后轮询MCSPI_CH(i)STAT[FFE],确保FIFO中所有剩余数据(可能由于流水线原因还有最后几个字)都被读取完毕。

4. 时钟、时序与引脚模式高级配置

4.1 时钟分频粒度与占空比

SPI时钟(SCLK)由参考时钟CLKSPIREF分频得到。分频系数Fratio的配置有两种粒度:

  1. 2的幂次方粒度(CLKG=0):分频系数为 2^CLKD,其中CLKD是配置值。这种方式产生的时钟占空比永远是精确的50%。
  2. 单周期粒度(CLKG=1):分频系数为EXTCLK.CLKD + 1,形成一个12位的值(1~4096)。这提供了更灵活的频率选择。对于偶数的Fratio,占空比仍是50%。对于奇数的Fratio,控制器会利用CLKSPIREF的下降沿来调整,最终输出的CLKSPIO高电平和低电平时间都是t_ref * (Fratio/2)仍然保持50%占空比。这是一个非常实用的设计,保证了时钟信号的稳定性。

频率计算示例:假设CLKSPIREF = 48 MHz(t_ref ≈ 20.83 ns)。

  • CLKG=0, CLKD=1Fratio = 2^1 = 2SCLK = 48MHz / 2 = 24 MHz,周期41.67 ns。
  • CLKG=1, EXTCLK=0, CLKD=2Fratio = 0.2 + 1 = 3SCLK = 48MHz / 3 = 16 MHz,周期62.5 ns,占空比50%。

4.2 片选时序控制

在4线主模式下,你可以精细控制片选信号SPI_SCS[n]相对于第一个和最后一个SCLK时钟边沿的时序。这是通过配置TCS位来实现的,它定义了以SCLK周期为单位的延迟。

这个功能对于满足不同从设备的时序要求至关重要。有些设备需要在CS有效后,等待一段时间(建立时间)才能出现第一个时钟边沿;同样,在最后一个时钟边沿之后,需要CS保持一段时间(保持时间)才可拉高。

计算公式(简化通用情况,Fratio >=2且为偶数时):

  • 建立时间=T_ref * Fratio * (TCS + 0.5)
  • 保持时间=T_ref * Fratio * (TCS + 0.5)其中T_ref是参考时钟周期,Fratio是分频系数。

特别注意的角落情况

  1. 时钟旁路模式(Fratio = 1):延迟会额外增加半个T_ref周期。
  2. 奇数分频且CLKG=1:计算方式略有不同,具体需查表。文档中的表格22-3完整列出了所有配置下的延迟计算公式,在时序要求严格的场合必须查阅。

4.3 3引脚模式

当你的系统只有一个SPI从设备时,可以考虑使用3引脚模式(PIN34=1)。此模式下,SPI_SCS[n]引脚被强制拉低(无效状态,具体电平取决于EPOL),通信仅通过SPI_SCLK,SPI_D[0],SPI_D[1]三根线完成。

使用前提

  1. 必须配置为单通道主模式(SINGLE=1)。
  2. 总线上只能连接一个从设备

在此模式下,所有与片选相关的配置(EPOL,TCS,FORCE)均无效。这节省了一个GPIO引脚,但失去了通过片选管理多个设备的能力,也失去了片选时序控制功能。通常用于固定连接一个从设备的简化场景。

5. 从设备模式关键要点

当MCU作为从设备时,其配置和使用方式与主模式有显著区别。

核心限制:在从模式下,只有通道0(Channel 0)是可用的。使能其他通道没有任何效果。通道0独享所有发送(MCSPI_TX)、接收(MCSPI_RX)寄存器和FIFO��源。

片选管理:从设备可以配置使用SPI_SCS[3:0]中的任意一个作为其片选输入信号,通过SPIENSLV位选择。时钟(SCLK)完全由外部主设备提供,因此从设备侧的时钟分频配置CLKD是不起作用的。

初始化流程:从设备的通道0必须在通信开始前被使能。作为从设备,它应该预先将待发送的数据写入发送寄存器。当主设备拉低片选并开始提供时钟时,从设备的数据才会被移出。因此,“提前准备数据”是从设备编程的关键。如果数据没有准备好,可能会发送旧数据或导致下溢。

中断与DMA:从模式同样支持TX_EMPTY, TX_UNDERFLOW, RX_FULL, RX_OVERFLOW这四种中断事件,也支持DMA请求。这对于从设备需要处理突发数据流非常有用,例如作为数据采集器向主设备发送大量数据。

6. 常见问题排查与调试技巧

在实际开发中,SPI问题层出不穷。以下是一些常见故障的排查思路:

问题1:数据收发错位或全为0xFF/0x00。

  • 检查时钟极性与相位:这是最常见的问题。用逻辑分析仪抓取SCLK、MOSI、MISO、CS波形,对照从设备数据手册的时序图,确认CPOL和CPHA设置是否正确。一个技巧是:观察第一个数据位是在SCLK的第一个边沿(上升沿或下降沿)采样,还是在第二个边沿采样。
  • 检查字长:确保主从双方设置的字长一致。8位设备配成16位模式会导致数据错位。
  • 检查字节序:有些SPI设备是MSB先行,有些是LSB先行。查看MCSPI_CH(i)CONF是否有相关配置位。

问题2:使能FIFO后,数据传输不完整或卡住。

  • 检查水位线对齐:确认AEL+1AFL+1是SPI字长的整数倍。使用16位字长时,AEL必须设置为奇数(1,3,5...)。
  • 检查DMA配置:如果使用DMA,确保DMA的传输数据宽度(字节、半字、字)和传输数量与FIFO水位线及SPI字长匹配。例如,16位SPI字,DMA应使用半字宽度,传输数量应是(AFL+1)/2的倍数。
  • 检查WCNT配置:如果使用了字计数,确认WCNTAEL的整数倍,并且传输完成后按流程(先禁通道,再轮询FFE清空FIFO)处理。

问题3:Turbo模式没有效果,或者使能多通道时Turbo失效。

  • 确认单通道:使用逻辑分析仪或调试器检查是否真的只有一个通道被使能(MCSPI_CHxCTRL[EN])。其他通道的使能位必须为0。
  • 检查调度:在Turbo模式下,确保你的程序能持续为发送寄存器或FIFO提供数据,并及时取走接收数据。如果CPU太慢导致发送寄存器空或接收寄存器满,传输依然会停顿。

问题4:作为从设备无法响应主设备。

  • 确认通道0已使能:从设备必须在通信前使能通道0。
  • 预先写入发送数据:从设备的发送寄存器需要在被选中前就准备好数据。检查是否在使能通道后、主设备发起传输前写入了TX寄存器。
  • 检查片选映射:确认SPIENSLV位配置正确,从设备监听的是主设备拉低的那根片选线。

调试利器:逻辑分析仪。一个支持SPI协议解码的逻辑分析仪(如Saleae)是调试SPI问题的必备工具。它能直观显示时钟、数据、片选波形,并解码出十六进制或二进制数据流,帮助你快速定位时序、数据内容或协议层面的问题。不要只依赖打印调试,眼见为实。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询