WinXP, RS485 and Delphi

This two-part article describes the PortTalk Delphi 7 kernel mode driver for fast RTS line switching as needed with a dumb RS485 converter under Windows XP.

The second part of this article can be found here.

Introduction

Embedded devices can be found 'under the hood' of all kinds of equipment used in industrial environments. Some may perform some specialized control or monitoring task in some specialized part of a machine that was specifically designed to partake in one of the zillion sorts of production processes taking place all over the world. The embedded device faithfully performs its humble part in this all and may typically require none to only a small amount of  'steering' information from a controlling agent higher up in the automation hierarchy. This is where you may find fieldbusses such as Profibus DP. Even more basic, perhaps for low to medium speed process data and/or configuration data only, you may find traditional serial connectivity wich has been possible through UARTS on even the most modest or oldest microcontrollers. RS485 is one of the venerable and robust industrial standards used to combine simple data exchange with small network features.

As in the figure shown below, the standard multidrop configuration uses a differential pair of signal lines (normally twisted for noise immunity) for half-duplex communication in a bus topology with line termination at the first and final nodes. Each node has a transceiver, which is a combination of a receiver and a transmitter of which the latter can be switched to a high impedance tri-state. Any node is normally in reception state (transmitter in High-Z) unless it has something to transmit (normally disabling the receiver in that case).

RS485 topologyFig.1 - RS485 topology

It is up to a protocol to decide what node is allowed to 'speak'. Usually a simple Master/Slave relation is established between a controller node and several worker nodes. Only the Master will start a communication by transmitting a message containing some node address, and only the addressed node will respond to that. Often simple proprietary protocols are being used or near clones of the ModBus protocol and often the Master node is in fact a PLC or PC running some control or configuration software.

Problem

I recently had to update the software for a controlling PC for a system as decribed above. Since the PC needed to be a detachable standard laptop, the system was equipped with a built-in RS232-RS485 converter. This converter is of the 'dumb' type; it requires the PC to switch the RTS line at the RS232 side  to switch between send and receive on the RS485 side. Modern RS232-RS485 converters can do that automatically, but this one didn't. The original control software was written for Windows 9X and it needed conversion to WindowsXP. Piece of cake. Not so! Here's why:

Windows XP - or any NT based version of Windows will not allow direct hardware access as is possible with Window 9x, so the Modbus/RS485 communication routines of the software - that previously switched RTS by direct hardware accesss - could no longer do this. The 'native' alternative is to let WinNT automatically handle RTS switching through the COMDRV itself. This can be done by specifying fRtsControl=RTS_CONTROL_TOGGLE in the DCB structure. Note, by the way, that this value and functionality is not supported in the Win9X API.

typedef struct _DCB {       // Type definition of the DCB structure
DWORD DCBlength;
DWORD BaudRate; // The DCB also specifies things as baudrate
DWORD fBinary :1;
DWORD fParity :1;
DWORD fOutxCtsFlow :1;
DWORD fOutxDsrFlow :1;
DWORD fDtrControl :2;
DWORD fDsrSensitivity :1;
DWORD fTXContinueOnXoff :1;
DWORD fOutX :1;
DWORD fInX :1;
DWORD fErrorChar :1;
DWORD fNull :1;
DWORD fRtsControl :2; // RTS_CONTROL_TOGGLE possible for RS485
DWORD fAbortOnError :1;
DWORD fDummy2 :17;
WORD wReserved;
WORD XonLim;
WORD XoffLim;
BYTE ByteSize;
BYTE Parity;
BYTE StopBits;
char XonChar;
char XoffChar;
char ErrorChar;
char EofChar;
char EvtChar;
WORD wReserved1;
} DCB;

The problem with this approach, however, is that it performs way too slow, as shown below with some real-life measurements. By the way: you can zoom out the scope images by clicking on them. And if you wonder: the noisy aspect of the shown signals originates from the weak step-up supply of the notebook's RS232 output. Don't complain though; it's already difficult enough these days to get a notebook that still sports a COM port Frown.

 

Modbus RS485 Query and Response This is a scope capture of a modbus monitoring transaction at the RS232 side of the converter. The upper channel is the master (PC) which repeatedly sends a short query message and the lower trace is the response by the addressed device. Baudrate is 19200 here. Due to other activities in the device, the reponse has a latency of a couple of ms.
 Response jitter This is the equivalent of the first capture above, but now shown with a 1 sec persistence setting. Note that we have a cyclic  monitoring sequence. The master requeries after receiving a response and the response latency may vary say 5 ms, but most of the time it comes in approx. 2.5 ms.
Varying RTS switch-back delay Here's wat happens with native WinNT switching of the RTS line. Upper channel is the master transmission, lower channel is the RTS line, again shown with persistence (2sec). RTS switches up relatively fast, but switch-back at the end of transmission may take a delay of anything between 1.3 to 6 ms. Most of the time, a response will have been produced while the master transceiver is still in transmission state. The response will therefore be garbled or it doesn't arrive at all. Any master retry will very propable fail too.
Correct RTS switching This is what we need and what is obtained by the solution given later in this article. RTS switches on and off neatly as an envelope around the transmission message.

Switching of RTS can be done using EscapeCommFunction() of the Win API, but there's no real other alternative for getting the required switch-back performance than polling the PC's UART registers to determine when the UART has shifted out the last (stop)bit of the last character of the message. The Win API simply does not provide an Event for that. The 'nearest' Event to use in WaitCommEvent() would be EV_TXEMPTY but this fires when the transmit buffer gets empty which is when the UART gets busy shifting out the last character and is therefore too early.

So direct register access is required and in order to make this possible under the NT architecture, we need the assistance of a kernel mode device driver.

The second part of this article goes into that.

Filed under code & stuff – Published 2006 Aug 18 – Modified 2006 Nov 9 – Permalink

Top