深入解析NXP PXS20 DSPI模块:FIFO机制、时序配置与高速SPI通信实战
2026/6/24 18:57:27 网站建设 项目流程

1. 项目概述

如果你在嵌入式领域摸爬滚打过几年,肯定对SPI(Serial Peripheral Interface)不陌生。它就像电子设备间的高速“方言”,简单几根线就能让主控芯片和外设“聊”起来,速度快、协议简单,是连接Flash、传感器、显示屏的常客。但当你真正上手调一个复杂的项目,尤其是数据吞吐量一大,或者时序要求苛刻时,就会发现标准SPI那套“一问一答”的轮询方式有点力不从心了。主控CPU频繁被中断去处理收发数据,效率低下不说,时序上稍有不慎就可能丢数据。

这时候,像Freescale(现NXP)PXS20这类微控制器里的DSPI模块,就显得格外“香”了。DSPI,全称Deserial Serial Peripheral Interface,你可以把它理解为SPI的“Pro Max”版本。它绝不仅仅是换个名字,其核心在于引入了硬件FIFO(First-In First-Out)缓冲区和一套更精细的内部状态机(FSM)。这意味着什么?意味着CPU可以一次性往发送FIFO里塞好几帧数据,然后去忙别的,DSPI的硬件会自己按顺序、按设定好的时序把数据发出去;接收时也一样,数据会自动存入接收FIFO,等攒到一定数量CPU再来批量读取。这大大解放了CPU,也使得实现高吞吐量、低延迟的通信成为可能。

我最近在调试一个基于PXS20的高速数据采集板,传感器通过SPI以10Mbps的速率吐数据,传统SPI接口根本处理不过来,CPU占用率飙升。正是深入折腾了DSPI的FIFO机制和各种时序参数,才让系统稳定跑了起来。这篇文章,我就结合PXS20的参考手册和实际踩坑经验,带你彻底搞懂DSPI,特别是它的FIFO工作机制和那些让人眼花缭乱的传输格式与延时配置。无论你是刚接触SPI的新手,还是想优化现有通信协议的老鸟,相信这些“干货”都能让你少走弯路。

2. DSPI核心架构与运行状态解析

要驾驭DSPI,首先得理解它的“大脑”和“工作状态”。和简单的GPIO模拟SPI不同,DSPI是一个相当复杂的片上外设,其行为由内部状态机精密控制。

2.1 模块的两种基本状态:STOPPED与RUNNING

DSPI模块在任何时候都处于两种基本状态之一:STOPPED(停止)RUNNING(运行)。这个设计非常关键,它区分了配置阶段和通信阶段。

当模块处于STOPPED状态时,它就像进入了“休眠”或“配置模式”。此时,如果DSPI被配置为主机,它不会主动发起任何传输;如果被配置为从机,它也不会响应外部主机的任何通信请求。这个状态是一个“安全区”,你可以放心地读写DSPI所有的配置寄存器(比如DSPI_MCR,DSPI_CTARx等),而不用担心正在进行的传输被打断或产生不可预知的结果。刚上电或复位后,DSPI默认就处于STOPPED状态。

当模块切换到RUNNING状态,DSPI就进入了“战斗模式”。主机会根据命令主动产生SCK时钟和PCS片选信号来发起传输,从机则时刻准备着响应外部主机的呼叫。所有的数据传输、FIFO操作都发生在这个状态。

那么,状态如何切换呢?模块的状态由DSPI_SR状态寄存器中的TXRXS位直观反映:该位为1表示RUNNING,为0表示STOPPED。

从STOPPED进入RUNNING(启动传输),必须同时满足以下三个条件,缺一不可:

  1. DSPI_SR[EOQF](传输队列结束标志)必须为0(即未结束)。
  2. 系统芯片(SoC)未处于调试模式,或者DSPI_MCR[FRZ](冻结位)被清零。这意味着在调试时,你可以通过设置FRZ位来冻结DSPI,方便观察状态。
  3. DSPI_MCR[HALT](暂停位)必须为0。

从RUNNING退出到STOPPED(停止传输),则简单得多,只要满足以下任一条件即可:

  1. DSPI_SR[EOQF]位被置1(通常由软件设置,表示主动结束队列)。
  2. SoC进入调试模式并且DSPI_MCR[FRZ]位被置1。
  3. DSPI_MCR[HALT]位被置1。

这里有个重要的时序细节:当有传输正在进行时,状态转换(RUNNING -> STOPPED)会发生在下一帧的边界;如果没有传输在进行,则会立即转换。这保证了当前帧的完整性,不会在半途被强行终止。

实操心得:在初始化DSPI时,务必先确保模块在STOPPED状态(检查TXRXS),再配置寄存器。配置完成后,再清除HALT或满足其他条件使其进入RUNNING。在需要动态修改关键参数(如波特率)前,一个稳妥的做法是先设置HALT位让其暂停,修改后再清除。直接“热修改”正在使用的寄存器是嵌入式开发的大忌,极易导致通信错乱。

2.2 SPI配置模式与主从模式

DSPI模块功能强大,支持SPI、DSI、CSI等多种配置。我们最关心的是其SPI配置模式,此时DSPI_MCR寄存器中的DCONF字段应为0b00。在这个模式下,数据通过移位寄存器串行传输,且帧长度可在4到16位之间灵活编程。

SPI配置下,数据流的核心路径是:主机CPU或DMA控制器将待发送的数据从外部内存搬运到DSPI内部的发送FIFO(TX FIFO);发送时,数据从TX FIFO加载到移位寄存器,再一位一位地从SOUT引脚移出。接收时,从SIN引脚移入的数据先存到移位寄存器,在一帧接收完成后,再被转存到接收FIFO(RX FIFO),最后由CPU或DMA读走。这个双FIFO结构是DSPI高性能的基石。

SPI配置支持两种角色:主模式(Master)从模式(Slave)。两种模式下的FIFO操作逻辑基本相似,核心区别在于传输的发起与控制权

主模式下,DSPI是“老板”,它完全掌控通信。它负责生成串行通信时钟(SCK)和外围设备片选(PCS)信号。最关键的是,TX FIFO中的每一个条目,不仅包含要发送的数据(Data Field),还包含一个SPI命令字段(Command Field)。这个命令字段是个“指挥棒”,它决定了本次传输使用哪一组时钟与传输属性寄存器(CTAR0-CTAR3)来设定波特率、时钟极性与相位等,以及具体断言(拉低)哪个PCS信号。这实现了“帧级”的精细控制,每一帧都可以有不同的通信参数。

而在从模式下,DSPI是“员工”,它只响应外部SPI主机的呼叫。它不主动发起传输,SCK和片选信号都由外部主机提供。因此,从机模式下的TX FIFO命令字段空间被“挪用”了——它存储的是待发送数据的高16位(假设数据是32位)。从机的通信参数(如时钟极性CPOL、相位CPHA、帧长)必须通过DSPI_CTAR0寄存器预先设定好,并且必须与主机严格匹配,否则通信无法进行。

注意事项:很多工程师在调试主从通信时,只关注主机的配置,忽略了从机也需要正确配置CPOLCPHA。即使从机不产生时钟,这两个参数也决定了从机在哪个时钟边沿采样数据和更新输出数据,必须与主机一致。此外,从机的TX FIFO如果没有及时填入数据,当主机发起读操作时,从机会发送命令字段中的内容(此时是数据高16位),这可能不是你期望的数据,需要特别注意。

3. FIFO缓冲机制深度剖析

FIFO是DSPI的灵魂,理解了它,就掌握了高效使用DSPI的钥匙。它本质上是一个硬件队列,解决了CPU与串行通信速度不匹配的问题。

3.1 TX FIFO:发送数据的蓄水池与调度中心

发送FIFO(TX FIFO)是一个深度为1到5个条目的缓冲区(具体深度取决于具体的SoC型号)。每个条目都是一个32位的“数据包”,其中包含16位的命令字段和16位的数据字段(对于8位帧,数据在低8位)。你可以通过写DSPI_PUSHR寄存器来向TX FIFO“压入(Push)”数据。

DSPI_SR寄存器中的TXCTR字段就像一个水位计,实时显示TX FIFO中有效条目的数量。每次写入PUSHR或从TX FIFO移出一个条目到移位寄存器时,这个计数器都会更新。TXNXTPTR则像是一个“读指针”,指向下一个将要被传输的FIFO条目。

填充TX FIFO:当TX FIFO未满时,状态寄存器中的TX FIFO Fill Flag (TFFF)会被置位。这个标志位非常有用,它可以触发DMA请求或中断,通知CPU或DMA控制器:“FIFO还有空位,可以继续送数据了!”当你向PUSHR写入数据填满FIFO后,TFFF会自动清零。如果试图向一个已满的TX FIFO写入数据,DSPI会直接忽略这次操作,且不会报错。因此,在编写发送程序时,必须通过查询TFFF标志或利用其中断/DMA来管理数据流,避免数据丢失。

排空TX FIFO:TX FIFO的条目是通过“移位发送”的方式被移除的。只要FIFO里有数据,DSPI的状态机就会自动将其加载到移位寄存器并发送出去。每发送一帧,TXCTR就减1。当一帧数据完全移出后,TCF(传输完成标志)位会被置位。你也可以通过设置DSPI_MCR[CLR_TXF]位来手动清空整个TX FIFO。

这里有一个从机模式下的特殊场景需要注意:发送下溢(Transmit FIFO Underflow)。如果外部主机向一个DSPI从机发起读操作,而此时从机的TX FIFO是空的,没有数据可以发送,那么从机的TFUF标志位就会被置位,并可能产生中断。这通常意味着从机端的软件没有及时准备待发送的数据。

3.2 RX FIFO:接收数据的收纳箱

接收FIFO(RX FIFO)的深度更大,通常是1到16个条目(同样SoC相关),用于缓冲接收到的数据。当一帧数据在移位寄存器中接收完毕,它会被自动转存到RX FIFO中。CPU或DMA通过读取DSPI_POPR寄存器来从RX FIFO中“弹出(Pop)”数据。

与TX FIFO类似,RXCTR指示RX FIFO中有效数据的数量,POPNXTPTR是弹出指针。当RX FIFO非空时,RFDF(RX FIFO Drain Flag)标志置位,可用于触发读取中断或DMA请求。

填充RX FIFO的过程是自动的。但如果RX FIFO和移位寄存器都满了,此时又有新的传输完成,就会发生溢出(Overflow)RFOF标志位会被置位。此时的行为由DSPI_MCR[ROOE]位控制:若ROOE=1,新数据会覆盖移位寄存器中的旧数据(可能造成数据丢失但维持通信);若ROOE=0,则新数据直接被丢弃。在高速连续接收场景下,必须确保及时读取RX FIFO,或使用DMA,避免溢出发生。

排空RX FIFO就是读取POPR的过程。尝试从一个空的RX FIFO读取数据会被忽略,读出的值是不确定的。RFDF标志在FIFO变空后,会在DMA读操作完成或软件写1清除时复位。

3.3 FIFO禁用模式:双缓冲简化操作

DSPI也提供了禁用FIFO的选项,通过设置DSPI_MCR[DIS_TXF]DIS_RXF位实现。当FIFO被禁用时,DSPI会退化为一个双缓冲的简易SPI接口。这对软件来说是透明的,你依然读写PUSHRPOPR寄存器,但此时它们直接对接移位寄存器。

在这种模式下,状态寄存器中的TFFFTFUFTXCTR等字段的行为就像FIFO只有1个深度条目一样。这对于那些不需要大数据缓冲、或者希望用最简逻辑控制SPI的场景非常有用,可以减少状态管理的复杂度。

避坑指南:关于FIFO指针和计数器,手册里提到当FIFO禁用时,TXNXTPTRPOPNXTPTR以及DSPI_TXFR/RXFR寄存器的内容是未定义的(undefined)。这意味着在禁用FIFO的模式下,不要试图去读取或依赖这些寄存器的值来判断状态,而应该只关心TFFFTCFRFDF这些核心标志位。我曾遇到过在禁用FIFO后还去查TXCTR导致程序逻辑错误的问题,排查了很久。

4. 波特率与时钟延时生成机制

