STM32H7A3 Nucleo的SPI中断与DMA无输出,轮询正常求助
SPI中断/DMA模式无输出排查建议
核心问题分析
轮询模式正常说明SPI硬件连接、基础配置(时钟、极性相位、数据位宽)没问题,中断/DMA模式失效大概率是中断/DMA链路未正确初始化、时序控制错误或HAL库调用/状态处理不当导致。
1. 中断模式排查与修复
- 函数参数错误:
HAL_SPI_Transmit_IT的原型是HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size),你代码里多了第四个参数20——轮询模式的HAL_SPI_Transmit有超时参数,但中断模式不需要,这是直接导致发送失败的核心原因。 - CS引脚时序错误:中断模式是异步发送,你当前仅在
ret != HAL_OK时拉高CS,但若ret == HAL_OK,CS会一直保持低电平,导致从设备持续处于选中状态,后续通信异常。正确做法是在发送完成回调中拉高CS,而非主函数中处理。 - 局部内存失效:
sendData是函数内的局部数组,中断模式下发送过程异步,函数退出后局部变量会被释放,导致中断访问无效内存。需将其改为静态变量或全局变量。
2. DMA模式排查与修复
- 同样的参数错误:
HAL_SPI_Transmit_DMA的原型是HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size),同样不需要第四个超时参数20,该错误会直接导致SPI无法启动发送。 - DMA配置问题:确认CubeMX中SPI1的TX DMA通道配置正确:方向为内存到外设,数据宽度(8位)与SPI匹配;循环模式仅适合连续数据流,单次发送无需开启。同时要启用DMA发送完成中断,否则无法触发回调函数。
- 内存对齐问题:STM32H7的DMA对内存地址有对齐要求(如32位通道需4字节对齐),若
sendData是局部数组,可能未满足要求。可通过__attribute__((aligned(4)))修饰数组,或把DMA数据宽度设为Byte规避。
3. 通用修复步骤
- 修正函数调用参数:
// 中断模式正确调用 ret = HAL_SPI_Transmit_IT(&hspi1, sendData, 2); // DMA模式正确调用 // ret = HAL_SPI_Transmit_DMA(&hspi1, sendData, 2); - 调整内存与CS控制逻辑:
HAL_StatusTypeDef spi_write(uint8_t reg, uint8_t *pData) { HAL_StatusTypeDef ret; static uint8_t sendData[2]; // 改为静态变量避免内存释放 sendData[0] = reg; sendData[1] = *pData; HAL_GPIO_WritePin(...); // CS拉低 ret = HAL_SPI_Transmit_IT(&hspi1, sendData, 2); if (ret != HAL_OK) { HAL_GPIO_WritePin(...); // 发送失败立即拉高CS } return ret; } // 重写SPI发送完成回调 void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) { if(hspi->Instance == SPI1) { HAL_GPIO_WritePin(...); // 发送完成后拉高CS } } - 配置验证:
- 确认NVIC中SPI1全局中断已启用,优先级设置合理(避免被系统关键中断抢占)。
- DMA模式下检查TX通道是否启用、数据宽度匹配、完成中断已开启。
- 调试验证:
- 在
HAL_SPI_TxCpltCallback中添加断点或LED翻转,确认是否进入回调。 - 查看SPI_SR寄存器的TXE、BSY位,DMA_ISR寄存器的完成标志,判断发送是否启动。
- 在
内容的提问来源于stack exchange,提问作者Stan woldes
相关产品推荐
相关产品推荐

