TM4C1294 QSSI寄存器深度解析:从SPI基础到DMA高效数据流实战
1. QSSI模块概述与核心价值
在嵌入式系统开发中,尤其是基于德州仪器Tiva™ C系列微控制器的项目里,与外设进行高效、可靠的数据交换是家常便饭。无论是读取传感器数据、驱动显示屏,还是与外部存储器通信,同步串行接口(SSI)都是实现这些任务的骨干。Tiva™ TM4C1294NCPDT这款微控制器更是集成了功能强大的四通道同步串行接口(QSSI)模块,它不仅仅是传统SPI的简单实现,更支持高级的双线和四线模式,为高带宽应用打开了大门。但功能越强大,配置就越复杂,尤其是那一堆寄存器,看着就让人头疼。很多开发者可能只停留在调用库函数的层面,一旦遇到时序问题、DMA配置不生效或者中断响应异常,排查起来就非常困难。究其根本,是对寄存器底层机制的理解不够透彻。
我自己在多个工业数据采集和电机控制项目中深度使用了TM4C1294的QSSI模块,从最初的磕磕绊绊到后来的游刃有余,深刻体会到“寄存器即王道”的道理。官方数据手册虽然详尽,但更像是字典,缺乏场景化的串联和实战中的“坑点”提示。这篇文章,我就结合自己的踩坑经验,带你深入TM4C1294 QSSI模块的寄存器世界。我们不只讲每个位是干什么的,更要讲清楚它们在实际配置流程中的相互作用、常见的配置陷阱,以及如何利用中断和DMA构建高效、稳定的数据链路。无论你是正在调试一块新的传感器板卡,还是希望优化现有通信代码的性能,相信这些从寄存器层面出发的干货都能给你带来直接的帮助。
2. QSSI核心控制寄存器(SSICR1)深度解析与配置策略
QSSI的控制寄存器1(SSICR1)是整个模块的“大脑”,它决定了QSSI以何种身份(主/从)、何种模式工作,并控制着一些高级功能。直接对照手册逐位解释意义不大,我们更需要理解这些位在具体场景下的配置逻辑和相互制约关系。
2.1 基础使能与模式选择:启动QSSI的正确姿势
SSICR1的最低几位(Bit 0-2, 6-7)是配置的起点。Bit 1 (SSE)是同步串行端口使能位,这是模块的总开关。一个至关重要的原则是:在修改SSE位以外的绝大多数配置位(包括SSICR0寄存器)之前,必须确保SSE=0。我见过不少新手直接在一段初始化代码里连续写多个寄存器,结果配置不生效,问题往往就出在这里。正确的初始化顺序应该是:先关闭模块(SSE=0),然后配置SSICR0(时钟极性、相位、数据大小等)和SSICR1的其他位,最后再打开SSE(SSE=1)。
Bit 2 (MS)用于选择主从模式。0为主机,1为从机。这个位同样只能在SSE=0时修改。作为主机,你掌控着时钟线(SSInClk)和片选线(SSInFss),主动发起通信。作为从机,你只能被动响应。在多点通信系统中,一个QSSI模块通常被配置为主机,控制多个从设备。
Bit 7:6 (MODE)这两位定义了QSSI的工作模式,这是TM4C1294 QSSI相较于传统SSI的增强之处:
- 00: Legacy SSI模式:即标准的SPI模式,使用SSInDAT0(MOSI)和SSInDAT1(MISO)两根数据线进行全双工通信。这是最常用的模式,兼容绝大多数SPI外设。
- 01: Bi-SSI模式:双向SSI模式。在此模式下,数据在单根数据线(SSInDAT0)上分时进行收发。这可以节省一个GPIO引脚,但牺牲了全双工能力,适合引脚资源紧张且对速率要求不高的场景。
- 10: Quad-SSI模式:四线SSI模式。同时使用SSInDAT0, DAT1, DAT2, DAT3四根数据线进行数据传输,理论上可以实现传统模式四倍的数据吞吐量。常用于连接Quad-SPI Flash等高速存储器。
- 11: Advanced SSI Mode with 8-bit packet size:高级SSI模式,数据包大小固定为8位。此模式支持更复杂的帧结构,例如可以配合Bit 11 (EOM)使用。当EOM位被置1时,该值会被硬件插入到发送FIFO数据项的Bit 12位,用于向接收方指示帧结束。这在需要硬件自动标识数据包边界的高级通信协议中非常有用。
实操心得:模式选择并非越高级越好。如果你的外设是标准SPI,选Legacy模式最稳妥。启用Quad-SSI前,务必确认你的硬件连接了所有四根数据线,并且外设支持该协议。我曾调试过一个Quad-SPI Flash,因为DAT2线虚焊,导致读写一直失败,排查了很久。
2.2 高级功能控制:时钟、方向与帧保持
Bit 9 (HSCLKEN)是高速时钟使能位。当系统主频较高,而你需要的SPI时钟(SSInClk)也很快时,可以启用此位。手册中特别强调了一个关键顺序:必须在QSSI模块复位后、使能SSE位之后、任何数据传输开始之前,设置HSCLKEN位。错误的顺序可能导致时钟异常。我的习惯是:在初始化函数中,先软复位模块(如果支持),然后配置SSICR0和SSICR1(此时SSE=0,HSCLKEN=0),接着置位SSE=1,紧接着再置位HSCLKEN=1(如果需要高速模式),最后再开始操作数据。
Bit 8 (DIR)控制数据传输方向。0为只发送(TX),1为只接收(RX)。在Legacy全双工模式下,这个位通常保持为0(发送),因为收发是同时进行的,使能发送自然会触发接收逻辑。但在Bi-SSI半双工或需要单独接收的场景下,这个位就非常重要了。你需要根据通信阶段,动态切换DIR位。
Bit 10 (FSSHLDFRM)控制片选信号SSInFss的行为。0表示在每个数据字节(注意,要求SSICR0中的DSS数据大小必须为8位)传输期间产生一个脉冲。1则表示在整个数据帧传输期间保持SSInFss有效(低电平)。后者对于需要连续传输多个字节、且期间片选必须保持有效的设备(如很多SPI Flash芯片)是必需的。如果你的设备在每个字节后都需要片选跳变,则需选择脉冲模式。
Bit 0 (LBM)是回环模式位。置1后,发送移位寄存器的输出在内部直接连接到接收移位寄存器的输入。这个功能用于软件自测试,在不连接外部硬件的情况下验证QSSI模块本身的发送和接收逻辑是否正常。在最终产品代码中,通常保持为0。
3. 数据与状态寄存器:实现可靠数据流的关键
配置好控制寄存器只是第一步,数据的搬入搬出、以及如何获知模块状态,则需要通过数据寄存器(SSIDR)和状态寄存器(SSISR)来完成。
3.1 数据寄存器(SSIDR)的读写玄机
SSIDR寄存器是一个16位宽的寄存器,但它扮演着“FIFO访问窗口”的角色。这一点必须理解透彻:对SSIDR的读写操作,实际上是对底层硬件FIFO的读写操作。
当你向SSIDR写入数据时,数据并不是直接进入发送移位寄存器,而是被写入发送FIFO的当前写指针位置。发送逻辑会按照配置的波特率,自动从发送FIFO中取出数据,加载到移位寄存器中,然后一位一位地发送出去。这意味着你可以提前向FIFO中填入多个数据,实现“蓄水”式发送,提高效率。
同理,当你从SSIDR读取数据时,你读取的是接收FIFO的当前读指针位置的数据。接收逻辑会将从线上采样到的完整数据帧放入接收FIFO。
这里有一个关键细节:SSIDR是读敏感的。手册中明确标注了“Important: This register is read-sensitive.”。这意味着每一次读操作,都会使接收FIFO的读指针前进。如果你在FIFO为空时读取SSIDR,读到的将是未定义的数据,并且会无意义地消耗一个FIFO位置。因此,在读取数据前,必须检查状态寄存器SSISR中的RNE位(接收FIFO非空)。
另一个要点是��据对齐。SSIDR是16位的,但你的数据帧大小(由SSICR0的DSS位域设置)可能是4到16位之间的任意值。规则是:写入时,软件必须将数据右对齐(即放在低有效位);读取时,硬件会自动将接收到的数据右对齐在低有效位,高位补零。例如,当你配置为8位数据模式时,你要发送的数据0xAB应该写作0x00AB再写入SSIDR。读取时,你得到的值也是0x00AB,你需要自己屏蔽掉高8位。
3.2 状态寄存器(SSISR)与轮询策略
SSISR寄存器提供了FIFO状态和模块忙状态,是实现轮询式(Polling)驱动的核心。
- Bit 0 (TFE): 发送FIFO空。为1表示发送FIFO完全空了。在发送完一批数据后,可以查询此位以确认所有数据都已移出。
- Bit 1 (TNF): 发送FIFO非满。为1表示发送FIFO还有空位,可以继续写入数据。在连续发送时,应检查此位以避免FIFO溢出(虽然写入满FIFO会被忽略,但可能意味着你的发送速度跟不上数据产生速度)。
- Bit 2 (RNE): 接收FIFO非空。为1表示接收FIFO中有数据可读。这是读取数据前的必要检查条件。
- Bit 3 (RFF): 接收FIFO满。为1表示接收FIFO已满。如果此时还有数据到来,会发生溢出错误(Overrun),数据会丢失。需要通过中断或DMA及时读取数据。
- Bit 4 (BSY): 忙状态位。为1表示QSSI模块正在发送或接收一帧数据,或者发送FIFO非空。这个位在判断一次传输是否完全结束时非常有用。一个常见的做法是:在发送完所有数据后,等待TFE=1且BSY=0,以确保最后一帧数据也已完全从移位寄存器发出。
一个简单的轮询发送函数伪代码示例如下:
void QSSI_SendData(uint32_t qssi_base, uint16_t *data, uint32_t count) { uint32_t i; for(i = 0; i < count; i++) { // 等待发送FIFO有空间 while((HWREG(qssi_base + SSI_O_SRIS) & SSI_SRIS_TXRIS) == 0) { // 或者使用轮询TNF位: while((HWREG(qssi_base + SSI_O_SR) & SSI_SR_TNF) == 0); } // 写入数据,注意右对齐 HWREG(qssi_base + SSI_O_DR) = data[i]; } // 可选:等待所有数据发送完毕 while((HWREG(qssi_base + SSI_O_SR) & (SSI_SR_BSY | SSI_SR_TFE)) != SSI_SR_TFE); }4. 时钟配置与波特率计算:精准控制通信速率
QSSI的通信速率由SSInClk时钟决定,而这个时钟来源于系统时钟(SysClk)经过两级分频。相关的寄存器是SSICPSR(时钟预分频寄存器)和SSICR0中的SCR(串行时钟速率)位域。
波特率计算公式手册已经给出:SSInClk = SysClk / (CPSDVSR * (1 + SCR))
- SysClk: 系统时钟频率,例如120MHz。
- CPSDVSR: 这是SSICPSR寄存器(7:0位)的值。它必须是2到254之间的一个偶数。如果你写入一个奇数,硬件会自动将最低位置零。例如,写入3,读回来会是2。
- SCR: 这是SSICR0寄存器中SCR位域(15:8位)的值,范围0-255。
因此,最终的波特率(Bit Rate)就是SSInClk。例如,在标准SPI模式下,每个时钟周期传输1位数据,那么波特率就等于SSInClk。
配置实战与避坑:
- 目标速率计算:首先确定你需要的目标波特率。例如,需要1 Mbps的SPI时钟。
- 分频因子选择:根据系统时钟计算总分频系数。
总系数 = SysClk / 目标SSInClk。例如,SysClk=120MHz,目标1MHz,则总系数=120。 - 分解系数:将总系数分解为
CPSDVSR * (1+SCR)。由于CPSDVSR必须是偶数,我们可以先设定一个合适的偶数值。例如,设CPSDVSR = 10,则(1+SCR) = 120 / 10 = 12,所以SCR = 11。 - 误差校验:计算实际SSInClk = 120M / (10 * 12) = 1.000 MHz,完全匹配。
- 寄存器写入:将计算好的
CPSDVSR(10)写入SSICPSR,将SCR(11)写入SSICR0的相应位域。 - 高频注意:当需要很高的SPI时钟时(例如大于系统时钟的1/4),需要检查是否超出模块允许的最高频率。同时,高频下PCB布线、负载电容的影响会变得显著,可能导致通信错误。
注意事项:SSICR0中的SPO(时钟极性)和SPH(时钟相位)位不直接影响波特率,但它们定义了数据采样的时钟边沿,必须与外设的要求严格匹配,否则数据会错位。常见的模式0(SPO=0, SPH=0)和模式3(SPO=1, SPH=1)都是在时钟的第一个边沿采样数据。
5. 中断系统详解:从使能、触发到清除的全流程
轮询方式简单,但效率低下,CPU需要不断查询状态。中断方式可以让CPU在数据就绪或发送完成时再被通知,从而解放出来处理其他任务。QSSI的中断系统涉及四个关键寄存器:SSIIM(中断掩码)、SSIRIS(原始中断状态)、SSIMIS(被屏蔽后的中断状态)和SSIICR(中断清除)。
5.1 中断源与掩码寄存器(SSIIM)
SSIIM寄存器用于使能或禁用特定的中断源。某位置1,则清除该中断的掩码(即使能中断);置0则设置掩码(禁用中断)。主要的中断源有:
- Bit 0 (RORIM): 接收溢出中断掩码。当接收FIFO已满(RFF=1)但又有新数据到来时,会触发溢出错误。使能此中断可以及时处理错误。
- Bit 1 (RTIM): 接收超时中断掩码。当接收FIFO非空(RNE=1)但一段时间内没有新数据到来也没有被读取时触发。用于处理不完整的数据帧。
- Bit 2 (RXIM): 接收FIFO中断掩码。当接收FIFO中的数据量达到或超过阈值(通常为半满)时触发。这是最常用的接收数据中断。
- Bit 3 (TXIM): 发送FIFO中断掩码。当发送FIFO中的数据量低于阈值(通常为半满)时触发。这意味着FIFO有空间了,可以填充更多待发送数据。
- Bit 4 (DMARXIM) / Bit 5 (DMATXIM): 接收/发送DMA中断掩码。当对应的DMA传输完成时触发。
- Bit 6 (EOTIM): 发送结束中断掩码。当发送FIFO为空并且最后一帧数据的最后一位已从移位寄存器发出(即传输真正结束)时触发。用于精确判断一次连续发送的结束时刻。
5.2 状态与清除寄存器(SSIRIS, SSIMIS, SSIICR)
这三个寄存器需要配合理解:
- SSIRIS: 原始中断状态寄存器。只要中断条件发生,对应的位就会被硬件置1,无论SSIIM中是否使能了该中断。读取它可以看到所有发生的中断事件。
- SSIMIS: 屏蔽后中断状态寄存器。只有当中断条件发生并且在SSIIM中被使能(掩码清除),对应的位才会为1。CPU中断服务程序(ISR)在响应中断后,应该首先读取此寄存器来判断是哪个中断源触发了本次ISR调用。
- SSIICR: 中断清除寄存器。这是一个“写1清除”的寄存器。在ISR中,处理完某个中断事件后,必须向SSIICR中对应的位写1,以清除SSIRIS和SSIMIS中的相应状态位。这是防止中断重复触发或丢失的关键步骤。
一个典型的中断服务程序流程如下:
void QSSI0_IRQHandler(void) { uint32_t mis_status; uint32_t base = QSSI0_BASE; // 1. 读取屏蔽后的中断状态,判断中断来源 mis_status = HWREG(base + SSI_O_MIS); // 2. 处理接收FIFO中断(有数据可读) if(mis_status & SSI_MIS_RXMIS) { // 循环读取接收FIFO中的所有数据 while(HWREG(base + SSI_O_SR) & SSI_SR_RNE) { g_rx_buffer[g_rx_index++] = HWREG(base + SSI_O_DR) & 0xFFFF; // 读取16位数据 } // 清除接收中断状态位(写1清除) HWREG(base + SSI_O_ICR) = SSI_ICR_RXIC; } // 3. 处理发送FIFO中断(FIFO有空位,可以继续填数据) if(mis_status & SSI_MIS_TXMIS) { // 如果还有待发送数据,则填充发送FIFO while((HWREG(base + SSI_O_SR) & SSI_SR_TNF) && (g_tx_index < g_tx_total)) { HWREG(base + SSI_O_DR) = g_tx_buffer[g_tx_index++]; } // 清除发送中断状态位 HWREG(base + SSI_O_ICR) = SSI_ICR_TXIC; } // 4. 处理接收溢出中断(错误处理) if(mis_status & SSI_MIS_RORMIS) { // 记录错误,可能需要清空FIFO等恢复操作 g_error_flag |= ERROR_RX_OVERRUN; // 清除溢出中断状态位 HWREG(base + SSI_O_ICR) = SSI_ICR_RORIC; } // ... 处理其他中断源 }重要提示:在清除中断状态位(向SSIICR写1)之前,必须确保已经处理完了触发该中断的条件。例如,对于RXMIS中断,你应该在ISR中读取完所有可用的数据(直到RNE=0)后再清除中断。否则,如果FIFO中还有数据,清除中断后硬件会立即再次置位中断标志,导致ISR被连续调用,陷入死循环。
6. DMA传输配置:解放CPU的高效数据搬运
对于大批量、高速的数据传输,使用中断仍然需要CPU频繁介入来搬移每个数据。直接存储器访问(DMA)可以将数据在QSSI的FIFO和系统内存之间直接搬运,无需CPU干预,极大提升效率。TM4C1294的微DMA(µDMA)控制器与QSSI模块紧密集成。
6.1 DMA使能与控制寄存器(SSIDMACTL)
配置DMA传输非常简单,核心就是SSIDMACTL寄存器:
- Bit 0 (RXDMAE): 接收DMA使能。置1后,当接收FIFO中有数据时,会触发µDMA通道的传输请求,将数据自动搬运到指定的内存区域。
- Bit 1 (TXDMAE): 发送DMA使能。置1后,当发送FIFO有空位时,会触发µDMA通道的传输请求,将内存中的数据自动搬运到发送FIFO。
使能DMA后,QSSI模块会根据FIFO的状态(半满/半空阈值)自动向µDMA控制器发起传输请求。你只需要正确配置µDMA控制器本身:设置好源地址(对于发送是内存,对于接收是SSIDR寄存器)、目的地址(对于发送是SSIDR寄存器,对于接收是内存)、传输数据量、数据宽度(必须与QSSI数据帧大小匹配)以及传输模式(通常使用Ping-Pong模式以实现连续传输)。
6.2 DMA中断与配置流程
DMA传输的完成通过中断来通知。你需要同时配置两方面:
- QSSI端:在SSIIM寄存器中使能DMARXIM和/或DMATXIM中断。
- µDMA控制器端:配置对应的DMA通道,并启用通道完成中断。
一个典型的发送DMA配置流程如下:
- 初始化QSSI模块(模式、波特率等),但先不使能SSE。
- 配置µDMA控制器:
- 选择与QSSI发送对应的DMA通道(参考数据手册映射)。
- 设置传输模式为“基本模式”或“Ping-Pong模式”。
- 设置源地址为存放待发送数据的数组地址(内存),目的地址为
QSSI0_BASE + SSI_O_DR。 - 设置源和目的的数据宽度(例如16位)。
- 设置传输数据项总数。
- 使能该DMA通道的完成中断。
- 在QSSI的SSIIM寄存器中使能DMATXIM中断。
- 使能QSSI模块的SSE位。
- 置位SSIDMACTL寄存器的TXDMAE位,启动DMA传输。
- CPU可以转而执行其他任务。
- 当DMA传输完成时,会触发QSSI的DMATXIM中断(映射到µDMA控制器的通道完成中断)。在对应的ISR中,你可以进行后续处理,例如准备下一批数据,或者关闭DMA。
避坑指南:
- 数据对齐:DMA传输的数据宽度必须与QSSI数据帧大小(SSICR0.DSS)以及内存中数据的实际存储宽度对齐。例如,QSSI配置为8位数据,但DMA设置为32位传输,那么一次DMA请求会搬4个字节到FIFO,这可能不是你想要的行为。
- FIFO阈值:DMA请求的触发与FIFO的阈值有关。发送DMA通常在TNF(非满)时触发,这意味着只要FIFO有空位就会请求DMA搬数据,直到达到设定的传输总数。确保你的DMA传输大小是FIFO深度的整数倍,以避免最后部分数据无法触发请求而残留。
- 并发操作:避免在DMA传输过程中,CPU同时去读写SSIDR寄存器,这会导致数据混乱。DMA和CPU访问需要互斥。
7. 高级功能与模块属性
除了核心的通信和控制寄存器,QSSI模块还提供了一些用于查询模块能力和配置时钟源的寄存器。
7.1 外设属性寄存器(SSIPP)
SSIPP寄存器是只读的,用于查询当前QSSI实例支持哪些高级功能。这在编写可移植的驱动代码时非常有用。
- Bit 0 (HSCLK): 指示是否支持高速时钟模式。
- Bit 2:1 (MODE): 指示支持的工作模式。
0x2表示支持Legacy、Advanced、Bi-SSI和Quad-SSI所有模式。0x1表示不支持Quad-SSI。0x0表示只支持Legacy模式。 - Bit 3 (FSSHLDFRM): 指示是否支持FSS保持帧模式。
在驱动初始化时,可以先读取此寄存器,判断硬件是否支持你想要配置的模式,从而编写出更健壮的代码。
7.2 时钟配置寄存器(SSICC)
SSICC寄存器用于选择QSSI模块的波特率时钟源。默认使用系统时钟(CS=0x0)。你也可以选择备用时钟源(CS=0x5),例如一个更精确的低速时钟,以满足特定的低功耗或精确时序要求。手册中特别强调:如果使用备用时钟(ALTCLK),在运行模式下,系统时钟频率必须至少是ALTCLK编程值的两倍。这是芯片内部时钟切换电路的要求,违反可能导致通信故障。
7.3 标识寄存器组(SSIPeriphIDx, SSIPCellIDx)
这一组只读寄存器提供了该外设的硅片标识符和PrimeCell ID。对于TM4C1294,这些值通常是固定的(例如PeriphID0为0x22,PCellID0为0x0D)。它们的主要用途是在启动时,由底层驱动或操作系统进行外设识别和验证,以确保软件兼容正确的硬件版本。在应用程序中一般不需要操作。
8. 实战配置流程与常见问题排查
理解了各个寄存器后,我们将其串联成一个完整的、稳健的QSSI初始化与使用流程。
8.1 标准SPI主机初始化流程(以QSSI0为例)
- 使能外设时钟:在系统控制模块(SYSCTL)中使能QSSI0模块的时钟(
SYSCTL_RCGCSSI_R |= 0x01;),并等待其稳定。 - 配置GPIO:将对应的GPIO引脚(PA2: SSI0Clk, PA3: SSI0Fss, PA4: SSI0Rx, PA5: SSI0Tx)复用为QSSI功能,并配置输出驱动强度、上下拉等(根据外设要求)。
- 禁用QSSI模块:向
QSSI0_BASE + SSI_O_CR1写入0(清除SSE位)。 - 配置主时钟源(可选):如果需要使用备用时钟,配置SSICC寄存器。
- 配置时钟分频:根据目标波特率和系统时钟,计算CPSDVSR和SCR,分别写入SSICPSR和SSICR0。
- 配置工作模式:在SSICR0中设置DSS(数据大小,如0x7表示8位)、SPO、SPH、FRF(帧格式,通常为0,摩托罗拉SPI格式)。
- 配置控制寄存器1:在SSICR1中设置MS=0(主机模式)、MODE=0(Legacy模式)、DIR=0(发送方向)。此时SSE仍应为0。
- (可选)配置中断/DMA:
- 如果需要中断,配置SSIIM使能所需中断源(如RXIM, TXIM),并在NVIC中使能QSSI0中断。
- 如果需要DMA,配置µDMA控制器通道,并在SSIIM中使能DMARXIM/DMATXIM。
- 使能模块:置位SSICR1的SSE位(SSE=1)。
- (可选)使能高速时钟:如果需要,在SSE=1后,置位HSCLKEN位。
- 模块就绪:此时QSSI0已准备好进行数据收发。
8.2 常见问题排查速查表
在实际调试中,QSSI通信失败是常见问题。下面是一个快速排查指南:
| 现象 | 可能原因 | 排查步骤与解决方法 |
|---|---|---|
| 完全无通信,时钟线无波形 | 1. 外设时钟未使能。 2. GPIO引脚复用错误。 3. QSSI模块未使���(SSE=0)。 4. 主/从模式配置错误。 | 1. 检查SYSCTL_RCGCSSI寄存器。 2. 用万用表或示波器检查GPIO配置寄存器,确认AFSEL、PCTL已设置正确。 3. 读取SSICR1寄存器,确认SSE位为1。 4. 确认主机MS=0,从机MS=1。 |
| 有时钟波形,但数据线无变化或数据错误 | 1. 时钟极性(SPO)和相位(SPH)不匹配。 2. 数据大小(DSS)设置错误。 3. 数据未右对齐写入SSIDR。 4. 波特率过高,信号质量差。 | 1.这是最常见原因!用示波器同时抓取时钟和数据线,对照外设数据手册,检查采样边沿是否正确。调整SPO和SPH。 2. 确认主机和从机的DSS设置一致。 3. 检查写入SSIDR的数据格式,确保在<16位模式下数据位于低有效位。 4. 降低波特率,检查PCB走线,确保信号完整性。 |
| 只能发送,无法接收数据 | 1. 在非全双工模式下DIR方向设置错误。 2. 接收FIFO溢出。 3. 未及时读取接收FIFO导致溢出。 | 1. 在Legacy全双工模式下,发送即会接收。检查DIR位,通常应为0。 2. 检查SSISR的RFF位或使能RORIM中断查看是否发生溢出。溢出后需要软件清空FIFO并处理错误。 3. 优化代码,确保在接收FIFO半满或更早时读取数据。 |
| 中断无法进入 | 1. 中断未在NVIC中使能。 2. SSIIM寄存器中未使能具体中断源。 3. 中断服务程序(ISR)中未清除中断标志。 4. 中断优先级配置过低,被其他中断屏蔽。 | 1. 调用IntEnable(INT_SSI0)或类似函数。2. 读取SSIIM寄存器,确认对应位已置1。 3. 在ISR中读取SSIMIS后,必须向SSIICR对应位写1清除。 4. 检查NVIC优先级设置。 |
| DMA传输不启动或数据错误 | 1. SSIDMACTL中DMA未使能。 2. µDMA通道未正确配置(源/目的地址、数据宽度、传输量)。 3. DMA传输大小与FIFO深度不匹配。 4. 内存缓冲区地址或对齐问题。 | 1. 确认TXDMAE/RXDMAE位已置1。 2. 仔细检查µDMA通道配置结构体,确保数据宽度与QSSI的DSS匹配(例如8位数据用8位DMA传输)。 3. 尝试将DMA传输总量设为FIFO深度的整数倍。 4. 确保内存缓冲区位于可被DMA访问的区域(如SRAM),且地址对齐符合要求。 |
| 通信一段时间后卡死 | 1. 接收溢出未处理,导致状态机卡住。 2. 中断嵌套或优先级导致状态混乱。 3. FIFO操作顺序错误,例如在FIFO空时持续读。 | 1. 使能RORIM中断,在ISR中清除错误并复位FIFO(有时需要先禁用再使能QSSI模块)。 2. 简化中断服务程序,避免在ISR内进行耗时操作或调用不可重入函数。 3. 所有读操作前检查RNE位,所有写操作前检查TNF位。 |
调试时,示波器或逻辑分析仪是最得力的工具。直接观察CLK、FSS、MOSI、MISO四条线上的实际波形,与你的寄存器配置预期进行比对,大部分时序问题都能迎刃而解。同时,善用调试器的寄存器查看和内存查看功能,实时监控SSISR、SSIDR等关键寄存器的值,是定位软件逻辑问题的有效手段。