This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM335x UART hardware flow control (linux-3.2.0-psp04.06.00.11)

Other Parts Discussed in Thread: AM3352

Hi,all,

   When I test uart1 auto hardware flow control function on beaglebone black board with ti-sdk-am335x-evm-06.00.00.00-Linux-x86-Install(linux-3.2.0-psp04.06.00.11)SDK package.

   It failed. I notice that "Features Not Supported Hardware Flow Control" in AM335x-PSP 04.06.00.11 Features and Performance Guide.

   I have two ideas:

1) In ti-sdk-am180x-evm-05.05.01.00-Linux-x86-Install(linux-2.6.37-psp03.21.00.04) SDK package, uart use 8250 serial driver and auto hardware flow control works well. So, how to use 8250 driver on AM335x. Could somebody give detailed guidance?

2) I have set auto hardware flow control in uart registers successfully. While RTS doesn't work. I think linux serial driver don't stop reading data from FIFO. How to use auto hardware flow control?

BTW, I have seen hardware flow control post on e2e website, http://e2e.ti.com/support/embedded/linux/f/354/p/162075/617414.aspx#617414. But not enough details to solve the problem. 

Best Regards,

Dragon

  • Hi,

    The AM335X Linux UART driver does not support hardware flow control.

  • Hi, Biser

         Thank you for your reply. 

         If I want to use auto hardware flow control on AM335x with Linux 3.2 kernel, Could TI give solutions or How can I get support in other ways.

    Best Regards,

    Dragon

  • Hi Dragon,

    Actually HW Flow control does work on the AM335x Sitara Linux SDK.  I'm currently checking into the why the wiki page you referenced says that it does not work.  The AM335x GP EVM bluetooth uses Uart HW flow control over UART1.  When bluetooth was integrated in Sitara Linux SDK 6.0 (linux 3.2 kernel), it was found that there was a bug in the board file setting up the pinmux for RTS and CTS.  After the modification below, HW flow control worked as expected. Below is the modification:

    Incorrect:

    From the board-file arch/arm/mach-omap2/board-am335xevm.c:

    static struct pinmux_config uart1_wl12xx_pin_mux[] = {

            {"uart1_ctsn.uart1_ctsn", OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

            {"uart1_rtsn.uart1_rtsn", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT},

            {"uart1_rxd.uart1_rxd", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},

            {"uart1_txd.uart1_txd", OMAP_MUX_MODE0 | AM33XX_PULL_ENBL},

            {NULL, 0},

     

    Correct:

    static struct pinmux_config uart1_wl12xx_pin_mux[] = {

            {"uart1_ctsn.uart1_ctsn", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT},

            {"uart1_rtsn.uart1_rtsn", OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

            {"uart1_rxd.uart1_rxd", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},

            {"uart1_txd.uart1_txd", OMAP_MUX_MODE0 | AM33XX_PULL_ENBL},

            {NULL, 0},

  • I found this article when I was trying to have the AM3352 drive a rs485 transceiver.  I tried it out and found that the patch gave VERY good RTS performance.

    https://support.criticallink.com/redmine/projects/armc8-platforms/wiki/Driving_RS-485_transceivers

    Chuck

  • Hi Jeff,

        I really appreciate your reply.

        1). I have tested uart0 hardware flow control on AM335x GP EVM board with modification of uart0 CTS  RTS pinmux. And I wrote a driver module to confirm the modification. Finally, the hardware flow control does not work in my test.

        2). Could you give a demo or guidance about how to test uart1 hardware flow control on AM335x GP EVM board.

    Best Regards,

    Dragon

  • Dragon,

    I also tested Uart0. Uart 1 is setup to be used by Bluetooth, so you would need to remove and add some zero ohm resistors to route Uart1 out to the daughter board on AM335x GP EVM.

    To test Uart0, I connected my Linux PC's serial port to the AM335x GP EVM Uart0 serial  port using a null-modem serial cable.  Since Linux uses Uart0 as the console, I had to disable this in Linux.

    In the filesystem for AM335x look at the file: /etc/inittab and edit the following line:

    S:2345:respawn:/sbin/getty 115200 ttyO0

    Comment it out

    # S:2345:respawn:/sbin/getty 115200 ttyO0

    Since Uart0 was used for command line interaction, I instead used an ssh console terminal over ethernet for command line interaction.

    Test summary:

    On Linux PC: run C code which toggles RTS every 1 second (on,off,on,off….) -- C code attached. (serial_test.c) Compiled natively on the LInux PC using gcc.

    On AM335x send continuous data out UART0. – C code attached. (uart_test.c) cross compiled using arm-linux-gnueabihf-gcc

    Notice both programs enable -CRTSCTS using tcgetattr and tcsetattr.

    I used an Oscope to monitor CTS and TX from the AM335x perspective showing HW Flow control is working as expected. (CTS-BLUE, TX-YELLOW))

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <termios.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    static struct termios oldterminfo;
    
    void closeserial(int fd)
    {
        if (close(fd) < 0)
        {
            perror("closeserial()");
            printf("closeserial(): close()\n");
        }
    }
    
    int openserial(char *devicename)
    {
        int fd;
        struct termios attr;
    
        if ((fd = open(devicename, O_RDWR)) == -1) {
            perror("openserial(): open()");
            return 0;
        }
    
        if (tcgetattr(fd, &oldterminfo) == -1) {
            perror("openserial(): tcgetattr()");
            return 0;
        }
        attr = oldterminfo;
        attr.c_cflag |= CRTSCTS | CLOCAL;
        attr.c_cflag |= CLOCAL;
        attr.c_oflag = 0;
        if (tcflush(fd, TCIOFLUSH) == -1) {
            perror("openserial(): tcflush()");
            return 0;
        }
        if (tcsetattr(fd, TCSANOW, &attr) == -1) {
            perror("initserial(): tcsetattr()");
            return 0;
        }
    
        return fd;
    }
    
    int setRTS(int fd, int level)
    {
        int status;
    
        if (ioctl(fd, TIOCMGET, &status) == -1) {
            perror("setRTS(): TIOCMGET");
            return 0;
        }
        if (level)
            status |= TIOCM_RTS;
        else
            status &= ~TIOCM_RTS;
        if (ioctl(fd, TIOCMSET, &status) == -1) {
            perror("setRTS(): TIOCMSET");
            return 0;
        }
        return 1;
    }
    
    int setDTR(int fd, int level)
    {
        int status;
    
        if (ioctl(fd, TIOCMGET, &status) == -1) {
            perror("setDTR(): TIOCMGET");
            return 0;
        }
        if (level)
            status |= TIOCM_DTR;
        else
            status &= ~TIOCM_DTR;
        if (ioctl(fd, TIOCMSET, &status) == -1) {
            perror("setDTR(): TIOCMSET");
            return 0;
        }
        return 1;
    }
    
    int print_status(int fd, char * device)
    {
        int status;
    
        if (ioctl(fd, TIOCMGET, &status) == -1) {
            perror("setDTR(): TIOCMGET");
            return 0;
        }
    //    printf("status in print = 0x%x\n", status);
    
        printf("Device: %s\n\n", device);
        printf("Signal  Pin  Pin  Direction  Status  Full\n");
        printf("Name    (25) (9)  (AM180x)           Name\n");
        printf("-----   ---  ---  ---------  ------  -----\n");
        printf("FG       1    -      -           -   Frame Ground\n");
        printf("TxD      2    3      out         -   Transmit Data\n");
        printf("RxD      3    2      in          -   Receive  Data\n");
        printf("RTS      4    7      out         %1d   Request To Send\n", !!(status & TIOCM_RTS));
        printf("CTS      5    8      in          %1d   Clear To Send\n", !!(status & TIOCM_CTS));
        printf("DSR      6    6      in          %1d   Data Set Ready\n", !!(status & TIOCM_DSR));
        printf("GND      7    5      -           -   Signal Ground\n");
        printf("DCD      8    1      in          %1d   Data Carrier Detect\n", !!(status & TIOCM_CAR));
        printf("DTR     20    4      out         %1d   Data Terminal Ready\n", !!(status & TIOCM_DTR));
        printf("RI      22    9      in          %1d   Ring Indicator\n", !!(status & TIOCM_RNG));
      return 0;
    }
    
    int main(int argc, char **argv)
    {
      int fd;
      char *c;
      int i;
      int num_iterations = 10;
    
      printf("Starting main()\n");
      if(argc == 2) {
        num_iterations = atoi(argv[1]);
        printf("Num Iterations = %d\n", num_iterations);
      }
      if(argc > 2) {
        printf("Usage: serial_test <num Iterations>\n");
        return(-1);
      }
      printf("opening serial\n");
      fd = openserial("/dev/ttyS0");
      printf("serial opened\n");
      if (!fd) {
        fprintf(stderr, "Error while initializing %s.\n", argv[1]);
        return 1;
      }
    
        for(i=0;i<num_iterations;i++)
        {
    //       setDTR(fd, (i & 0x1));
           setRTS(fd, (i & 0x1));
           sleep(1);       // pause 1 second
           print_status(fd, argv[1]);
        }
    
      closeserial(fd);
      return 0;
    }
    

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <termios.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    static struct termios oldterminfo;
    
    void closeserial(int fd)
    {
        if (close(fd) < 0)
        {
            perror("closeserial()");
            printf("closeserial(): close()\n");
        }
    }
    
    int openserial(char *devicename)
    {
        int fd;
        struct termios attr;
    
        if ((fd = open(devicename, O_RDWR)) == -1) {
            perror("openserial(): open()");
            return 0;
        }
    
        if (tcgetattr(fd, &oldterminfo) == -1) {
            perror("openserial(): tcgetattr()");
            return 0;
        }
        attr = oldterminfo;
        attr.c_cflag |= CRTSCTS | CLOCAL;
        attr.c_cflag |= CLOCAL;
        attr.c_oflag = 0;
        if (tcflush(fd, TCIOFLUSH) == -1) {
            perror("openserial(): tcflush()");
            return 0;
        }
        if (tcsetattr(fd, TCSANOW, &attr) == -1) {
            perror("initserial(): tcsetattr()");
            return 0;
        }
    
        return fd;
    }
    
    int setRTS(int fd, int level)
    {
        int status;
    
        if (ioctl(fd, TIOCMGET, &status) == -1) {
            perror("setRTS(): TIOCMGET");
            return 0;
        }
        if (level)
            status |= TIOCM_RTS;
        else
            status &= ~TIOCM_RTS;
        if (ioctl(fd, TIOCMSET, &status) == -1) {
            perror("setRTS(): TIOCMSET");
            return 0;
        }
        return 1;
    }
    
    int setDTR(int fd, int level)
    {
        int status;
    
        if (ioctl(fd, TIOCMGET, &status) == -1) {
            perror("setDTR(): TIOCMGET");
            return 0;
        }
        if (level)
            status |= TIOCM_DTR;
        else
            status &= ~TIOCM_DTR;
        if (ioctl(fd, TIOCMSET, &status) == -1) {
            perror("setDTR(): TIOCMSET");
            return 0;
        }
        return 1;
    }
    
    int print_status(int fd, char * device)
    {
        int status;
    
        if (ioctl(fd, TIOCMGET, &status) == -1) {
            perror("setDTR(): TIOCMGET");
            return 0;
        }
    //    printf("status in print = 0x%x\n", status);
    
        printf("Device: %s\n\n", device);
        printf("Signal  Pin  Pin  Direction  Status  Full\n");
        printf("Name    (25) (9)  (AM180x)           Name\n");
        printf("-----   ---  ---  ---------  ------  -----\n");
        printf("FG       1    -      -           -   Frame Ground\n");
        printf("TxD      2    3      out         -   Transmit Data\n");
        printf("RxD      3    2      in          -   Receive  Data\n");
        printf("RTS      4    7      out         %1d   Request To Send\n", !!(status & TIOCM_RTS));
        printf("CTS      5    8      in          %1d   Clear To Send\n", !!(status & TIOCM_CTS));
        printf("DSR      6    6      in          %1d   Data Set Ready\n", !!(status & TIOCM_DSR));
        printf("GND      7    5      -           -   Signal Ground\n");
        printf("DCD      8    1      in          %1d   Data Carrier Detect\n", !!(status & TIOCM_CAR));
        printf("DTR     20    4      out         %1d   Data Terminal Ready\n", !!(status & TIOCM_DTR));
        printf("RI      22    9      in          %1d   Ring Indicator\n", !!(status & TIOCM_RNG));
      return 0;
    }
    
    int main(int argc, char **argv)
    {
      int fd;
      char *c;
      int i;
      int num_iterations = 10;
    
      printf("Starting main()\n");
      if(argc == 2) {
        num_iterations = atoi(argv[1]);
        printf("Num Iterations = %d\n", num_iterations);
      }
      if(argc > 2) {
        printf("Usage: serial_test <num Iterations>\n");
        return(-1);
      }
      printf("opening serial\n");
      fd = openserial("/dev/ttyO0");
      printf("serial opened\n");
      if (!fd) {
        fprintf(stderr, "Error while initializing %s.\n", argv[1]);
        return 1;
      }
    
      c =  "zz";
      //continually write out chars
      while(1)
      {
        write(fd, c, 2);
        write(fd, "\n", 1);
      }
      closeserial(fd);
      return 0;
    }
    

  • This link is excellent.

  • I am not able to toggle RTS line, uart_test.c not toggling the RTS line. I am using USB-to-Serial converter.