Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

RS485 & Linux: Must toggle DTR quickly

0 views
Skip to first unread message

Olav Woelfelschneider

unread,
Mar 25, 1999, 3:00:00 AM3/25/99
to
Keywords: RS485-Network, Linux

I try to run a small RS485 network off the serial port of a PC. The PC polls
some gadgets with microcontrollers in them.

The PC is coupled via a RS232-RS485 converter which uses DTR to
switch between transmit and receive. (I use the half-duplex approach with
only one pair of wires.)

So, to send some data, I turn DTR on, write() the bytes and turn DTR off
again after the last byte fell out of the UART.

Now waiting for end of transmission to turn off DTR is my problem.

If I use tcdrain() to wait, it takes too long, since the kernel doesn't
return quick enough to my process for it to turn DTR off. This means I
lose the response from the device which received the data, as it answers
really quick.

The alternative is a busy loop polling with TIOCSERGETLSR, waiting for
end of transmission. This works, but I don't like it, since it hogs the
CPU, uses tons of system calls and feels very ugly.

Imagine what happens if the scheduler decides to schedule the process away
right after write() but before turning DTR off. Kaboom, the bus stays locked.

This is the code snipplet for that approach:

{
int arg;

/* DTR on */
ioctl(com, TIOCMGET, &arg);
arg|=TIOCM_DTR;
ioctl(com, TIOCMSET, &arg);

/* Send data */
if (write(com, buf, bp)!=bp) return -1;

/* Wait for transmitter to finish -- UGLY! */
do {
ioctl(com, TIOCSERGETLSR, &arg);
} while((arg & TIOCSER_TEMT)==0);

/* DTR off */
ioctl(com, TIOCMGET, &arg);
arg&=~TIOCM_DTR;
ioctl(com, TIOCMSET, &arg);
}

Before I go and hack up the serial driver to include automatic DTR toggling,
I wonder what other people might think.

Any hints greatly appreciated!

Thanks,
--
Olav "Mac" Wölfelschneider wo...@cardware.de
PGP fingerprint = 06 5F 66 B3 2A AD 7D 2D B7 19 67 3C 95 A7 9D AF
Mer muß doch nur emol e bissje nochdenke. -- Mundstuhl

Tom Aschenbrenner

unread,
Mar 25, 1999, 3:00:00 AM3/25/99
to
Olav.....I went thru the very same thought process you are going thru. I also
use a rs485 network
in the half duplex mode (on 2 wires) communicating with some 8051 based
controllers....after much
work the solution i used was a VERY SIMPLE hardware solution....turns out there
are times when
a few parts replace alot of software and result in a much more reliable
system....since i had built a
simple rs232 to rs485 converter (worked the same as yours...DTR enabled the
rs485 tranmit) i just
added a single one shot that was triggered off the falling edge of the rs232
signal and whose output
enabled the rs485 transmit....set the one shot for the byte time and your
DONE!!!! now i fought this
solution for a few weeks as i am a software guy at heart but when i saw how
simple it was in the
hardware domain and versus how complex it was in the software domain i switched.
This approach
allowed me to use standard drivers and also the standard linux time slice
scheduler rather then the
SCHED_FIFO mod to be able to get the execution resoltion i needed to control the
DTR lead from
user space.
Regards, Tom A - Dallas, Tx.

Matthew T. Linehan

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to
On Thu, 25 Mar 1999 18:44:41 +0100, Olav Woelfelschneider
<wo...@cardware.de> wrote:

>So, to send some data, I turn DTR on, write() the bytes and turn DTR off
>again after the last byte fell out of the UART.
>
>Now waiting for end of transmission to turn off DTR is my problem.

More so than you have realized yet. I'm not familiar with the Linux
implementation, but most serial drivers consider the buffer flushed,
and done as soon as the last byte to be transmitted as been sent to
the uart. The problem is, it takes about 1mS (9600 baud) for the uart
to finish transmitting the character. If your using a buffered uart,
the problem gets much worse!

