2. 硬件平台介绍:常用MCU的SPI外设架构与DMA控制器特性

本章以STM32系列MCU(特别是STM32F4/F7/H7系列)为典型硬件平台,深入剖析SPI外设的内部架构、数据流路径以及DMA控制器的关键特性。理解这些硬件细节是后续实现“轮询模式配置DMA传输”的基础。

2.1 SPI外设架构详解

STM32的SPI模块是一个同步、全双工串行通信接口,支持主/从模式。其核心架构围绕一个8/16位移位寄存器和双缓冲收发数据寄存器构建。

核心数据路径: 发送数据时,CPU或DMA将数据写入发送数据寄存器(SPI_DR),硬件自动并行加载到移位寄存器,再通过MOSI线逐位输出;接收数据时,移位寄存器逐位从MISO线采样,完成后并行传输到接收数据寄存器(同样是SPI_DR),等待CPU或DMA读取。

2.1.1 SPI外设关键寄存器与数据流

寄存器/信号 功能描述 与DMA的交互点
SPI_DR (数据寄存器) 发送和接收共用的双缓冲寄存器。写操作填充发送缓冲,读操作清空接收缓冲。 DMA请求源:TXE(发送缓冲空)触发DMA读内存写DR;RXNE(接收缓冲非空)触发DMA读DR写内存。
SPI_SR (状态寄存器) 包含TXE、RXNE、BSY(忙标志)、MODF(模式错误)等标志位。 轮询模式中,CPU循环检查TXE和RXNE位以决定是否进行下一次数据搬运。
SPI_CR1/CR2 (控制寄存器) 配置波特率、CPOL/CPHA、数据帧格式(8/16位)、主从模式、以及DMA使能位(TXDMAEN/RXDMAEN)。 CR2中的TXDMAEN和RXDMAEN位是开启DMA传输的硬件开关。
SPI_CRCPR (CRC多项式寄存器) 用于CRC校验,在DMA传输中需注意CRC计算的时机和DMA传输完成中断的配合。 DMA传输结束时,需等待CRC计算完成,否则可能丢失最后一个字节。
开发避坑: SPI_DR的读写操作必须严格遵循“先读后写”或“先写后读”的时序,否则会导致数据错位。在DMA模式下,由于DMA控制器自动处理,此问题较少出现,但需注意DMA传输长度必须与SPI数据帧对齐。

2.1.2 SPI外设架构图

下图展示了SPI外设内部的数据流路径,以及它与CPU、DMA控制器和外部设备的连接关系。

SPI外设内部架构与数据流 CPU 核心 DMA 控制器 SPI 外设 SPI_DR (数据寄存器) SPI_SR (状态寄存器) SPI_CR1/CR2 (控制寄存器) 移位寄存器 外部 SPI 设备 轮询读/写 DMA 请求/应答 并行加载 MOSI/MISO 状态标志 说明:轮询模式下CPU直接操作SPI_DR;DMA模式下DMA控制器接管SPI_DR的读写,CPU仅在初始化时配置。

2.2 DMA控制器特性

DMA(Direct Memory Access)控制器允许外设与存储器之间直接传输数据,无需CPU干预。STM32的DMA控制器具有多个数据流(Stream)和通道(Channel),支持多种传输模式。

2.2.1 DMA控制器核心特性

  • 多数据流与通道: 每个DMA控制器包含8个数据流(Stream 0~7),每个数据流可配置8个通道(Channel 0~7),分别对应不同的外设请求源。
  • 传输方向: 支持外设到内存、内存到外设、内存到内存三种传输方向。
  • 数据宽度: 支持字节(8位)、半字(16位)、字(32位)三种数据宽度,且外设与内存的数据宽度可独立配置(自动对齐或填充)。
  • 传输模式: 支持普通模式(传输完成后停止)、循环模式(传输完成后自动重载,适用于连续数据流)。
  • 优先级: 每个数据流有4级可编程优先级(低、中、高、非常高),用于仲裁多个DMA请求。
  • FIFO与直接模式: 每个数据流内置一个4字(16字节)FIFO,可启用FIFO模式进行数据打包/解包,或使用直接模式降低延迟。

2.2.2 SPI与DMA的典型连接配置

在STM32中,SPI外设的TX和RX请求分别映射到DMA的不同数据流和通道。以STM32F4为例:

