HAL_UART_Transmit_IT blocks until end of transmission
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-01-10 6:19 AM
I am using STM32CubeIDE + STM32F103C8T6 MCU with USART1. I am transmitting data by calling this function:
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size)
The function is generated by CubeIDE. It turns out that this call blocks until the last character is sent out. I found that what is blocking is the following line in this function:
__HAL_UART_ENABLE_IT(huart, UART_IT_TXE);
HAL_UART_TxCpltCallback is called some microseconds before HAL_UART_Transmit_IT returns.
Any ideas why this happens? I would expect HAL_UART_Transmit_IT to return immediately, while transmitting the data should be done in the background.
Solved! Go to Solution.
- Labels:
-
STM32CubeIDE
-
STM32F1 Series
-
UART-USART
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-01-10 6:49 AM
Your baud rate is high. You have about 10us between characters, which may not be enough for the IRQ handler to finish, although it should be enough if your clock settings are maxed. Slow down your baud rate by an order of magnitude. If that still blocks, instrument HAL_UART_IRQHandler in the same manner to see how long it takes and where it's getting held up and/or to confirm that's what is actually blocking execution.
The small delay between the "G" and "H" characters suggests your IRQ handler is barely keeping up with feeding the peripheral data.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-01-10 6:30 AM
If characters are being sent out correctly, it means the ISR is getting called. Perhaps the system is overwhelmed with calls and can't make progress in the main loop.
It's not possible for that call to really block. There's no logic within it which would cause that. See for yourself:
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-01-10 6:43 AM
Thanks for your reply. I have already seen the syntax of __HAL_UART_ENABLE_IT and totally agree that there is no logic for this to block. However, let me give more details.
Main loop:
while (1) {
DIAGN_Print("ABCDEFGHIJKLM\n");
HAL_GPIO_TogglePin(nLED_GPIO_Port, nLED_Pin);
HAL_IWDG_Refresh(&hiwdg);
HAL_Delay(50);
}
Called functions:
#define DIAGN_HUART huart1
#define DIAGN_BUFFER_SIZE 128
static char diagn_buffer[DIAGN_BUFFER_SIZE];
static void Print(const char *data_ptr, size_t size) {
HAL_GPIO_WritePin(OUT_1_GPIO_Port, OUT_1_Pin, 1);
while ((&DIAGN_HUART)->gState != HAL_UART_STATE_READY) {
}
HAL_GPIO_WritePin(OUT_3_GPIO_Port, OUT_3_Pin, 1);
if (HAL_UART_Transmit_IT(&DIAGN_HUART, (uint8_t*) data_ptr, size) != HAL_OK) {
Error_Handler();
}
HAL_GPIO_WritePin(OUT_1_GPIO_Port, OUT_1_Pin, 0);
}
void DIAGN_Print(const char *ptr) {
HAL_GPIO_WritePin(OUT_0_GPIO_Port, OUT_0_Pin, 1);
Print(ptr, strlen(ptr));
HAL_GPIO_WritePin(OUT_0_GPIO_Port, OUT_0_Pin, 0);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
HAL_GPIO_WritePin(OUT_3_GPIO_Port, OUT_3_Pin, 0);
}
Instrumented HAL_UART_Transmit_IT (the only difference is added HAL_GPIO_WritePin before and after __HAL_UART_ENABLE_IT):
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Check that a Tx process is not already ongoing */
if (huart->gState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(huart);
huart->pTxBuffPtr = pData;
huart->TxXferSize = Size;
huart->TxXferCount = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_BUSY_TX;
/* Process Unlocked */
__HAL_UNLOCK(huart);
/* Enable the UART Transmit data register empty Interrupt */
HAL_GPIO_WritePin(OUT_2_GPIO_Port, OUT_2_Pin, 1);
__HAL_UART_ENABLE_IT(huart, UART_IT_TXE);
HAL_GPIO_WritePin(OUT_2_GPIO_Port, OUT_2_Pin, 0);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
Result (D0...3 is the state of OUT_0...3; D4 is the Tx pin):
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-01-10 6:49 AM
Your baud rate is high. You have about 10us between characters, which may not be enough for the IRQ handler to finish, although it should be enough if your clock settings are maxed. Slow down your baud rate by an order of magnitude. If that still blocks, instrument HAL_UART_IRQHandler in the same manner to see how long it takes and where it's getting held up and/or to confirm that's what is actually blocking execution.
The small delay between the "G" and "H" characters suggests your IRQ handler is barely keeping up with feeding the peripheral data.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-01-10 7:08 AM
Thanks TDK, this was a super fast solution! I wasn't aware of the fact that HAL_UART_IRQHandler gets called after every character transmission as well, I was erroneously supposing it only gets called once at the end of packet transmission.
​
HAL_UART_IRQHandler takes ~11us @ 16MHz so this explains why I was stuck with 921.6kbps.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-01-10 7:15 AM
For _DMA, the ISR is only called on certain conditions, like half transfer complete or full transfer complete or an error.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2021-01-10 12:47 PM
Great, I switched to transmission in DMA mode which finally allows me to keep the high baud rate and non-blocking call of DIAGN_Print().
Thanks for explanation!
