SPI学习(QA)
硬件SPI+DMA驱动方式
SPI+DMA驱动方式最快
HAL_SPI_Transmit_DMA
HAL_SPI_Transmit_DMA函数调用后此函数快速返回(非阻塞),CPU 可立即执行其他任务。
uint8_t tx_buf[100] = {0x01, 0x02, ...}; // 提前准备好数据
HAL_SPI_Transmit_DMA(&hspi1, tx_buf, 100); // 启动DMA发送,立即返回
等待传输完成(可选,非阻塞)
传输完成后,DMA 会触发中断,HAL 库会调用回调函数
// DMA传输完成后,此回调函数会被中断触发
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) {if (hspi == &hspi1) {// 处理传输完成逻辑(如启动下一次发送)}
}
HAL_SPI_TxCpltCallback 通知 CPU。若需同步等待(不推荐,会浪费 CPU),可轮询 SPI 状态,但无需死等,可配合超时机制
// 不推荐:轮询等待(阻塞CPU)
while (HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY) {// 可添加超时判断,避免死等
}
为什么不需要死等?
DMA 独立工作:一旦启动,DMA 控制器会自动按配置从缓冲区取数据发送,CPU 无需参与,死等会浪费 CPU 资源。
缓冲区访问安全:启动 DMA 后,禁止修改缓冲区数据(DMA 可能正在读取),但 “写入缓冲区” 是在启动前完成的,启动后无需操作缓冲区,因此无需等待。
异常处理:若传输卡住,可通过 DMA 超时中断或轮询状态检测,而非死等。
硬件SPI
HAL_SPI_Transmit 和 HAL_SPI_Transmit_IT
HAL_SPI_Transmit 和 HAL_SPI_Transmit_IT 都是 STM32 HAL 库中用于 SPI 发送数据的函数,但核心区别在于 工作方式(同步阻塞 vs 异步中断)
- 工作方式
HAL_SPI_Transmit:同步阻塞方式。函数调用后,CPU 会一直等待 SPI 外设完成所有数据的发送(逐字节发送,直到 Size 计数为 0),期间 CPU 无法执行其他任务,直到发送完成后函数才返回。
HAL_SPI_Transmit_IT:异步中断方式。函数仅启动发送过程(配置参数、使能中断)后立即返回,后续发送过程由硬件中断驱动(无需 CPU 干预),发送完成后通过 HAL_SPI_TxCpltCallback 回调函数通知。
想都不用想,硬件SPI方式的话,HAL_SPI_Transmit_IT肯定是最好的,速度最快不堵塞
// 同步发送(阻塞)
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);// 异步发送(中断)
HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size);
差异点:HAL_SPI_Transmit 多了一个 Timeout 参数(超时时间,单位:ms),用于指定最大等待时间,超时未完成则返回 HAL_TIMEOUT。
| 特性 | HAL_SPI_Transmit(同步) | HAL_SPI_Transmit_IT(异步) |
|---|---|---|
| CPU | 阻塞,直到发送完成 | 非阻塞,启动后立即释放 CPU |
| 完成通知 | 函数返回即表示完成 | 通过 HAL_SPI_TxCpltCallback 回调 |
| 超时机制 | 支持 Timeout 参数 | 无超时参数(需手动处理异常) |
| 数据缓冲区访问 | 发送期间可修改(但不建议) | 发送期间不可修改(中断可能访问) |
| 代码复杂度 | 低(线性逻辑) | 较高(需处理回调和状态同步) |
HAL_SPI_Transmit_IT中断是发送完成后回调还是发送开始就回调?
HAL_SPI_TxCpltCallback 是 SPI 数据发送完成后 才会被调用的回调函数,并非发送开始时触发。
具体来说,当通过 HAL_SPI_Transmit_IT 启动异步发送后,SPI 外设会在后台通过中断逐字节发送数据,直到所有数据(即 Size 参数指定的长度)全部发送完毕,硬件会触发 “传输完成(TC)” 中断。此时,HAL 库的中断服务程序(ISR)会最终调用 HAL_SPI_TxCpltCallback,通知用户 “整个发送过程已完成”。
因此,该回调函数的触发时机是 发送操作彻底结束后,可以在此处执行发送完成后的后续逻辑(如释放缓冲区、启动下一次传输等)。
