eSlavko
eSlavko

Reputation: 450

serial latency on raspberry AMA0

I wish to make software PLC on raspberry pi. I did reserve one core just for PLC task and I got latency under 100 micro seconds. But the PLC need RS485 communication at 1 Megabit. It works, but the serial read take a lot of time. I use builtin serial of raspbbery to avoid additional latency of USB converters.

Transmitting to RS485 with

write (SerialId, buf, len);

take up to 85 microseconds.

but the receiving part with

int bytes = read (SerialId, RxBuf, sizeof RxBuf);

is really bad as it can take over 10 miliseconds.

I setup serial to be nonblocking and buffer big enough so every read will be timeouted. I measure how much read take and it can be anything from few micros to over 10 millis. How to achive better response time?

And this is setup routine:

 void SetupSerial(){
        char *portname = "/dev/ttyAMA0";
        int speed=B1000000;
        SerialId = open (portname, O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK);
        if (SerialId < 0){
            printf ("FastPLC: Error %d opening %s: %s\n", errno, portname, strerror (errno));
            exit(errno);
        }
        printf ("FastPLC: %s is open\n", portname);
        struct termios tty;
        if (tcgetattr (SerialId, &tty) != 0)    {
            printf ("FastPLC: Error %d from tcgetattr", errno);
            exit(errno);
        }
        cfsetospeed (&tty, speed);
        cfsetispeed (&tty, speed);
        cfmakeraw(&tty);
        tty.c_cc[VTIME] = 0;                //nonblocking
        tty.c_cc[VMIN] = 0;
        if (tcsetattr (SerialId, TCSANOW, &tty) != 0)   {
                printf ("FastPLC: Error %d from tcsetattr", errno);
                exit(errno);
        }
    }

Upvotes: 1

Views: 51

Answers (1)

eSlavko
eSlavko

Reputation: 450

Finally got working code. The issue is that I was read with timeout (and timeout is set to 0) So it should work, and it does, but introduce some delay (up to 10ms).

The proper solution seems to be to check how many bytes are in buffer with ioctl and if there are some bytes and not more than buffer ten then read it. something like this:

  int  bytes;
  ioctl(SerialId, FIONREAD, &bytes);
  if (bytes>sizeof(RxBuf)) bytes=sizeof(RxBuf);
  if (bytes) bytes = read (SerialId, RxBuf, bytes);                 //read characters from input queue

with this I have latency around 150 us.

Upvotes: 1

Related Questions