SPI外设 DMA控制器 TX数据流/通道 RX数据流/通道 备注
SPI1 DMA2 Stream 3, Channel 3 Stream 0, Channel 3 常用高速SPI接口
SPI2 DMA1 Stream 4, Channel 0 Stream 3, Channel 0 中等速率SPI接口
SPI3 DMA1 Stream 5, Channel 0 Stream 2, Channel 0 低速或备用SPI接口
关键配置约束: 在轮询模式下配置DMA传输时,必须确保DMA数据流未被其他外设占用。此外,SPI的TX和RX DMA请求必须使用不同的数据流,即使它们属于同一个DMA控制器。同时,DMA传输完成中断(TCIF)和SPI的BSY标志必须协同处理,以避免数据丢失。

2.2.3 DMA传输配置流程图

下图展示了从初始化到启动DMA传输的完整配置流程,其中轮询模式体现在等待传输完成的阶段。

轮询模式下SPI DMA传输配置流程 1. 使能时钟 2. 配置GPIO复用 3. 初始化SPI参数 4. 配置DMA数据流 5. 使能SPI的DMA请求 6. 轮询等待传输完成 轮询模式关键点 CPU循环检查DMA传输完成标志 或SPI的BSY标志,不进入中断

2.3 轮询模式与DMA的协同机制

在轮询模式下实现SPI DMA传输,核心思想是:CPU负责初始化配置,DMA负责数据搬运,CPU通过轮询标志位来同步传输完成状态。这种模式既利用了DMA的高效性,又避免了中断上下文切换的开销,适用于中等数据量的同步通信场景。

典型应用场景: 读取外部Flash存储器、配置传感器寄存器、与LCD控制器通信等。这些场景通常需要发送命令后等待响应,数据量在几十到几千字节之间,轮询模式足以满足实时性要求。

2.3.1 轮询等待的两种策略

  • 策略一:轮询DMA传输完成标志 —— 检查DMA数据流的传输完成中断标志(TCIF),该标志在DMA传输完预设数量的数据后由硬件置位。优点:精确知道传输结束时刻。缺点:需额外清除标志。
  • 策略二:轮询SPI的BSY标志 —— 检查SPI_SR寄存器的BSY位,该位在SPI总线空闲时清零。优点:确保SPI总线完全释放。缺点:BSY位在最后一个字节传输完成后可能仍有短暂延迟。

在实际开发中,通常组合使用两种策略:先轮询DMA TCIF标志确认DMA传输完成,再轮询SPI BSY标志确认总线空闲,最后读取接收缓冲区数据。

2.3.2 轮询模式代码框架示例

/* 轮询模式SPI DMA传输函数 */
void SPI_DMA_Polling_Transfer(SPI_TypeDef* SPIx, 
                              uint8_t* tx_buf, 
                              uint8_t* rx_buf, 
                              uint16_t len)
{
    /* 1. 配置DMA传输参数(源地址、目标地址、长度) */
    DMA_Config_Transfer(SPIx, tx_buf, rx_buf, len);
    
    /* 2. 使能DMA数据流 */
    DMA_Stream_Enable(DMA2_Stream3);  /* 以SPI1 TX为例 */
    DMA_Stream_Enable(DMA2_Stream0);  /* 以SPI1 RX为例 */
    
    /* 3. 使能SPI的DMA请求 */
    SPIx->CR2 |= SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN;
    
    /* 4. 轮询等待DMA传输完成 */
    while(!(DMA2->LISR & DMA_LISR_TCIF0));  /* 等待RX Stream完成 */
    
    /* 5. 轮询等待SPI总线空闲 */
    while(SPIx->SR & SPI_SR_BSY);
    
    /* 6. 清除DMA标志 */
    DMA2->LIFCR |= DMA_LIFCR_CTCIF0;
    
    /* 7. 禁用DMA和SPI的DMA请求(可选) */
    SPIx->CR2 &= ~(SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN);
    DMA_Stream_Disable(DMA2_Stream3);
    DMA_Stream_Disable(DMA2_Stream0);
}
性能提示: 轮询等待期间CPU处于忙等待状态,不适合在实时操作系统(RTOS)的任务中长时间占用CPU。如果数据量较大(超过1KB),建议使用中断模式或DMA传输完成中断配合信号量,以释放CPU给其他任务。