Serial communication timing/buffering issues

Can anyone explain why this:

(arduino pde:)

int count = 0;

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  Serial.print("fish ");
  Serial.println(count++);
  if (count > 20000)
    count = 0;
}

(C on PC:)

#include <stdio.h>
#include <string.h>

char buffer[200];

main(void)
{
      FILE *tty = fopen("/dev/ttyUSB2", "r");
      memset(buffer, 0, 200);
      while(1)
      {
            fgets(buffer, 200, tty);
            printf("%s", buffer);
            usleep(10000);
      }
      fclose(tty);
}

(output of program:)

fish 1
fish 2
fish 3
...
fish 1000ish
[mixed letters and numbers]
fish 4000ish

happens?

Thanks :).

maybe a buffer problem with the FTDI chip? Try it on Windows. Some people experienced problems with the drivers for Linux and Mac when burst serial communication is performed.

And why do you do this:

usleep(10000);

The sleep is to see what would happen if sampled at intervals rather than continuously to get a better idea of how the serial operations work.

Try changing "count > 20000" to "count > 200". Sounds like a buffer overrun issue in the driver.

With 'count > 200' it's OK for the first few iterations, then:

fish 182
fish 183
fish 184
fish 185
fish 186
fish 187
fish 188
sh 8
fish 9
fish 10
fish 11
fish 12
fish 13
fish 14

What happens if you make your buffer slightly larger than required?

Does it do the same at slower baud rates?

It seems to break above 9600 baud. Is it of any relevance that above that, the tx light is not on steady (it's on and off, the ratio depending on the baud)?

I've also tried setting the buffer in my program to 10, and that didn't seem to help.

I'm wondering if the usleep is the problem. Does it fail without it?

Try replacing usleep with nanosleep.

Still breaks with nanosleep :(. With C code:

#include <stdio.h>
#include <string.h>
#include <time.h>

char buffer[10];

main(void)
{
      FILE *tty = fopen("/dev/ttyUSB2", "r");
      struct timespec sleep_time;

      memset(buffer, 0, 10);
      sleep_time.tv_sec = 0;
      sleep_time.tv_nsec = 10000000;

      while(1)
      {
            fgets(buffer, 10, tty);
            printf("%s", buffer);
            nanosleep(&sleep_time, NULL);
      }
      fclose(tty);
}

I'm still getting funny output:

fish 37
fish 38
fish 39
fisish 54
fish 55
fish 56
fish 57
fish 58
fish 59
fish 60
fish 61
fish 62
fish 63
fish 64
fish 65
fish 66
fish 67
fish 68sh 135
fish 136
fish 137

I'm also curious about how exactly serial communication with the tty works. Is it sending to a buffer PC-side, which signals the MCU when it's full, which blocks until there's space again?

There is no "flow control" in the Serial library so the MCU doesn't block when the PC is busy. Characters are just lost.

But this is unlikely. At 19200 bps it takes 0.5ms to transmit 1 character, so in the 10ms you're waiting on the PC side only 20 characters could have come by.

What if the screen display is the problem -- wouldn't be the first time. Try using fprintf to write to a file rather than printf to write to the screen.

Still breaks with output to file with fprintf :-/

After I've waited 10 ms, are the characters it fetches those that are coming in at that moment? When the tx light goes off on the board during the program, what exactly is happening, if it isn't blocking?

I got curious enough to duplicate your problem on my system and, sure enough, it is a problem for me too.

Looks like XON/XOFF flow control does solve the problem. The following modification to your code has no more hiccups. I'm pretty surprised that the PC-side driver can't keep up with this data rate.

int count = 0;
int flowCount = 0;

void setup()
{
  Serial.begin(19200);
}

void loop()
{
  int c;

  if ((c=Serial.read()) == 0x13 /*XOFF*/) {
    flowCount++;
  } else if (c == 0x11 /*XON*/) {
    if (flowCount) flowCount--;
  }

  if (flowCount==0) {
    Serial.print("fish ");
    Serial.println(count++);
    if (count > 20000)
      count = 0;
  }
}

Duh...the problem is much simpler than that. Your 10ms sleep is artificially limiting the rate that you can receive data.

At 19200 bps, the Arduino can send 1920 characters per second. By printing "fish XXX\r\n" every 10ms you are "receiving" (and printing) 10 characters in 10ms, or 1000 characters per second. Thus you're not allowing yourself to output data at the rate that it's coming in. This is why it works at 9600 bps, that's only 960 characters per second coming in.

Hmm...that being the case, why aren't the numbers weird from the very beginning of the output? The way it works in my head at the moment is that Arduino sends some characters -> PC receives them, waits 10 ms, during which time Arduino sends more which are lost during the 10ms sleep, but this doesn't seem to correspond to what actually happens...

Also, a character being 1 byte long, why 960 characters at 9600bps, rather than 9600/8=1200? Am I correct in regarding baud as equivalent to bits/second?

Thanks for your help. :slight_smile:

They aren't weird from the beginning because the PC does have a buffer. Say you have a 4K buffer, you receive data at 2000 characters per second, but only print out at 1000 characters per second. That means after 1 second, you've received 2000 characters, printed out 1000, then stored the remaining 1000 in the buffer. After 2 seconds, there are 2000 in the buffer, etc. After 4 seconds, the buffer is full and you start losing data.

A character is 1 byte but the RS232 serial protocol also requires a start bit and a stop bit, so there are 10 bits transmitted for every 8 bits of "useful" data. The baud rate is truly bits per second, including the "overhead" start/stop bits, not "useful" bits per second.

Ah, that makes sense. Thanks for your explanation. :smiley: