8250 driver RS485 troubles

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Dear kernel community,

I am working on an embedded Linux device that that is using the Linux 4.7 Kernel on the Xilinx Zynq platform. I am having trouble getting the RS485 part of the 8250 serial driver to work. All the functions needed for switching the RS485 transceiver using the RTS pin are already present in the 8250_port.c file, but I had to add a rs485_config() function to the 8250_of.c file to support configuration using TIOCSRS485 ioctl() calls.

My problem was that at first, that the functions responsible for setting the RTS pin was only called at the beginning of transmission, leaving the transceiver in send mode. I found out that there may be a bug in the __stop_tx() function from 8250_port.c

static inline void __stop_tx(struct uart_8250_port *p)
{
    struct uart_8250_em485 *em485 = p->em485;

    if (em485) {
        unsigned char lsr = serial_in(p, UART_LSR);
        /*
         * To provide required timeing and allow FIFO transfer,
         * __stop_tx_rs485 must be called only when both FIFO and
         * shift register are empty. It is for device driver to enable
         * interrupt on TEMT.
         */
        if ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
        {
            return;
        }

        del_timer(&em485->start_tx_timer);
        em485->active_timer = NULL;
    }
    __do_stop_tx(p);
    __stop_tx_rs485(p);
}

BOTH_EMPTY translates to THRE and TEMT bits in the LSR register. THRE is set when tx data has been transferred from the holding register to the shift register, indicating, that the cpu may write a new byte to the UART. TEMT is set when the data has been shifted out of the shift register, ie. has actually been sent over the line. Therefore, TEMT will always be set AFTER THRE was set, with the delay of the time it takes to shift the byte on the line, including start-, stop- and parity-bits.

I believe the problem is, that THRE and TEMT are tested together but they may not have been set when the function is called, especially when a low baudrate is used (19200 Bd in my case). I verified that the return in the middle was always taken, even after the last byte, when it was supposed to call __stop_tx_rs485(). That is why the transceiver was never switched back to receive.

I simply commented the return out and it's working now, kind of. But that is another question/problem I will ask later. I'd like to hear your opinion on this topic first. This code is still present in the 4.12 kernel files.

Greetings, Florian

PS: Please CC your answers to my email address.


--
G. Lufft Mess- und Regeltechnik GmbH, Gutenbergstr. 20, 70736 Fellbach, Deutschland
Geschäftsführer / Managing directors: Dr. Martin Nicklas, Axel Schmitz-Hübsch, Jörg Mayer, Dr. Anton Felder
Handelsregisternummer und zuständiges Amtsgericht / Trade register and local district court: Amtsgericht Stuttgart HRB 721373
Umsatzsteuer-ID / VAT-ID: DE 250580689, Steuernummer / tax no. 90490/28336, WEEE-Reg.-Nr. DE98036552
Tel: ++49 711 51822 0, Fax: ++49 711 51822 41, E-Mail: info@xxxxxxxx
��.n��������+%������w��{.n�����{��ǫ����{ay�ʇڙ���f���h������_�(�階�ݢj"��������G����?���&��




[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux