How to properly set up serial communication on Linux

28,890

I prefer Serial Programming Guide for POSIX Operating Systems.

You should delete the fcntl(mainfd, F_SETFL) statement, since it's not required and incorrectly implemented (F_GETFL not done prior and missing third argument).

Try using cfmakeraw to setup non-canonical mode, since your initialization code is incomplete:

options->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
        | INLCR | IGNCR | ICRNL | IXON);
options->c_oflag &= ~OPOST; 

For non-canonical mode, you also need to define

options.c_cc[VMIN]  = 1;
options.c_cc[VTIME] = 2;

1 and 2 are just suggested values.

Add testing of return status after all system calls.

rc = tcgetattr(mainfd, &options);
if (rc < 0) {
    printf("failed to get attr: %d, %s\n", mainfd, strerror(errno));
    exit (-3);
}

Try testing with slower baudrates (e.g. 115200 or even 9600).

Share:
28,890
sj755
Author by

sj755

Updated on May 11, 2020

Comments

  • sj755
    sj755 almost 4 years

    I'm attempting to read and write data from and to an FPGA board. The board itself came with a driver that create a terminal device called ttyUSB0 whenever the board is plugged in. On the FPGA, an asynchronous receiver and transmitter were implemented, and they seem to work.

    However, there seems to be an issue on C side of things. I've been using some test vectors to test if the FPGA is outputting the proper information. I've noticed a few things things:

    1. The device sometimes does not open correctly
    2. The terminal attributes sometimes fail to be retrieved or set.
    3. The read is sometimes non-blocking and doesn't retrieve the proper value.

    Below is how I set up terminal and file descriptor options. Much of it was taken from here: http://slackware.osuosl.org/slackware-3.3/docs/mini/Serial-Port-Programming

    Any advice or comments as to why the program may be failing would be greatly helpful.

    #include <stdio.h>   // Standard input/output definitions
    #include <string.h>  // String function definitions
    #include <unistd.h>  // UNIX standard function definitions
    #include <fcntl.h>   // File control definitions
    #include <errno.h>   // Error number definitions
    #include <termios.h> // POSIX terminal control definitions
    
    int open_port(void){
    
        int fd;    // File descriptor for the port
        fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);
    
        if (fd == -1){
            fprintf(stderr, "open_port: Unable to open /dev/ttyUSB0 %s\n",strerror(errno));
            exit(EXIT_FAILURE);
        }
    
        return (fd);
    }
    
    int main(void){
    
        int fd = 0;              // File descriptor
        struct termios options;  // Terminal options
    
        fd = open_port();    // Open tty device for RD and WR
    
        fcntl(fd, F_SETFL);            // Configure port reading
        tcgetattr(fd, &options);       // Get the current options for the port
        cfsetispeed(&options, B230400);    // Set the baud rates to 230400
        cfsetospeed(&options, B230400);
    
        options.c_cflag |= (CLOCAL | CREAD);    // Enable the receiver and set local mode
        options.c_cflag &= ~PARENB;             // No parity bit
        options.c_cflag &= ~CSTOPB;             // 1 stop bit
        options.c_cflag &= ~CSIZE;              // Mask data size
        options.c_cflag |=  CS8;                // Select 8 data bits
        options.c_cflag &= ~CRTSCTS;            // Disable hardware flow control  
    
        // Enable data to be processed as raw input
        options.c_lflag &= ~(ICANON | ECHO | ISIG);
    
        // Set the new attributes
        tcsetattr(fd, TCSANOW, &options);
    
        ////////////////////////////////////
        // Simple read and write code here//
        ////////////////////////////////////
    
        // Close file descriptor & exit
        close(fd)
        return EXIT_SUCCESS
    }  
    

    UPDATE I've modified my code based on the first answer. This is what I have now:

    #include <errno.h>      // Error number definitions
    #include <stdint.h>     // C99 fixed data types
    #include <stdio.h>      // Standard input/output definitions
    #include <stdlib.h>     // C standard library
    #include <string.h>     // String function definitions
    #include <unistd.h>     // UNIX standard function definitions
    #include <fcntl.h>      // File control definitions
    #include <termios.h>    // POSIX terminal control definitions
    
    // Open usb-serial port for reading & writing
    int open_port(void){
    
        int fd;    // File descriptor for the port
        fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);
    
        if (fd == -1){
            fprintf(stderr, "open_port: Unable to open /dev/ttyUSB0 %s\n",strerror(errno));
            exit(EXIT_FAILURE);
        }
    
        return fd;
    }
    
    int main(void){
    
        int              fd = 0;     // File descriptor
        struct termios   options;    // Terminal options
        int              rc;         // Return value
    
        fd = open_port();            // Open tty device for RD and WR
    
        // Get the current options for the port
        if((rc = tcgetattr(fd, &options)) < 0){
            fprintf(stderr, "failed to get attr: %d, %s\n", fd, strerror(errno));
            exit(EXIT_FAILURE);
        }
    
        // Set the baud rates to 230400
        cfsetispeed(&options, B230400);
    
        // Set the baud rates to 230400
        cfsetospeed(&options, B230400);
    
        cfmakeraw(&options);
        options.c_cflag |= (CLOCAL | CREAD);   // Enable the receiver and set local mode
        options.c_cflag &= ~CSTOPB;            // 1 stop bit
        options.c_cflag &= ~CRTSCTS;           // Disable hardware flow control
        options.c_cc[VMIN]  = 1;
        options.c_cc[VTIME] = 2;
    
        // Set the new attributes
        if((rc = tcsetattr(fd, TCSANOW, &options)) < 0){
            fprintf(stderr, "failed to set attr: %d, %s\n", fd, strerror(errno));
            exit(EXIT_FAILURE);
        }
    
        ////////////////////////////////
            // Simple Read/Write Code Here//
            ////////////////////////////////
    
        // Close file descriptor & exit
        close(fd);
        return EXIT_SUCCESS;
    } 
    

    Just to clarify, the receiver and transmitter use 8 data bits, 1 stop bit, and no parity bit.