深入解析ARM Cortex-M SPI/SSI:从TM4C123寄存器到DMA实战应用

1. 项目概述:为什么需要深入理解SSI?

在嵌入式开发领域,尤其是基于ARM Cortex-M内核的微控制器项目里,与外设打交道是家常便饭。无论是读取一个温湿度传感器的数据,还是驱动一块TFT屏幕,亦或是与外部Flash存储器进行数据交换,都离不开一种高效、可靠的通信方式。在众多通信协议中,除了大家熟知的UART和I2C,同步串行接口(SSI),或者说我们更常听到的SPI,扮演着至关重要的角色。它以其全双工、高速、硬件简单的特点,成为连接各类传感器、存储器和显示模块的首选。

然而,很多开发者对SPI/SSI的理解可能停留在“四根线(SCLK, MOSI, MISO, CS)、主从模式、模式0/1/2/3”的层面。当项目遇到通信不稳定、数据错位、DMA传输效率低下或者需要驱动一些特殊时序的外设时,这种浅层的理解就显得捉襟见肘了。这时,深入芯片数据手册,理解SSI模块内部的运作机制,就成了解决问题的关键。

Tiva™ TM4C123GH6ZRB作为TI公司Cortex-M4F内核的经典代表,其集成的SSI模块功能相当完善和典型。它不仅仅是一个简单的SPI控制器,更是一个支持多种帧格式、内置深度FIFO、并可与µDMA高效协作的通信引擎。理解它的寄存器配置、时钟生成逻辑、FIFO操作细节以及中断机制,不仅能帮你搞定TM4C123GH6ZRB本身的项目,其原理和思路也完全可以迁移到其他ARM芯片的SPI外设上。本文就将以这颗芯片的SSI模块为蓝本,带你深入同步串行接口的“五脏六腑”,从硬件信号到软件配置,从理论时序到实战避坑,为你构建一个清晰、透彻的SSI知识体系。

2. SSI模块整体架构与核心特性解析

TM4C123GH6ZRB微控制器内部集成了4个独立的SSI模块(SSI0~SSI3)。每个模块都是一个完整的、可配置的同步串行通信控制器。在开始摆弄寄存器之前,我们需要先建立起对它的整体认知。

2.1 核心功能与特性一览

根据数据手册,该SSI模块的核心特性可以归纳为以下几点,这也是我们评估其能力的基础:

  • 协议兼容性:它并非只支持标准的SPI。通过配置,它可以模拟三种主流的同步串行协议:
    • Texas Instruments 同步串行格式:TI自家的标准,其特点是帧同步信号(SSInFss)在每个数据帧前产生一个时钟周期宽的高脉冲。
    • 飞思卡尔 SPI 格式:这其实就是我们最常说的SPI模式,通过配置时钟极性(CPOL/SPO)和相位(CPHA/SPH)来匹配不同外设的时序要求。
    • MICROWIRE 格式:一种半双工协议,先由主机发送一个8位命令字,然后从机返回4-16位数据,常用于一些老式的串行器件。
  • 主/从模式:每个模块既可作主机,主动发起通信并产生时钟;也可作从机,响应外部主机的时钟进行数据收发。这在多主机系统或级联应用中非常有用。
  • 灵活的时钟系统:位速率(波特率)可通过两级分频器精细调节。一级是固定的偶数预分频器(CPSDVSR,2~254),二级是可编程的时钟速率分频器(SCR,0~255)。计算公式为:SSInClk = SysClk / (CPSDVSR * (1 + SCR))。这为匹配不同速度的外设提供了极大的灵活性。
  • 硬件FIFO缓冲:这是提升通信效率的关键。发送和接收各有一个独立的、8单元深、16位宽的FIFO。这意味着CPU可以一次性写入最多8个数据到发送FIFO,或者从接收FIFO中连续读出最多8个数据,而不必在每个字节传输完成后都进行中断处理,大大减轻了CPU的负担。
  • 可编程数据帧长:数据帧长度可以在4位到16位之间自由设定,而非常见的8位固定。这使其能够直接适配那些使用非标准字节长度(如12位ADC、16位DAC)的外设,无需软件进行位拼接,简化了操作。
  • µDMA支持:这是TM4C系列的一大亮点。SSI模块可以与微直接存储器访问(µDMA)控制器无缝协作。发送和接收通道可以独立配置DMA请求,实现数据在内存和SSI FIFO之间的大批量、零CPU干预的自动搬移,极大释放了CPU资源,尤其适合高速数据流应用(如音频流、图像数据传输)。
  • 丰富的终端机制:提供了多种中断源,包括FIFO触发中断(半满、四分之三满等)、接收超时中断、接收溢出中断以及传输结束(EOT)中断。开发者可以根据应用场景灵活选择中断触发条件,平衡响应速度和系统开销。
  • 环回模式:用于诊断和调试。在此模式下,发送器的输出会在内部直接连接到接收器的输入,无需外部连线即可测试SSI模块本身的收发功能是否正常。

