0

I have a TI Cortex-based Pengwyn board running embedded Linux that I am trying to use to read raw serial data from a USB-ftdi peripheral so I can process it into data packets.

To do this I've written a simple program (using Qt) and the termios framework. This works no problem on my desktop (Ubuntu VM) machine - it opens /dev/ttyUSB0, configures the serial port, reads and process the data without problems.

I run into problems when I run the same program (cross-compiled for arm obviously) on the pengwyn board... The read() function call does not populate the buffer - although it returns a non-error value, indicating the number of bytes that have been read???

(I also had to rebuilt the linux kernel for the pengwyn board to include teh USB-ftdi serial driver.)

I suspect it is a target configuration issue but I have compared the file permissions and termios settings between both the platforms and they look okay. I am new to this platform and serial/termios stuff so I have undoubtedly over-looked something but I've looked through the "Serial Programming Guide for POSIX Operating Systems" and searched for similar posts regarding arm and usb-ftdi read problems but have yet to find anything.

Any suggestions/observations?

Relevant excerpts from test program:

void Test::startRx(void)
{   
    bool retval = false;
    m_fd = open(m_port.toLocal8Bit(),O_RDONLY |O_NOCTTY | O_NDELAY);
    if (m_fd == -1)
    {
        qDebug() << "Unable to open: " << m_port.toLocal8Bit() << strerror(errno);
    }
    else
    {
        m_isConnected = true;
        qDebug() << m_port.toLocal8Bit() << "is open...";
        fcntl(m_fd, F_SETFL, 0);

        struct termios options;
        if (tcgetattr(m_fd, &options)!=0)
        {
           qDebug() << "tcgetattr() failed";
        }

        //Set the baud rates to 9600
        cfsetispeed(&options, B9600);
        cfsetospeed(&options, B9600);

        //Enable the receiver and set local mode
        options.c_cflag |= (CLOCAL | CREAD);

        //Set character size
        options.c_cflag &= ~CSIZE; /* Mask the character size bits */
        options.c_cflag |= CS8;    /* Select 8 data bits */

        //No parity 8N1:
        options.c_cflag &= ~PARENB;
        options.c_cflag &= ~CSTOPB;
        options.c_cflag &= ~CSIZE;
        options.c_cflag |= CS8;

        //Disable hardware flow control
        options.c_cflag &= ~CRTSCTS;

        //Disable software flow control
        options.c_iflag &= ~(IXON | IXOFF | IXANY);

        //Raw output
        options.c_oflag &= ~OPOST;

        //Raw input
        options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

        //Set the new options for the port...
        tcsetattr(m_fd, TCSANOW, &options);

        int status;
        ioctl(m_fd, TIOCMGET, &status );
        qDebug() << "current modem status:" << status;


        QThread* m_reader_thread = new QThread;
        m_serial_port_reader = new SerialPortReader(0, m_fd);

        if (m_serial_port_reader)
        {            
            qDebug() << "creating serial port reader thread...";
            m_serial_port_reader->moveToThread(m_reader_thread);
            connect(m_serial_port_reader, SIGNAL(notifyRxPacketData(QByteArray *)), this, SLOT(processRxPacketData(QByteArray*)));

            //connect(m_serial_port_reader, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
            connect(m_reader_thread, SIGNAL(started()), m_serial_port_reader, SLOT(process()));
            connect(m_serial_port_reader, SIGNAL(finished()), m_reader_thread, SLOT(quit()));
            connect(m_serial_port_reader, SIGNAL(finished()), m_serial_port_reader, SLOT(quit()));
            connect(m_reader_thread, SIGNAL(finished()), m_reader_thread, SLOT(deleteLater()));
            m_reader_thread->start();
            retval = true;
        }

....

void SerialPortReader::readData(int i)
{
    m_socket_notifier->setEnabled(false);
    if (i == m_fd)
    {
        unsigned char buf[BUFSIZE] = {0};
        int bytesRead = read(m_fd, buf, BUFSIZE);
        //qDebug() << Q_FUNC_INFO << "file decriptor:" << m_fd << ", no. bytes read:" << bytesRead;

        if (bytesRead < 0)
        {
          qDebug() << Q_FUNC_INFO << "serial port read error";
          return;
        }
        // if the device "disappeared", e.g. from USB, we get a read event for 0 bytes
        else if (bytesRead == 0)
        {
           //qDebug() << Q_FUNC_INFO << "finishing!!!";
           return;
        }
        //process data...
    }
    m_socket_notifier->setEnabled(true);
}
  • You may want to verify the hardware/kernel driver with a terminal program, and also to try writing a much simpler test program. It sounds like you are saying you get no data filled at all, but you should also be aware that read() can give you fewer bytes than you requested. – Chris Stratton Oct 08 '13 at 15:58
  • The serial port is set up for non-canonical mode, but you forgot to define the **VMIN** and **VTIME** parameters. Since the program would use the default values, that could account for the difference between the two environments. Before correcting this issue, print out the values of the **VMIN** and **VTIME** after `tcgetattr()` to see if the default value are actually different between Ubuntu and your embedded systems. BTW `fcntl()`, `tcsetattr()` and `ioctl()` calls should have their return values checked. – sawdust Oct 08 '13 at 19:53
  • Thanks for the suggestions. Unfortunately VMIN (1) and VTIME (0) were the same on both. I am starting to think it is an issue with the driver or how I have configured the target system. I don't have access a terminal program on the device but I have used: `od -x < /dev/ttyUSB0` to show a hex dump of the traffic and it either shows nothing or `ttyUSB0: 2 input overrun(s)` – SiHaswell78 Oct 09 '13 at 10:06

0 Answers0