How to tell when the serial transmission is done

I have 3 serial devices hooked up to the Tx pin on an ATmega168, I use the first three pins on PORTB to decide which device should receive the data.

Example code for one of the devices

void SendtoKontroler(unsigned char cmd)
{
      PORTB = 0x06;
      USART_Transmit(cmd);      
      while((UCSR0A&(1<<UDRE0)) == 0); 
      PORTB = 0x07;

}

This doesn't work because when I checked it with a scope, PORTB pin0 goes high 200us before the transission ends, cutting off the last bit and stop bit.

NOTE:
-the transmission only goes through when the corresponding control pin is low (PORTB Pins 0, 1, and 2).
-Also I thought the UDRE0 bit in register UCSR0A goes high only after the transmission finishes, apparently not.

It would be more helpful if you would post the full code. Also annotating the code can be a big help as well. That way we get a better understanding of what is going on with the code.

while((UCSR0A&(1<<UDRE0)) == 0);

You want to check TXC0 here instead of UDRE0. UDRE0 (Data Register Empty) tells you when the transmit buffer is able to accept another byte (at which time the actual shift register is still shifting out the previous byte.) TXC0 is (according to the datasheet) "transmit complete" (done shifting AND no more data in DR.)

That's the thing according to the data sheet TXC0 is "transmit complete" but when I use the line

while((UCSR0A&(1<<TXC0)) == 0);

This makes it worse, now the control pin goes high 400us!! before the end of the transmission. Cutting off the last 3 bits.

There must be something I'm overlooking because using that line
while((UCSR0A&(1<<TXC0)) == 0);

is the same as if I commented it out?!?!
//while((UCSR0A&(1<<TXC0)) == 0);

Ah. I didn't read the fine print:

The TXCn Flag bit is automatically cleared when a transmit complete interrupt is executed, or it can be cleared by writing a one to its bit location.

So TXC0 isn't self-clearing unless you're using it to trigger an interrupt. That's ... really annoying! You can use code like this:

void wait_for_done()
{
  UCSR0A |= 1<<TXC0;  // clear flag!
  while((UCSR0A&(1<<TXC0)) == 0);
}

But if the transmit is already done when you call this, it will loop forever.
I guess a rather inelegant but safe solution is to include a timeout:

void wait_for_done()
{
  char timeout = 10;  // delay in 100 us units
  
  UCSR0A |= 1<<TXC0;  // clear flag!
  while((UCSR0A&(1<<TXC0)) == 0) {
     delayMicroseconds(100);
     if (--timeout <= 0)
        break;
  }
}

(As a test program, I've been changing the speed after Serial.print(). If the output isn't done, you get garbage...)

void setup()
{
}

void loop()
{
  Serial.begin(19200);
  Serial.print("\n0123456789");
  delay(10);
  wait_for_done();
  Serial.begin(9600); //change speed
  delay(10000);
}

westfw:

So TXC0 isn't self-clearing unless you're using it to trigger an interrupt. That's ... really annoying!

This is the case for most, if not all, of the flags. The flag is cleared automatically if and when the appropriate interrupt service routine runs. The flag must be cleared manually if it is just being polled.

Don

Cool, just slight confusion here.

Here's my pseudo code understanding of it.

Usart_transmit(char) //Send byte to USART for transmission
Set TXC0 to (1)      //Clear the TXC0 FLAG.
TXC0 gets set to (0) //The USART hardware sets it to (0) while data is shifted out???
Wait for TXC0 to rise back to a (1) //This signals the transmission finished
Then TXC0 falls back to a (0) //????

That does not seem correct, right?

Usart_transmit(char) //Send byte to USART for transmission
Set TXC0 to (1) //Clear the TXC0 FLAG.
TXC0 gets set to (0) //The USART hardware sets it to (0) while data is shifted out???

TXC0 sets it to 0 as soon as you write the 1. This is relatively common for Interrupt Status registers (that writing a 1 sets things to zero.) It's not uncommon to see code like:

    status = INTSTATUS;  // read interrupt status
    INTSTATUS = status;  // clear all bits
    if (status & RXINT) {
        :

This way all interrupts get cleared even if they're not ones you were expecting.

Wait for TXC0 to rise back to a (1) //This signals the transmission finished

Yep.

Then TXC0 falls back to a (0) //????

Nope. This is the crux of the matter. TXC0 does NOT "fall back" unless it is either explicitly reset (as in your first step), or if it generates a TXC interrupt.

@floresta: Most status bits that are sticky don't have "obvious" things that would reset them. if you've receive some sort of error (for example), you want the bit to stay set until you notice. OTOH, TXC really ought to get cleared whenever you write a new byte to the TX data register, IMO. Like the similar UDRE. Being able to tell that some previous transmission "finished" even after you've started several additional transmissions is pretty useless...

@westfw - You answered his question while I was working on mine. Here is part of that answer for your analysis.

I haven't done much with the USART but here is how it looks to me:

If you want to send a string of characters it is not very efficient to wait until the transmit shift register is empty between characters, that's why the transmit buffer is there. I guess this scheme would work.

(1) Poll the TXC0 flag until you find it set
(2) Clear the TXC0 flag
(3) Load a character into the transmit buffer
(4) Repeat

If you want to send a string of characters you generally check the transmit buffer between characters, not the transmit shift register. This buffer appears to have a flag that is automatically cleared (when you load the buffer).

(1) Poll the UDRE0 flag until it is set
(2) Load a character into the transmit buffer
(3) repeat

You can find a diagram of how I think things interact by following the Reference Diagrams For Programmers link at http://web.alfredstate.edu/weimandn. You will have to scroll down the page to find the link. Then scroll down that page to find the USART link.

Don

Thank you both for the help. I'll try this out when I get back to my dorm on monday.