1. 项目概述:深入Tiva QSSI的SPI通信核心
在嵌入式开发,尤其是基于德州仪器Tiva™系列微控制器的项目中,SPI(串行外设接口)几乎是连接外部传感器、存储器和显示模块的“标配”。但很多开发者,包括我早期,都曾有过这样的困惑:明明按照标准SPI时序写了驱动,为什么和某些特定芯片通信就是不稳定,甚至完全不通?问题往往就出在“帧格式”和“时钟模式”的配置细节上。Tiva微控制器内部的Quad同步串行接口(QSSI)模块功能强大,它不仅仅支持我们常说的“标准SPI”,还完整兼容Freescale(现NXP)和TI自家的同步串行帧格式。这两种格式在信号行为,特别是片选信号(SSInFss)和时钟(SSInClk)的空闲状态、启动时序上有着根本性的区别。更关键的是,在Freescale SPI模式下,通过SPO(时钟极性)和SPH(时钟相位)这两个比特位的组合,可以衍生出四种不同的数据采样时序模式。如果配置与外设芯片的要求不匹配,数据采样边沿对不上,通信自然失败。这篇文章,我就结合手册和实际调试经验,为你彻底拆解Tiva QSSI模块的这两种帧格式,以及Freescale SPI的四种工作模式。我会用示波器抓取的实际波形图(虽然这里用文字描述)和寄存器配置代码片段,让你不仅知道怎么配,更明白为什么要这样配,以及在不同场景下如何做出最合适的选择。
2. 核心概念解析:SPI通信的基石
在深入QSSI模块的具体实现之前,我们必须先统一几个核心概念的理解。这些概念是理解后续所有配置差异和时序图的基础。
2.1 信号线定义与角色
Tiva QSSI模块的SPI接口通常由四根线构成,理解每根线的角色至关重要:
- SSInClk (Serial Clock): 串行时钟线,由主机产生,用于同步主从设备之间的数据移位。它的频率、极性和相位是本文讨论的核心。
- SSInFss (Frame Select): 帧选择信号,在SPI语境下通常作为片选(Chip Select, CS)或从机选择(Slave Select, SS)信号。它的行为模式是区分Freescale和TI格式的关键。
- SSInTx/SSInDAT0 (Master Out Slave In, MOSI): 主机输出、从机输入数据线。主机通过此线向从机发送数据。
- SSInRx/SSInDAT1 (Master In Slave Out, MISO): 主机输入、从机输出数据线。主机通过此线接收从机数据。
注意:在高级的Bi-SSI或Quad-SSI模式下,DAT0-DAT3所有引脚都可能被用作双向数据线,但这超出了基础SPI讨论范围。本文聚焦于标准四线SPI模式。
2.2 时钟极性(CPOL)与时钟相位(CPHA)
这是SPI配置中最容易混淆,也最核心的两个参数。在QSSI的寄存器中,它们对应SPO (SSICR0[6])和SPH (SSICR0[7])位。
时钟极性 SPO (Clock Polarity):
- SPO = 0: 时钟空闲时为低电平。这意味着在数据传输的间隙,SSInClk线保持为低。
- SPO = 1: 时钟空闲时为高电平。在数据传输间隙,SSInClk线保持为高。
- 关键影响:它决定了时钟信号在空闲时的静态电平,是波形的基础。
时钟相位 SPH (Clock Phase):
- SPH = 0: 数据在第一个时钟边沿被采样(捕获)。对于SPO=0,第一个边沿是上升沿;对于SPO=1,第一个边沿是下降沿。
- SPH = 1: 数据在第二个时钟边沿被采样。对于SPO=0,第二个边沿是下降沿;对于SPO=1,第二个边沿是上升沿。
- 关键影响:它决定了数据采样发生的时刻,直接关系到数据建立(Setup)和保持(Hold)时间是否满足从机要求。SPH位对传输的第一个数据位影响最大,因为它决定了在第一个数据位有效之前,是否有一个额外的半个时钟周期的延迟。
这两个位的四种组合(SPO/SPH: 0/0, 0/1, 1/0, 1/1),构成了常说的SPI Mode 0, 1, 2, 3。具体对应关系为:Mode 0 (CPOL=0, CPHA=0), Mode 1 (CPOL=0, CPHA=1), Mode 2 (CPOL=1, CPHA=0), Mode 3 (CPOL=1, CPHA=1)。你所连接的外设数据手册中,一定会明确指定其工作在哪种Mode。
2.3 帧格式:Freescale vs. TI
这是Tiva QSSI模块提供的两种底层协议格式选择,通过FRF (SSICR0[5:4])位域进行选择。
Freescale SPI Frame Format (FRF = 0x0):
- 这是我们最常接触的“经典”SPI格式。在此格式下,
SSInFss信号作为纯粹的低有效片选信号。其行为与SPO/SPH的配置紧密相关。 - 在空闲时,
SSInFss通常被拉高(无效)。当主机要发起传输时,先将SSInFss拉低选中从机,然后根据SPO/SPH的配置产生时钟并收发数据。 - 它支持全部四种SPO/SPH模式,提供了最大的灵活性以适配各种外设。
- 这是我们最常接触的“经典”SPI格式。在此格式下,
Texas Instruments Synchronous Serial Frame Format (FRF = 0x1):
- 这是TI定义的一种格式。在此格式下,
SSInFss信号的行为更像一个帧同步脉冲,而非持续的片选。 - 在空闲时,
SSInClk和SSInFss都被强制为低电平。当发送FIFO中有数据时,SSInFss会先产生一个时钟周期的高电平脉冲,然后在下一个时钟上升沿,数据帧的最高位(MSB)开始移出。 - 重要限制:在TI格式下,SPO和SPH位必须为0(即SPO=0, SPH=0),且不可配置。它固定了一种时序模式。
- 这是TI定义的一种格式。在此格式下,
选择哪种格式,完全取决于你要通信的从设备要求。绝大多数SPI外设(如Flash、ADC、传感器)都遵循Freescale SPI格式。而一些TI自家的或其他特定协议的芯片,可能会要求使用TI同步串行帧格式。
3. 帧格式与工作模式深度对比
理解了基本概念后,我们进入实战分析环节。手册中的Table 20-4提供了一个高层次的特性对比,但我们需要结合时序图来理解这些特性在信号电平上的具体表现。
3.1 特性对比总览
| 特性 (Feature) | Freescale SPI 模式 | TI 模式 | 说明与影响 |
|---|---|---|---|
| 帧保持 (Frame Hold) | 可用 | 不可用 | 在Freescale格式下,可通过FSSHLDFRM位控制SSInFss是在整个数据帧期间保持有效(=1),还是每字节产生一个脉冲(=0)。TI格式下SSInFss固定为单周期脉冲。 |
| 高速模式 (仅主机接收) | 可用 | 不可用 | 在Freescale格式下,主机接收时可使用更高速度的内部时钟,提升吞吐量。通过HSCLKEN位使能。 |
| SPO/SPH配置 | 完全可配置 (0/0, 0/1, 1/0, 1/1) | 固定为 SPO=0, SPH=0 | 这是两种格式最根本的差异之一。Freescale格式的灵活性使其能适配绝大多数SPI从机。TI格式则固定了一种时序。 |
| 频率 (系统时钟:SSInClk) | 主机 1:2 从机 1:12 | 主机 1:2 从机 1:12 | 分频器设置相同,最大通信速率理论值一致。但实际最高速率受限于GPIO速度、板级布线等因素。 |
| 高级/Bi-/Quad-SSI模式支持 | 支持,但有限制 | 支持,但有限制 | 在这些增强模式下,两种格式都支持帧保持和高速模式。但关键限制是:SPO和SPH必须配置为0。这意味着在增强模式下,只能使用Freescale格式的Mode 0 (SPO=0, SPH=0)。 |
实操心得:这个对比表是你选型的快速参考。如果你的项目需要使用Bi-SSI或Quad-SSI模式(例如驱动QSPI Flash以提升速度),那么无论从机支持哪种模式,你都只能将其配置为Freescale SPI格式,且SPO=0, SPH=0。这是硬件限制,软件无法绕过。
3.2 Texas Instruments (TI) 同步串行帧格式详解
当FRF位设置为0x1时,QSSI工作在TI格式下。这种格式的时序相对简单固定。
核心特点:
- 空闲状态:
SSInClk和SSInFss均被强制为低电平。发送数据线SSInTx为高阻态。 - 启动传输:当发送FIFO中有数据时,硬件自动将
SSInFss拉高一个SSInClk周期。这个上升沿和下降沿构成了一个同步脉冲。 - 数据移出:在
SSInFss脉冲的下一个时钟上升沿,数据帧的最高位(MSB)开始从SSInTx引脚移出。同时,从机也应在此刻将其数据的MSB放到SSInRx引脚上。 - 数据采样:主从双方都在每个时钟的下降沿将数据采样到各自的移位寄存器中。这是一个固定的“上升沿变化,下降沿采样”的模式,对应SPO=0, SPH=0。
- 连续传输:在背靠背连续传输时,
SSInFss会在每帧数据之间再次产生一个单周期的高脉冲,作为下一帧的起始信号。
配置示例与代码: 假设我们需要在TI格式下,以主模式、1Mbps速率、8位数据长度进行通信。系统时钟为20MHz。 根据公式:SSInClk = SysClk / (CPSDVSR * (1 + SCR))我们需要CPSDVSR * (1 + SCR) = 20MHz / 1MHz = 20。 一个典型配置是:CPSDVSR = 2,SCR = 9。因为2 * (1+9) = 20。
// 假设使用QSSI0模块 void QSSI0_TI_Mode_Init(void) { // 1. 确保SSE位为0,禁用QSSI以进行配置 SSI0_CR1_R = 0x00000000; // 清除SSE // 2. 配置为主机模式 (MS=0) // 此时SSE=0,所以可以直接写SSICR1的MS位,但通常我们直接写整个寄存器更清晰 // 实际上,在初始化序列中,我们会在最后一步才设置SSE,所以这里可以先不管CR1 // 3. 配置时钟预分频器 CPSDVSR = 2 SSI0_CPSR_R = 0x00000002; // 4. 配置控制寄存器0 (SSICR0) // DSS = 0x7 (8-bit data) // FRF = 0x1 (TI format) // SPO = 0, SPH = 0 (TI格式固定为此值) // SCR = 0x9 // 计算: DSS=7, FRF=1, SPO=0, SPH=0, SCR=9 // 位域: DSS[3:0]=0x7, FRF[5:4]=0x1, SPO[6]=0, SPH[7]=0, SCR[15:8]=0x09 // 寄存器值: (SCR<<8) | (SPH<<7) | (SPO<<6) | (FRF<<4) | DSS // = (0x09<<8) | (0<<7) | (0<<6) | (1<<4) | 0x07 // = 0x0900 | 0x00 | 0x00 | 0x10 | 0x07 = 0x0917 SSI0_CR0_R = 0x00000917; // 5. 最后,使能QSSI模块 (设置SSE位) // 同时确认MS位为主机模式(0) SSI0_CR1_R = 0x00000002; // SSE=1, MS=0, 其他位为0 }这个配置产生的时序将严格遵循上文描述的TI格式。注意,在这种格式下,你无法通过修改SPO/SPH来调整采样边沿。
3.3 Freescale SPI格式的四种模式详解
当FRF位设置为0x0时,QSSI工作在Freescale SPI格式下。此时,SPO和SPH位的配置将决定四种不同的时序模式。这是调试SPI驱动时最需要关注的部分。
通用空闲状态(对于所有Freescale模式):
SSInFss被强制为高电平(无效)。SSInTx为高阻态。SSInClk的电平由SPO位决定:SPO=0时为低,SPO=1时为高。
3.3.1 模式0:SPO=0, SPH=0
这是最常用的SPI模式之一。
- 时序特点:
- 空闲时,时钟
SSInClk为低,片选SSInFss为高。 - 传输开始时,主机先将
SSInFss拉低选中从机。 - 第一个数据捕获边沿发生在
SSInClk的第一个上升沿。也就是说,在SSInFss变低后,数据线(SSInTx和SSInRx)上的数据必须在第一个时钟上升沿到来之前就已经稳定(满足建立时间)。 - 数据在时钟上升沿被采样,在下降沿发生变化。
- 空闲时,时钟
- 连续传输的坑:当
SPH=0时,从机的移位寄存器在片选有效期间会被“冻结”。这意味着,在背靠背连续传输时,主机必须在每个数据字传输结束后,将SSInFss拉高至少一个时钟周期,然后再拉低开始下一个字的传输,以便从机内部能锁存当前数据并准备下一个数据。如果SSInFss一直保持低电平,从机将无法更新其发送数据寄存器,导致主机连续读到同一个数据。 - 配置代码片段:
// 配置为Freescale SPI, Mode 0 (SPO=0, SPH=0), 8-bit data // SCR 和 CPSDVSR 根据所需波特率计算 SSI0_CR0_R = (SCR << 8) | (0 << 7) /*SPH*/ | (0 << 6) /*SPO*/ | (0 << 4) /*FRF=0*/ | 0x07 /*DSS=8-bit*/;
3.3.2 模式1:SPO=0, SPH=1
- 时序特点:
- 空闲状态同模式0。
- 传输开始时,主机拉低
SSInFss。 - 关键区别:在第一个时钟边沿(上升沿)到来时,数据线尚未准备好有效数据。数据是在第一个上升沿之后才被放到数据线上的。
- 第一个数据捕获边沿发生在
SSInClk的第一个下降沿。即数据在时钟下降沿被采样,在上升沿发生变化。
- 连续传输的优势:由于
SPH=1,从机在片选有效期间可以更新其数据寄存器。因此,在背靠背连续传输时,SSInFss可以始终保持低电平,无需在字与字之间插入高电平脉冲,从而实现真正的全速连续流传输。 - 配置代码片段:
// 配置为Freescale SPI, Mode 1 (SPO=0, SPH=1) SSI0_CR0_R = (SCR << 8) | (1 << 7) /*SPH*/ | (0 << 6) /*SPO*/ | (0 << 4) /*FRF=0*/ | 0x07;
3.3.3 模式2:SPO=1, SPH=0
- 时序特点:
- 空闲时,时钟
SSInClk为高,这是与模式0/1的主要视觉区别。 - 传输开始时,主机拉低
SSInFss。 - 第一个数据捕获边沿发生在
SSInClk的第一个下降沿。因为空闲时钟为高,第一个边沿是下降沿。 - 数据在时钟下降沿被采样,在上升沿发生变化。
- 空闲时,时钟
- 连续传输的限制:与模式0相同,由于
SPH=0,在背靠背传输时,SSInFss需要在字间置高。 - 重要硬件配置:当设置
SPO=1时,空闲时钟为高。为了防止时钟线浮空导致的不确定状态,必须将对应的GPIO引脚(即SSInClk)配置为内部上拉。这是手册中明确强调的一点,否则可能导致从机在空闲时误采样到时钟边沿。// 在GPIO初始化中,除了配置AFSEL、PCTL、DEN外,还需要使能上拉 GPIO_PORTA_PUR_R |= (1 << 2); // 假设SSI0Clk在PA2 - 配置代码片段:
// 配置为Freescale SPI, Mode 2 (SPO=1, SPH=0) SSI0_CR0_R = (SCR << 8) | (0 << 7) /*SPH*/ | (1 << 6) /*SPO*/ | (0 << 4) /*FRF=0*/ | 0x07;
3.3.4 模式3:SPO=1, SPH=1
- 时序特点:
- 空闲时,时钟
SSInClk为高。 - 传输开始时,主机拉低
SSInFss。 - 第一个时钟边沿(下降沿)到来时,数据尚未有效。
- 第一个数据捕获边沿发生在
SSInClk的第一个上升沿。数据在上升沿采样,在下降沿变化。
- 空闲时,时钟
- 连续传输的优势:与模式1相同,由于
SPH=1,支持SSInFss保持低电平的背靠背连续传输。 - 同样需要上拉:与模式2相同,必须配置
SSInClk对应GPIO的上拉电阻。 - 配置代码片段:
// 配置为Freescale SPI, Mode 3 (SPO=1, SPH=1) SSI0_CR0_R = (SCR << 8) | (1 << 7) /*SPH*/ | (1 << 6) /*SPO*/ | (0 << 4) /*FRF=0*/ | 0x07;
调试经验:当SPI通信不通时,第一个要检查的就是模式匹配。用逻辑分析仪或示波器抓取
SSInClk、SSInFss和SSInTx的波形。首先看空闲时SSInClk的电平(确定SPO),然后看第一个数据位的变化是发生在SSInFss有效后的第一个时钟边沿之前还���之后(确定SPH)。将抓到的波形与外设数据手册的时序图对比,就能立刻发现问题。
4. 初始化配置流程与实战示例
理解了原理,我们来看如何一步步正确配置QSSI模块。手册第20.4节给出了标准的初始化步骤,我结合自己的经��将其细化并补充关键细节。
4.1 标准初始化步骤拆解
使能模块时钟:通过
RCGCSSI寄存器使能目标QSSI模块的时钟。这是访问任何外设寄存器的前提。SYSCTL->RCGCSSI |= (1 << 0); // 使能 SSI0 模块时钟 __asm__ volatile("nop"); // 插入少量延时,等待时钟稳定 __asm__ volatile("nop");使能GPIO时钟与引脚复用:
- 通过
RCGCGPIO使能连接QSSI信号的GPIO端口时钟。 - 查询芯片数据手册的“引脚复用表”(例如Table 30-5),确定
SSInClk、SSInFss、SSInTx、SSInRx具体复用到哪个GPIO引脚。 - 设置对应GPIO引脚的
AFSEL(交替功能选择)位为1。 - 配置
PCTL(端口控制)寄存器,将引脚功能映射到对应的SSI数字功能编号。 - 设置
DEN(数字使能)位为1,使能数字功能。
// 假设SSI0使用PA2(Clk), PA3(Fss), PA5(Tx), PA4(Rx) SYSCTL->RCGCGPIO |= (1 << 0); // 使能 GPIO Port A 时钟 while(!(SYSCTL->PRGPIO & (1 << 0))); // 可选:等待就绪 GPIOA->LOCK = 0x4C4F434B; // 解锁GPIO Commit寄存器(如果芯片需要) GPIOA->CR |= 0x3C; // 允许修改PA2-PA5 GPIOA->AFSEL |= (1<<2)|(1<<3)|(1<<4)|(1<<5); // 使能PA2-PA5的复用功能 GPIOA->PCTL &= ~0x00FF0000; // 清除PA2-PA5的旧复用设置 GPIOA->PCTL |= 0x00222200; // 配置PA2-PA5为SSI0功能 (0x2) GPIOA->DEN |= (1<<2)|(1<<3)|(1<<4)|(1<<5); // 使能数字功能 // 如果SPO=1,必须使能SSInClk引脚的上拉! // GPIOA->PUR |= (1 << 2);- 通过
配置QSSI控制寄存器(核心):
- 禁用SSI:确保
SSICR1寄存器中的SSE位为0。在Legacy模式下,大部分配置必须在SSE=0时进行。 - 设置主从模式:配置
SSICR1的MS位。0为主机,1为从机。 - 选择时钟源:通过
SSICC寄存器选择系统时钟或精确内部时钟等。 - 设置时钟分频:写入
SSICPSR寄存器设置CPSDVSR值(2-254的偶数)。 - 配置
SSICR0:这是最关键的一步。设置数据长度DSS、帧格式FRF、时钟极性SPO、时钟相位SPH以及时钟速率因子SCR。SCR和CPSDVSR共同决定波特率:SSInClk = SysClk / (CPSDVSR * (1 + SCR))。- 通常先确定
CPSDVSR(一个较小的偶数,如2),然后计算SCR。SCR的范围是0-255。
- 禁用SSI:确保
(可选)配置DMA:如果需要使用DMA搬运数据,配置μDMA通道,并设置
SSIDMACTL寄存器中的TXDMAE或RXDMAE位。使能QSSI:最后,将
SSICR1寄存器中的SSE位置1,模块开始工作。
4.2 完整配置示例:1 Mbps Freescale SPI Mode 3
假设系统时钟为20MHz,我们需要配置QSSI0为主机,使用Freescale SPI格式,Mode 3 (SPO=1, SPH=1),波特率1Mbps,8位数据。
计算分频:SSInClk = SysClk / (CPSDVSR * (1 + SCR)) = 1 MHzCPSDVSR * (1 + SCR) = 20 MHz / 1 MHz = 20取CPSDVSR = 2(偶数,且在2-254范围内),则1 + SCR = 10,所以SCR = 9。
寄存器值计算:
DSS = 0x7(8-bit)FRF = 0x0(Freescale)SPO = 1SPH = 1SCR = 0x09SSICR0值 =(0x09 << 8) | (1 << 7) | (1 << 6) | (0x0 << 4) | 0x07 = 0x09C0 | 0x0047 = 0x09C7。这里注意,(1<<7)=0x0080,(1<<6)=0x0040,0x09C0 + 0x0080 + 0x0040 + 0x07 = 0x09C7。
初始化代码:
void SSI0_Master_Mode3_Init(void) { // 1. 使能SSI0时钟 SYSCTL->RCGCSSI |= (1 << 0); // 2. 使能GPIOA时钟并配置引脚 (PA2, PA3, PA4, PA5) SYSCTL->RCGCGPIO |= (1 << 0); // 简短延时,等待时钟稳定 volatile uint32_t delay = SYSCTL->RCGCGPIO; GPIOA->LOCK = 0x4C4F434B; // 解锁(针对TM4C129等型号) GPIOA->CR = 0xFF; // 允许修改所有引脚 GPIOA->AFSEL |= (1<<2)|(1<<3)|(1<<4)|(1<<5); GPIOA->PCTL &= ~0x00FF0000; GPIOA->PCTL |= 0x00222200; // PA2-PA5复用为SSI0 GPIOA->DEN |= (1<<2)|(1<<3)|(1<<4)|(1<<5); // Mode 3 (SPO=1),必须使能时钟线上拉! GPIOA->PUR |= (1 << 2); // 3. 禁用SSI0以进行配置 SSI0->CR1 = 0x00000000; // 4. 配置为主机模式 (MS=0),先写CR1的低位,SSE稍后使能 // SSI0->CR1 = 0x00000000; // 默认就是0,可省略 // 5. 配置时钟预分频器 CPSDVSR = 2 SSI0->CPSR = 0x00000002; // 6. 配置SSICR0: SCR=9, SPH=1, SPO=1, FRF=0, DSS=8-bit SSI0->CR0 = 0x000009C7; // 0x09C7 // 7. 使能SSI0模块 SSI0->CR1 |= (1 << 1); // 设置SSE位为1 }4.3 高级/Bi-/Quad-SSI模式配置要点
当需要使用增强模式时(例如与QSPI Flash通信),配置流程有额外限制和步骤:
- 关键限制:在
SSICR1的MODE位设置为非0(即01=Bi-SSI, 10=Quad-SSI, 11=Advanced SSI)时,SSICR0中的FRF必须为0(Freescale),且SPO和SPH必须为0。这是硬件强制要求。 - 配置顺序:手册示例展示了如何在一次通信中切换模式。基本流程是:
- 先配置
SSICR1的MODE和FSSHLDFRM等位。 - 向发送FIFO写入数据。在写入最后一个数据包(或想结束帧时)的数据前,设置
EOM(End of Message)位。 - 如果需要切换模式(例如从Advanced切到Bi-SSI),需要重新配置
MODE位,并再次设置EOM来标记新模式的帧结束。
- 先配置
- DMA注意事项:手册提到,在Bi/Quad-SSI模式下,当SSICLK频率高于系统时钟的1/6时,使用μDMA会在每个字节传输间插入等待状态。这是因为DMA访问SRAM的仲裁开销和SSI输出吞吐量增加导致的。在设计高速QSPI通信时,需要评估此性能影响。
5. 常见问题排查与调试技巧
即使按照手册配置,在实际硬件调试中也可能遇到问题。以下是我总结的一些常见坑点和排查方法。
5.1 通信完全无响应
- 检查清单:
- 时钟与电源:确认微控制器和从设备都已上电,且核心时钟已正确配置并运行。用示波器测量主控的时钟输出引脚,确认系统时钟是否存在。
- 引脚复用:这是最常见的问题。反复检查
AFSEL、PCTL、DEN寄存器的配置,确保SPI功能正确映射到了你连接的物理引脚上。一个快速验证方法是,将引脚配置为GPIO输出模式,手动拉高拉低,用万用表或示波器测量,确认硬件连接正确。 - 模块时钟使能:确认
RCGCSSI和RCGCGPIO寄存器中对应位已置1。可以读取PRSSI和PRGPIO寄存器确认外设是否就绪。 - SSE位状态:配置完成后,是否将
SSICR1的SSE位置1?模块必须使能后才能工作。同时检查MS位是否正确设置了主从模式。
5.2 能发送,但接收数据全为0或全为0xFF
- 可能原因1:模式不匹配:这是最高频的原因。主机的SPO/SPH模式与从机不匹配。用逻辑分析仪同时抓取
SCK、MOSI、MISO、CS四根线。重点对比第一个时钟边沿和MOSI/MISO数据变化的关系。与从机数据手册的时序图逐项核对CPOL和CPHA。 - 可能原因2:从机未就绪或损坏:确认从机芯片的电源、复位引脚状态正常。有些传感器需要特定的初始化序列后才能响应SPI读取。
- 可能原因3:MISO线连接或配置问题:在主机端,MISO是输入引脚。确保GPIO配置为输入(或复用功能输入)。检查硬件上MISO线是否虚焊、短路。
5.3 通信速度不稳定或出错
- 可能原因1:波特率计算错误:重新计算
CPSDVSR和SCR。确保CPSDVSR是2-254之间的偶数。计算出的SSInClk不能超过模块和从设备支持的最大频率。过高的速率会导致建立保持时间不足。 - 可能原因2:电气问题:对于高速SPI(>10MHz),需要考虑信号完整性。检查PCB走线是否过长,是否靠近干扰源。可��在时钟和数据线上串联小电阻(如22-33欧姆)来减少振铃。
- 可能原因3:中断或DMA冲突:如果使用了中断或DMA,确保中断服务程序处理时间足够快,或者DMA缓冲区管理正确,避免发生溢出(Overrun)或下溢(Underrun)错误。检查SSI中断状态寄存器
SSIRIS和SSIMIS。
5.4 连续读取时数据错位或重复
- 可能原因:
SSInFss时序问题(针对Freescale SPI, SPH=0):如前文所述,在SPH=0的模式下,从机需要SSInFss在字间有一个高电平脉冲来更新其内部数据寄存器。如果你的驱动在连续传输时没有操作SSInFss(或使用了FSSHLDFRM保持功能),就会导致这个问题。解决方案是:在SPH=0时,要么在软件上控制CS引脚在每个字传输后翻转,要么使用QSSI的FSSHLDFRM=0(脉冲模式)功能(注意此功能要求数据长度为8位)。
5.5 使用逻辑分析仪/示波器调试SPI
这是最有效的调试手段。连接好探头,设置好触发(通常用SSInFss下降沿触发),抓取一次完整的传输。
- 看空闲电平:先看
SSInClk的空闲电平,确定SPO设置是否正确。 - 看第一个数据边沿:找到
SSInFss变低后,SSInClk的第一个有效边沿(如果SPO=0则是上升沿,SPO=1则是下降沿)。观察在这个边沿之前,SSInTx(主机发送)的数据是否已经稳定?如果稳定了,说明SPH=0;如果在这个边沿之后才稳定,说明SPH=1。 - 看采样边沿:观察
SSInRx(从机返回)的数据在哪个边沿发生变化,在哪个边沿保持稳定。稳定的边沿就是采样边沿。与主机配置对比。 - 看帧间间隔:在连续传输时,观察
SSInFss信号的行为,是否符合你配置的模式(保持低或脉冲)。
通过波形分析,几乎可以定位所有时序相关的配置错误。配置QSSI模块的SPI通信,关键在于理解“帧格式”和“时钟模式”这两个维度的选择。帧格式(Freescale vs TI)决定了SSInFss信号的行为逻辑,而时钟模式(SPO/SPH的四种组合)则决定了数据与时钟边沿的精确对齐关系。记住那个核心公式SSInClk = SysClk / (CPSDVSR * (1 + SCR)),以及高级模式下SPO/SPH必须为0的限制。在调试时,逻辑分析仪是你的最佳伙伴,对照波形和数据手册,没有解决不了的问题。最后,别忘了那个小细节:当SPO=1时,记得给时钟线加上拉。