How to block until WiringPi finishes to sent serial data (UART)?

702 Views Asked by At

Device description (for context, skip it if you don't feel comfortable with electronic):

For a simple device, the communication is done in half-duplex UART (TX and RX are on the same wire), in the following way:

  • One pin (write-mode) indicate if the UART is sending or receiving (1: TX, 0:RX)
  • One pin write to the wire (TX).
  • One pin read from the wire (RX).

When the write-mode is in TX (writing), the RX pin is in high-impedance and TX in transmitting. While the write-mode is in RX (reading), the TXpin is in high-impedance and RXreceiving.

This is just for context, I do not expect electronic question/answers here.

WiringPI sample:

For this to happens, I have the following sample:

#include <wiringPi.h>
#include <wiringSerial.h>

int main()
{
    wiringPiSetup ();
    auto fd = serialOpen ("/dev/ttyAMA0", 115200);
    
    pinMode(0, OUTPUT);
    
    for(size_t i=0; i<10; ++i)
    {
        digitalWrite(0, HIGH);
        serialPutchar(fd, '\x55');
        digitalWrite(0, LOW);
        delay(1000);
    }

    serialClose(fd);
}

Using an oscilloscope, I can clearly see that the write-mode pin is reset before the UART end to send the data.

Obviously, I tried to add some "delay" or empty-loop to adjust, but this is not reliable for μs times (due to usual precision in timers on OS).

The question:

How to synchronize, so the write-mode pin is reset just after the UART byte is sent? (No more than approximately 150μs later).

2

There are 2 best solutions below

6
On BEST ANSWER

I see 2 ways to implement this:

1. I can't test this right now, but it seems you could use the

 void serialFlush (int fd) ;

According to the docs "This discards all data received, or waiting to be send down the given device" see at http://wiringpi.com/reference/serial-library/

(Edit: after re-reading that sentence, it's clear that it would indeed flush also the data to be written, so this option is out...)

  1. Using tcdrain() (https://linux.die.net/man/3/tcdrain), where you pass the fd given back by serialOpen()
2
On

Set blocking on the file descriptor.

How to restore file descriptor operation to blocking mode can be found in many places. You may use code from this answer and do:

set_blocking_mode(fd, 1);
serialPutchar(fd, '\x55');

After that write() inside serialPutchar will be blocking. Note that fd is opened with O_NONBLOCK in serialOpen().