Jetson NX uart1,I want use uart1 as rs422 ,FullDuplex-Mode, Meet error 'TIOCSRS485:Inappropriate ioctl for device'

On Jetson NX for Uart1, there is RTS and CTS pin, I want use uart1 as rs485/rs422 port, I add a voltage trancfer, Then I want set uart1 to 422/232 mode.

image

Test code:

#ifndef SER_RS485_TERMINATE_BUS
#define SER_RS485_TERMINATE_BUS     (1 << 5)
#endif
#define SET_UART_RTS_ACTIVE_LOGIC(flags, logic)  \
    do{\
        if(logic){\
            flags &= ~(SER_RS485_RTS_ON_SEND);   \
            flags |= (SER_RS485_RTS_AFTER_SEND); \
        }else{\
            flags |= (SER_RS485_RTS_ON_SEND);     \
            flags &= ~(SER_RS485_RTS_AFTER_SEND);}\
    }while(0)
#define GET_UART_RTS_ACTIVE_LOGIC(flags)  (!((flags) & SER_RS485_RTS_ON_SEND))
static E_STATUS ttyuart_switchto_rs422(const char *uartdev)
{
  int fd = open(uartdev, O_RDWR);
    if(fd < 0)
    {
        ERROR("open %s failed", uartdev);
        return e_IO_ERROR;
    }
    struct serial_rs485 rs485conf;
    memset(&rs485conf, 0, sizeof(rs485conf));
    rs485conf.flags |= SER_RS485_ENABLED | SER_RS485_RX_DURING_TX;
int ret = ioctl(fd, TIOCSRS485, rs485conf);
    if(ret < 0)
    {
	printf("error no:%d\n",ret);
        perror("Error,TIOCSRS485:");
    }
    return ret
}

I try to followed " https://www.kernel.org/doc/Documentation/serial/serial-rs485.txt "

I had disabled /dev/ttyTHS0 at previous with

systemctl stop nvgetty
systemctl disable nvgetty

in default status. use echo "verify..." > /dev/ttyTHS0, serial can output this log. But when test code execute “ioctl(fd, TIOCSRS485, rs485conf);” , it always error. error code was -1.
pin UART1_RTS and UART1_CTS always no signal.

for Kernel, it was based on 4.9.253 from Jetpack4.6

I want to ask:

  1. Did this kernel support ioctl for TIOCSRS485, what I should do to make it support this comond.

  2. if this ioctl was not support TIOCSRS485, is there any other comond or ioctl micro can replace it.

  3. For this module, What should I do to make uart1 switch to RS422/RS485 mode.

hello 411203060,

please also refer to similar discussion thread, Topic 124848 for RS485 configuration.
you should also refer to post #9 to force the pin as low state for testing,
thanks

Hi JerryChang, Thanks for your reply, I will try them on my board.

I had add patch, IOCTL was not meet error now, but RTS pin and CTS pin seem always 0 and 1, when send date at rs485 mode, RTS pin has no signal change at all。
I tried both previous code and this code. no signal change at all.

...
    struct termios term;
    fd = open(uartdev, O_RDWR);
...
    memset(&term, 0, sizeof(term));
    if ( -1 == tcgetattr(fd, &term))
    {
        perror("Can not get standart input discription:");
        close(fd);
        return e_IO_ERROR;
    }
    cfsetspeed(&term, speed);
    
    term.c_cflag |= (CLOCAL | CREAD);   // ignore modem controls 
    term.c_cflag &= ~CSIZE;              
    term.c_cflag |= CS8;                // 8-bit parity bit
    term.c_cflag &= ~PARENB;            // no parity bot
    term.c_cflag &= ~CSTOPB;            // only need 1 stop bit
//    term.c_cflag &= ~CRTSTS;          // no hardware flow control, not use at here
    term.c_cflag |= CRTSCTS;            // use RTS/CTS 
    
     // setup for non-canonical mode
    term.c_iflag &= !(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR| IGNCR | ICRNL | IXON);
    term.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
    term.c_oflag &= ~OPOST;
    
    // fetch bytes as they become available
    term.c_cc[VMIN] = 1;    // 
    term.c_cc[VTIME] = 1;   // 100ms

    if (-1 == tcflush(fd, TCIOFLUSH))
    {
        printf("error at tcflush. error no:%d", errno);
        close(fd);
        return e_IO_ERROR;
    }
  
    if (0 != tcsetattr(fd, TCSANOW, &term))
    {
        printf("error at tcsetattr. error no:%d", errno);
        close(fd);
        return e_IO_ERROR;
    }
    close(fd);

and I find there is no RTS pin at device tree, should I add them (something like pin control ) to device tree. is there any example for it?

hello 411203060,

could you please try below.

diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
@@ -56,6 +56,7 @@
 #define TEGRA_UART_MCR_CTS_EN                  0x20
+#define TEGRA_UART_MCR_FORCE_RTS_LOW            0x02

@@ -216,9 +217,9 @@ static void set_rts(struct tegra_uart_port *tup, bool active)

        mcr = tup->mcr_shadow;
        if (active)
-               mcr |= TEGRA_UART_MCR_RTS_EN;
+               mcr |= TEGRA_UART_MCR_FORCE_RTS_LOW;
        else
-               mcr &= ~TEGRA_UART_MCR_RTS_EN;
+               mcr &= ~TEGRA_UART_MCR_FORCE_RTS_LOW;

Thanks for you response, the new change was not work, did it work on you sites? or other change need done ?

Inturth, I want use this Pin for Both Half Duplex-mode and full Duplex-mode. For uart1, did Jetson xavier nx support Half Duplex-mode, if not support, I think I should find another solution.

Has someone else successful configuration uart as Half Duplex-mode on Xavier NX?


the SOC manual told support FULL -duplex but not told harf-duplex.

I add debug log at function, set_rts, when output date, value of mcr:96 ,after send finish,value of mcr:33, it seems that
image


value of RTS_EN and CTS_EN was both set to 1, But it always no signal change on RTS and CTS, both of then low status.
I found that GPIO 428 was RTS pin, if I set GPIO AS output, and echo 1 > /sys/clase/gpio/gpio428/value, then it found that RTS pin was pull up. at least.

All of them seems like