您的问题在于SPI状态未被正确复位,导致后续传输因BUSY状态失败。以下是解决方案及优化代码:
根本原因分析
- SPI状态未复位:首次传输后SPI状态机停留在
BUSY状态,后续无法启动新传输。
- CS中断处理冲突:CS上升沿(取消选中)未正确处理,可能打断传输。
- 回调缺失:未实现SPI传输完成回调函数来清理状态。
解决方案
1. 修改CS中断处理(HAL_GPIO_EXTI_Callback)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if(GPIO_Pin == GPIO_PIN_4) { // 对应CS_PIN
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET) { // CS下降沿(选中)
// 启动SPI传输前确保SPI就绪
if(HAL_SPI_GetState(&hspi1) == HAL_SPI_STATE_READY) {
HAL_SPI_TransmitReceive_IT(&hspi1, tx_data, rx_data, LEN);
}
}
else { // CS上升沿(取消选中)
// 关键:传输被迫中止时复位SPI状态
if(HAL_SPI_GetState(&hspi1) == HAL_SPI_STATE_BUSY) {
HAL_SPI_Abort(&hspi1); // 强制复位SPI
}
}
}
}
2. 实现SPI传输完成回调
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
if(hspi == &hspi1) {
// 此处可处理接收到的数据(rx_data)
// 状态机会被HAL库自动重置为READY
}
}
3. 实现SPI错误回调(关键)
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) {
if(hspi == &hspi1) {
HAL_SPI_Abort(&hspi1); // 出错时强制复位SPI
}
}
关键配置检查
- SPI初始化:确保配置正确(时钟极性/相位需匹配从设备)
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; // 常规模式1
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; // 常规模式0
- CS引脚配置:
工作流程说明
- CS拉低(选中) → 触发下降沿中断 → 启动SPI传输
- 传输完成 → 自动触发
TxRxCpltCallback → SPI状态重置为READY
- CS拉高(取消选中) → 触发上升沿中断 → 若SPI仍BUSY则强制终止
- 传输出错 → 触发
ErrorCallback → 强制复位SPI
注意事项
- 超时处理:在
HAL_SPI_TransmitReceive_IT()前可添加超时检测
uint32_t timeout = 100; // 适当超时值
while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY && timeout--);
- 避免频繁中断:在传输完成后才允许新CS中断(可通过全局变量标志控制)
- SPI时钟速度:过高时钟可能导致从设备响应不及时,适当降低测试
实测建议:在HAL_SPI_Abort()后添加10μs延时,确保硬件复位完成:
HAL_SPI_Abort(&hspi1);
HAL_Delay(1); // 1ms延时(根据实际调整)
通过上述修改,可确保SPI状态机被正确复位,解决连续传输时的BUSY状态锁死问题。
您的问题在于SPI状态未被正确复位,导致后续传输因BUSY状态失败。以下是解决方案及优化代码:
根本原因分析
- SPI状态未复位:首次传输后SPI状态机停留在
BUSY状态,后续无法启动新传输。
- CS中断处理冲突:CS上升沿(取消选中)未正确处理,可能打断传输。
- 回调缺失:未实现SPI传输完成回调函数来清理状态。
解决方案
1. 修改CS中断处理(HAL_GPIO_EXTI_Callback)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if(GPIO_Pin == GPIO_PIN_4) { // 对应CS_PIN
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET) { // CS下降沿(选中)
// 启动SPI传输前确保SPI就绪
if(HAL_SPI_GetState(&hspi1) == HAL_SPI_STATE_READY) {
HAL_SPI_TransmitReceive_IT(&hspi1, tx_data, rx_data, LEN);
}
}
else { // CS上升沿(取消选中)
// 关键:传输被迫中止时复位SPI状态
if(HAL_SPI_GetState(&hspi1) == HAL_SPI_STATE_BUSY) {
HAL_SPI_Abort(&hspi1); // 强制复位SPI
}
}
}
}
2. 实现SPI传输完成回调
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
if(hspi == &hspi1) {
// 此处可处理接收到的数据(rx_data)
// 状态机会被HAL库自动重置为READY
}
}
3. 实现SPI错误回调(关键)
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) {
if(hspi == &hspi1) {
HAL_SPI_Abort(&hspi1); // 出错时强制复位SPI
}
}
关键配置检查
- SPI初始化:确保配置正确(时钟极性/相位需匹配从设备)
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; // 常规模式1
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; // 常规模式0
- CS引脚配置:
工作流程说明
- CS拉低(选中) → 触发下降沿中断 → 启动SPI传输
- 传输完成 → 自动触发
TxRxCpltCallback → SPI状态重置为READY
- CS拉高(取消选中) → 触发上升沿中断 → 若SPI仍BUSY则强制终止
- 传输出错 → 触发
ErrorCallback → 强制复位SPI
注意事项
- 超时处理:在
HAL_SPI_TransmitReceive_IT()前可添加超时检测
uint32_t timeout = 100; // 适当超时值
while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY && timeout--);
- 避免频繁中断:在传输完成后才允许新CS中断(可通过全局变量标志控制)
- SPI时钟速度:过高时钟可能导致从设备响应不及时,适当降低测试
实测建议:在HAL_SPI_Abort()后添加10μs延时,确保硬件复位完成:
HAL_SPI_Abort(&hspi1);
HAL_Delay(1); // 1ms延时(根据实际调整)
通过上述修改,可确保SPI状态机被正确复位,解决连续传输时的BUSY状态锁死问题。
举报