QSerialPort transmit errors while sending 0xff
-
Hello,
i try to implement a communication between an embedded device and my computer. During development, i observed that i get a lot errors during the communication, when the byte array contains magic bytes like 0xff.
It got more strange when i tried to send only characters like 0xff. On my serial adapter i can see, that the TX LED stars stuttering. If i send other bytes like 0x55 or something like that, the LED is smoothly flashing and i have no errors during transmit.
It is really easy to reproduce and to prove that my target has no influence. I disconnected my target and i can still see that the LED stutters during 0xff and not during other characters on my serial adapter.
To make it more confusing: The majority of bytes is transmitted correctly. Just a small percentage of 0xff's is not transmitted correctly.
I am using Mac OS Mojave and tried it with Qt 5.6 and 5.12. Both show exactly the same behavior.Has someone an idea from where this is coming and how i can fix this?
Greetings
Tobias -
I'm using QtSerialPort to transmit binary data to one of my self-built embedded devices using FTDI serial adapters - without problems.
So there are three possible things that could be wrong on your side:
- Your hardware - which is that?
- Your code - can you show it?
- Are you using a software protocol like XON/XOFF?
Regards
-
Hi,
this is not the most clean code, but it does the job:
#include "serialportwriter.h" #include <QCoreApplication> #include <QDebug> #include <QThread> QT_USE_NAMESPACE #define TEST_BYTE ((uint8_t)0xff) #define END_ADDR 0xf SerialPortWriter::SerialPortWriter(QSerialPort *serialPort, QObject *parent) : QObject(parent) , m_serialPort(serialPort) , m_standardOutput(stdout) , m_bytesWritten(0) , m_testByte(TEST_BYTE) { m_timer.setSingleShot(false); connect(m_serialPort, &QSerialPort::bytesWritten, this, &SerialPortWriter::handleBytesWritten); connect(m_serialPort, static_cast<void (QSerialPort::*)(QSerialPort::SerialPortError)>(&QSerialPort::error), this, &SerialPortWriter::handleError); connect(&m_timer, &QTimer::timeout, this, &SerialPortWriter::handleTimeout); connect(m_serialPort, &QSerialPort::readyRead, this, &SerialPortWriter::readReady); m_timer.start(35); } SerialPortWriter::~SerialPortWriter() { } void SerialPortWriter::handleBytesWritten(qint64 bytes) { } void SerialPortWriter::handleTimeout() { static bool read = false; static uint32_t readCycle = 0; static uint32_t writeCycle = 0; static uint16_t addr = 0; if (read) { QByteArray readData; readData.push_back((char)0x1); // Read Command readData.push_back((char)(addr >> 8)); // 23:16 readData.push_back((char)(addr & 0xff)); // 15:8 readData.push_back((char)0x0); // 7:0 readData.push_back((char)0x40); // Size in DWord if (addr < END_ADDR) { write(readData); addr++; } else { addr = 0; read = false; qDebug() << "Read cylce" << readCycle++; } } else { QByteArray writeData; writeData.push_back((char)0x2); // Write Command writeData.push_back((char)(addr >> 8)); // 23:16 writeData.push_back((char)(addr & 0xff)); // 15:8 writeData.push_back((char)0x0); // 7:0 writeData.push_back((char)0x40); // Size in DWord // Payload for (int i = 0; i < 0x40; i++) { writeData.push_back((char)m_testByte); writeData.push_back((char)m_testByte); writeData.push_back((char)m_testByte); writeData.push_back((char)m_testByte); } if (addr < END_ADDR) { write(writeData); addr++; } else { qDebug() << "Write cylce" << writeCycle++; addr = 0; read = true; } } } void SerialPortWriter::handleError(QSerialPort::SerialPortError serialPortError) { if (serialPortError == QSerialPort::WriteError) { m_standardOutput << QObject::tr("An I/O error occurred while writing the data to port %1, error: %2").arg(m_serialPort->portName()).arg(m_serialPort->errorString()) << endl; QCoreApplication::exit(1); } } void SerialPortWriter::readReady() { QByteArray r = m_serialPort->readAll(); for (int i = 0; i < r.size(); i++) { if ((uint8_t)(r.at(i)) != m_testByte) { qDebug() << "Read Error actual:" << QString::number((uint8_t)(r.at(i))).toInt() << "should:" << QString::number(m_testByte).toInt(); } } } void SerialPortWriter::write(const QByteArray &writeData) { m_writeData = writeData; qint64 bytesWritten = m_serialPort->write(writeData); if (bytesWritten == -1) { m_standardOutput << QObject::tr("Failed to write the data to port %1, error: %2").arg(m_serialPort->portName()).arg(m_serialPort->errorString()) << endl; QCoreApplication::exit(1); } else if (bytesWritten != m_writeData.size()) { m_standardOutput << QObject::tr("Failed to write all the data to port %1, error: %2").arg(m_serialPort->portName()).arg(m_serialPort->errorString()) << endl; QCoreApplication::exit(1); } //m_serialPort->flush(); }
What i am doing here? I write 0xff in some memory and when i am done with this, i try to read it back. And that is what i am doing forever.
If i am using for TEST_BYTE 0xAA or something like that, everything works fine. If it is 0xff than something goes wrong. If i read the memory back, i get errors on random places.
The error outputs like thisRead Error actual: 251 should: 255 Read Error actual: 254 should: 255 Read Error actual: 251 should: 255 Read Error actual: 254 should: 255 Read Error actual: 251 should: 255
As a serial converter i am using an ordinary FT232.
Greetings
Tobias -
Your code still looks a bit complicated and is missing important pieces, like the serial port set up. Which baud rate are you using? Am I right that you repeat that cycle every 35 ms?
On my serial adapter i can see, that the TX LED stars stuttering.
Ok, then I'd start with a simple program that only transmits a fixed frame, containing 0xff. Does that work? If yes, then do it from a timer with a timeout large enough that the previous frame is completely transmitted (to avoid buffer overflows).
I really can't see why transmitting arbitrary data should lead to problems like you described.
Regards
-
Hi,
yes, the init
#include "serialportwriter.h" #include <QtSerialPort/QSerialPort> #include <QCoreApplication> #include <QString> #include <QDebug> QT_USE_NAMESPACE int main(int argc, char *argv[]) { QCoreApplication coreApplication(argc, argv); int argumentCount = QCoreApplication::arguments().size(); QStringList argumentList = QCoreApplication::arguments(); QTextStream standardOutput(stdout); if (argumentCount != 3) { standardOutput << "Version 1.0.0 (Compile date: " << __DATE__ << " " << __TIME__ << ")" << endl; standardOutput << QObject::tr("Usage: %1 <serialportname> <baudrate>").arg(argumentList.first()) << endl; return 1; } QSerialPort serialPort; QString serialPortName = argumentList.at(1); serialPort.setPortName(serialPortName); int serialPortBaudRate = argumentList.at(2).toInt(); serialPort.setBaudRate(serialPortBaudRate); serialPort.open(QIODevice::ReadWrite); serialPort.setParity(QSerialPort::NoParity); serialPort.setStopBits(QSerialPort::OneStop); serialPort.setFlowControl(QSerialPort::NoFlowControl); serialPort.setDataBits(QSerialPort::Data8); SerialPortWriter serialPortWriter(&serialPort); return coreApplication.exec(); }
I am using 115200 baud.
I use that timer to periodically send one frame of data. After every 15 timer shots i switch from sending payload to reading payload. Theoretically i can send around 500 bytes within this 35ms and currently sending around 261.
I tried also now to just send a byte array containing only 0xff. I also increased the time of the timer. The TX LED on the FT232 is still stuttering.
Greetings
Tobias -
I guess i found a solution which i don't like.
I observed also two crashes of my USB stack on my Mac which are (obviously) related to this stuff. Sometimes when i start this program all my USB ports are dying and the kernel tasks runs with 100% load. I can only resurrect the USB ports by a reboot of my computer. If i connect the serial adapter on a nativ USB port, it works as intended without any errors.
The USB Hub should have enough power. It is a Hub which is powered from an external power plug.
For sure, i would be really thankful if anyone know a better workaround to this bug instead of utilizing one of the very rare native USB ports on a Mac, but in this case, i guess, it is an Apple problem and not an Qt related one.
Thank you very much for your help
Greetings
Tobias