cancel
Showing results for 
Search instead for 
Did you mean: 

How to handle Variable length receive data via UART

VChau
Associate II

Hi All,

The idea, to use variable length data on UART receiver is that "Use a timer ",

I am using a timer with interrupt, Once the first byte is received timer start and on second byte receive timer STOP and store the data and start the time again, At the last byte received timer will expired and generate the interrupt Then I process the complete frame. Timer value should be greater than 1 byte time

I want to know is it a right way to do So...?

6 REPLIES 6
JPeac.1
Senior

You can improve on this technique by using a timer with a reset input. Connect the RxD input to the timer reset so that the timer is constantly reset while data is being received. When RxD is idle the timer is not rest, times out and frames the received data. This works especially well when using DMA to receive USART data. Halt the DMA transfer when the timer overflows. There is essentially no overhead while receiving data, no interrupt time until the end of transmission.

Some of the later STM32s have a programmable RxD IDLE time, which can replace a dedicated timer if the maximum idle time is within design goals. A good place to use IDLE instead of a hard timer is framing MODBUS RTU binary packets, where the inter-frame time between messages has a relatively short minimum.

Jack Peacock

Karl Yamashita
Lead II

What are you receiving data from? Another Microcontroller? Is this binary data or ASCII?

If you find my answers useful, click the accept button so that way others can see the solution.

In most cases timers should not be used for UART operation. The best way is to use circular DMA receiving buffer. You start DMA single time and any data received will be written to circular buffer guaranteed. Amount of data need to be parsed is calculated by checking NDTR / CNDTR register and processed bytes counter variable.

uint32_t cnt=myPortPtr->rxBufSize-*myPortPtr->ndtrPtr;
 
	if (cnt!=myPortPtr->rxPos)
	{
		*b=( (myPortPtr->rxBufPtr)[myPortPtr->rxPos] & 0xff);
		myPortPtr->rxPos++;
		if (myPortPtr->rxPos==myPortPtr->rxBufSize) 
		{myPortPtr->rxPos=0;}
 
		updateCRC32byte(*b,&HYDRA_CRC32_RX);
		return true;
	}
 
	myPortPtr->rxFail=true;
	return false;

Circular DMA works when timing is not used to frame messages. However, it doesn't work with protocols like MODBUS where messages are framed by a minimum inter-frame gap. DMA alone does not capture that gap, which results in messages running together without a frame marker.

If messages are framed (i.e. STX-ETX or CRLF) then yes, circular DMA is ideal, though the stream must be parsed to separate messages. When using an RTOS with stream support (i.e. FreeRTOS) the message stream can be used where entire messages are queued to the network stack without the need for an intermediate parser.

S.Ma
Principal

Start with the 8 bit mcu way with byte by byte interrupt a header lock algo and a sw fifo.

Then, if relevant, use a regular timer interval with dma buffer cycling to poll for incoming message, which is the other way. If the uart is 115200bps, keep the dma for higher bit rate needs such as SPI buses.

A DMA offload the core and may save little power down the road, it hardly help for WCET and latency constrains.

I would save input capture values for each arriving byte to second circular DMA buffer and calculate inter-byte time gaps by substracting adjacent elements. It is better to avoid non-DMA approach or setting highest USART interrupt priorities.

update: With timer/interrupt approach it would be pretty difficult to make adequate 8-port device. Or if you control time sensitive high power electronics and delay overhear sensitive switching by some high priority USART/timer interrupt.