Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. QSerialPort transmit errors while sending 0xff
Forum Updated to NodeBB v4.3 + New Features

QSerialPort transmit errors while sending 0xff

Scheduled Pinned Locked Moved Unsolved Mobile and Embedded
6 Posts 2 Posters 531 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    tobias423412
    wrote on last edited by tobias423412
    #1

    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

    aha_1980A 1 Reply Last reply
    0
    • T tobias423412

      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

      aha_1980A Offline
      aha_1980A Offline
      aha_1980
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi @tobias423412

      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:

      1. Your hardware - which is that?
      2. Your code - can you show it?
      3. Are you using a software protocol like XON/XOFF?

      Regards

      Qt has to stay free or it will die.

      1 Reply Last reply
      0
      • T Offline
        T Offline
        tobias423412
        wrote on last edited by tobias423412
        #3

        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 this

        Read 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

        aha_1980A 1 Reply Last reply
        0
        • T tobias423412

          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 this

          Read 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

          aha_1980A Offline
          aha_1980A Offline
          aha_1980
          Lifetime Qt Champion
          wrote on last edited by
          #4

          @tobias423412

          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

          Qt has to stay free or it will die.

          1 Reply Last reply
          1
          • T Offline
            T Offline
            tobias423412
            wrote on last edited by
            #5

            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

            1 Reply Last reply
            0
            • T Offline
              T Offline
              tobias423412
              wrote on last edited by
              #6

              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

              1 Reply Last reply
              0

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved