0

I need to write a sequence of values (buffer, ~10bytes) via UART.

This sequence needs to start with a BREAK delimiter, and in my case I need to decrease the baud rate to a lower value.

Details about my environment:

  • Development board: BeagleBone Black.
  • Linux Kernel version: 3.8.13-bone70.
  • Serial driver used by the tty discipline: omap-serial.

What I finally get is something like this:

UARTIOHandler->setBaudRate(B9600);

unsigned char breakChar[] = { 0 };

UARTIOHandler->write(breakChar, 1);

UARTIOHandler->setBaudRate(B19200);

UARTIOHandler->write({1, 2, 3, 4, 5, 6, 7, 8, 9, 10});

The write method is implemented this way:

int UARTIOHandler::write(const std::initializer_list<uchar8> &data) {
    uchar8 buffer[data.size()];

    int counter = 0;
    for(auto i : data) {
        buffer[counter++] = i;
    }

    auto output = ::write(this->fd_write, buffer, data.size());

    this->flush();

    return output;
}

And finally the flush() method:

void UARTIOHandler::flush() {
    tcflush(this->fd_write, TCIOFLUSH);
}

The problem with this code is that the flushing doesn't always work, sometimes the distance between the BREAK and the first byte of data (observed on a scope) is ~500us (which is fine for my application), and sometimes is up to ~3ms.

EDIT: This is the actual behavior: For the first five seconds everything works fine (the distance between the BREAK and the rest of the message doesn't exceed ~1ms), then, after five seconds there are some frames that exceed this inter-byte timing (for up to ~3ms). There's always the code that I posted which is executed, so there's no possible way that I somehow forget flushing the buffers.

Why do this variations happen?

I have searched for relevant problems and found this, one workaround described there is to use a delay in front of the tcflush(...) function call. I can't use this method in my application because it will affect the functionality.

Another comment in that topic suggests that this was a bug in the Linux kernel, could this also be in my case?

Community
  • 1
  • 1
mariusmmg2
  • 713
  • 18
  • 37
  • "Flushing" doesn't work as expected because apparently you don't know its purpose. Did you read the man page? What you are you trying to accomplish by calling **tcflush()** after a **write()**? **tcflush()** discards data!!! Shouldn't you be using **tcdrain()** instead? BTW transmitting a null character at a slow baudrate is not the same as a real break condition. What unit of time is a `qs`? – sawdust Jul 14 '16 at 01:05
  • You're right, I wasn't doing what I thought I was. I did now replace **tcflush()** with **tcdrain()** and the problem seems almost solved, I say almost because there're still some packets where the inter-byte is higher than ~2.5ms (they appear in let's say 10% of cases). Regarding the `BREAK` sequence, this is the only way I know for doing this (there's also the **tcsendbreak()** function, but it outputs a very long `BREAK` sequence). It's actually `us` (microseconds), my mistake. – mariusmmg2 Jul 14 '16 at 05:46
  • 1
    Using `write(); tcdrain(); write();` in C, I measure a 0.8 ms dead time between messages. For generating a BREAK condition, there's also the Linux **ioctl()** commands TIOCSBRK and TIOCCBRK, but they're not POSIX and therefore not portable. The shortest possible BREAK (that I have generated) using **ioctl()** s with no delay in between is 3.0 ms duration. An immediate **write()** appears 1.2 ms later. – sawdust Jul 14 '16 at 23:16
  • Do you know any faster method? As I understood, `tcdrain() ` only flushes the application level buffers, and there are also the kernel level ones which are not flushed. – mariusmmg2 Jul 15 '16 at 13:55
  • *"tcdrain() only flushes ..."* -- No it doesn't. You persist in misusing the terminology. What are you calling *"application level"* buffers? Read the man page for tcdrain(); there's only mention of "all output", not specific buffers. This is asynchronous communication. Idle time should be tolerated and not be meaningful (except for dangerous protocols like Modbus). So "faster" methods are not available using standard APIs. – sawdust Jul 15 '16 at 19:40

0 Answers0