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>