If you manage to get a fast DTR shut off routine working, you WILL cut
off the last few bits of your last character. Been there, done that.

The easiest solution is to not control the 485 transmitter in
software. Use a one shot circuit in the RS-232 to 485 converter to do
the dirty work for you.

B&B has just such an animal, and it works great! We use about 20-30
485TBLED units per year. DB25 for RS-232 side, Screw terminals for the
485 side.

Check out: http://www.bb-elec.com/


--
+------------------------+---------------------+--------------------+
| Matthew T. Linehan | AKA -=(UDIC)=- | All Round Computer |
| American LED-gible Inc | Quantum Void Dragon | Nerd. Hardware, |
| Engineer | Ultima Fanatic | Software, Other :-)|
+------------------------+---------------------+--------------------+

Etienne Lorrain

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to
Hi,

Olav Woelfelschneider wrote:

> [...] So, to send some data, I turn DTR on, write() the bytes and turn DTR off


> again after the last byte fell out of the UART.
>
> Now waiting for end of transmission to turn off DTR is my problem.
>

> If I use tcdrain() to wait, it takes too long, since the kernel doesn't
> return quick enough to my process for it to turn DTR off. This means I
> lose the response from the device which received the data, as it answers
> really quick.
>
> The alternative is a busy loop polling with TIOCSERGETLSR, waiting for
> end of transmission. This works, but I don't like it, since it hogs the

> CPU, uses tons of system calls and feels very ugly. [...]

The main problem here is hardware: none of the 16450, 16550 and
other UART give the information "char completely sent", they just
give the information "Tx serialisator empty"... a small difference: the
stop and parity bits. Linux could calculate when the char will go
out of the chip to switch a pin (quite a complex calculus) but after
some experiment you will see that each manufacturer has implemented
the "Tx serialisator empty" bit his own way and the only way to
get reliable result is to wait "enough" before returning to tcdrain().
I do not think there is a software solution to your problem...

Etienne.


Tony Williams

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to
In article <36fd8476....@news.netcomuk.co.uk>,
Peter <z...@ds1.com> wrote:
> They do give the "all sent" info but only as a status bit - you cannot
> program an interrupt from it.

> > The main problem here is hardware: none of the 16450, 16550 and
> > other UART give the information "char completely sent", they just
> > give the information "Tx serialisator empty"...

I had a very similar problem in "2-wire" RS-485
comms, where each Tx/Rx only gets switched into
Tx when required, and *must* drop back into an
Rx'er asap. 5-byte packets into an 8-byte fifo.
With a receiver hanging on the line you simply
receive your own outgoing bytes, and as soon as
the last byte ends, smack it back into Rx, and
flush buffs. You don't actually have to read your
own bytes, just count the ints from your own uart,
each int being a signal that a full byte has gone.

--
Tony Williams.

Gerard van der Sel

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to
Olav Woelfelschneider wrote:
>
> Keywords: RS485-Network, Linux
>
> I try to run a small RS485 network off the serial port of a PC. The PC polls
> some gadgets with microcontrollers in them.
>
> The PC is coupled via a RS232-RS485 converter which uses DTR to
> switch between transmit and receive. (I use the half-duplex approach with
> only one pair of wires.)
>

Well there is a software solution. Since you are using halduplex
protocol I persume that transmit is coupled with receive through the
rs485. When you get an receive interrupt from the last character you can
savely turn the transmitter of :-).
So no extra hardware is necessary
--
Met vriendelijke groet,

Gerard van der Sel
Mailto:gvand...@hr.nl
"De dinosaurussen hadden hun komeet, wij hebben de Windows computer" -
me
"The box said: 'install on Windows 95, NT 4.0 or better'.
So I installed it on Linux."

Ralph Goff

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to

R.E. Smith in the US makes a 232 to 485 converter that will take care
of all this messy timing for you. You just send the data.
R.E. Smith Co.
4311 Tylersville Rd.
Hamilton, OH 45011
513-874-4796

I've never used them, just seen them advertised. Under $100.

Ralph


In article <9msdd7...@hex.athome.de>, Olav Woelfelschneider <wo...@cardware.de> says:
>
>Keywords: RS485-Network, Linux
>
>I try to run a small RS485 network off the serial port of a PC. The PC polls
>some gadgets with microcontrollers in them.
>
>The PC is coupled via a RS232-RS485 converter which uses DTR to
>switch between transmit and receive. (I use the half-duplex approach with
>only one pair of wires.)
>

>So, to send some data, I turn DTR on, write() the bytes and turn DTR off
>again after the last byte fell out of the UART.
>

<snip>

Tewpin Andrey (Тюпин Андрей)

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to

Olav Woelfelschneider пишет в сообщении <9msdd7...@hex.athome.de> ...
>Keywords: RS485-Network, Linux
>

>This is the code snipplet for that approach:
>
> {
> int arg;
>
> /* DTR on */
> ioctl(com, TIOCMGET, &arg);
> arg|=TIOCM_DTR;
> ioctl(com, TIOCMSET, &arg);
>
> /* Send data */
> if (write(com, buf, bp)!=bp) return -1;
>
> /* Wait for transmitter to finish -- UGLY! */
> do {
> ioctl(com, TIOCSERGETLSR, &arg);
> } while((arg & TIOCSER_TEMT)==0);
>
> /* DTR off */
> ioctl(com, TIOCMGET, &arg);
> arg&=~TIOCM_DTR;
> ioctl(com, TIOCMSET, &arg);
> }

Pls, try so...

{
int arg;

//
// m.b. off Tx FIFO? I do it for NT4, in Linux I'm nothing, yet.
// And do not know as work write in last.

/* DTR on */
ioctl(com, TIOCMGET, &arg);
arg|=TIOCM_DTR;
ioctl(com, TIOCMSET, &arg);

/* Send data */
*(buf+bp)=0x00; // paddle fake byte: must be 0x00
if (write(com, buf, bp+1)!=(bp+1)) return -1;

/* Wait for transmitter to finish -- UGLY! */

// do {
// ioctl(com, TIOCSERGETLSR, &arg);
// } while((arg & TIOCSER_TEMT)==0);
//

/* DTR off */
ioctl(com, TIOCMGET, &arg);
arg&=~TIOCM_DTR;
ioctl(com, TIOCMSET, &arg);
}

>Before I go and hack up the serial driver to include automatic DTR toggling,
>I wonder what other people might think.
>
>Any hints greatly appreciated!
>
>Thanks,
>--

>Olav "Mac" Wцlfelschneider wo...@cardware.de


>PGP fingerprint = 06 5F 66 B3 2A AD 7D 2D B7 19 67 3C 95 A7 9D AF

>Mer muЯ doch nur emol e bissje nochdenke. -- Mundstuhl


At7


Rufus V. Smith

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to
I thought that status bit could cause an interrupt in Line Status Change or
Modem Status Change.

Peter wrote in message <36fd8476....@news.netcomuk.co.uk>...


>They do give the "all sent" info but only as a status bit - you cannot
>program an interrupt from it.
>
>> The main problem here is hardware: none of the 16450, 16550 and
>> other UART give the information "char completely sent", they just
>> give the information "Tx serialisator empty"...
>
>

>--
>Peter.
>
>Return address is invalid to help stop junk mail.
>E-mail replies to zX...@digiYserve.com but remove the X and the Y.
>Please do NOT copy usenet posts to email - it is NOT necessary.

Stephen Tell

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to
In article <9msdd7...@hex.athome.de>,
Olav Woelfelschneider <wo...@cardware.de> wrote:

>The PC is coupled via a RS232-RS485 converter which uses DTR to
>switch between transmit and receive. (I use the half-duplex approach with
>only one pair of wires.)

I went through the same thought process and code experiments that you did,
and finally just bought a half-duplex RS232-RS485 converter that does the
transmit control automaticly in hardware.

two sources of these:
http://www.bb-elec.com/
http://www.rs485.com/