SPI通信的时序是其稳定性的核心。DSPI提供了非常灵活的时钟和延时控制,这也是它比基础SPI强大的地方。所有这些时序参数,都是通过DSPI_CTAR0~DSPI_CTAR3这组时钟与传输属性寄存器来配置的。

4.1 波特率(Baud Rate)计算

波特率就是SCK的频率。DSPI通过两级分频来从系统时钟(fsys)得到SCK:一个预分频器(PBR)和一个分频器(BR),并且可以通过双波特率位(DBR)选择是否将分频系数减半。计算公式如下:SCK频率 = fsys / [(1+DBR) * PBR * BR]其中PBR和BR的值由CTAR寄存器中的PBRBR字段选择,它们对应着固定的分频系数(如PBR=0b00对应分频系数2,BR=0b0000对应分频系数2)。DBR为0时,分母中的(1+DBR)为1;DBR为1时,则为2,相当于波特率翻倍。

例如,手册中的例子:fsys=100MHz,PBR=0b00(2),BR=0b0000(2),DBR=0,则SCK = 100MHz / (2*2) = 25MHz。这是一个非常直观的计算过程,在编程时,我们通常是根据需要的SCK频率,反向推算出合适的PBR、BR和DBR组合。

4.2 关键时序延时详解

除了波特率,三个关键的延时参数对匹配不同外设的时序要求至关重要:

  1. PCS到SCK延时(tCSC):从片选信号PCS有效(通常拉低)到第一个SCK时钟边沿出现之间的时间。这个延时给了从设备一个准备时间,确保在时钟开始前,片选已稳定建立。其计算方式与波特率类似:tCSC = (PCSSCK * CSSCK) / fsysPCSSCKCSSCKCTAR中的配置字段。

  2. SCK后延时(tASC):从最后一个SCK时钟边沿到片选信号PCS无效(通常拉高)之间的时间。这个延时保证了在时钟结束后,数据有足够的保持时间(Hold Time)被从设备采样。计算公式:tASC = (PASC * ASC) / fsys

  3. 传输后延时(tDT):前一帧的PCS无效到下一帧的PCS有效之间的最小空闲时间。它用于分隔两次独立的传输。计算公式:tDT = (PDT * DT) / fsys特别注意:在连续时钟模式(CONT_SCKE=1)下,此延时固定为1个SCK周期。

这些延时参数的单位都是系统时钟周期。通过灵活配置它们,你可以精确地满足各种SPI外设数据手册中规定的tCSS(片选建立时间)、tCSH(片选保持时间)等参数要求。

4.3 外设片选选通使能(PCSS)

这是一个高级功能,用于生成一个额外的PCSS信号。当DSPI_MCR[PCSSE]置位时,PCSS信号可以作为外部多路选择器的控制信号,将有限的几个PCS引脚(如PCS[0:4], [6:7])解码成多达128个无毛刺的片选信号。PCSS的断言和置位延时分别由tPCSSCKtPASC控制,其计算直接依赖于PCSSCKPASC字段的值:tPCSSCK = PCSSCK / fsys。这在对片选切换时序有严苛要求,或者需要扩展大量片选时非常有用。

参数配置经验:在配置这些延时参数时,我习惯先根据外设数据手册的要求,计算出所需的最小时间(单位纳秒),然后根据系统时钟频率换算成需要的时钟周期数。接着,对照CTAR寄存器中PCSSCKCSSCK等字段的取值表(这些字段通常是几位二进制数,对应一个预设的分频系数乘数),选择能够提供大于等于所需周期数的组合。宁大勿小,多留一点余量有利于系统在极端温度或电压下稳定工作。例如,某Flash芯片要求tCSH > 20ns,我的fsys=100MHz(周期10ns),那么tASC至少需要配置为2个系统时钟周期(20ns)。

5. SPI传输格式与连续模式实战

SPI通信有四种基本“方言”,由时钟极性(CPOL)、时钟相位(CPHA)和修改传输格式使能(MTFE)共同决定。理解这四种格式的波形,是调试SPI通信的必修课。

5.1 经典SPI格式(CPHA=0 与 CPHA=1)

CPHA=0:数据在第一个时钟边沿被采样。具体来说,主机在片选有效后,会先将第一位数据放到MOSI(主出从入)线上,然后等待tCSC延时,再产生第一个SCK边沿(对于CPOL=0是上升沿,CPOL=1是下降沿)。主从设备都在这个奇数边沿采样数据,在随后的偶数边沿更新输出数据。这种格式下,数据在时钟边沿到来之前就已经稳定,适合对数据建立时间要求宽松的从设备。

CPHA=1:数据在第二个时钟边沿被采样。主机在片选有效并等待tCSC后,先产生第一个SCK边沿,同时将第一位数据放到MOSI线上。从设备则在第一个边沿时,将它的第一位数据放到MISO(主入从出)线上。主从设备都在偶数边沿采样数据,在奇数边沿更新输出数据。这种格式下,数据在时钟边沿到来时才变化,给了从设备更多的准备时间。

CPOL则决定了SCK时钟空闲时的电平:CPOL=0为低电平,CPOL=1为高电平。CPOL和CPHA的组合,构成了SPI的四种模式(Mode 0-3)。主从设备的模式必须完全一致。

5.2 修改的SPI传输格式(MTFE=1)

当通信速率非常高时,PCB走线延时、器件输入输出延时等会成为不可忽视的因素。经典SPI格式假设主从设备在时钟边沿的中心点采样,但在高速下,这个假设可能不成立,导致采样错误。

DSPI的修改传输格式(MTFE=1)就是为了解决这个问题。它允许主设备推迟采样点。通过配置DSPI_MCR[SMPL_PT]字段,可以将主设备对SIN(即MISO)的采样点,从时钟边沿延迟1个或2个系统时钟周期。这相当于给了从设备发送的数据更长的“旅行时间”到达主设备,提高了高速通信的容错性。

手册中的时序图清晰地展示了这一点。在MTFE=1且CPHA=0的格式下,从设备依然在奇数SCK边沿采样主机数据,但DSPI作为主机,其采样点(SMPL_PT)可以延后。当系统时钟与SCK频率比(fsys/fsck)小于4时,建议将SMPL_PT设为0。

5.3 连续选择与连续时钟模式

连续选择格式由TX FIFO命令字段中的CONT位控制。当CONT=0时,每传输完一帧,PCS片选信号都会恢复到空闲状态(由PCSISn位定义),并在下一帧开始前插入tDT延时。这是最常见的方式。

CONT=1时,PCS信号在连续的多个帧传输期间保持有效,帧与帧之间没有tDT延时。这对于那些需要在一个片选有效周期内传输多字节命令和数据的设备(如很多SPI Flash的页编程命令)非常有用。

重要警告:使用连续选择格式时,必须确保在TX FIFO变空之前,将所有需要在同一个PCS有效期内连续发送的帧全部填入FIFO。并且,最后一个使PCS保持有效的帧(即TX FIFO中最后一个CONT=1的帧)之后,必须紧跟一个CONT=0的帧来结束本次连续传输。否则,如果FIFO空了而PCS还保持有效,从设备可能会误解后续的通信,或者导致DSPI从机模式下发生TX FIFO下溢错误。

连续时钟模式通过设置DSPI_MCR[CONT_SCKE]来启用。在此模式下,SCK时钟在帧与帧之间不会停止,而是持续运行。这仅支持CPHA=1的模式。启用连续时钟后,tCSCtDT延时被简化或固定:tDT固定为1个SCK周期。这种模式适用于那些需要持续时钟的从设备。

避坑指南:手册中特别用NOTE强调,在连续时钟模式下进行SPI传输,必须使用CTAR0,并且在启动传输前必须使用MCR.CLR_TXF位清空TX FIFO。我曾在启用连续时钟后未清空FIFO就发起传输,结果出现了难以解释的时序错乱。另外,在连续时钟且连续选择(CONT=1)模式下,如果TX FIFO空了但PCS还保持有效,SCK会继续空跑,这可能导致从设备采样到错误数据。因此,必须严格管理好CONT位的设置和FIFO的数据流。

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

调通DSPI,尤其是用到FIFO和复杂时序时,总会遇到各种“坑”。下面是我在实际项目中总结的一些典型问题及排查思路。

6.1 通信完全无反应或数据全错

  1. 检查基本配置:这是最基础的。确认主从设备的CPOLCPHA、数据位顺序(LSBFE)、帧长度(FMSZ)是否完全一致。一个字节位序设反,整个数据就面目全非。
  2. 确认模块状态:使用调试器或通过软件读取DSPI_SR[TXRXS]位,确认DSPI模块是否已从STOPPED进入了RUNNING状态。如果HALTFRZ位被意外置位,模块是不会工作的。
  3. 检查时钟和引脚:用示波器或逻辑分析仪测量SCK、PCS、SIN、SOUT引脚。首先看SCK有没有波形,频率是否正确(计算波特率)。如果SCK都没有,检查DSPI_MCR的模块使能位、对应引脚的复用功能是否已正确设置为DSPI。
  4. 验证FIFO操作:如果SCK有,但没数据。检查TX FIFO是否已填入数据(查TXCTRTFFF)。对于从机,检查主机发起传输时,从机的TX FIFO里是否有待发送数据,避免下溢。

6.2 FIFO数据卡住或传输不连续

  1. 中断/DMA未正确处理:如果依赖TFFF中断来填充TX FIFO,或RFDF中断来清空RX FIFO,必须确保中断服务程序(ISR)正确清除中断标志位(通常通过写1清除)。标志位没清,后续中断就无法触发。
  2. FIFO指针溢出:虽然不常见,但如果你手动操作PUSHR/POPR的速率和硬件移位速率不匹配,理论上可能导致TXNXTPTRPOPNXTPTR指针溢出(超过DSPI_HCR[TXFR/RXFR]定义的最大值)。通常让硬件自动管理即可,但极端测试时需留意。
  3. 连续模式下的CONT位错误:在连续选择(CONT=1)模式下传输一串数据后,通信突然停止或出错。务必检查你是否在TX FIFO的最后一个条目中将CONT位设为了0,以正确结束本次连续传输并释放PCS线。

6.3 时序不稳定,高速时出错

  1. 延时参数不足:这是高速SPI的常见病。用逻辑分析仪抓取波形,重点测量tCSC(PCS有效到第一个SCK边沿)、tASC(最后一个SCK到PCS无效)。与外设数据手册要求的最小建立时间(tSU)和保持时间(tHOLD)对比。如果不足,增大PCSSCK/CSSCKPASC/ASC的配置值。
  2. 启用修改传输格式(MTFE):在SCK频率接近或超过10MHz时,强烈建议尝试启用MTFE=1,并调整SMPL_PT。这能有效补偿板级延时。可以先从SMPL_PT=2(延迟2个系统时钟)开始测试。
  3. 检查PCB布局:高速SPI对走线非常敏感。确保SCK线尽可能短,并远离其他高速或噪声源。MISO和MOSI线最好等长,并做好阻抗控制。如果可能,在信号线上串联一个小电阻(如22欧姆)有助于减少过冲和振铃。

6.4 从机模式下的特殊问题

  1. 从机无响应:确保从机的DSPI_CTAR0中的CPOLCPHAFMSZ与主机完全匹配。同时,检查从机模块是否已使能并进入RUNNING状态。
  2. 从机发送错误数据:在从机模式下,当TX FIFO为空时,发送的数据是TX FIFO命令字段的内容(此时是数据高16位),这可能是一个固定值或上次残留值。确保在主机发起读操作前,从机已将要发送的数据写入TX FIFO(写入PUSHR的低16位数据字段部分,高16位会被忽略/用作命令?这里需注意:从机模式下,写入PUSHR的32位字中,高16位会被当作待发送数据的高位,低16位是数据低位。手册原文是“the SPI command field space is used for 16 most significant bit of the transmit data.”)。

调试DSPI,一个好的逻辑分析仪是必不可少的。我习惯设置触发条件为PCS下降沿,然后同时捕获SCK、MOSI、MISO四路信号。通过分析波形,可以直观地看到数据是否对齐、延时是否满足、CONT位是否生效,比单纯看代码和寄存器值高效得多。最后,耐心阅读芯片参考手册的时序图,结合波形反复比对,是解决复杂时序问题的终极法宝。

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

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

立即咨询