cancel
Showing results for 
Search instead for 
Did you mean: 

What is the best way to receive uart serial data at 115k Baud in a FreeRtos based app?

Julian Winpenny
Associate II
Posted on October 03, 2017 at 19:54

MCU: STM32F765

Using FreeRtos

10 REPLIES 10
Julian Winpenny
Associate II
Posted on October 03, 2017 at 20:07

The data is of variable length, so fixed length DMA transfer is not suitable

Richard Lowe
Senior III
Posted on October 03, 2017 at 20:44

A good rule of thumb is to use SIGNALS for ISRs and have the receiving and transmissions in separatetasks.

Here's anexample:

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
 if(huart->Instance == USART3)
 {
 osSemaphoreRelease(host_tx_semHandle);
 }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
 if(huart->Instance == USART3 )
 {
osSignalSet( host_rx_taskHandle, HOST_RX_ISR_FLAG );
 }
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

These are the handlers for the tasks. On the transmission, I'm using DMA, so when the UART is finished transmission the semaphore is released.

Here are the tasks:

void host_rx_process(void const * argument)
{
 // Buffer to hold message
 static uint8_t rx_buffer[HOST_RX_BUFFER] = {0};
 static uint8_t index = 0;
 static bool in_frame = false;
 uint8_t tmp_char = 0;
 HAL_UART_Receive_IT( &huart3, rx_tmp_buffer, 1 );
 for(;;)
 {
osSignalWait( HOST_RX_ISR_FLAG, osWaitForever );
tmp_char = *( huart3.pRxBuffPtr - huart3.RxXferSize );
// Do whatever needs to be done to the new char that just arrived
 //....
 // Be sure to set the interrupt for the next char
 if( HAL_UART_Receive_IT( &huart3, (huart3.pRxBuffPtr - huart3.RxXferSize), 1 ) != HAL_OK)
 {
 Error_Handler();
 }
 }
}
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

What's important here is that I'm waiting for the signal to the rx process which is set by the ISR handler. Doing this saves the most amount of cycles on the ISR so the RTOS can manage the tasks effectively.

Posted on October 03, 2017 at 21:18

Read it into a buffer? State machine processing/parsing in the USART IRQHandler?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on October 03, 2017 at 21:36

Thanks Clive, Yes, I was thinking I'll have to use receive interrupt and write to a fifo, then read it out and process in a task.

AVI-crak
Senior
Posted on October 03, 2017 at 23:42

DMA does a great job of transferring data using the FIFO buffer, and writing 32b words into memory. You need to use a communication protocol that is understandable for both sides. Even if you use your own unique data container, the required number of received or transmitted data will always be known. It came with an error in the transfer - just request the whole package again. Make it once, and use it in all your projects. Because it is a universal thing. It does not depend on the processor used, it does not depend on the compiler, it's just an algorithm - which will always be executed. Although it is much more logical to take a suitable example from an open repository, for example with GIT.

Option when the amount of data is unknown, or just laziness.

Use of cyclic variant of DMA operation, without checks, without detectors, without hardware capabilities of the uart block. This is a mega custom level of arduino in programming - where the contents of the memory of the receiving buffer are checked programmatically in continuous mode. Search there the same.
Posted on October 03, 2017 at 21:49

Depends a lot of the type and volume of the data. I tend to create a sufficiently deep FIFO buffer to hold a packet, or manage processing latency, with a rapid IRQ and then have a consuming task pull and process the data in a less time critical manner.

I would generally avoid using the USART IRQ handler from causing a task switch

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on October 10, 2017 at 17:58

Thanks Richard. The receive process works well.

How would the transmit process work please ?

Posted on October 10, 2017 at 18:32

Something like:

void host_tx_process(void const * argument)
{
osEvent evt;
for(;;)
{
evt = osMessageGet(host_tx_handle, WDT_MAX_WAIT_TIME );
if( evt.status == osEventMessage )
{
message_t *msg = (message_t*)evt.value.p;
// Take binary semaphore for UART
osSemaphoreWait(host_tx_semHandle, osWaitForever);
memcpy( (void*)&tx_buffer[4], (void*)msg->buffer, msg->msg_len );
tx_buffer[msg->msg_len++] = END_OF_FRAME;
HAL_UART_Transmit_DMA( &huart3, (uint8_t*)tx_buffer, msg->msg_len );
osPoolFree( message_pool, msg );
}
}
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

My application is specific, but the idea is passing a message to the host transmit thread and it sends everything over DMA.

Posted on November 06, 2017 at 22:29

This goes wrong if data received very fast (streamed) and can only recover with another call to

HAL_UART_Receive_IT( &huart5, RxBuffer, 1 );

Somehow the signal is missed.

Any ideas what's wrong?

void vGPRSTaskRx(void * pvParameters)

{

   HAL_UART_Receive_IT( &huart5, RxBuffer, 1 );

   while(1)

   {

      osSignalWait( HOST_RX_ISR_FLAG, osWaitForever );

      ch = *( huart5.pRxBuffPtr - huart5.RxXferSize );

      /* Echo .... */

      GPRSSendByte(ch);

      if ( HAL_UART_Receive_IT(&huart5, RxBuffer, 1) != HAL_OK )

      {

         Error_Handler();

      }

   }

}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)

{

      if(UartHandle->Instance == UART5)

      {

         osSignalSet( xGPRSRxTaskHandle, HOST_RX_ISR_FLAG );

      }

}