>Before I go and hack up the serial driver to include automatic DTR toggling,
>I wonder what other people might think.

I think that if you want it done right, it needs to go in the driver like
this.
--
--
Steve Tell | te...@cs.unc.edu | http://www.cs.unc.edu/~tell | KF4ZPF
Research Associate, Microelectronic Systems Laboratory
Computer Science Department, UNC@Chapel Hill. W:919-962-1845

Olav Woelfelschneider

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to
Matthew T. Linehan <mlin...@columbus.rr.com> wrote in comp.os.linux.development.system:
MTL> More so than you have realized yet. I'm not familiar with the Linux
MTL> implementation, but most serial drivers consider the buffer flushed,
MTL> and done as soon as the last byte to be transmitted as been sent to
MTL> the uart.
Not with Linux. At least if I do the TIOCSERGETLSR I will in fact find
out the actual end of transmission. The driver really checks for transmitter
empty, not for kernel buffer empty.

MTL> If you manage to get a fast DTR shut off routine working, you WILL cut
MTL> off the last few bits of your last character. Been there, done that.

AOL, AOL! Umh, I meant, mee too. (-:

On some microcontrollers or UARTS you have no chance detecting when the
last byte fell out of the shift register. In that cases I had to send
a final dummy byte (0xFF) which was shut off right after the start bit.
I had to make sure the protocol doesn't get confused by this.

MTL> The easiest solution is to not control the 485 transmitter in
MTL> software. Use a one shot circuit in the RS-232 to 485 converter to do
MTL> the dirty work for you.

This is easy for constant speeds. If you want to build a universal device,
then you have either an ugly pot to adjust or a complex circuit which
analizes the data. These discussions pop up on c.a.e every now and then...

But I think I might just go that way. After all, the data rate will be
constant.

Greetings,
--
Olav "Mac" Wölfelschneider wo...@cardware.de


PGP fingerprint = 06 5F 66 B3 2A AD 7D 2D B7 19 67 3C 95 A7 9D AF

Mer muß doch nur emol e bissje nochdenke. -- Mundstuhl

James Youngman

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to
Olav Woelfelschneider <wo...@cardware.de> writes:

> Keywords: RS485-Network, Linux
>
> I try to run a small RS485 network off the serial port of a PC. The PC polls
> some gadgets with microcontrollers in them.
>

> The PC is coupled via a RS232-RS485 converter which uses DTR to
> switch between transmit and receive. (I use the half-duplex approach with
> only one pair of wires.)
>

> So, to send some data, I turn DTR on, write() the bytes and turn DTR off

> again after the last byte fell out of the UART.

IIRC, you can't tell that. IIRC, the 16{4,5,6}50 will only tell you
when the last byte has passed from the FIFO (or holding register) into
the shift register.

Maybe I'm thinking of the Zilog SCC series or the Motorola MFP,
though. It's been a while...

--
ACTUALLY reachable as @free-lunch.demon.(whitehouse)co.uk:james+usenet

James Youngman

unread,
Mar 26, 1999, 3:00:00 AM3/26/99
to
mlin...@columbus.rr.com (Matthew T. Linehan) writes:

> More so than you have realized yet. I'm not familiar with the Linux

> implementation, but most serial drivers consider the buffer flushed,

> and done as soon as the last byte to be transmitted as been sent to

> the uart. The problem is, it takes about 1mS (9600 baud) for the uart
> to finish transmitting the character. If your using a buffered uart,
> the problem gets much worse!

Actually, IIRC it's a holding-register versus shift-register problem.

> If you manage to get a fast DTR shut off routine working, you WILL cut

> off the last few bits of your last character. Been there, done that.

Something that just occurred to me is that you may be able to put the
UART into loopback mode and hence know to toggle the DTR when you have
*received* the character. This will only work if the Tx line is not
tri-stated (or otherwise not actually outputting) while in loopback
mode (I can't remember). If you do this, though, you will also have
to turn off the receive FIFO or wait a couple of character-times :-(

> The easiest solution is to not control the 485 transmitter in

> software. Use a one shot circuit in the RS-232 to 485 converter to do

> the dirty work for you.

Actually the easiest solution is to use an extra 2 wires :-)

Timothy Wall

unread,
Mar 27, 1999, 3:00:00 AM3/27/99
to
A couple notes on interacting with the linux serial driver (I've been using
kernels 2.0.34-36):

* TIOCMGET directly accesses the UART registers, and when used from a user-level
program can mess up the serial driver's internal state (since many registers are
cleared when read/written).

* scheduling delay can be up to 10ms.

If you can't change the hardware, you might consider writing a custom character
driver for the device. Get Alessandro Rubini's "Writing Linux Device Drivers"
book, and you can have a working solution in less than a week.

Tim Wall

> >Before I go and hack up the serial driver to include automatic DTR toggling,
> >I wonder what other people might think.
> >

> >Any hints greatly appreciated!
> >
> >Thanks,
> >--

> >Olav "Mac" Wцlfelschneider wo...@cardware.de


> >PGP fingerprint = 06 5F 66 B3 2A AD 7D 2D B7 19 67 3C 95 A7 9D AF

> >Mer muЯ doch nur emol e bissje nochdenke. -- Mundstuhl
>
> At7


Olav Woelfelschneider

unread,
Apr 7, 1999, 3:00:00 AM4/7/99
to
Sergio Tanzilli <ta...@tin.it> wrote in comp.arch.embedded:
ST> Here is an hardware solution to this problem.

Posting binaries is generally frowned upon.

Anyway, I did it in software by writing my own driver which bangs directly
on the uart, listens to its echo and turns the driver off as soon as
all bytes came back. Timeouts ensure that nothing hangs in the process.

As a bonus, this approach does also collision detection.

--
Olav "Mac" Wölfelschneider wo...@cardware.de


PGP fingerprint = 06 5F 66 B3 2A AD 7D 2D B7 19 67 3C 95 A7 9D AF

Mer muß doch nur emol e bissje nochdenke. -- Mundstuhl

Tommy Thorn

unread,
Apr 8, 1999, 3:00:00 AM4/8/99
to
Olav Woelfelschneider <wo...@cardware.de> writes:
> Anyway, I did it in software by writing my own driver which bangs directly
> on the uart, listens to its echo and turns the driver off as soon as
> all bytes came back. Timeouts ensure that nothing hangs in the process.
>
> As a bonus, this approach does also collision detection.

Two (possible ignorant) questions:

1) Do you turn it off after *each* char sent, or only the last char
in a packet?