2.2 信号引脚与GPIO复用

SSI模块的信号并非直接连接到芯片引脚,而是通过GPIO复用功能映射到具体的物理引脚上。这一点对于硬件设计和软件初始化都至关重要。

以SSI0为例,其四个标准信号在TM4C123GH6ZRB上的默认映射是:

  • SSI0Clk (时钟)-> PA2
  • SSI0Fss (帧同步/片选)-> PA3
  • SSI0Rx (主入从出 MISO)-> PA4
  • SSI0Tx (主出从入 MOSI)-> PA5

注意:SSI0的这组引脚在复位后默认就是SSI功能,这是一个特例。对于SSI1、SSI2、SSI3,其引脚复位后默认为GPIO,需要手动配置复用功能。

配置一个GPIO引脚为SSI功能,需要两步操作:

  1. GPIOAFSEL寄存器中,将对应引脚的位置位,启用备用功能。
  2. GPIOPCTL寄存器中,为对应引脚选择正确的**端口控制(PMC)**编码。对于SSI0,PA2~PA5的PMC编码是2

例如,在TivaWare库中,初始化SSI0引脚通常这样调用:

// 启用GPIOA端口的时钟 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); // 配置PA2, PA3, PA4, PA5为SSI功能 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);

其他SSI模块的引脚有多个可选的映射位置(如SSI1可以映射到PD0~PD3或PF0~PF3),这为PCB布局布线提供了灵活性,但也要求我们在软件中明确指定使用哪一组。

3. 核心寄存器详解与配置实战

理解了整体框架后,我们进入核心环节——寄存器配置。SSI模块的行为完全由一组寄存器控制。盲目地调用库函数而不懂其背后原理,一旦出现问题就会无从下手。

3.1 关键寄存器功能解析

TM4C123GH6ZRB的SSI模块寄存器数量不多,但每个都至关重要。下面我们挑出最核心的几个进行拆解:

1. SSI控制寄存器 0 (SSICR0)这是配置的核心中的核心,决定了通信的基本格式。

  • SCR (位15:8):时钟速率分频因子。用于公式1+SCR的第二级分频。设置范围0-255。
  • SPH (位7):时钟相位。在飞思卡尔SPI模式下,决定数据在时钟的第一个边沿(0)还是第二个边沿(1)采样。
  • SPO (位6):时钟极性。决定时钟空闲时的电平,低电平(0)或高电平(1)。SPH和SPO共同构成了SPI的四种模式(Mode 0-3)。
  • FRF (位5:4):帧格式选择。
    • 00: Texas Instruments同步串行格式
    • 01: 飞思卡尔SPI格式
    • 10: MICROWIRE格式
    • 11: 保留
  • DSS (位3:0):数据大小选择。设置帧长度,0011表示4位,0111表示8位,1111表示16位。注意:这里配置的是数据位数-1,例如要设置8位数据帧,应写入0x7

2. SSI控制寄存器 1 (SSICR1)主要用于启用模块和设置工作模式。

  • SSE (位1):SSI使能位。必须最后设置,在所有其他配置(时钟、格式等)完成后,将此位置1,模块才开始工作。
  • MS (位2):主/从模式选择。0为主机模式,1为从机模式。
  • EOT (位4):传输结束中断行为(仅主机模式有效)。如果使用DMA,通常需要将此位置1,以确保在一次DMA传输完成后产生EOT中断。

3. SSI时钟预分频寄存器 (SSICPSR)设置第一级分频系数CPSDVSR。该值必须是2到254之间的一个偶数。这是产生目标波特率的第一步。

