Dingodoodl
Dingodoodl

Reputation: 19

Hardware flow control with termios (CRTSCTS) for UART Device

Right now I'm communicating with a device over UART in C++ on a Udoo Neo. For this I'm using termios to set up the connection and write data to the device. For this purpose I want to use hardware flow control and have set the flag (CRTSCTS) with termios.

For the hardware flow control I've connected the device RTS line to the board's CTS and I've also checked via oscilloscope, that the device is giving me an active high, if it is not ready to read.

The problem is that I still lose bytes in the following example of just spamming the device with numbers, but the boards output says that everything was written correctly.

I thought the UART would be blocked when using HW flow control, so that no information is lost. Am I not understanding this correctly - or is there an error in the code?

Thanks for the help.

    const char dev[] = "/dev/ttymxc4";

    int main(int argc, char **argv) {

    int fd;
    struct termios t; ///< control structure for a general asynchronous interface
    // edited code
    tcgetattr(fd, &t);

    t.c_iflag &= ~(IGNBRK | BRKINT | ICRNL |
                     INLCR | PARMRK | INPCK | ISTRIP | IXON);
    t.c_oflag = 0;
    t.c_cflag &= ~(CSIZE | PARENB);
    t.c_cflag |= (CS8 | CRTSCTS);

    // edited code 
    t.c_cflag |= (CLOCAL | CREAD);
    
    t.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);

    t.c_cc[VMIN]  = 0;
    t.c_cc[VTIME] = 0;

    cfsetispeed(&t,B57600); /* normal shall be: B115200 Baud */

    fd = ::open(dev, O_RDWR);
    if (fd==-1) {
        printf("UART: cannot open file: %s\n",dev);
        return -1;
    }

    tcsetattr(fd,TCSANOW, &t);
    
    // edited code
    fcntl(fd, F_SETFL, 0);

    int count = 0;
    while (true) {

        count++;
        std::stringstream output;
        output << count << ",";

        ::write(fd, output.str().c_str(), output.str().length());
        printf("%d, writing: %s\n", fd, output.str().c_str());
        usleep(10000);
    }
    return 0;
}

Upvotes: 0

Views: 12580

Answers (1)

lnksz
lnksz

Reputation: 501

Referring to the links by @sawdust, the HW flow control is manipulated via

CCTS_OFLOW and CRTS_IFLOW via libc-doc

Macro: tcflag_t CCTS_OFLOW
If this bit is set, enable flow control of output based on the CTS wire (RS232 protocol).
Macro: tcflag_t CRTS_IFLOW
If this bit is set, enable flow control of input based on the RTS wire (RS232 protocol).

CNEW_RTSCTS and CRTSCTS via SerProgGuide

Some versions of UNIX support hardware flow control using the CTS (Clear To Send) and RTS (Request To Send) signal lines. If the CNEW_RTSCTS or CRTSCTS constants are defined on your system then hardware flow control is probably supported. Do the following to enable hardware flow control:

options.c_cflag |= CNEW_RTSCTS;    /* Also called CRTSCTS */

Note the "Some versions..." and "...is probably supported."

On my particular cross compilation toolchain (Linaro GCC 6.5-2018.12) if I grep for these values, CRTSCTS is not documented, but defined, CCTS_OFLOW is in a lot of info files, but in no header files...

libc/usr/include/bits/termios.h:
174:# define CRTSCTS  020000000000              /* flow control */

As you have said in your comment

... I just thought this would be handled by the kernel?

I am seeing the phenomenon, that even if I add the relevant rts/cts properties in the device-tree ({rts,cts}-gpios or uart-has-rtscts), the command stty -a -F /dev/ttyS still reports back -crtscts meaning that the RTS/CTS handshake is disabled, so even without the userspace application this doesn't seem to be a trivial config. (Kernel 5.4)

Upvotes: 1

Related Questions