Pages: [1] 2 3   Go Down
Author Topic: How to know when serial has finished sending  (Read 2007 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Full Member
***
Karma: 0
Posts: 127
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

How can I tell (from the user-program) when a serial stream has finished being transmitted?

I want something like

uint8_t Serial.sending();

that returns true if it's still sending, or false if it has completed (nothing in the send queue). Otherwise it could return the number of bytes in the send queue, it doesn't really matter either way.
Logged

Chile
Offline Offline
Edison Member
*
Karma: 32
Posts: 1233
Arduino rocks?
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

How can I tell (from the user-program) when a serial stream has finished being transmitted?

I want something like

uint8_t Serial.sending();

that returns true if it's still sending, or false if it has completed (nothing in the send queue). Otherwise it could return the number of bytes in the send queue, it doesn't really matter either way.

You have to add something to each transmission at the end or via timeout, like if nothing was received in "n" milis -> Sending is false
Logged

My website: http://ried.cl

0
Offline Offline
Full Member
***
Karma: 0
Posts: 127
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I mean, how can I tell when it has finished transmitting from itself. I want it to send an array of bytes, and I don't want the program to continue until the last bit has been transmitted.
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 127
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nevermind, I just realized that "flush" does what I want.

OT, but doesn't it seem that "flush" is mis-termed? Flush normally means "remove any data in the rx buffers", and not "wait until the tx queue is empty".
« Last Edit: August 17, 2012, 09:01:53 pm by mattallen37 » Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 127
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Okay, so I guess I do need a different solution after all. flush seems to return as soon as the last byte has started to send, not when it has finished sending.

I can use flush and then delay for 1ms though, since is takes much less than 1ms to finish transmitting the last byte at 115200 baud.
Logged

Chile
Offline Offline
Edison Member
*
Karma: 32
Posts: 1233
Arduino rocks?
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, you need another approach. I built an example for you:

Code:
#define MAXDATA 50
#define TIMEOUT 10
void setup()
{
  // This code will only run once, after each powerup or reset of the board
  Serial.begin(9600);
}

long timeoutOver;
char data[MAXDATA];
  
void loop()
{
  // This code will loops consecutively
  boolean somethingReceived = false;
  int pos = 0;
  
  if(Serial.available())
  {
    somethingReceived = true;
    do
    {
      while(Serial.available())
      {
        data[min(pos,MAXDATA-1)] = Serial.read();
        timeoutOver = millis()+TIMEOUT; pos++;
      }
    }
    while(millis()<timeoutOver);
    data[pos] = '\0';
  }
  
  if(somethingReceived)
  {
    // Do something
    Serial.print("Received: ");
    Serial.println(data);
  }
}
Logged

My website: http://ried.cl

Offline Offline
Edison Member
*
Karma: 35
Posts: 1429
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nick Gammon posted code which checks the hardware to make sure the last byte has gone:
Code:
  Serial.flush ();
  // wait for transmit buffer to empty
  while ((UCSR0A & _BV (TXC0)) == 0)
    {}

Pete
Logged

Where are the Nick Gammons of yesteryear?

0
Offline Offline
Full Member
***
Karma: 0
Posts: 127
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@eried thanks but I don't need help with receiving data.

@el_supremo Thanks. What library do I need to #include to get access to that functionality?
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

No library. That code stands on its own.
Logged

Dallas, TX USA
Offline Offline
Edison Member
*
Karma: 47
Posts: 2347
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nick Gammon posted code which checks the hardware to make sure the last byte has gone:
Code:
  Serial.flush ();
  // wait for transmit buffer to empty
  while ((UCSR0A & _BV (TXC0)) == 0)
    {}

Pete

In my testing that was not good enough. It worked when only 1 character was sent but it failed
if there was still a character in the TX data register when the polling started.
It is very unfortunate that the bit isn't a "BUSY" bit. It is merely a transition bit that clears when the last bit
of a character leaves the shift register. This means that if multiple characters have been sent,
the bit also has to be set appropriately when the character is fed into the USART data register otherwise
you end up seeing the bit clear for the 2nd to last character since there are two characters in the USART.
1 in the shift register and one in the data register.

It took a patch in HardwareSerial.cpp to be able to set the bit appropriately to ensure that there
were no race conditions.
I had to modify the UDRE0 ISR routine and the flush() routine to make flush() work correctly and reliably
in my testing.

--- bill
Logged

Chile
Offline Offline
Edison Member
*
Karma: 32
Posts: 1233
Arduino rocks?
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

@eried thanks but I don't need help with receiving data.

@el_supremo Thanks. What library do I need to #include to get access to that functionality?

The code I posted is just a simple way to wait for the "full" data (timeout 10 ms), not just receive data.
Logged

My website: http://ried.cl

0
Offline Offline
Full Member
***
Karma: 0
Posts: 127
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@Nick Gammon, the compiler complains that some of the variables are undeclared (as if maybe I need to #include something).

@bperrybap, shouldn't the flush at the beginning wait till there is only one byte left to send? At that point, there should only be 1 byte, so shouldn't it work fine? If not, can you please post the changes you made to the HardwareSerial library?

@eried the code you posted is a way to wait until an entire string has been received not sent.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This may sound like a ridiculous question from a noob, because it is, but - when you read a byte from the serial receive buffer, is it removed from the buffer automatically at that time?
Logged

Dallas, TX USA
Offline Offline
Edison Member
*
Karma: 47
Posts: 2347
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@bperrybap, shouldn't the flush at the beginning wait till there is only one byte left to send? At that point, there should only be 1 byte, so shouldn't it work fine? If not, can you please post the changes you made to the HardwareSerial library?

flush() currently waits until there are no characters in the s/w queue,
but there are still up to two characters still in the USART remaining to be transmitted.
One in the transmit shift register that is currently being shifted and transmitted
out and one in the transmit data buffer register (TXB).

I don't like the way Atmel implemented their TXCn bit.
It marks a transition and isn't a state. The only automatic clearing of this
bit is by execution of a TXCI interrupt, which not normally an interrupt
that is used or needed for interrupt driven transmission.
(UDR interrupts are used to allow for the double buffering to ensure back to back transmission)
This makes TXCn status kind of a pain to use.
s/w has to clear it for the hardware to set it
but it has do it in a way that doesn't create a race condition.

A robust flush() solution has to handle all conditions when called.
- A character in the transmit shift register and no character in TXB.
- A character in TXB and in the transmit shift register
- No characters in TXB or the shift register.

What I found is that some potential solutions didn't handle all of the
above situations or couldn't handle them more than once.


--- bill
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 127
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@GCone for questions that are OT, it's best to start your own thread. However, the answer is yes (unless you just peek).
Logged

Pages: [1] 2 3   Go Up
Jump to: