cancel
Showing results for 
Search instead for 
Did you mean: 

USART writes seem to block or slow down reads

markmark9125
Associate II
Posted on February 09, 2013 at 15:35

I'm really stumped on this one, and hoping someone can help. I'm using USART_ReceiveData() to receive data off of a USB line at 9600 baud, on an STM32F0Discovery. It works without any trouble until I try to send out any data, i.e.

while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
USART_SendData(USART2, 42);

As soon as I start sending data, USART_ReceiveData seems to start missing bytes. For instance, if I try to read two consecutive bytes, the second one just doesn't get read. However, if I separate the two bytes by about 20ms or more, then USART_ReceiveData has no trouble catching them. Does anyone have any idea what might be causing this? #stm32f0discovery-usart
5 REPLIES 5
Posted on February 09, 2013 at 15:47

Does anyone have any idea what might be causing this?

Grinding in while() loops instead of using interrupts? If you have to poll do it in a manner that doesn't block incessantly.

while(1)
{
if (TXE) Send();
if (RXNE) Receive();
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
markmark9125
Associate II
Posted on February 11, 2013 at 17:41

Obviously I'd prefer to use interrupts, but unfortunately I'm working with a 3rd-party library that requires me to implement read() and write() functions. I suppose I could hack interrupts into this, but it doesn't seem like the most elegant solution.

But basically what you are saying is that because writing data takes a finite amount of time, and it blocks reading, then I'm likely to ''miss'' bytes that arrive while I'm writing? Does the STM32F0 USART have a buffer, or does it only hold one byte at a time?

Thanks so much for your help, I'm quite new to embedded programming.
Posted on February 11, 2013 at 19:22

The design of the USART is diagrammed in the manual. Both the transmit and receive paths have independent holding, and shifting registers. There is no FIFO, and very little elasticity.

If you sit blocking on an RXNE, you may be stepping on time that could be used more effectively for transmitting as TXE may be asserted. TXE may then be stuck low for 10 bit times while the current shift register content departs.  Blocking here on TXE would then preclude you recognizing an RXNE.

If you have to transmit a 100 characters, you can't ignore RXNE during than entire period, the receiver will overrun.

My pseudo code illustrates pulling data into a receive buffer if some new data arrives, and if the transmitter is empty feed it the next available data from the transmit buffer. ie it does not perpetually dwell on TXE or RXNE to the exclusion of the other.

 

The other way is to provide a buffering abstraction for the read/write routines, and service those buffers via the USART interrupt. Which is what most people would do rather than polling the USART directly in a foreground or blocking loop.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
markmark9125
Associate II
Posted on February 11, 2013 at 20:23

Thanks a lot, I think your advice got me back on track. I found that the way Arduinos handle this is to provide a buffering abstraction, exactly as you describe, in the HardwareSerial class.

For anyone else who comes across this topic, the following introduction to the STM32 is very helpful, and covers the issues around polling and interrupts in more detail: 

http://www.cs.indiana.edu/~geobrown/book.pdf

Andrew Neil
Evangelist III
Posted on February 12, 2013 at 00:36

''I'm working with a 3rd-party library that requires me to implement read() and write() functions. I suppose I could hack interrupts into this, but it doesn't seem like the most elegant solution.''

Why ever not?

As clive1 says, it is common to have read() and write() functions with a ring buffer as the interface to the transmission & reception ISRs...