4. SSI数据寄存器 (SSIDR)这是数据进出的门户。写操作将数据压入发送FIFO,读操作从接收FIFO弹出数据。它是一个16位寄存器,但实际有效数据位由SSICR0.DSS决定。写入时,数据需右对齐;读出时,数据也是右对齐的,高位无效位为0。

5. SSI状态寄存器 (SSISR)用于查询模块的实时状态,在查询式编程(非中断/DMA)中非常有用。

  • BSY (位4):忙标志。当发送FIFO非空或正在发送时,此位为1。在关闭SSI模块前,应查询此位确保传输已完成。
  • RFF (位3):接收FIFO满。
  • RNE (位2):接收FIFO非空。可用于轮询检查是否有数据可读。
  • TNF (位1):发送FIFO未满。可用于轮询检查是否可以写入新数据。
  • TFE (位0):发送FIFO空。

6. SSI中断相关寄存器 (SSIIM, SSIRIS, SSIMIS)

  • SSIIM:中断屏蔽寄存器。对相应位写1使能中断,写0屏蔽。
  • SSIRIS:原始中断状态寄存器。反映中断事件是否发生,无论是否被屏蔽。
  • SSIMIS:屏蔽后中断状态寄存器。只有被SSIIM使能的中断事件才会在此寄存器中显示。中断服务程序通常读取此寄存器来判断中断源

3.2 配置流程与实战示例

假设我们需要将SSI0配置为:主机模式,飞思卡尔SPI格式,模式0 (CPOL=0, CPHA=0),8位数据帧,波特率1MHz,系统时钟为16MHz

步骤一:计算分频系数根据公式SSInClk = SysClk / (CPSDVSR * (1 + SCR))目标SSInClk = 1 MHzSysClk = 16 MHz。 我们需要选择一对CPSDVSR(偶数)和SCR(0-255)的整数,使得等式成立。 一个简单的策略是先确定CPSDVSR。为了分频后时钟尽量干净,通常先尝试较小的偶数。我们选CPSDVSR = 2。 则(1+SCR) = 16MHz / (2 * 1MHz) = 8。 所以SCR = 7。 验证:16MHz / (2 * (1+7)) = 16MHz / 16 = 1MHz。符合。

步骤二:软件配置流程(基于寄存器直接操作)

// 1. 启用SSI0和GPIOA的外设时钟(假设时钟已配置为16MHz) SYSCTL->RCGCSSI |= 0x01; // 启用SSI0时钟 SYSCTL->RCGCGPIO |= 0x01; // 启用GPIOA时钟 // 等待外设时钟稳定(简短延时或检查PRGPIO) __asm__ volatile("nop"); __asm__ volatile("nop"); // 2. 配置GPIO引脚为SSI功能 GPIOA->AFSEL |= 0x3C; // 使能PA2, PA3, PA4, PA5的备用功能 GPIOA->PCTL &= ~0x00FFFF00; // 清除PA2-PA5的PMC位域 GPIOA->PCTL |= 0x00222200; // 设置PA2-PA5的PMC为2 (SSI0) GPIOA->DEN |= 0x3C; // 使能PA2-PA5的数字功能 // 3. 禁用SSI模块以进行配置 (SSE=0) SSI0->CR1 = 0x00; // 4. 配置SSICR0: SCR=7, SPH=0, SPO=0, FRF=飞思卡尔SPI, DSS=8位 SSI0->CR0 = (7 << 8) | (0 << 7) | (0 << 6) | (0x01 << 4) | 0x07; // 0x0707 // 5. 配置SSICPSR: CPSDVSR = 2 SSI0->CPSR = 2; // 6. 配置SSICR1: 主机模式,使能SSI模块 SSI0->CR1 = (1 << 1); // SSE=1

配置完成后,SSI0就处于就绪状态。可以通过查询SSISR.TNF位来发送数据,查询SSISR.RNE位来接收数据。

步骤三:基础数据收发函数

// 阻塞式发送一个字节 void SSI0_SendByte(uint8_t data) { while((SSI0->SR & 0x02) == 0); // 等待TNF(发送FIFO未满) SSI0->DR = data; // 写入数据寄存器,自动进入发送FIFO } // 阻塞式接收一个字节 uint8_t SSI0_ReceiveByte(void) { while((SSI0->SR & 0x04) == 0); // 等待RNE(接收FIFO非空) return (uint8_t)(SSI0->DR); // 读取数据寄存器 } // 全双工交换一个字节(常用SPI操作) uint8_t SSI0_TransferByte(uint8_t data) { SSI0_SendByte(data); return SSI0_ReceiveByte(); // 发送和接收是同步进行的 }

