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控制器和外部设备的连接关系。
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传输的完整配置流程,其中轮询模式体现在等待传输完成的阶段。
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给其他任务。