uart / printf() interference?

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've noticed while trying to debug my code using a lot of printf() statements that the more printf() statements I put in seems to adversely affect the performance of my code. And I realize that the printf(), for example, takes time... and if you over-run your frame time problems may arise. What I don't understand, though... is what the mechanism of this interference actually is. In my case, for example, all I have done is enabled a UART for serial communication with a digital compass... The UART communication works fine until I make the string in my printf() statement too long. I first thought it was simply a display issue, and assumed my code actually had the right value from the digital compass and it was just coming out wrong on my terminal every now and then due to issueing the printf() statement too frequently for it to keep up. As it turns out, this was not the case... when the value comes out wrong in my terminal, it was really read in wrong during the UART communication. This problem completely goes away when I disable my printf() statements. Why would printing to one UART have any bearing on communication with another UART? I'm using ISR driven receive on the UART communicating with the digital compass. I would think that no matter how much time is being spent in the printf() function, or how frequently it is called, that it would jump away from this to get the incoming byte from the digital compass? But apparently, it doesn't seem to work that way. Anyway, I can live with what's happening... because the problem goes away when I eliminate my printf() statements, it just worries me that I don't understand why this happens. It makes me wonder if communication with multiple devices over two different UARTs would cause similar problems as well. Does anyone know why this type of behaviour occurs?

Thanks,
James

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Simply enough is that every time a byte is sent to the UART, the code wait for the transmit buffer to be empty (give time to the character to go out on the cable, or more exactly to the shift register, before writing the new byte to the transmit register).

Every characters sent take some time. So, for example, at 19200 bauds, you can send 1920 characters per seconds (1 start bit, 8 data bit, 1 stop bit per characters).

So, every time you send a string, this will slow down the AVR accordingly (waiting for the buffer to clear).

Here, the printf may be taking all the time. Even though you read on the other UART in an ISR, is it possible that the main code does not read the value before your ISR is triggered again and overwrite your data?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
is it possible that the main code does not read the value before your ISR is triggered again and overwrite your data?

I'm guessing that that's what is happening... but just don't understand why. Even though the outgoing printf() statement may have to sit and spin on a "while ( !( UCSR0A & (1<<UDRE0)) )" statement and chew up time... I thought that if an incoming byte came in on the other UART it would break away from this while() loop in main() and go read the incoming byte in my Rx ISR? In my UART Rx ISR, all I do is read the character into an array and then do an "atoi" on it later in main(). For example, all my ISR is is the following:

ISR(USART2_RX_vect)
{
	// Verify no Framing Error detected
	if (bit_is_clear(UCSR2A, FE2))  
	{
		// Add char to UART2 Buffer Array
		UART2Buffer[UART2BufferIndex] = UDR2;
		
		// Flag Event for main()... 
		UART2CharReceived = 1;
	}
}

And then in my main() I do something like...

Heading = atoi(UART2Buffer);

after the ',' delimiter is reached.

Anyway, this all works great until I introduce too long of a printf() statement. I know it works flawlessly otherwise by putting in tests that I would break on if any type of unexpected value was read in. The ONLY time this happens is when I introduce printf() messages to be seen in my hyperterminal. If the problem is that my main() is being tied up in that while() statement, is there any way of avoiding this? I just thought it would've broke away to go process the ISR if one came in during this process?

- James

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, but what happen if the printf take long enough for your ISR to be called twice (or more) before printf return, letting your main code read the buffer?

Something that is not clear in the code posted above, your ISR write to UART2Buffer[UART2BufferIndex] and immediately signal main(). I guess that main() is then expected to increment UART2BufferIndex, which it won't if stucked in printf() during 2 UART2 receive events...

In any case, it's a bit hard to control, because printf() can take a long time, depending on the number of chars sent. The buffer may fill-up anyway. However, if the data from the compass come slowly enough (with a long enough delay between each datagram), maybe moving the UART2BufferIndex auto-increment in the ISR could do the trick.

What would be needed in an ideal world is a circular buffer. You have, for example, a 16 or 32-byte buffer, with a read and write index pointer. The write index is incremented (mod 15 or 31) in the ISR, while a subroutine of main() handle the read pointer. Then, the ISR will have some slack before it start discarding data (which occur if the buffer is full). Although, this may be a bit of work to code, possibly unnecessary if you can live without it (i.e. in normal condition, without the printf). In any case, data WILL be lost eventually if you spend more time in printf than you can process data.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
maybe moving the UART2BufferIndex auto-increment in the ISR could do the trick

Oh, I see your point... I will try that first & see how it does. Thank you...

- James

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just make sure that the buffer does not overflow if, for some reason, the main() does not reset the index in time for the buffer to fill-up.

Regards