2) Has anyone written a RS485 kernel-level driver for Linux that they
would share?

Thanks,

/Tommy

Sergio Tanzilli

unread,
Apr 8, 1999, 3:00:00 AM4/8/99
to
>Posting binaries is generally frowned upon.


Ok, I'm sorry

Olav Woelfelschneider

unread,
Apr 8, 1999, 3:00:00 AM4/8/99
to
Tommy Thorn <th...@lalla.irisa.fr> wrote in comp.arch.embedded:
TT> 1) Do you turn it off after *each* char sent, or only the last char
TT> in a packet?

Of course, after the last char of the packet came back as an echo.
A timeout ensures that this does not hang if there is no echo (eg. because
someone pulled the plug).

If you want to code this yourself, be careful with the FIFO. The receiver
FIFO threshold must be set to 1, or you will still turn off too late.
With a high FIFO threshold, it can take some 4 character times before
the actual receive interrupt happens, if the FIFO is not full.

However, the uart permits to change the threshold on the fly, so I usually
leave it on 14 when idly waiting for incoming data. I set it to 4 at the
start of transmission and then set it down to 1 when I got at least 4 bytes.
Given a packet is at least 4 bytes long, this minimizes the number of
interrupt triggers. Beware, this idea is not yet thoroughly tested and it
might just shoot into your foot...

Oh, and I still recommend Rubini´s book on kernel device drivers. It´s great.

0 new messages