4. FIFO与中断机制深度剖析

查询式传输简单,但效率低下,CPU被完全占用。利用FIFO和中断才是发挥SSI性能的正道。

4.1 FIFO操作策略与中断配置

SSI的发送和接收FIFO都是8级深。中断可以基于FIFO的填充水平来触发,这通过SSIIM寄存器配置:

  • TXIM:发送中断屏蔽。当发送FIFO中的数据量小于或等于可编程的触发水平(默认是半满,即4个)时,产生中断。这意味着发送FIFO有空间了,CPU可以填充新数据。
  • RXIM:接收中断屏蔽。当接收FIFO中的数据量大于或等于可编程的触发水平(默认是半满,即4个)时,产生中断。这意味着接收FIFO有足够数据了,CPU可以来读取。

一个典型的中断驱动双缓冲策略如下:

  1. 初始化时,设置FIFO触发水平(例如半满),并使能TXIM和RXIM中断。
  2. 在发送中断服务程序(ISR)中,检查发送FIFO是否还有空间(TNF),如果有,则从应用程序的发送缓冲区填充数据到FIFO,直到FIFO满或应用程序缓冲区空。
  3. 在接收中断服务程序(ISR)中,检查接收FIFO是否有数据(RNE),如果有,则从FIFO读取数据到应用程序的接收缓冲区,直到FIFO空或应用程序缓冲区满。
  4. 这样,CPU只在FIFO需要服务时才被中断,大部分时间可以处理其他任务,通信效率大幅提升。

配置示例:使能发送和接收FIFO半满中断

// 清除所有挂起的中断 SSI0->ICR = 0x0F; // 使能发送FIFO半满中断和接收FIFO半满中断 SSI0->IM = (1 << 3) | (1 << 2); // TXIM=1, RXIM=1 // 在NVIC中启用SSI0中断 NVIC_EnableIRQ(SSI0_IRQn);

4.2 接收超时中断与传输结束中断

除了FIFO水平中断,还有两个重要的中断:

  • 接收超时中断 (RTIM):如果接收FIFO非空,但在32个SSI时钟周期内没有收到新数据,就会触发此中断。这非常有用!例如,在与一个需要时间准备数据的慢速从机通信时,主机发完命令后,从机可能延迟一段时间才返回数据。使用查询或FIFO水平中断可能无法及时捕获这个延迟后的数据。而超时中断可以在总线空闲一段时间后,提醒CPU“接收FIFO里还有未读的数据,快来取走”。在ISR中读取完数据后,必须向SSIICR寄存器的RTIC位写1来清除此中断
  • 传输结束中断 (EOTIM):仅用于主机模式。当发送移位寄存器的最后一位数据移出后,此中断触发。它标志着一帧或一次连续传输的物理结束。在配合DMA进行大批量数据传输时,EOT中断是判断DMA传输完成的可靠标志。注意:在飞思卡尔SPI模式下,即使FIFO是满的,每个字节发送完也可能产生EOT脉冲,这在与某些特殊外设或DMA回环测试时需要留意。

4.3 µDMA高效传输配置

对于需要连续传输大量数据的场景(如读写SD卡、刷新显示屏),µDMA是终极解决方案。SSI模块的发送和接收通道可以独立产生DMA请求。

DMA请求类型

  • 单次请求:发送通道在发送FIFO有空闲单元时产生;接收通道在接收FIFO有数据时产生。适合精细控制。
  • 突发请求:发送通道在发送FIFO有4个或以上空闲单元时产生;接收通道在接收FIFO有4个或以上数据单元时产生。这是更高效的模式,允许DMA控制器一次搬运多个数据,减少总线仲裁开销。

配置SSI以使用µDMA的基本步骤

  1. 启用µDMA控制器时钟。
  2. 配置µDMA通道的控制结构,设置源地址(发送时为内存,接收时为SSI数据寄存器)、目的地址(发送时为SSI数据寄存器,接收时为内存)、传输数据量、传输模式等。
  3. 在SSI端,设置SSIDMACTL寄存器:
    • TXDMAE:置1使能发送DMA。
    • RXDMAE:置1使能接收DMA。
  4. 对于发送,还需要将SSICR1寄存器的EOT位置1,以确保在DMA传输完成后能产生正确的EOT中断来通知CPU。
  5. 启动µDMA通道。之后,数据的搬移将由DMA控制器自动完成,CPU完全解放。

