Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 9 Mar 2003 00:00:25 +0100 (CET)
From:      Luuk van Dijk <lvd@mndmttr.nl>
To:        FreeBSD-gnats-submit@FreeBSD.org
Cc:        lvd@mndmttr.nl
Subject:   kern/49039: add support for RS485 hardware where direction is controlled by RTS line
Message-ID:  <200303082300.h28N0PxH000575@wonder.mndmttr.nl>

next in thread | raw e-mail | index | archive | help

>Number:         49039
>Category:       kern
>Synopsis:       add support for RS485 hardware where direction is controlled by RTS line
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sat Mar 08 15:10:00 PST 2003
>Closed-Date:
>Last-Modified:
>Originator:     Luuk van Dijk
>Release:        FreeBSD 4.7-RELEASE i386
>Organization:
Mind over Matter B.V.  (http://www.mndmttr.nl)
>Environment:
System: FreeBSD wonder.mndmttr.nl 4.7-RELEASE FreeBSD 4.7-RELEASE #3: Fri Dec 27 07:26:14 CET 2002 root@wonder.mndmttr.nl:/usr/src/sys/compile/WONDER i386

The Nagasaki PC104-550VL single board computer 
(http://www.nagasaki.com.tw/activity/PC04-550VL.htm)
with built in RS485 interface, running 4.7-RELEASE

>Description:

The abovementioned single board PC contains two 16550A's, one of which is
jumper-configurable to drive an RS485 line, instead of the traditional RS232.
The RS485 bus is much used in industrial environments: it is a two-line
interface, to which multiple senders and listeners can be connected.

The main difference from a software point of view is that the RS485 is half
duplex, and has to be switced from 'receive' to 'transmit' mode and back in
some way.  The designers of this board have chosen to use the RTS handshake
signal to drive rx/tx mode, a solution that also allows dirt-cheap (<10$)
home made converters from RS232 to RS485, with nothing but voltage level 
converters.
A full fledged RS232 to 485 converter on the other hand has to contain a
complete microcontroller to detect and decide which way the traffic flows,
which makes them far more expensive (>100$). 

Problem with this design is that the hardware has to be switched back to
receive mode fast enough not to lose data from responding parties on the
bus. In practice this is within a word-length of data on the bus.  By 
ioctl'ing and termios from userland, the timeresolution is about 10ms
which is way to slow.  the best solution is to do it deep in the interupt
handler for the serial port.  The patch below has been tested and works fine
at least at 9600 baud.


>How-To-Repeat:

connect an oscilloscope to an RS485 bus connected in the above described manner,
and initiate some traffic on the bus. You will notice bus contention by the
fact that the voltage changes, but doesn't change polarity.  This is because
one transmitter keeps the bus high, and the other tries to drive it low.
you really need a storage scope to study this stuff, so I was really lucky
to have borrowed one, otherwise I'd never have guessed why my RS485 didn't
work.



>Fix:

The patch below implements the desired behaviour on sio's that
have flag 0x04, but not 0x01 set in the kernel config (0x04 otherwise
only has meaning for multiport sio's, = 0x01  ). 
this way one can easily select at kernel compile time which ports
need this.  It is trivial to change this to use the DSR instead of RTS.
This is all for 4.7, as I haven't gotten around to 5.0 yet.


--- isa/sio.c.orig      Sun Feb 16 13:51:38 2003
+++ isa/sio.c   Wed Feb 19 00:15:04 2003
@@ -133,6 +133,12 @@
 #define        COM_NOTAST4(flags)      ((flags) & 0x04)
 #endif /* COM_MULTIPORT */
 
+/* LVD 2003/02/16 EXPERIMENT */
+/* on non-multiport use flag 0x04 to mean RTS enables XMIT (for my RS485 hardware) */
+
+#define COM_RTSXMIT(flags)     (((flags) & 0x05) == 0x04)
+
+
 #define        COM_CONSOLE(flags)      ((flags) & 0x10)
 #define        COM_FORCECONSOLE(flags) ((flags) & 0x20)
 #define        COM_LLCONSOLE(flags)    ((flags) & 0x40)
@@ -2113,6 +2119,23 @@
                                        com->state &= ~CS_ODEVREADY;
                        }
                }
+
+
+
+               /* LVD 2003/02/16 EXPERIMENT */
+               /* if sending, ensure RTS asserted */
+               if( COM_RTSXMIT( com->flags ) ){
+                 if( com->state >= (CS_BUSY | CS_TTGO ) ) {
+
+                   if( !(com->mcr_image & MCR_RTS) ) 
+                     outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+                   
+                 } else {  /* when done sending, ensure RTS cleared if TSRE */
+                   if( !(line_status & LSR_TSRE) )
+                     if( (com->mcr_image & MCR_RTS) ) 
+                       outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
+                 }
+               } /* RTSXMIT */
 
                /* output queued and everything ready? */
                if (line_status & LSR_TXRDY


>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200303082300.h28N0PxH000575>