STM32F105S使用中断接收,触发UART_Receive_IT()中的 ...... if(--huart->RxXferCount == 0) { __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE); /* Check if a transmit process is ongoing or not */ if(huart->State == HAL_UART_STATE_BUSY_TX_RX) { huart->State = HAL_UART_STATE_BUSY_TX; } else { /* Disable the UART Parity Error Interrupt */ __HAL_UART_DISABLE_IT(huart, UART_IT_PE); /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */ __HAL_UART_DISABLE_IT(huart, UART_IT_ERR); huart->State = HAL_UART_STATE_READY; } HAL_UART_RxCpltCallback(huart); ...... 进入HAL_UART_RxCpltCallback(huart);后,判断huart->State 尽然不是上面的2个中的一个,然后返回HAL_BUSY状态,导致死锁 请问哪位遇到过这种情况吗?请指点下,系统使用了FREERTOS. 现象: 串口发送(没用中断发送),---->有接收,又触发发送,导致死锁 |
最近调试stm32f407vet6+freeRTOS+uart3/uart6的小程序。uart3/uart6都使用HAL_UART_Transmit_IT函数发送,uart3使用HAL_UART_Receive_IT接收,uart6只发送。上位机每40ms查询uart3,uart3反馈结果。
当然,在调试中肯定遇到了上面说的uart3不能接收的问题。设置了错误中断处理,仍然出现uart3随机性失去响应。调试中发现问题不是上面的原因,而是出现在hal库中HAL_UART_Receive_IT/HAL_UART_Transmit_IT函数处理上,具体讲, __HAL_LOCK(huart)处理不当。
上述两个函数存在于Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c中,大约786~863行。HAL库版本是:STM32Cube_FW_F4_V1.21.0。
发送函数和接收函数中,都出现了 __HAL_LOCK(huart)操作。这实现了对端口的全局加锁。然而,此处却是欠考虑:huart是全双工的,如果APP调用HAL_UART_Transmit_IT在tx操作中执行了 __HAL_LOCK(huart)操作,还没有执行 __HAL_UNLOCK(huart)时发生了rx接收中断,在HAL_UART_RxCpltCallback调用中重新设定HAL_UART_Receive_IT就会出现HAL_BUSY错误。而实际上,这种状态下,硬件都是正常,完全能工作的。观察两个函数中 __HAL_LOCK(huart)和 __HAL_UNLOCK(huart)之间保护的全局变量,只有一个 huart->ErrorCode = HAL_UART_ERROR_NONE是存在冲突的。然而,在错误处理回调函数中,这个错误码一般都检测不到。换句话说,这个加锁操作锁的范围比较大,造成了 Tx和Rx操作的冲突。
当然,如果在启动Rx设定时发生Tx中断,也会因相同原因发生Tx启动失败。
总结一句话,出现HAL_BUSY错误的原因之一是两个函数中加锁操作造成的。
解决的办法:检查HAL_UART_RxCpltCallback调用中重新设定HAL_UART_Receive_IT的返回值,若出现HAL_BUSY错误,进一步检查huart->RxState是否忙,决定是否重新调用启动接收。
当然,不推荐的做法是简单注释掉HAL库中HAL_UART_Receive_IT加锁语句也能正常工作。
不能靠应用级别的标识来判断线程之间的同步和运行,而是要靠RTOS自身的信号量、事件等等来判断和同步线程。
你可以不用RTOS测试下,先保证应用可用,再调RTOS吧。
感谢回复,!~~~~
当前UART中断确实不是RTOS的,但是相对于来说比RTOS的中断级别要优先吧?
从当前的现在来看就是进入串口中断后,还是触发了串口发送,这个可能是RTOS引起的,因为这个中断接收串口里面没有LOCK,导致可以串口继续发送
谢谢版主!~~
应该不是溢出,因为每次我只接收一个字节!~~
重新初始化确实可以!~~
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_UART_RxCpltCallback can be implemented in the user file
*/
if(huart->Instance == USART3){
......//recv process
cRxBuffPtr[0] = 0;
if(HAL_UART_Receive_IT(huart,cRxBuffPtr[0],1) != HAL_OK){
HAL_UART_Transmit(&huart5, (uint8_t *)"uart3 err\r\n", 11, 0xff);
}
}
}
你的程序逻辑有严重的潜在问题!
HAL_UART_RxCpltCallback()函数是在中断里被调用的,而你又在该函数里面调用了发送函数:
HAL_UART_Transmit()。
你看代码,HAL_UART_Transmit()会判断uart的状态,此时返回了HAL_BUSY。
另外即使不是由上述原因产生的,也没有这么用的。收发尽量一直(要么中断,要么阻塞式)。
再者,HAL_UART_RxCpltCallback()里面只能用HAL_UART_Receive_IT()类型的开启中断函数。
这个发送是调试串口,只是为了测试使用。
HAL_UART_RxCpltCallback里面也不能用HAL_UART_Receive_IT, 会把ErrorCode覆盖掉, HAL_UART_Receive_IT只是开启中断函数, 可以在对应的IRQHandler最后执行.
遇到问题一摸一样,只是用了CUBEMX简单生成代码,中断接收,什么也没做,然后主循环发送固定字符,pc发送数据一百几十个就无法接收了。不会再中断接收了。如果循环判断再次中断接收是否成功,那么会导致发送也锁死了。