USART_ReadBlocking()

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

USART_ReadBlocking()

2,430 Views
Nadia
Contributor III

Hi all, I am having a problem with the USART_ReadBlocking() instruction. In this function, the last parameter is the amount of data to be read, in my case it is 3. The instruction is inside an interrupt, and every time it is enabled it enters and reads what is in the port. The problem is that sometimes these data arrive incomplete, and instead of 3 I get 2 or 1, and this instruction is blocked.

Does anyone know what I can do so that this does not happen?

 

0 Kudos
Reply
5 Replies

2,425 Views
frank_m
Senior Contributor III

> Does anyone know what I can do so that this does not happen?

Relatively simple - organize your code in a different way, and do not use blocking functions for asynchronous transmissions.

UART communications is inherently unsafe, i.e. characters can get lost or corrupted. Relying on a fixed sequence and stable timing will throw off you application quickly, and it will never recover until a reset.

A better method is to use single character reception (or more than one character in case of a FIFO).

And, use a protocol with at least a designated end character (like e.g. '\n'), or designated start and end characters. An example would be the NMEA-183 output of GPS receivers, where sentences always starts with '$', and always ends with '\r\n'.

The interrupt handler receives individual characters and stores them, and passes them on to the main loop once an end character is received.

Additionally, your handler would need to check for receive buffer overflows, and "stray" start characters. And you would need to make a copy of the bufferfor the main loop, else follow-up transmissions overwrite your data.

0 Kudos
Reply

2,421 Views
Nadia
Contributor III

I have tried to read byte by by byte, and I get stuck in the usart driver module. In the following line:

while ((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) == 0U)

0 Kudos
Reply

2,417 Views
frank_m
Senior Contributor III

> while ((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) == 0U)

Looping on the RXNOTEMPTY flag is exactly the problem. This is a blocking read.

You cannot solve tasks relating to asynchronous events (like serial communication) with strictly sequential methods. Multitasking / multiprocessing would be another example of such concurrency. Like e.g. this POSIX thread tutorial: https://randu.org/tutorials/threads/

In your case, the serial interrupt behaves like a separate thread, controlled by the external device via UART.

0 Kudos
Reply

2,420 Views
Nadia
Contributor III

@frank_m 

I have tried to read byte by by byte, and I get stuck in the usart driver module. In the following line:

while ((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) == 0U)

0 Kudos
Reply

2,403 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Nadia,

As Frank said it was correct behavior of MCU which stuck in the while() line in polling mode.

As you know there are three methods to transfer data: polling mode, interrupt mode and DMA mode, the while ((base->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) == 0U) belongs to polling mode, it continues to poll if the USART_FIFOSTAT_RXNOTEMPTY_MASK bit in base->FIFOSTAT is set, it does nothing else, that is why is it is calling USART_ReadBlocking.

I suggest you use interrupt mode, when the USART receives a character, the USART_FIFOSTAT_RXNOTEMPTY_MASK bit in base->FIFOSTAT register is set immediately, the event can trigger an interrupt, then the MCU will stop the current task and enter the ISR of the USART and execute the ISR. In the ISR, you can read the character from receiver. You can call the

hal_uart_status_t HAL_UartTransferReceiveNonBlocking(hal_uart_handle_t handle, hal_uart_transfer_t *transfer)
{
hal_uart_state_t *uartHandle;
status_t status;
assert(handle);
assert(transfer);
assert(HAL_UART_TRANSFER_MODE);

uartHandle = (hal_uart_state_t *)handle;

status = USART_TransferReceiveNonBlocking(s_UsartAdapterBase[uartHandle->instance], &uartHandle->hardwareHandle,
(usart_transfer_t *)transfer, NULL);

return HAL_UartGetStatus(status);
}

Hope it can help you

BR

XiangJun Rong

0 Kudos
Reply