深入解析TI Tiva QSSI:FIFO、高级模式与DMA优化实战

📅 2026/7/22 16:38:28
深入解析TI Tiva QSSI:FIFO、高级模式与DMA优化实战
1. QSSI接口核心机制与设计思路在嵌入式系统开发中同步串行接口Synchronous Serial Interface, SSI尤其是其最普遍的实现形式SPISerial Peripheral Interface是连接微控制器与传感器、存储器、显示屏等外设的“高速公路”。我接触过不少芯片的SPI模块但像TI Tiva系列微控制器中的Quad SSIQSSI这样功能丰富、设计精巧的模块确实值得深入聊聊。它不仅仅是传统SPI的简单实现更通过引入FIFO缓冲、高级传输模式和多数据线并行等机制将串行通信的效率和灵活性提升到了一个新的层次。理解QSSI本质上是在理解如何平衡硬件效率与软件复杂度以及如何针对不同应用场景选择最优的通信策略。传统SPI通信中一个核心痛点在于处理器核心与外设速度不匹配带来的频繁中断或轮询开销。比如主控以50MHz运行而SPI时钟可能只有1MHz每传输一个字节CPU都可能被中断或需要主动检查状态大量时间浪费在等待和上下文切换上。QSSI模块内置的FIFOFirst-In, First-Out缓冲区就是为解决这个问题而生的硬件“蓄水池”。它允许数据在硬件层面进行暂存和排队让CPU可以一次性写入或读取多个数据从而大幅减少总线占用和中断频率这是提升系统整体响应能力和能效的关键设计。除了基础的FIFOQSSI真正吸引我的地方在于其“高级模式”Bi-SSI双线和Quad-SSI四线。标准SPI是全双工但只使用两条数据线MOSI和MISO。在需要极高吞吐量的场景如驱动高分辨率显示屏或读写QSPI Flash时两条线的带宽可能成为瓶颈。Bi-SSI和Quad-SSI模式通过将数据线扩展到2条或4条进行并行传输理论上能在相同时钟频率下将数据吞吐量提升2倍或4倍。但这里有一个非常重要的设计取舍在Bi-SSI和Quad-SSI模式下通信是半双工的。这意味着同一组数据线不能同时进行收发需要在发送和接收之间进行切换。这种设计权衡了引脚资源、硬件复杂度和带宽需求非常典型。理解何时该用全双工的标准模式何时该切换到半双工的高速模式是进行硬件选型和驱动优化的基本功。最后帧格式的选择直接决定了你能否与目标外设“对上话”。QSSI支持Freescale SPI和TI同步串行两种主要帧格式每种格式下还有时钟极性SPO和相位SPH的组合变化。这四种组合CPOL/CPHA构成了SPI的四种模式是几乎所有SPI设备数据手册都会明确规定的。而TI同步串行格式则有其独特的帧同步脉冲。选择错误的格式或模式通信根本无法建立。更复杂的是在高级模式Bi/Quad-SSI下帧格式的选择是受限的这常常是调试时容易踩坑的地方。因此深入理解每种帧格式的时序细节并掌握在QSSI模块中正确配置它们的方法是打通通信链路的第一步。2. 接收FIFO的深度解析与实战要点接收FIFO是QSSI模块数据流入的“第一站”它的稳定工作是一切可靠通信的基础。根据文档QSSI的接收FIFO是一个16位宽、8个位置深的缓冲区。这个“16位宽”很有意思它意味着每个FIFO单元可以存放一个16位的数据。但在实际使用中我们传输的数据宽度可以是4到16位传统模式或固定的8位高级模式。硬件是如何处理这个位宽差异的呢实际上无论你设置的数据位宽是多少接收到的数据都会被存放到FIFO单元的低位部分高位部分在非16位模式下通常无效或补零。CPU通过读取SSIDRSSI数据寄存器来消费FIFO中的数据每读一次就弹出一个数据项。这里有一个至关重要的机制FIFO满时的流控。当接收FIFO已满即8个位置都存有数据而此时主设备或从设备又接收到新数据时硬件会“按住”数据暂停时钟或通过其他方式通知发送方等待直到FIFO中有空位为止。这个硬件流控机制避免了数据溢出丢失对于保证通信可靠性至关重要。在软件设计时我们需要通过查询状态寄存器如SSISR中的RNE位或利用中断确保在FIFO快满或已有数据时及时读取维持数据流的畅通。一个特别需要注意的细节出现在主模式接收数据时。文档明确指出“SSI only provides an SSIClk while transmitting data.” 这意味着QSSI模块只在发送数据时才产生时钟。那么当主机只想读取从机数据而不发送时时钟从哪里来解决方案是一个“哑写”dummy write操作。在启动接收之前主CPU必须先向SSIDR寄存器执行一次写操作写入的数据内容通常无关紧要如0x00或0xFF。这个写操作会触发QSSI模块开始生成时钟信号从机在时钟驱动下才会将数据发送出来并存入主机的接收FIFO。忘记这个“哑写”是新手调试SPI主机接收时最常见的错误之一会导致时钟线毫无动静自然也就收不到任何数据。注意在传统模式Legacy Mode下用于高级模式的SSInXDAT1引脚功能就是标准的SSInRX主入从出MISO。硬件引脚是复用的但功能由模式决定配置GPIO复用功能时需对照芯片数据手册的引脚映射表确保将引脚配置到正确的QSSI功能上。2.1 FIFO中断与超时机制的应用策略仅仅知道FIFO的存在还不够高效地使用它需要借助中断机制。QSSI可以产生多种中断与接收FIFO直接相关的有接收FIFO服务中断当FIFO中的数据量达到或超过半满时触发、接收超时中断、以及接收溢出中断。接收FIFO服务中断是最常用的。你可以设置一个阈值例如当FIFO中数据达到4个半满或更多时产生中断。这样你的中断服务程序ISR可以一次读取多个数据而不是每收到一个字节就中断一次极大地降低了CPU中断负载。配置方法是设置SSIIM中断屏蔽寄存器中对应的位。接收超时Timeout中断是一个很实用的功能用于处理数据流不连续的场景。它的工作原理是一旦接收FIFO非空RNE1一个32个SSIClk周期的倒计时器就开始工作。每当有新数据写入FIFO计时器就会重置。如果长达32个时钟周期都没有新数据进来计时器归零就会产生超时中断。这个中断告诉你“当前这批数据应该已经接收完了可以来处理了”。这在接收不定长数据包时特别有用避免了软件轮询或等待。接收溢出中断则是一个错误指示。当接收FIFO已满但硬件又试图写入新数据时就会发生溢出相应的错误标志位会被置位。如果使能了中断也会触发。发生溢出通常意味着你的软件读取速度跟不上硬件接收速度需要检查你的中断服务程序效率或者考虑使用DMA来搬运数据。在实际编程中我的习惯是对于高速、连续的数据流使能接收FIFO半满中断并配合DMA对于低速、间歇性的数据使用接收超时中断来判断一帧数据的结束。同时初始化后一定会使能溢出中断并将其ISR设计为记录错误日志并复位FIFO这能快速定位通信异常。3. 高级模式Bi-SSI/Quad-SSI的配置与半双工实战高级模式是QSSI提升吞吐量的利器但其配置和操作逻辑与传统SPI有显著不同需要仔细梳理。3.1 模式选择与核心配置寄存器Bi-SSI和Quad-SSI模式的启用完全由SSICR1寄存器中的MODE位段控制。同时DIR方向位决定了当前传输是发送TX还是接收RX。这是理解其半双工特性的关键发送模式DIR0数据引脚被配置为输出CPU向TX FIFO写数据QSSI模块将数据通过多根数据线移出。在此模式下接收RXFIFO被自动禁用因为你不会收到数据。接收模式DIR1数据引脚被配置为输入QSSI模块从多根数据线上采样数据存入RX FIFO。此时你需要通过“哑写”TX FIFO来产生时钟驱动从设备发送数据。高级模式Advanced SSI则有些特殊。当MODE0x3且DIR0发送时它和Bi/Quad-SSI的发送模式一样禁用RX FIFO。但当DIR1接收时高级模式却可以工作在全双工状态。文档对此描述有些绕我的理解是MODE0x3更像是一个“扩展模式”开关具体的双工/半双工行为由DIR位和具体的数据引脚使用情况共同决定。对于纯粹的Bi/Quad-SSI半双工是硬性规定。一个必须遵守的配置铁律是在Bi-SSI或Quad-SSI模式下SSICR0寄存器中的DSS数据大小选择字段必须设置为0x7即8位数据。这是硬件设计的要求。如果你忘记设置QSSI模块会回退到传统模式行为将不可预测。在8位模式下你写入TX FIFO的数据包占据其低8位[7:0]而高8位中的[15:13]这三个比特被用来编码本次传输的操作模式0x1Bi-SSI0x2Quad-SSI0x3Advanced SSI。这意味着你需要在软件层面组装一个16位的值写入FIFO。例如要使用Quad-SSI模式发送数据0x5A你需要写入TX FIFO的值是(0x2 13) | 0x5A即0x405A。3.2 帧开始与结束的控制FSSHLDFRM与EOM位在多字节传输中帧同步信号SSInFss通常作为片选CS的行为至关重要。QSSI提供了精细的控制通过SSICR1中的FSSHLDFRM位和TX FIFO条目中的EOMEnd Of Message位来实现。FSSHLDFRM位控制SSInFss信号在字节间的行为FSSHLDFRM 0在每个字节传输后SSInFss信号都会拉高变为无效下一个字节开始时再拉低。这适用于需要严格以字节为单位控制从设备的场景。FSSHLDFRM 1只要TX FIFO中还有数据SSInFss信号就保持低电平有效。只有当TX FIFO完全清空传输彻底结束时SSInFss才拉高。这用于传输一个完整的、连续的多字节数据块。EOM位则嵌入在TX FIFO的每个数据条目中位12。它标志着一个帧的结束。当硬件处理到某个TX FIFO条目且其EOM位为1时它会在该数据包传输完成后将SSInFss信号拉高。这个机制允许你在一个FIFO队列里混合多个长短不一的数据帧并通过设置EOM位来告诉硬件在哪里断帧。例如你需要先发送一个3字节的命令帧再发送一个10字节的数据帧。你可以将第三个字节的EOM位置1将第十个字节的EOM位置1。这样硬件会自动在命令帧和数据帧之间拉高一下SSInFss。实操心得在连续发送大量数据时我通常将FSSHLDFRM设为1并只在最后一个数据的EOM位置1让SSInFss在整个传输期间保持有效获得最高的传输效率。而在需要与严格遵循字节使能协议的外设通信时则设置FSSHLDFRM为0。EOM位非常强大但要注意它是在数据被写入TX FIFO的那个时钟周期被清除的所以你需要为每个想标记为帧尾的数据单独设置。3.3 模式切换的允许与禁止文档明确指出了事务序列的组合规则这是硬件序列器设计的约束传统SSI模式如果配置为此模式不建议在单次事务中切换到任何其他高级模式。允许的序列高级SSI模式后接Bi-SSI模式。高级SSI模式后接Quad-SSI模式。高级SSI模式 - Bi-SSI模式 - 高级SSI模式。高级SSI模式 - Quad-SSI模式 - 高级SSI模式。不鼓励的切换在单次事务中不建议在Quad-SSI和Bi-SSI模式之间直接切换。这意味着高级SSI模式MODE0x3是切换的“枢纽”或“安全模式”。如果你想从传统模式进入多线模式或者在不同多线模式间切换最好先经过高级SSI模式过渡。违反这些规则可能导致不可预知的引脚行为或数据错误。4. 高速时钟模式HSCLKEN与性能优化当QSSI工作在主模式时可以启用高速时钟模式来进一步提升时序性能这对于高时钟频率下的稳定采样尤其重要。启用该模式的方法是设置SSICR1寄存器中的HSCLKEN位。这个模式的原理是“时钟环回”clock loopback。通常主设备产生的SSInCLK输出到引脚经过PCB走线后到达从设备这个物理延迟会导致主设备内部采样点与从设备数据变化点之间存在偏差。在高速下这个偏差可能吃掉宝贵的数据建立/保持时间。开启HSCLKEN后QSSI模块会将输出到引脚的SSInCLK信号环回内部作为一个名为HSPEEDCLK的采样时钟。接收数据不再直接用系统时钟或分频后的时钟采样而是用这个环回的HSPEEDCLK采样。由于HSPEEDCLK和实际到达从设备的时钟同源且路径更接近用它来采样返回的数据SSInRX可以更精确地对齐时钟与数据的相位关系相当于在内部做了时序补偿从而允许系统运行在更高的SPI时钟频率下。关键配置顺序文档特别强调为了高速模式正常工作HSCLKEN位必须在任何SSI数据传输开始之前设置或者在对QSSI模块进行复位之后设置。同时必须在设置HSCLKEN之前确保SSICR1中的SSESSI使能位已经置1。错误的顺序会导致功能异常。5. 帧格式的深度剖析与配置指南帧格式决定了数据位在时钟线上的排列规则是主从设备能够正确解码彼此数据的基础。QSSI支持两种基础帧格式由SSICR0寄存器的FRF位选择。5.1 TI同步串行帧格式这是一种TI特有的格式。其最大特征是在每次数据传输开始时SSInFss帧同步信号会先产生一个持续一个时钟周期的高电平脉冲然后才开始传输数据位。在整个数据帧传输期间SSInFss保持低电平。数据在SSInClk的上升沿移出在下落沿被采样。这种格式的优点是帧起始边界非常清晰通过一个独立的脉冲来标记抗干扰能力相对较强。它通常用于TI自家的音频编解码器等器件。在配置时需要注意在此格式下时钟极性SPO和相位SPH通常是固定的根据器件手册不像Freescale SPI那样有四种组合。5.2 Freescale SPI帧格式这是业界最通用的SPI格式也是我们平时接触最多的。其核心在于时钟极性CPOL, SPO和时钟相位CPHA, SPH的四种组合Mode 0-3。SSInFss在此格式下通常作为低有效的片选信号CS在整帧数据传输期间保持有效低电平。SPO (Clock Polarity)0空闲时时钟线SSInClk为低电平。1空闲时时钟线SSInClk为高电平。SPH (Clock Phase)0数据在时钟的第一个边沿即SSInClk从空闲状态跳变到有效状态的边沿被采样在第二个边沿切换。1数据在时钟的第二个边沿被采样在第一个边沿切换。这四种模式必须与从设备的数据手册要求严格匹配。一个快速记忆方法是SPH0时数据在时钟边沿的“开头”采样SPH1时在“中间”采样。而SPO决定了时钟空闲时的状态。一个至关重要的限制当使用**高级模式Advanced/Bi-/Quad-SSI**时只允许使用Freescale SPI格式且必须配置为SPO0 SPH0即Mode 0。这是硬件设计上的约束。如果你需要在高级模式下通信必须确保你的从设备支持Mode 0。下表总结了不同模式下的帧格式支持情况操作模式支持的帧格式允许的SPO/SPH配置备注传统模式 (Legacy)TI格式 Freescale格式SPO0/1, SPH0/1 (四种组合)全功能支持高级/Bi-/Quad-SSI模式仅Freescale格式仅 SPO0, SPH0 (Mode 0)硬件强制要求5.3 帧格式时序图解读与关键节点文档提供了丰富的时序图理解它们对于调试硬件问题至关重要。我们以最常用的Freescale SPI Mode 0 (SPO0, SPH0) 为例拆解其单次传输的时序空闲期SSInClk为低SSInFss为高数据线为高阻态。帧开始主机拉低SSInFss。这使能从设备的输出。第一个半时钟周期主机将第一位数据MSB放到SSInTx线上。从设备也可能同时将其第一位数据放到SSInRx线上取决于具体器件。第一个时钟上升沿这是数据采样边沿。主从设备在此刻采样对方数据线上的电平即锁存输入的数据位。第一个时钟下降沿这是数据切换边沿。主从设备在此刻将各自要发送的下一位数据放到数据线上。后续位传输重复步骤4和5直到LSB传输完毕。帧结束在最后一个位LSB被采样后的一个时钟周期主机拉高SSInFss。在连续传输Back-to-back时Mode 0的行为需要注意如果SPH0有些从设备要求在字节间SSInFss有一个短暂的高电平脉冲来锁存数据。因此即使连续发送主机也可能需要在字节间短暂拉高SSInFss。具体行为取决于FSSHLDFRM位的设置和从设备的要求。6. DMA集成与高效数据搬运对于大批量数据传输使用CPU通过中断来搬运FIFO中的数据效率太低直接内存访问DMA是必选项。QSSI模块与Tiva芯片的μDMA控制器紧密集成提供了独立的发送和接收DMA通道。启用DMA的步骤首先通过RCGCSSI和RCGCGPIO等寄存器使能QSSI和对应GPIO模块的时钟并完成引脚复用配置这是所有QSSI操作的前提。配置μDMA控制器为QSSI的发送和/或接收通道设置好源地址、目的地址、传输数据量等。在QSSI端通过SSIDMACTL寄存器使能DMA通道设置RXDMAE位使能接收DMA。设置TXDMAE位使能发送DMA。可选在SSIIM寄存器中使能DMA完成中断DMARXIM/DMATXIM。DMA请求逻辑发送通道当发送FIFO中至少有1个空位置时会产生单次传输请求当有4个或以上空位置时会产生突发Burst传输请求。接收通道当接收FIFO中有至少1个数据时会产生单次传输请求当有4个或以上数据时会产生突发传输请求。μDMA控制器会根据你的配置单次或突发模式来响应这些请求自动在内存和QSSI FIFO之间搬运数据完全解放CPU。一个关键的软件处理点发送DMA完成中断的处理。当μDMA完成从内存到TX FIFO的数据搬运后SSIRIS寄存器中的DMATXRIS位会被置位。这个标志位不能通过简单地写SSIICR寄存器的DMATXIC位来清除。正确的清除流程是在DMA完成中断服务程序ISR中首先清除SSIDMACTL寄存器的TXDMAE位禁用发送DMA。然后设置SSIICR寄存器的DMATXIC位写1清除中断。当你需要再次启动DMA发送时必须重新设置TXDMAE位。这个“先禁用再清除”的流程是为了确保在清除中断标志时DMA通道处于确定的状态避免残留请求导致中断标志立即被再次置起。这是一个容易忽略的细节不按此操作会导致DMA完成中断无法被正确清除陷入持续中断。性能注意文档提到在Bi-SSI或Quad-SSI主模式下当SSICLK频率高于系统时钟的1/6时使用μDMA会在每个字节传输间插入等待状态。这是因为μDMA访问SRAM的仲裁延迟以及SSI输出吞吐量增加导致的。在设计高带宽应用时需要评估此因素对实际传输速率的影响。7. QSSI初始化、配置流程与实战示例一份可靠的初始化代码是通信成功的基石。以下是基于文档的通用初始化步骤我结合自己的经验补充了细节和注释7.1 基础初始化与配置流程使能模块时钟通过系统控制模块的RCGCSSI寄存器使能目标QSSI模块例如SSI0的时钟。同时通过RCGCGPIO使能连接QSSI引脚的那个GPIO端口的时钟。配置GPIO引脚复用找到数据手册的引脚复用表确定SSIClk,SSIFss,SSIRx,SSITx等信号对应的具体GPIO引脚例如PF0, PF1, PF2, PF3。设置对应GPIO引脚AFSEL交替功能选择位为1。在GPIOPCTL寄存器中配置PMCn端口控制字段将QSSI功能映射到这些引脚上。设置GPIODEN位使能引脚的数字功能。强烈建议根据情况配置上拉/下拉电阻。特别是如果SSIClk空闲状态为高SPO1务必将该引脚配置为内部上拉以避免初始状态浮空。配置QSSI控制寄存器关键步骤 a.确保SSE0如果是从复位初始化先清除SSICR1的SSE位关闭模块。 b.设置主从模式 - 主模式SSICR1 0x0000.0000- 从模式输出使能SSICR1 0x0000.0004- 从模式输出禁用SSICR1 0x0000.000Cc.选择时钟源通过SSICC寄存器选择系统时钟或精确内部振荡器PIOSC等。 d.设置时钟分频写入SSICPSR寄存器设置时钟预分频器CPSDVSR。此值需为偶数范围2-254。 e.配置SSICR0寄存器这是核心配置。 -SCR串行时钟速率与SSICPSR共同决定最终比特率。 -SPH,SPO选择Freescale SPI的时钟模式。 -FRF选择帧格式0为Freescale1为TI。 -DSS数据位大小传统模式4-16位高级模式固定为0x7即8位。可选配置DMA如前述步骤配置μDMA和SSIDMACTL。使能QSSI将SSICR1寄存器的SSE位置1模块开始工作。7.2 配置计算实例与代码片段假设我们需要将QSSI0配置为主机Freescale SPI Mode 0 (SPO0, SPH0)比特率1 Mbps数据位8位系统时钟20 MHz。比特率计算 公式SSIClk SysClk / (CPSDVSR * (1 SCR))代入1 MHz 20 MHz / (CPSDVSR * (1 SCR))为了得到整数分频我们选择CPSDVSR 2则(1SCR) 10所以SCR 9。SSICR0寄存器值计算DSS 0x7(8位数据)FRF 0x0(Freescale格式)SPO 0,SPH 0SCR 0x9将这些字段组合起来具体位域参考数据手册假设SSICR0寄存器位[15:8]是SCR[7:6]是SPH/SPO等那么计算出的值可能是0x0000.09C7具体值需根据寄存器位域掩码计算此处为示例。C语言初始化代码示例基于TI TivaWare库风格#include stdint.h #include stdbool.h #include inc/hw_memmap.h #include driverlib/ssi.h #include driverlib/gpio.h #include driverlib/pin_map.h #include driverlib/sysctl.h void QSSI0_Master_Init(void) { // 1. 使能外设时钟 SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); // 假设SSI0在GPIO A口 // 等待外设就绪良好习惯 while(!SysCtlPeripheralReady(SYSCTL_PERIPH_SSI0)); while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA)); // 2. 配置GPIO引脚复用 // PA2 - SSI0Clk, PA3 - SSI0Fss, PA4 - SSI0Rx, PA5 - SSI0Tx GPIOPinConfigure(GPIO_PA2_SSI0CLK); GPIOPinConfigure(GPIO_PA3_SSI0FSS); GPIOPinConfigure(GPIO_PA4_SSI0RX); GPIOPinConfigure(GPIO_PA5_SSI0TX); GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5); // 3. 配置并启用SSI // 主模式 Mode 0, 1 Mbps, 系统时钟20MHz 数据位8位 SSIConfigSetExpClk(SSI0_BASE, 20000000, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 1000000, 8); // 4. 使能SSI模块 SSIEnable(SSI0_BASE); }这段代码使用了TI的驱动库来简化寄存器操作。关键函数SSIConfigSetExpClk内部会计算CPSDVSR和SCR值并配置SSICR0和SSICPSR寄存器。7.3 高级模式配置示例假设我们需要先以Advanced SSI模式发送2字节再切换到Bi-SSI模式发送2字节。以下是基于直接寄存器操作的思路首先完成上述基础初始化并确保DSS8。配置SSICR1寄存器设置MODE0x3Advanced SSIFSSHLDFRM1帧保持MS0主模式。准备发送数据到TX FIFO第一个字节Advanced SSI模式数据 (0x3 13) | data1。EOM位先设为0。第二个字节结束帧数据 (0x3 13) | data2 | (1 12)。这里(1 12)即设置EOM1表示Advanced SSI帧结束。写入这两个16位数据到SSIDR。此时硬件会自动发送这两个字节并在第二个字节后拉高SSInFss。在SSInFss拉高后可通过查询状态或中断判断无需重新初始化直接更改SSICR1的MODE位为0x1Bi-SSIDIR0发送。准备Bi-SSI数据第三个字节Bi-SSI模式数据 (0x1 13) | data3。EOM0。第四个字节结束帧数据 (0x1 13) | data4 | (1 12)。写入TX FIFO。硬件会以Bi-SSI模式发送这两个字节。这个过程演示了如何利用FIFO中的模式位和EOM位在单次FIFO队列中组织混合模式的多帧传输。关键在于确保模式切换符合文档允许的序列此例中Advanced - Bi-SSI是允许的。