LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

RTS control for RS485

I have an application that uses RS485 communications.
This has been running for several years, using MOXA CP-132 PCI cards.
These have automatic transmit / receive switching.

I wish to port the software to an Amplicon Impact-E 40, solid state PC.
This has built in RS48r capability, but without the automatic transmit / receive switching.

I therefore need to be able to raise the RTS line, to enable the transmitter, then lower it to disable the transmitter and thus receive data.

How do I do this?  I cannot find appropriate commands within the CVI environment.
0 Kudos
Message 1 of 11
(6,236 Views)

The later versions of CVI have a ComSetEscape() library call, which allows direct control over the RTS/DTR lines. This should do what you want. (I'm not sure what version has it - just check your CVI help.)

JR

Message 2 of 11
(6,228 Views)
Thanks.  I have ComSetEscape(), but no documentation as to how to use it.
What escape codes are required to turn RTS on and off?

0 Kudos
Message 3 of 11
(6,190 Views)
From the CVI help:
 
    ComSetEscape (portNo, CLRRTS);    // Clears the RTS line
    ComSetEscape (portNo, SETRTS);    // Sets the RTS line
 
If the function returns -1, the device driver does not support the escape code specified.
 
JR
Message 4 of 11
(6,179 Views)
Thanks, not sure how I missed the escape codes in the documentation - doh!

I can set and clear RTS OK, but I still have a problem:
The comport is set to 9600, and here is a code fragment

001  status = ComWrt(comms_channel, buf, 4) ;
002
003   x = GetOutQLen(comms_channel) ;
004
005   Delay(0.002) ;
006     
007   do {  /* Wait until all sent */
008      y = GetOutQLen(comms_channel) ;
009      x = GetOutQLen(comms_channel) ;
010      } while ((x != 0) || (y != 0)) ;
011
012   ComSetEscape(comms_channel, CLRRTS) ;

If I set the Delay period to 0.004, the routine sort of works, but I want it to work for higher baud rates, and the Delay routine does not have sufficient resolution, so I tried to use GetOutQLen() to determine when the output queue is empty, but it does not seem to work ( hence the experimental lines 003 and 009).
Despite sending 4 characters and waiting (with the delay) for two to be sent, both lines 003 and 008 return an output queue length of zero.
Consequently, line 012 clears the RTS line and the transmitter is disabled before all the characters are sent.
? ? ?

0 Kudos
Message 5 of 11
(6,159 Views)
There's been dialogue on the discussion board about serial writes not occurring right away.

I believe the gist of it was that you have to process system events to get the serial write to actually take place.  It may be that this is true only if you're using an output queue.

The serial hardware may have a hardware buffer - 16 bytes deep is typical - so it could be that the "software" output queue is indeed empty but all of the bytes haven't yet been emitted from the serial port.  

Another issue is the output queue.  NI commonly recommends not using an output queue (set size = -1) to reduce complexity (the serial library starts up a separate thread to manage an output queue) and there's a known race condition in CVI 8.1 if you have an output queue and you use the FlushOutQ() function from your application.  Doesn't look like you're using it.

If you're waiting anyway, just don't use an output queue and see if that makes it work.

Menchar
Message 6 of 11
(6,153 Views)
Thanks JR and Menchar,

It seems that there is a bit of isolation between my application code and the actual I/O hardware.
I have tried not using an output queue, but to no avail.

Initialisation code is as follows:
   comms_channel_failure = OpenComConfig(new /* COMPort, */
                  , ""              /* char deviceName[] */
                  , baud_rate       /* long baudRate, (9600 used)  */
                  , 0               /* int parity */
                  , 8               /* int dataBits */
                  , 1               /* int stopBits */
                  , 0               /* int inputQueueSize = 512*/
                  , -1) ;           /* int outputQueueSize = not used */

And here is my test code:

static int           number = 5 ;
   clock_t           start, end, duration ;

   start = clock() ;          /* get start time */

   ComSetEscape(comms_channel, SETRTS) ;   // turn on RTS to enable RS485 driver
  
   strcpy(buf, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") ;
   status = ComWrt(comms_channel
               , buf
               , number) ;

// ProcessSystemEvents() ;

   end = clock() ;
  
   duration = end - start ;   // calculate duration of routine

   ComSetEscape(comms_channel, CLRRTS) ;    // turn off RTS to disable driver and permit reception
  
   number += 5 ;

This allowed me to check the length of time that the ComWrt routine was taking.  It was tested using ProcessSystemEvents() and also with that routine commented out.
The following table records the calculated durations for various send string lengths.
number    duration     PSEduration
5                      0                    13
10                    0                    13
15                    0                    19
20                    0                    13
25                    0                    1    honest!
30                    0                    12
35                   33                   34
40                   32                   45
45                   32                   34
50                   32                   45
55                   33                   33
60                   32                   45
65                   66                   67

Where to from here.  I am sure that this could be done if I write my own device driver, but that is something I have not done before and I don't think I have the necessary tools or knowledge.
Any ideas folks will be much appreciated.

0 Kudos
Message 7 of 11
(6,142 Views)
A bit of further information.
I emailed Amplicon as follows
Hi, I am attempting to use the E 40's RS485 port.
I need a driver that will control the RS485 driver, so that when no data is being transmitted, the driver is disabled so that data can be received.
I am using National Instruments CVI Measurement Studio, which has high level serial port routines, but I cannot effectively control the RTS line to switch the driver off immediately after the end of a transmission. (No problem switching the driver on).
Can you help?

This elicited the following reply:
The Impact E-40 uses software flow control for the RS-485 port. Unfortunately this can cause compatibility problems with some applications and is likely to be the issue with CVI Measurement Studio.
 
To resolve your problem, you would need to either use a suitable RS-485 plug-in PCI card, or an external RS232 - RS485 converter. If you wish to discuss these options, I can arrange for one of our Data Comms specialists to give you a call.

So it looks like back to our original solution of using the MOXA RS485 card ! ! !
Thanks again for your help.


 
0 Kudos
Message 8 of 11
(6,124 Views)
Having physical support to turn the bus transmitter off as the MOXA card has is as you have found about the ideal situation for a half duplex bus.  The windows OS and drivers get in the way of knowing when your last character has been transmitted at the software level. 
I did implement a system where I looped the output bus back to a second serial port and used the "echoed" input from that port to determine when the last character had been transmitted by the first port and the bus driver could be turned off.  It was a cheap solution for a lower speed system.  Using a serial port on a  dedicated "smart" serial card that can control the operation of its own uart and line drivers in realtime works in high speed situations. 
Message 9 of 11
(6,116 Views)
Thanks mvr, I guess that sums it up -
Can't really do it without the hardware support, especially at higher baud rates - we use 38400.
VDTD (Very Difficult To Do) without hardware implementation.
0 Kudos
Message 10 of 11
(6,106 Views)