2015-04-26 12:29 PM
I was struggling for quite a few hours to get the simplest UART input ring buffer working. As soon as an ''overrun'' error occurred, the thing stopped, while the code was prepared to handle that situation (or so I hoped).
After quite a struggle, the following things were observed in theHAL_UART_IRQHandler
code:a) when an Overrun error is detected by the hardware, the huart->ErrorCode field is setb) if the hardware has received a data byte, theUART_Receive_IT
routine is called;that routine stores the received byte in the user-provided buffer, decreases the buffer counter, and if it becomes zero (this always happens when we are reading byte-by-byte, using a single-byte buffer), the route calls [user-supplied]HAL_UART_RxCpltCallback
Unless the buffer is filled andHAL_UART_RxCpltCallback
is called, theUART_Receive_IT
code does not touch neither huart->Status nor huart->Error fields. c) finally, just before completing,HAL_UART_IRQHandler
checks if the huart->Error field contains some error. If it does, the IRQ routine calls the [user-supplied]HAL_UART_ErrorCallback
routine. But before it does this, it MODIFIES the State field: huart->State = HAL_UART_STATE_READY; Let us review the following situations. For simplicity sake we review only the Receive side of things, ignoring the fact that UART Transfers can take place at the same time:I) an overrun error is detected, data is received, [remaining] buffer size is 1 byte.huart->Error is set to OverrrunUART_Receive_IT
is called, and moves the input to the buffer: it's the last byteUART_Receive_IT
sets huart->State to HAL_UART_STATE_READY, callsHAL_UART_RxCpltCallback
HAL_UART_RxCpltCallback
should check for and remember the huart->Error field, and use the newHAL_UART_RECEIVE_IT
call to re-initiate next byte reading.If the routine itself does not clear the huart->Error field,HAL_UART_RECEIVE_IT
does it in any case;huart->State is set to HAL_UART_STATE_BUSY_RXthe (c) check inHAL_UART_IRQHandler
is not firedall is fine and clean for now.II) an overrun error is detected, data is NOT receivedhuart->Error is set to OverrrunUART_Receive_IT
is not called;huart->State
remains atHAL_UART_STATE_BUSY_RX
, hardware is reading data, operation continuesthe (c) check in HAL_UART_IRQHandler is FIRED (Error field is not empty):State is changed toHAL_UART_STATE_READY
[user-supplied]HAL_UART_ErrorCallback
is called.Here we hit the problem:a) the user assumes that if theirHAL_UART_ErrorCallback
is called, the transaction has been cancelled by HAL. The user tries to start a new one, usingUART_Receive_IT
- and it results in an Overrun error appearing again immediately: while the ''software'' part thinks that the hardware is in the idle state, in reality the hardware is still reading data.b) the user assumes that if theirHAL_UART_ErrorCallback
is called, they must record huart->Error code somewhere, but not do anything else, i.e. the operation continues. But now it will never get the next byte: when the byte is received, and the IRQ routine is called, the huart->State field is set toHAL_UART_STATE_READY
, and theUART_Receive_IT
will not be called to process the received byte.III) an overrun error is detected, data is received, but the buffer is longer than 1 byte.UART_Receive_IT
is called, and moves the input to the bufferit's NOT the last byte,UART_Receive_IT
simply returnsthe (c) check inHAL_UART_IRQHandler
is FIRED (Error field is not empty):State is changed toHAL_UART_STATE_READY
[user-supplied]HAL_UART_ErrorCallback
is called.The situation is the same as in case II. Fortunately, in our code we know for sure if there is a reading and/or writing operation pending when our HAL_UART_ErrorCallback routine is called. So, we just restore the huart->Status value back to HAL_UART_STATE_BUSY_RX or AL_UART_STATE_BUSY_TX_RX in that routine, before returning to IRQ.But this is obviously just a dirty fix, and if the analysis above is correct, it would be nice to have a fix in the HAL_UART_IRQHandler. It looks like huart->State should not be modified there. #hal #uart2015-11-30 12:19 PM
(STM32Cube F4 v1.9.0) When using HAL_UART_Receive_IT(), I also encountered the problem you describe. Upon Rx buffer overrun, the HAL driver does not properly manage its internal states. As you outlined, the driver sets huart->State to HAL_UART_STATE_READY without clearing the Rx interrupt process, resulting in continual Rx interrupts and blocking the application.
I used the dirty workaround you mention:void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart){ if (huart->ErrorCode == HAL_UART_ERROR_ORE) // overrun { huart->State = HAL_UART_STATE_BUSY_RX; }}2015-12-01 03:05 PM
Hello, On My project I found a similar situation and after many hours/days debugging to find the cause and its solution, essentially I solved with:
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{//I implement this .. but eventually you can decide with different approach
//Many macros/proc on this code .. is just to be a hint (mem/rec about this possibility) __HAL_UART_CLEAR_OREFLAG(huart); __HAL_UART_CLEAR_NEFLAG(huart); __HAL_UART_CLEAR_FEFLAG(huart);/* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
__HAL_UART_DISABLE_IT(huart, UART_IT_ERR);//The most important thing when UART framing error occur/any error is restart the RX process
if(huart->Instance == USART1) { //Restarting the RX, .. 1 byte. .. u8DATUartShortRxBuffer is My own rx buffer HAL_UART_Receive_IT(huart, u8DATUartShortRxBuffer1, 1); }if(huart->Instance == USART2)
{ //Restarting the RX, .. 1 byte. HAL_UART_Receive_IT(huart, u8DATUartShortRxBuffer2, 1); }}
===============================================
STM32CubeMX 4.11.0, Firmware package for Family STM32F0 1.4.0 STM32F042C6Tx uController with LQFP48 package. UART1Tx = PIN30, UART2Rx=PIN31, UART2Tx=12 and UART2Rx=13My microcontroller is communicating with another embedded coomunication module (RF/module) by USART2.
Eventually it can help you or somelse too,
Greg2015-12-02 05:41 AM
I also confirm the bug, and your workaround solves the issue.
2016-01-25 11:55 PM
Hi,
I always face noise error (HAL_UART_ERROR_NE) when receive serial data but the solution above works too.Do you guys know why noise error happend?Thanks2018-07-11 10:28 PM
I also faced this issue and I fixed by restarting the reception by calling the HAL_UART_Receive_IT() in error callback. I am receiving one by one byte. I was always calling this API in Rx callback but once this particular corner case occurs of ORE error and no data then UART_EndRxTransfer() is called and UART does not trigger interrupt on reception and hence no Rx call back is called. That's why I called
HAL_UART_Receive_IT() in error callback for this case.
Thanks for detailed comment.