SPI驱动开发实战:从寄存器配置到FIFO/DMA优化

📅 2026/7/22 8:50:54
SPI驱动开发实战:从寄存器配置到FIFO/DMA优化
1. 项目概述从芯片手册到可落地的SPI驱动理解搞嵌入式开发尤其是涉及到各种传感器、存储芯片或者显示屏驱动SPISerial Peripheral Interface接口绝对是绕不开的一道坎。手册上那些密密麻麻的寄存器位描述、时序图还有各种模式配置第一次看的时候确实容易让人头大。最近在调一个基于TI某款处理器的项目正好需要深度配置SPI去驱动一块高速ADC于是又把那份经典的SPRUGZ8G技术参考手册翻了出来特别是其中关于SPI控制器和SATA PLL寄存器的部分。我发现很多中文资料对SPI的讲解停留在“四根线”、“主从模式”的概念层面一旦涉及到具体的寄存器配置比如如何根据外设特性精确设置时钟相位PHA、极性POL或者如何利用FIFO和DMA来提升吞吐量往往就语焉不详了。这次我就结合手册里那些“硬核”的寄存器描述比如SATA_TXSTATUS、SATA_TESTCFG以及SPI模块本身的MCSPI_CHxCONF等来一次彻底的“拆解”目标是让你看完后不仅能读懂手册更能写出稳定、高效的SPI驱动代码。无论你是正在学习嵌入式的新手还是遇到SPI通信时序难题的老手这篇从原理到寄存器实操的解析应该都能给你带来一些直接的帮助。2. SPI核心原理与架构再认识在直接翻寄存器之前我们必须把SPI最本质的工作原理和TI这个SPI控制器的架构特点吃透。很多问题都源于对基础原理的模糊理解。2.1 不仅仅是四根线同步串行的本质SPI常被简化为四根线SCLK时钟、MOSI主出从入、MISO主入从出、SS片选。但这只是全双工模式下的典型连接。其核心是同步和串行。同步意味着通信双方共享一个时钟信号SCLK。数据在时钟边沿被采样或输出这消除了异步通信如UART需要双方预先约定波特率所带来的误差累积问题可以实现更高的速率手册中该控制器支持最高48MHz。串行数据一位一位地传输。这节省了引脚但要求控制器内部有移位寄存器负责并行数据与串行比特流之间的转换。手册中的图22-1和架构描述清晰地展示了这一点主机通过SPI_SCLK线提供时钟通过SPI_SCS[n]片选线选择目标从机数据则在SPI_D[0]和SPI_D[1]上流动。关键在于SPI_D[0]和SPI_D[1]的角色是MOSI还是MISO是可编程的这带来了极大的灵活性。2.2 TI SPI控制器特色多通道与统一端口控制TI的这款SPI控制器以手册描述的为例有几个在驱动开发中非常实用的高级特性理解了它们才能用好寄存器多通道主模式Master Multichannel Mode一个SPI控制器硬件上支持最多4个独立的“通道”Channel 0-3。每个通道可以拥有自己独立的配置时钟、字长、片选极性等。这意味着你可以用同一个SPI硬件模块以不同的通信参数去连接多个不同的SPI从设备而无需在软件中频繁地重配置整个模块。控制器内部通过轮询仲裁Round Robin机制来决定下一个服务哪个已就绪的通道。统一数据端口控制SPI_D[0]和SPI_D[1]没有固定的MOSI/MISO角色。你需要在每个通道的配置寄存器里指定对于这个通道SPI_D[0]是输入还是输出SPI_D[1]是输入还是输出。这让你可以灵活适配各种非标或特殊接法的从设备。内置FIFO与DMA支持每个通道可以启用一个最大64字节的共享FIFO缓冲区。这对于大数据量传输至关重要。配合DMA可以在几乎不占用CPU资源的情况下完成SPI数据搬运极大提升系统效率。寄存器中的FFER接收FIFO使能和FFEW发送FIFO使能位就是用来控制这个的。灵活的时钟与片选管理时钟分频系数、相位(PHA)、极性(POL)可配是标准操作。此外片选信号SPI_SCS[n]的极性高有效或低有效、是否在两帧数据之间保持有效FORCE位、甚至是是否启用片选3线模式都是可编程的。手册中SATA_TESTCFG寄存器里对测试模式的配置也侧面反映了其对传输波形强大的控制能力。3. 关键寄存器深度解析与配置逻辑手册里寄存器表格很多我们挑最核心、最容易出错的几个来讲并把它们和实际驱动代码中的配置步骤关联起来。3.1 模块级控制寄存器MCSPI_MODULCTRL这个寄存器是SPI模块的总开关。最重要的位是MSMaster/Slave位。将其清零模块工作在主模式置1则工作在从模式。大部分情况下我们的MCU作为主机此位应设为0。在初始化SPI模块时这是第一个要配置的寄存器之一。3.2 通道配置寄存器MCSPI_CHxCONF这是每个通道的核心配置寄存器决定了这个通道与外设通信的所有基本参数。驱动代码的绝大部分配置工作都在这里。我们结合手册表22-2和字段描述来逐一拆解TRMTransfer Mode传输模式。0x0: 发送接收模式全双工。0x1: 只发送模式。0x2: 只接收模式。配置逻辑根据外设功能选择。例如向Flash发送写命令后读取状态寄存器就需要切换模式。很多简单的传感器可能只需要只读或只写。WLWord Length字长。支持4-32位。这里有个大坑这个“字长”指的是一次SPI传输过程中SCLK的脉冲个数也就是移位的位数。它不一定等于你数据缓冲区的数据类型如uint8_t。如果你设置WL8但写入一个32位数据到发送寄存器控制器也只会发送低8位。EPOLChip Select Polarity片选极性。0表示低电平有效常见1表示高电平有效。必须与外设数据手册要求严格一致。POLClock Polarity与 PHAClock Phase这是SPI时序的灵魂决定了数据在时钟的哪个边沿采样和变化。共有4种模式Mode 0-3。手册中的图22-5和22-6、22-7是理解它的关键。POL0时钟空闲时为低电平。POL1时钟空闲时为高电平。PHA0数据在第一个时钟边沿即SCLK从空闲状态第一次跳变时被采样。数据需要在片选有效后、第一个时钟边沿前就准备好。PHA1数据在第二个时钟边沿被采样。数据在第一个时钟边沿时变化。配置逻辑完全取决于你的从设备必须查阅从设备数据手册的时序图。例如大部分SPI Flash芯片工作在Mode 0POL0 PHA0或Mode 3POL1 PHA1。配置错误会导致数据错位通信完全失败。CLKDClock Divider时钟分频因子。用于生成最终的SPI_SCLK频率。计算公式通常为SPI_SCLK SPI_REF_CLK / (CLKD1)。需要根据外设支持的最高SCLK频率和系统稳定性来设置并非越快越好。ISInterface Selection与 DPEData Pin Enable这两个位共同决定了数据线的使用方式。IS选择单线还是双线模式。DPE[1:0]分别控制SPI_D[1]和SPI_D[0]是输入还是输出。配置逻辑对于标准全双工设置IS0双线DPE0x3D0输出为MOSI D1输入为MISO。对于半双工或单线设备则需要根据具体接线配置。FFER/FFEWFIFO Enable如前所述使能接收/发送FIFO。在需要连续传输大量数据时务必启用并配合MCSPI_XFERLEVEL寄存器设置FIFO触发水位AFL, AEL。3.3 通道控制与状态寄存器MCSPI_CHxCTRL 与 MCSPI_CHxSTATMCSPI_CHxCTRL主要就是一个ENEnable位。在配置好CHxCONF后将此位置1该通道才被激活参与轮询仲裁。在修改CHxCONF的某些关键字段如POL, PHA前必须先禁用EN0该通道。MCSPI_CHxSTAT提供了通道的实时状态。TXSTransmit Shift Empty发送移位寄存器空。为1时表示可以向TX寄存器写入新数据。RXSReceive Shift Full接收移位寄存器满。为1时表示可以从RX寄存器读取数据。EOTEnd Of Transfer一次字传输完成。在查询方式非中断/DMA下可以通过轮询此位来判断一次SPI传输是否结束。3.4 传输控制寄存器MCSPI_XFERLEVEL当使用FIFO时这个寄存器至关重要。AFLAlmost Full Level设置接收FIFO“几乎满”的阈值。当FIFO中数据量达到此值时会触发RX_FULL中断或DMA请求。合理设置可以避免频繁中断或DMA请求。AELAlmost Empty Level设置发送FIFO“几乎空”的阈值。当FIFO中空闲空间达到此值时会触发TX_EMPTY中断或DMA请求提示CPU或DMA可以继续填充数据。WCNTWord Count字计数器。可以设置一个传输总量当传输字数达到此值时产生“End of Word Count”中断。适用于已知固定长度传输的场景实现精确控制。3.5 关联寄存器解析SATA_TXSTATUS 与 SATA_TESTCFG手册中在SPI章节前提到了SATA控制器的SATA_TXSTATUS和SATA_TESTCFG寄存器。虽然它们属于SATA模块但其设计思想与SPI测试息息相关可以作为理解硬件调试的延伸。SATA_TXSTATUS这个寄存器主要用于反映发送状态。其中TESTFAIL位位0尤其值得注意。当在测试序列中遇到错误或发送串行器在特定模式下发生溢出/下溢时此位会被置高。这给我们一个启示在复杂的串行通信控制器中通常都会有专门的状态寄存器来指示硬件级别的错误。在编写健壮的SPI驱动时除了关注数据本身也应该在关键操作后查询类似的状态位如果SPI模块有提供可能是全局错误状态寄存器以便及时发现并处理硬件异常。SATA_TESTCFG这个寄存器用于控制和选择测试模式。例如其RX_TESTPATT字段可以选择接收端测试图案交替的0/1、7位LFSR线性反馈移位寄存器、23位LFSR、31位LFSR等。这在SPI驱动开发和硬件调试中是一个高级技巧。在系统集成初期为了验证SPI物理链路和基本配置是否正确我们可以在发送端循环发送一个简单的已知模式如0xAA或0x55即0101交替在接收端验证。更复杂的可以像这个寄存器支持的那样用LFSR生成伪随机序列进行压力测试以检验数据传输在高波特率下的稳定性。虽然标准SPI寄存器可能没有直接集成如此丰富的测试模式但我们可以通过软件在应用层实现类似的功能这是一个非常重要的调试手段。4. SPI传输模式实战与驱动编写要点理解了寄存器我们来看看如何将它们组合起来实现不同的传输模式。这里以主模式为例。4.1 全双工传输标准模式配置流程这是最常见的模式用于需要同时收发数据的场景如读取传感器ID、与SRAM通信等。初始化与模块配置使能SPI模块的时钟涉及手册中提到的CM_DEFAULT_SATA_CLKCTRL之类的电源时钟管理寄存器这部分通常由芯片启动代码或HAL库完成。配置MCSPI_MODULCTRL设置MS0主模式。如果需要配置全局中断使能。通道参数配置以Channel 0为例确保MCSPI_CH0CTRL.EN 0禁用通道。配置MCSPI_CH0CONFTRM 0x0发送接收模式。WL 0x7假设传输8位数据值字长-1。根据从设备手册设置POL和PHA。例如设为POL0, PHA0Mode 0。设置EPOL 0片选低有效。设置IS 0DPE 0x3双线模式D0输出D1输入。根据系统时钟和外设要求计算并设置CLKD分频值。如果使用FIFO设置FFER1FFEW1并配置MCSPI_XFERLEVEL中的AFL和AEL。启动传输将MCSPI_CH0CTRL.EN置1启用通道。向MCSPI_TX0寄存器写入要发送的数据。写入后TXS状态位会清零。控制器会自动处理片选拉低、时钟生成和数据移位。轮询MCSPI_CH0STAT.EOT位或等待RX_FULL中断/DMA请求当一次传输完成后从MCSPI_RX0寄存器读取接收到的数据。传输结束后如果需要释放片选则清除MCSPI_CH0CTRL.EN或由硬件根据配置自动完成。4.2 半双工与单线模式应用有些设备如某些温湿度传感器、OLED屏可能采用半双工或单线如SPI三线制通信。这时就需要利用MCSPI_CHxCONF中的IS和DPE位。半双工分时复用一根数据线设置IS 1单线模式。在发送阶段配置DPE让对应的数据线如SPI_D[0]为输出。发送数据。在接收阶段必须先重新配置DPE将同一根数据线改为输入然后再启动接收操作。这是一个关键步骤切换方向必须在通道禁用或确保总线空闲时进行否则会造成总线冲突。只读模式如查询只读传感器设置TRM 0x2只接收模式。配置DPE将MISO对应的数据线设置为输入。即使不需要发送数据为了产生SCLK时钟通常也需要向TX寄存器写入一个哑元Dummy数据通常是0xFF或0x00时钟才会产生从而从设备那里读出数据。4.3 利用FIFO与DMA进行高效批量传输当需要连续读取大量数据如图像传感器或写入大块数据如Flash编程时查询或标准中断方式会消耗大量CPU资源。FIFODMA是解决方案。配置FIFO在MCSPI_CHxCONF中使能FFER和/或FFEW。在MCSPI_XFERLEVEL中设置AFL和AEL。例如对于64字节FIFO设置AFL16AEL48这样当FIFO有16字节数据时触发接收DMA有16字节空位时触发发送DMA平衡了响应速度和中断频率。配置DMA控制器将SPI的TX寄存器地址设置为DMA的源地址内存到SPI或目的地址SPI到内存。将SPI的RX寄存器地址设置为DMA的目的地址或源地址。配置DMA传输数据宽度与SPI字长匹配、传输总量。使能SPI通道的DMA请求MCSPI_CHxCTRL中的DMAW和DMAR位。启动传输启用SPI通道和DMA通道。CPU只需准备好发送数据缓冲区或目标接收缓冲区SPI和DMA硬件会自动协作完成数据搬运并在传输完成后通过DMA中断通知CPU。整个过程CPU干预极少。5. 调试技巧与常见问题排查实录SPI调试软件逻辑对了硬件不一定通。以下是在实际项目中踩过的一些坑和总结的技巧。5.1 问题排查速查表现象可能原因排查步骤与解决方案完全无通信用逻辑分析仪看不到SCLK和片选1. SPI模块时钟未使能。2. 模块未配置为主模式MS0。3. 对应通道未启用EN0。4. GPIO引脚复用功能未正确配置。1. 检查芯片时钟树确认SPI外设时钟源已开启。2. 确认MCSPI_MODULCTRL.MS0。3. 确认MCSPI_CHxCTRL.EN1。4.最常用使用芯片的引脚复用配置工具或直接查寄存器确保SPI_SCLK、SPI_D[x]、SPI_SCS[n]引脚已配置为SPI功能而非普通的GPIO。有SCLK和片选但MOSI/MISO上无数据或数据全为高/低1. 数据线方向DPE配置错误。2. 发送寄存器未写入数据TXS一直为1。3. 从设备未上电或损坏。4. 单线模式切换时机错误。1. 仔细核对MCSPI_CHxCONF.IS和DPE设置确保与硬件连接匹配。2. 在启动传输前检查并确保已向MCSPI_TXx写入有效数据。3. 测量从设备电源和信号电平。4. 在半双工切换方向时确保一次完整的收发周期结束再更改DPE配置。能收到数据但数据错误错位、反码等1.时钟相位(PHA)和极性(POL)配置错误最常见。2. SPI字长WL设置与外设不匹配。3. 数据传输的MSB/LSB顺序问题某些外设要求LSB先行。4. 时钟频率过高信号质量差。1.重中之重用逻辑分析仪捕获SCLK、MOSI、MISO波形与从设备数据手册的时序图逐位对比确认采样边沿是否正确。依次尝试Mode 0, 1, 2, 3。2. 确认WL设置。发送32位数据但WL8只会发低8位。3. 检查外设手册数据格式。SPI控制器通常固定为MSB先行若外设要求LSB先行则需在软件中对每个字节进行位反转。4. 降低CLKD分频系数检查PCB布线确保信号完整。通信不稳定偶尔出错高负载时易出错1. 未处理FIFO溢出/下溢。2. 中断服务程序处理太慢导致数据丢失。3. DMA配置错误传输长度或地址不对齐。4. 电源噪声或地线干扰。1. 在中断或状态查询中检查MCSPI_IRQSTATUS中的溢出/下溢错误标志并做相应处理如清空FIFO重置通道。2. 优化中断服务程序只做必要的数据搬运和标志清除。考虑使用DMA。3. 检查DMA传输宽度与SPI字长是否匹配内存缓冲区地址是否对齐特别是手册要求256位对齐时。4. 增加电源去耦电容检查地平面连接缩短SPI走线。多通道切换时数据发错设备1. 片选信号SPI_SCS[n]映射错误。2. 通道配置如时钟、模式在切换时未正确更新。3. 轮询仲裁机制下未等待当前通道传输完成就切换配置。1. 确认每个通道的SPI_SCS[n]引脚与目标从设备的片选线正确连接。2. 为每个从设备建立独立的通道配置结构体切换通道时完整重载该通道的CHxCONF寄存器注意先禁用通道。3. 在切换通道前通过查询EOT位或确保FIFO/DMA传输完成等待当前通道总线空闲。5.2 逻辑分析仪不可或缺的调试利器对于SPI调试一个哪怕是最基础的逻辑分析仪如Saleae Logic系列或国产平价替代品的价值都远超其价格。它能直观地展示SCLK、MOSI、MISO、CS线上的每一个比特让你直接对比实际波形与数据手册的理论波形。在排查相位、极性、数据内容问题时这是最直接、最有效的方法。配置逻辑分析仪时要正确设置采样率至少为SPI时钟频率的4倍以上和解码协议SPI并正确指定各信号线。5.3 关于“锁定位Lock Bit”的注意手册在描述SATA_TXSTATUS和SATA_TESTCFG寄存器时反复提到了一个“锁定位lock bit”的概念。当锁定位为1时寄存器不可访问。这提醒我们在访问一些关键的系统或外设控制寄存器时可能会存在写保护或访问权限控制机制。在TI的SPI模块或其他复杂外设中也可能存在类似的保护寄存器例如需要先向一个密钥寄存器写入特定值才能修改某些配置。在驱动初始化时如果发现某些配置寄存器写入不生效除了检查时钟使能也要查阅手册是否有此类解锁步骤。SPI接口的精髓在于灵活和高效而灵活的背后是复杂的可配置性。真正掌握SPI不在于死记硬背那四根线而在于深刻理解时钟相位、极性如何影响采样时刻在于能根据外设手册准确地将那些抽象的寄存器位描述转化为正确的配置值在于能利用FIFO、DMA等高级特性解放CPU更在于当通信不通时有一套科学的排查方法。希望这篇结合了TI手册实例的深度解析能帮你把SPI这块硬骨头啃得更透彻一些。在实际项目中最笨但最有效的方法永远是仔细读手册包括MCU的和外设的、善用逻辑分析仪、编写模块化的驱动代码并做好错误处理。