一个简化的DMA发送示例思路

// 假设已有数据缓冲区 uint16_t txBuffer[100]; // 1. 配置µDMA通道(此处省略详细DMA配置代码) // 设置:源地址 = txBuffer,目的地址 = &(SSI0->DR),传输大小 = 100,使用突发请求。 // 2. 配置SSI SSI0->DMACTL |= (1 << 1); // 使能发送DMA (TXDMAE) SSI0->CR1 |= (1 << 4); // 置位EOT位 // 3. 启动DMA传输 // 4. 等待DMA传输完成中断或SSI的EOT中断

使用DMA后,数据吞吐率可以接近SSI时钟的理论极限,CPU占用率极低。

5. 三种帧格式的时序差异与实战选择

SSI支持的三种帧格式,其根本区别在于时钟(SSInClk)和帧同步信号(SSInFss)的时序关系。选择哪种格式,完全取决于你要通信的外设芯片的数据手册要求。

5.1 Texas Instruments同步串行格式

这是TI的“原生”格式,时序最简单。

  • 空闲状态SSInClk为低,SSInFss为低。
  • 帧开始:当发送FIFO有数据时,SSInFss产生一个一个时钟周期宽的高脉冲
  • 数据采样/输出:在SSInClk上升沿,主机和从机同时输出数据位(到各自的Tx线);在下降沿,双方同时采样输入数据(从各自的Rx线)。数据从MSB开始。
  • 特点:每个数据帧前都有一个独立的帧同步脉冲。这种格式在某些ADC/DAC中比较常见,帧信号明确指示了每个数据字的开始。

5.2 飞思卡尔SPI格式(最常用)

这就是我们通常所说的SPI,通过SPOSPH组合成4种模式。

  • 空闲状态:由SPO决定。SPO=0时,SSInClk为低;SPO=1时,SSInClk为高。SSInFss(此时作为片选CS)在空闲时为高。
  • 帧开始:主机拉低SSInFss(CS)。
  • 数据采样时刻:由SPHA决定。
    • SPHA=0:数据在时钟的第一个边沿采样。对于SPO=0,第一个边沿是上升沿;对于SPO=1,第一个边沿是下降沿。
    • SPHA=1:数据在时钟的第二个边沿采样。
  • 数据输出时刻:总是在采样时刻的相反边沿输出。
  • 模式总结
    • Mode 0 (CPOL=0, CPHA=0):时钟空闲低,数据在上升沿采样,下降沿输出。
    • Mode 1 (CPOL=0, CPHA=1):时钟空闲低,数据在下降沿采样,上升沿输出。
    • Mode 2 (CPOL=1, CPHA=0):时钟空闲高,数据在下降沿采样,上升沿输出。
    • Mode 3 (CPOL=1, CPHA=1):时钟空闲高,数据在上升沿采样,下降沿输出。
  • 实战选择99%的外设SPI模式都是Mode 0或Mode 3。务必仔细查阅外设数据手册的时序图,看其要求在时钟的哪个边沿采样数据,以及时钟空闲电平,然后对应到SPI模式。

5.3 MICROWIRE格式

这是一种半双工协议,主要用于一些较老的串行EEPROM或数字电位器等器件。

  • 操作过程
    1. 主机拉低SSInFss开始会话。
    2. 主机先发送一个8位的控制字(命令或地址)到从机。在此期间,主机不会接收数据(MISO线可能为高阻或无效)。
    3. 8位控制字发送完毕后,总线空闲一个时钟周期
    4. 从机在解析控制字后,在接下来的时钟周期里,向主机返回4到16位的数据。主机在此期间只接收,不发送。
  • 特点:一次通信的总长度是固定的(控制字8位 + 数据位N位)。SSI模块需要配置为MICROWIRE格式,并设置好数据帧长度(DSS),这个长度指的是返回数据阶段的位数。例如,要操作一个返回16位数据的MICROWIRE器件,DSS应配置为16位(写入0xF)。

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

在实际项目中,SSI通信出问题很常见。下面是我踩过的一些坑和总结的排查思路。

6.1 通信完全失败,无波形或波形异常

  • 检查清单
    1. 时钟和电源:确认MCU和外设的电源正常,系统时钟已正确配置并启用。用SysCtlClockGet()验证系统时钟频率是否符合你的计算。
    2. GPIO配置:这是最易出错的一步!确认你正确启用了GPIO端口的时钟,并将正确的引脚配置为了SSI功能(AFSELPCTL)。对于MISO引脚(SSInRx),即使你只发送不接收,也必须正确配置为输入功能,否则内部电路可能无法正常工作。使用示波器或逻辑分析仪检查引脚是否有信号输出。
    3. SSI模块使能顺序:务必遵循“先配置,后使能”的原则。即先设置好CR0,CPSR等所有参数,最后才将CR1SSE位置1。在修改重要参数(如波特率、帧格式)前,也应先将SSE清零。
    4. 主从模式与片选:确认主机和从机的MS位配置正确。主机要主动拉低片选(SSInFss),从机则配置为输入。检查从机的片选信号是否被正确拉低/释放。
    5. 波特率计算:用示波器测量实际的SSInClk频率,看是否与预期相符。检查CPSDVSR是否为偶数,SCR值是否过大导致分频后时钟过低。特别注意从机模式的时钟限制:在从机模式下,系统时钟频率必须至少是SSInClk的12倍,且SSInClk不能超过6.67MHz。如果主机时钟太快,从机可能无法正确采样。

6.2 数据错位或字节顺序错误

  • 数据帧长度(DSS)不匹配:这是导致数据错位的头号原因。如果主机配置为8位(DSS=0x7),而从机期望16位,那么主机发2个字节,从机可能认为只发了1个16位字。务必确保双方的数据宽度一致。
  • MSB/LSB顺序:SSI总是先发送最高位(MSB)。有些外设(特别是某些显示驱动器)可能要求先发送最低位(LSB)。如果遇到数据镜像(如0x01被识别为0x80),就需要在软件中对每个字节进行位反转,或者寻找外设是否支持配置字节顺序。
  • SPI模式不匹配:这是导致采样点错误,数据位完全读错的根本原因。用逻辑分析仪捕获SCLK,MOSI,MISO,CS四路信号,对照外设手册的时序图,逐个检查时钟极性、相位和采样边沿。逻辑分析仪是调试SPI的必备神器

6.3 FIFO和中断相关的问题

  • 中断不触发
    • 检查NVIC中是否使能了SSI的中断。
    • 检查SSIIM寄存器是否使能了特定的中断源(如RXIM,TXIM)。
    • 检查FIFO触发水平。如果你只发送一个数据,而触发水平是半满(4个),那么发送中断不会产生。对于单字节操作,更适合用查询方式或EOT中断。
    • 在中断服务程序(ISR)中,必须读取SSIMIS寄存器来判断中断源,并操作SSIICR寄存器清除对应的中断标志。如果忘记清除,会导致中断持续触发,程序卡死在ISR。
  • DMA传输卡住或数据丢失
    • 确保在启动DMA前,SSI的发送/接收DMA使能位(TXDMAE/RXDMAE)已置位。
    • 对于发��DMA,通常需要将SSICR1.EOT位置1,以保证帧结束时产生中断,用于通知CPU或进行下一次DMA配置。
    • 检查DMA通道的配置:源/目标地址是否对齐,传输数据量单位(8位、16位)是否与SSI数据宽度匹配,传输模式是否正确(如基本模式、Ping-Pong模式)。
    • 内存一致性:如果使用了Cache(TM4C123有指令Cache),确保DMA操作的内存区域是**非缓存(Non-cacheable)**的,或者在DMA操作前后执行缓存清洗(Clean)和无效(Invalidate)操作,否则CPU和DMA看到的内存数据可能不一致。

6.4 利用环回模式进行自检

当怀疑是硬件连接问题还是软件配置问题时,环回模式(Loopback)是绝佳的调试手段。通过设置SSICR1寄存器的LBM位为1,可以在芯片内部将发送端直接连接到接收端。

SSI0->CR1 |= (1 << 0); // 启用环回模式

启用后,你发送的任何数据都会立刻被自己接收。你可以编写一个简单的测试函数,发送一组已知数据(如0xAA, 0x55, 0x01, 0x80等),然后读取接收到的数据进行比较。如果环回测试通过,说明SSI模块本身的配置和功能是正常的,问题很可能出在外部电路、引脚连接或外设上。