1. 课程导论:SPI通信协议基础、DMA传输原理、轮询模式与中断模式对比
1.1 SPI通信协议基础
SPI(Serial Peripheral Interface,串行外设接口)是一种由Motorola公司推出的全双工、同步、高速串行通信总线。在嵌入式系统中,SPI常用于连接MCU与传感器、ADC/DAC、LCD显示屏、Flash存储器等外设。
1.1.1 物理层与信号线
SPI总线采用主从(Master-Slave)架构,通常由4根信号线组成:
| 信号线 | 全称 | 方向 | 功能描述 |
|---|---|---|---|
| SCLK | Serial Clock | Master → Slave | 由主设备产生的同步时钟信号,决定数据传输速率 |
| MOSI | Master Out Slave In | Master → Slave | 主设备输出数据线,从设备接收数据 |
| MISO | Master In Slave Out | Slave → Master | 从设备输出数据线,主设备接收数据 |
| CS/SS | Chip Select / Slave Select | Master → Slave | 片选信号,低电平有效,用于选中目标从设备 |
1.1.2 工作模式与时钟极性/相位
SPI协议通过时钟极性(CPOL)和时钟相位(CPHA)的组合定义了4种工作模式,决定了数据采样和输出的时钟边沿:
| 模式 | CPOL | CPHA | 空闲时钟电平 | 数据采样边沿 |
|---|---|---|---|---|
| Mode 0 | 0 | 0 | 低电平 | 第一个跳变沿(上升沿) |
| Mode 1 | 0 | 1 | 低电平 | 第二个跳变沿(下降沿) |
| Mode 2 | 1 | 0 | 高电平 | 第一个跳变沿(下降沿) |
| Mode 3 | 1 | 1 | 高电平 | 第二个跳变沿(上升沿) |
开发提示: 在配置SPI外设时,必须确保主设备和从设备的工作模式一致。多数SPI Flash和传感器默认使用Mode 0或Mode 3,建议优先查阅外设数据手册确认。
1.1.3 SPI数据传输流程
SPI的每次数据传输本质上是主从设备内部移位寄存器的循环交换过程。以发送1字节数据为例:
- 拉低CS:主设备将片选信号置为低电平,激活目标从设备。
- 时钟驱动:主设备在SCLK线上产生8个时钟脉冲。
- 数据移位:每个时钟周期,主设备通过MOSI线移出1位数据,同时通过MISO线移入1位数据。
- 交换完成:8个时钟周期后,主设备的发送寄存器内容已移入从设备,从设备的发送寄存器内容已移入主设备。
- 拉高CS:传输结束,主设备将CS置为高电平,释放从设备。
1.2 DMA传输原理
DMA(Direct Memory Access,直接存储器访问)是一种允许外设与存储器之间直接传输数据而无需CPU干预的硬件机制。在SPI通信中引入DMA,可以显著降低CPU负载,提升系统吞吐量。
1.2.1 DMA的核心工作流程
DMA传输由DMA控制器(DMAC)管理,其基本工作流程如下:
- CPU配置DMA:设置源地址、目标地址、传输长度、传输宽度、触发源等参数。
- 外设触发:当SPI外设的接收数据寄存器非空(RXNE)或发送数据寄存器空(TXE)时,向DMA控制器发出请求。
- DMA接管总线:DMA控制器通过总线仲裁获得系统总线控制权,执行一次数据传输。
- 传输完成:DMA将数据从源地址搬运到目标地址,传输计数器递减。
- 中断通知:当传输计数器减至0时,DMA控制器可产生传输完成中断,通知CPU。
1.2.2 DMA传输的关键参数
| 参数 | 说明 | 典型配置 |
|---|---|---|
| 源地址 | 数据来源的起始地址 | SPI_DR(数据寄存器)或内存缓冲区 |
| 目标地址 | 数据存放的目标起始地址 | 内存缓冲区或SPI_DR |
| 传输宽度 | 每次传输的数据位宽 | 8位、16位或32位 |
| 传输长度 | 总共需要传输的数据单元个数 | 1 ~ 65535(取决于DMA控制器) |
| 地址增量模式 | 每次传输后地址是否自动递增 | 外设地址固定,内存地址递增 |
| 循环模式 | 传输完成后是否自动重新开始 | 常用于连续数据流场景 |
1.3 轮询模式与中断模式对比
在SPI驱动开发中,轮询模式和中断模式是两种最基本的CPU与外设交互方式。理解它们的差异,是选择合适驱动架构的前提。
1.3.1 轮询模式(Polling Mode)
轮询模式是指CPU通过循环检查外设状态寄存器的标志位,来判断数据是否准备好发送或接收。以SPI发送为例:
// SPI轮询模式发送1字节(伪代码)
void SPI_Polling_Send(uint8_t data) {
// 等待发送缓冲区空(TXE标志位)
while (!(SPI->SR & SPI_SR_TXE));
// 写入数据寄存器
SPI->DR = data;
// 等待传输完成(BSY标志位清除)
while (SPI->SR & SPI_SR_BSY);
}
1.3.2 中断模式(Interrupt Mode)
中断模式是指当外设状态满足条件时(如接收数据寄存器非空),外设向CPU发送中断请求,CPU暂停当前任务,执行中断服务函数(ISR)处理数据。
// SPI中断模式接收1字节(伪代码)
void SPI_IRQHandler(void) {
if (SPI->SR & SPI_SR_RXNE) {
// 读取数据寄存器,清除RXNE标志
uint8_t data = SPI->DR;
// 将数据存入接收缓冲区
rx_buffer[rx_index++] = data;
}
}
1.3.3 三种模式综合对比
| 对比维度 | 轮询模式 | 中断模式 | DMA模式(本课程重点) |
|---|---|---|---|
| CPU占用率 | 高(持续占用CPU等待) | 中(仅ISR执行时占用) | 低(仅初始化配置) |
| 实时响应 | 差(受轮询周期影响) | 好(硬件触发立即响应) | 好(硬件自动搬运) |
| 实现复杂度 | 低(简单循环检查) | 中(需配置中断向量、优先级) | 高(需配置DMA通道、流、请求映射) |
| 适用数据量 | 小(1~10字节) | 中(10~100字节) | 大(100字节以上) |
| 代码可读性 | 高(线性执行) | 中(主循环+ISR分离) | 中(配置+回调分离) |
| 典型场景 | GPIO模拟SPI、调试阶段 | 按键响应、小数据量通信 | Flash读写、LCD刷屏、音频流 |
课程定位说明: 本课程选择“轮询模式实现SPI通信DMA传输配置”作为切入点,原因有二:第一,轮询模式代码结构清晰,便于初学者理解DMA配置流程;第二,在实际工程中,轮询+DMA的组合常用于“单次大数据块传输”场景,既能保证传输完整性,又能降低CPU负载。后续章节将逐步拆解这一组合的完整实现。
1.3.4 模式选择决策树
在实际项目开发中,可根据以下条件快速选择SPI驱动模式:
- 数据量 < 10字节 → 轮询模式(简单高效,无需中断开销)
- 数据量 10~100字节,且CPU有其他任务 → 中断模式(平衡响应与负载)
- 数据量 > 100字节,或需要连续传输 → DMA模式(解放CPU,提升吞吐量)
- 系统对实时性要求极高 → 中断模式或DMA模式(避免轮询阻塞)
- 调试阶段或功能验证 → 轮询模式(便于单步跟踪和问题定位)
常见误区: 初学者容易认为DMA模式一定比中断模式好。实际上,DMA的初始化配置和通道占用本身也有开销。对于小数据量传输,中断模式的整体效率可能更高。选择驱动模式时,应结合具体硬件资源和应用场景综合评估,而非盲目追求“高级”特性。