# FreeRTOS and 3 UARTS

I have application which has 3 UARTS (GSM / Debug / GPS) and will be developed under FreeRTOS (not the matter here but STM32F1 will be used).

What would be the pattern to use with this setup regarding:

GSM: Will be used to receive message commands and send feedback from sensors. GPS: Will be processed to get new location ASAP. Debug: Will output information on the status of the system.

My thoughts:

2. GSM communication
3. Debug output

GPS will get location and put it into global buffer then signal via semaphore that location is available. If semaphore has not been taken (either put that new location into circular buffer or discard it).

GSM will receive data into queueRX and queueTX and send when possible to the server.

Debug output will also receive in queueRX and queueTX and send to dedicated UART.

Application task will coordinate all of the main algorithm (take location, acquire sensor info and send output to GSM and debug).

Now comes the question, because there is 3 UARTS in the same time (two at 115200 and GPS at 9600) what would be the best / pattern approach of handling that Tx/Rx.

I have made some tests for GPS and tried to put every RX char into queue but that generates too much Interrupts, also using DMA has issue because you can easily miss ending \r\n and then you are in wait.

• What do you define as "too much interrupts"? – Jeroen3 Oct 27 '19 at 10:29
• As long as your interrupt handlers are short & to-the-point as they should be, you shouldn't suffer from "too-much-interrupts" with only 2 x 115200 + 1 x 9600. Your micro should be able handle that & still spend the majority of its time sleeping. – brhans Oct 27 '19 at 14:10
• "too much interrupts" refers that this should not be called frequently and while getting stream of NMEA it is. – user505160 Oct 27 '19 at 20:58

To add to the answer from stiebrs, here's a start for the relevant DMA interrupt handlers to add Idle detection. You need to implement RegisterRemainingBuffer_ISR() yourself, reacting to \r\n etc. Also, you need to distinguish the different UARTs.

//Called from interrupt when the buffer is completely filled (DMA will
//wrap around).  An IDLE interrupt will still follow if this happened
//to be the last data.
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
//The buffer is filled, hence number of remaining bytes is 0.
RegisterRemainingBuffer_ISR(0);
}

//"There is no received byte for more than 1 byte time length"
//Called from interrupt
void HAL_UART_RxIdleCallback(UART_HandleTypeDef *huart) {
// This is the number of bytes in the buffer *not* written:
uint16_t remainingBuffer = huart->hdmarx->Instance->CNDTR;
//RegisterRemainingBuffer_ISR() must handle the case where no new
//data has been written.
RegisterRemainingBuffer_ISR(remainingBuffer);
}

//Called from interrupt.
//Not enabled right now! The interrupt is disabled in STM32 HAL!
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart) {
uint16_t remainingBuffer = huart->hdmarx->Instance->CNDTR;
RegisterRemainingBuffer_ISR(remainingBuffer);
}


Before going the DMA route, check whether the MCU has separate DMA channels for the UARTs you wish to use in parallel. The 9600 baud UART is less important to use DMA with.

By the way, there's no functional advantage to relegate UART Tx to the task also dealing with UART Rx on a particular UART bus, since UART is full duplex. The important thing is to avoid race condition if multiple tasks use the same UART bus. Simply blocking until the bus is available, then doing a blocking write might be good enough.

Use DMA with IDLE detection, don't process data in interrupts. Your interrupt handler just signals your tasks, that IDLE has been detected and returns number of characters and pointer to the buffer to task responsible for processing it. Tasks just process the data or sleep, if all is done.

Note, that you'll have to implement IDLE detection yourself, for STM HAL does not do that yet. But I've seen in forums patches for this.