QtSerialPort blocking write in raspberry pi(raspbian pixel)
-
Hi guys, I'm asking for your help.
I'm writing an application for interaction of the raspberry pi with the device using the RS485 interface using the QtSerialPort(Qt 5.3).
I do not have the ability to organize a blocking write operation, because by the RS485 standard it is necessary to specify the direction of transmission (high pin s$My code
gpio->writeState(Gpio::IOEnable, Gpio::Set); serial.write(data); if (serial.waitForBytesWritten(500)) { qDebug() << "Success"; } else { qDebug() << "Timeout"; return; } gpio->writeState(Gpio::IOEnable, Gpio::Reset);
This code is executed successfully. When viewed with an oscilloscope, the pin becomes a unit not for the entire transmission time, as required by the interface standard. However, waitForBytesWritten returns after 5-10 milliseconds.
Any thoughts on this?
-
@Vasily-S: Hi, and welcome to the Qt Forum!
I guess your problem is buffering. The Linux Kernel is likely to keep a bunch of serial data in an internal buffer and sending it in background. Normally this is useful, but in your case it's a problem :)
I see three possibilities for a proper solution:
- Use a microcontroller without operating system, where you have full control over the registers. I do similar tasks on 16 bit microcontrollers every day.
- Search for an existing or write your own Linux Kernel driver. The driver knows when the last character has been sent and can change the pin state.
- Use feedback of sent characters to know when sending is completed. You need to connect the UART TX pin to the (same or another) UART RX pin (if you use the same UART RX, you will need to decouple the pins with a diode, of course). With that change, you can "hear what you sent". This will allow you to easily do your task in user space (i.e. Qt)
-
One more note "Mobile and Embedded" would have been a better sub-forum for this question.
-
@Vasily-S What you could also try is to flush the send buffer as far as possible.
First, insert serial.flush() after your serial.write(data); [1]
If that is not enough (I guess so), you can try flushing the Kernel buffers [2]. You will need the serial port handle for that [3]
[1] http://doc.qt.io/qt-5/qserialport.html#flush
[2] https://stackoverflow.com/questions/16398588/flush-linux-os-serial-buffer
[3] http://doc.qt.io/qt-5/qserialport.html#handle -
@aha_1980 Many thanks, everything turned out. The problem was in the kernel buffer.
It works
#include <termios.h> ... void SerialTransport485::write(const QByteArray & msg) { mGPIO.writeState(GPIO::IOEnable, GPIO::Set); mPort->write(msg); mPort->flush(); int serialHandle = mPort->handle(); tcdrain(serialHandle); mGPIO.writeState(GPIO::IOEnable, GPIO::Reset); }
-
Also you can try to use the bytesWritten(qint64 bytes) signal to know, how much bytes are written. And after this signal fired, to do reset the pin. It is preferrable unblocking way (also you can add tcdrain() here if need).