2022-05-10 07:13 AM
Hello everyone,
I would like to transmit strings of characters (which could be different sizes) using the Nucleo's UART serial communication. I'm using HAL_UART_Receive_IT(&huart2, &rx_buffer, 1), which receives the characters one by one and stores them into my rx_buffer, replacing the previous one.
If I increase the amount of data elements to be received, the smaller strings of characters will not be enough to fulfill the expected amount of data elements to be received, and the HAL_UART_RxCpltCallback() will not be triggered.
Is there a way to get the whole string of character, or to know if the the communication has ended, like a timeout flag?
Thanks in advance!
Loïc
Solved! Go to Solution.
2022-05-10 07:35 AM
I suggest to use USART with DMA and idle line detection.
below is an example
uint8_t RxBuffer[256],RxLenght;
// in init
HAL_UART_Receive_DMA(&huart3,RxBuffer,255);
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
/**
in it file
*/
void USART3_IRQHandler(void)
{
/* USER CODE BEGIN USART3_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE))
{
HAL_UART_DMAStop(&huart3);
//Calculate the length of the received data
RxLenght= 255 - __HAL_DMA_GET_COUNTER(&hdma_usart3_rx);
//Restart to start DMA transmission of 255 bytes of data at a time
HAL_UART_Receive_DMA(&huart3, (uint8_t*)RxBuffer, 255);
}
/* USER CODE END USART3_IRQn 0 */
HAL_UART_IRQHandler(&huart3);
/* USER CODE BEGIN USART3_IRQn 1 */
/* USER CODE END USART3_IRQn 1 */
}
2022-05-10 07:22 AM
With strings, people frequently use end-of-line indicators like <CR><LF>, ie "\r\n", or some combo thereof.
One could also time-stamp the character reception,and process the time-out elsewhere to take the line. Works less well for human interaction as they are slow and unpredictable.
Check if the L4 has some "LINE IDLE" type interrupt.
2022-05-10 07:35 AM
I suggest to use USART with DMA and idle line detection.
below is an example
uint8_t RxBuffer[256],RxLenght;
// in init
HAL_UART_Receive_DMA(&huart3,RxBuffer,255);
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
/**
in it file
*/
void USART3_IRQHandler(void)
{
/* USER CODE BEGIN USART3_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE))
{
HAL_UART_DMAStop(&huart3);
//Calculate the length of the received data
RxLenght= 255 - __HAL_DMA_GET_COUNTER(&hdma_usart3_rx);
//Restart to start DMA transmission of 255 bytes of data at a time
HAL_UART_Receive_DMA(&huart3, (uint8_t*)RxBuffer, 255);
}
/* USER CODE END USART3_IRQn 0 */
HAL_UART_IRQHandler(&huart3);
/* USER CODE BEGIN USART3_IRQn 1 */
/* USER CODE END USART3_IRQn 1 */
}
2022-05-10 07:37 AM
Hi @Community member !
Thank you for your fast answer. I'm looking how to do this and trying to do it by myself. I'll reply back for learning more if I have any issue.
Loïc
2022-05-10 07:50 AM
Hi @Muhammed G�ler !
Thanks for the screenshot and code, seems pretty simply and efficient. I'll give it a try and let you know about it.
Loïc
2022-05-10 07:50 AM
Hi @Tesla DeLorean (Community Member) !
Thank you for your fast answer. I'm looking how to do this and trying to do it by myself. I'll reply back for learning more if I have any issue.
Loïc
2022-05-11 12:31 AM
Hi again!
I'm trying to detect the '\r' character at the end of the sent string, but when sending a string via the STM32CubeIDE built-in serial monitor in debugging mode, I get a strange behavior. See in the screenshot below, sometimes there is the '\r' at the end of the string (when I first sent "CMD" and hit Enter), sometimes not (then I sent "kCMD").
How could I manage to get the '\r' every time when I send a string?
Loïc
2022-05-11 02:27 AM
Hi again @Muhammed G�ler !
I'm trying the DMA method with the UART communication. There's no USART3 on the Nucleo-L432KC so I'm using the USART2.
With your code, I'm having a strange behavior. Indeed, the USART2_IRQHandler() is constantly triggered, even if I'm not sending anything through the serial monitor.
What's the issue here?
2022-05-11 08:26 AM
To reply to my previous question, I figured out that the USART2_IRQHandler() is constantly triggered because of the __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE). It sets an interrupt that's triggered when IDLEFLAG is set (when there is no UART communication).
To make the interrupt happen only once, I clear the IDLEFLAG using __HAL_UART_CLEAR_IDLEFLAG(&huart2) in the USART2_IRQHandler().
Also, I don't want to trigger the USART2_IRQHandler() at my program's beginning. The IDLEFLAG is firstly set at the MX_USART2_UART_Init(), so I've put my __HAL_UART_CLEAR_IDLEFLAG(&huart2) just after it.
My issue there is the following: in debugging mode, the IDLEFLAG reset works if I run the lines one by one, but seems to be skipped if I don't make a stop on the line.
How to be sure to reset the IDLEFLAG in normal run?
Loïc
2022-05-11 09:43 AM
The HAL_UART_IRQHandler function needs to contain the __HAL_UART_CLEAR_IDLEFLAG macro. (at least it's in the F4 library)
If you increase the value of a variable where you stop and start DMA, you can see if the number of incoming packets matches the number of times the interrupt function runs.