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).
Fig.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
.
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.



