c - How to properly set up serial communication on Linux -
i'm attempting read , write data , fpga board. board came driver create terminal device called ttyusb0 whenever board plugged in. on fpga, asynchronous receiver , transmitter implemented, , seem work.
however, there seems issue on c side of things. i've been using test vectors test if fpga outputting proper information. i've noticed few things things:
- the device not open correctly
- the terminal attributes fail retrieved or set.
- the read non-blocking , doesn't retrieve proper value.
below how set terminal , file descriptor options. of taken here: http://slackware.osuosl.org/slackware-3.3/docs/mini/serial-port-programming
any advice or comments why program may failing 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 port fd = open("/dev/ttyusb0", o_rdwr | o_noctty); if (fd == -1){ fprintf(stderr, "open_port: unable 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 rd , wr fcntl(fd, f_setfl); // configure port reading tcgetattr(fd, &options); // current options port cfsetispeed(&options, b230400); // set baud rates 230400 cfsetospeed(&options, b230400); options.c_cflag |= (clocal | cread); // enable receiver , 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 processed raw input options.c_lflag &= ~(icanon | echo | isig); // set new attributes tcsetattr(fd, tcsanow, &options); //////////////////////////////////// // simple read , write code here// //////////////////////////////////// // close file descriptor & exit close(fd) return exit_success }
update i've modified code based on first answer. 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 reading & writing int open_port(void){ int fd; // file descriptor port fd = open("/dev/ttyusb0", o_rdwr | o_noctty); if (fd == -1){ fprintf(stderr, "open_port: unable 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 rd , wr // current options port if((rc = tcgetattr(fd, &options)) < 0){ fprintf(stderr, "failed attr: %d, %s\n", fd, strerror(errno)); exit(exit_failure); } // set baud rates 230400 cfsetispeed(&options, b230400); // set baud rates 230400 cfsetospeed(&options, b230400); cfmakeraw(&options); options.c_cflag |= (clocal | cread); // enable receiver , 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 new attributes if((rc = tcsetattr(fd, tcsanow, &options)) < 0){ fprintf(stderr, "failed 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 clarify, receiver , transmitter use 8 data bits, 1 stop bit, , no parity bit.
i prefer serial programming guide posix operating systems.
you should delete fcntl(mainfd, f_setfl)
statement, since it's not required , incorrectly implemented (f_getfl not done prior , missing third argument).
try using cfmakeraw setup non-canonical mode, since initialization code incomplete:
options->c_iflag &= ~(ignbrk | brkint | parmrk | istrip | inlcr | igncr | icrnl | ixon); options->c_oflag &= ~opost;
for non-canonical mode, need define
options.c_cc[vmin] = 1; options.c_cc[vtime] = 2;
1 , 2 suggested values.
add testing of return status after all system calls.
rc = tcgetattr(mainfd, &options); if (rc < 0) { printf("failed attr: %d, %s\n", mainfd, strerror(errno)); exit (-3); }
try testing slower baudrates (e.g. 115200 or 9600).
Comments
Post a Comment