Can someone please explain CTS RTS UART

Specifically I'm using a VDIP1, but it could be any device.

In my head this is how it works:

-I set the pin connected to RTS on the VDIP1 to high
-I wait in a loop for the pin connected to CTS to go high
-Then I send serial data.
-Then I reset my pin connected to RTS to low until I need to send data again

The part that confuses me is that I can do serial communication with the VDIP if I just connect the CTS/RTS pins on the VDIP to eachother which tells me that the above scenario is opposite and I really should be looking at it from the point of view of the VDIP1

So, anytime I want to send data to the VDIP1 I should

I found some insight here: http://www.dontronics-shop.com/FTDI-VDIP1-sp-67.html

In summary it appears that you hold CTS low and watch RTS. RTS will tell you when the buffer is "nearly" full. You can then have your code wait until RTS signals LOW and continue sending data.

I believe I will modify the conditions of my logging while loop to set this up.

Alas, it can't be "any device"; there are at least two major ways to use RTS/CTS that are completely different. What you describe in your first message is (more or less) traditional "per rs232 specification" modem control used for doing things like changing the direction that half-duplex modems will send data. This is hardly seen any more.
The other common usage is "hardware flow control", which is (cough) outside the official spec. It works mostly like you describe in your second message. One side gets to use (as transmit) RTS and the other CTS, and they turn the signal "False" to indicate that they're running out of buffer space, hopefully causing the other side (using the same wire as recieve) to stop sending.

I'm still getting collisions and buffer overrun:

 while (digitalRead(buttonApin) == HIGH){
   if (digitalRead(rtsPin) == LOW){
     Serial.print("WRF ");

     long t1 = ( (lookup_temp(analogRead(t1pin))) );
     long t2 = ( (lookup_temp(analogRead(t2pin))) );
     long oil = ( lookup_oil_temp(analogRead(tempPin))); 
     long press =  lookup_boost(analogRead(boostPin));
     long ax = getAccelerometerData (xval);
     long ay = getAccelerometerData (yval);
     long tmillis = millis();

     int negcount = 0;
     if (t1<0){negcount++;}   
     if (t2<0){negcount++;}
     if (oil<0){negcount++;}   
     if (press<0){negcount++;}   
     if (ax<0){negcount++;}   
     if (ay<0){negcount++;}   
   
     //calc the number of characters
     int linelen = negcount + 7 + numberofdigits2(tmillis) + numberofdigits2(t1) + numberofdigits2(t2) + numberofdigits2(oil) + numberofdigits2(press) + numberofdigits2(ax) + numberofdigits2(ay);
     Serial.print(linelen);    //print the number of characters for this line
     Serial.print(13, BYTE);
   
     Serial.print(tmillis);
     Serial.print(",");
   
     Serial.print(t1);
     Serial.print(",");
     //get T2 and convert
     //Serial.print( lookup_temp(analogRead(t2pin)) );
     Serial.print(t2);
     Serial.print(",");
     //get oil temp and convert
     //Serial.print( analogRead(tempPin) );
     Serial.print(oil);
     Serial.print(",");
     //get boost and convert
     Serial.print(press);
     //Serial.print("###");
     Serial.print(",");
     //get x accel
     Serial.print(ax);
     Serial.print(",");
     //get y accel
     Serial.print(ay);
     Serial.print(13, BYTE);
     Serial.print(13, BYTE);
     delay(50);
   }
 }

I'm confused...btw I added the 50 ms delay just now, but haven't tested it yet.

Where are you seeing overruns/etc? Are you sure you don't have the sense of rtsPin backward? I thought by the time it hit an AVR pin, HIGH meant OK to transmit (note that this would be a LOW voltage on a real rs232 connection.) You're printing a significant amount of data; it certainly seems like it would be possible for this to overflow the buffer eventually (HW flow control should happen more quickly than SW flow control. Devices that implement it in actual hardware will need you to stop (typically) within a FIFO length of whatever uart is in use, or less.)

Can you tell whether RTS ever changes value? What bit rate are you using.

(Ah. I see. RTS on VDIP is inverted "RTS#, so your check is probably right.)

Browsing the VDIP manual, I see that successful commands result in a "reply" prompt. I think your code should wait for that prompt before sending the next command, regardless of RTS state. For short commands rather than bulk data, I'd think that the prompt could be used INSTEAD of needing to monitor RTS.

I will try those things tonight when I get home from work:

-Does RTS ever change to high (will just spam softserial with this info if it goes high)?

-Use the Serial monitor on the arduino IDE to determine if/what prompt comes back after a successful send of data. Use this prompt as a conditional for sending more data. See if I can, then avoid losing data.

Thanks for all your help.

1)RTS does go high. I even modified the code to wait in a while loop when RTS is high.

  1. monitoring for a prompt with Serial.read doesn't give me much.

Compare the following:
serial monitor - http://www.robotmeter.com/meter/serialmonitor.txt
log file - http://www.robotmeter.com/meter/LOG0.txt

(for some reason the forum wouldn't let me post the spill from these sources, even though it was bellow the character limit)

I usually get the first error line in the log at around 22 or 23 lines, but i have gotten it as early as the first line.

I tried:

if (digitalRead(rtsPin) == HIGH){
     vSerial.print("rtsHIGH");
     while  (digitalRead(rtsPin) == HIGH) {}
     
   }
   if (digitalRead(rtsPin) == LOW){
     Serial.print("WRF "); ...

...the guy in the Dontronics article tests after each command but that shouldn't matter.

This morning I had a lot of free time to wait around. During that time I had access to my logs but not my code.

I noticed that the "WRF " lines started to report numbers much lower than the actual number of characters to be output towards the end of the log. I haven't the slightest idea why this is happening.

I also noted that the WRF is the correct number on the other lines which are messed up.

I will take a look at my character counting code again when I get home.

The code example on the ftdi site (for a pic) http://www.vinculum.com/downloads/samples/vpic-hello.zip has a function for writing to the device, and writes a character at a timelike this

WARNING PIC CODE NOT ARDUINO DO NOT USE THIS AS IS

void serial_sendbyte(char TX_BYTE)
{
if (FLOW_CONTROL_ENABLED == 0x01)
{
while (portc & _CTS); // Wait for CTS# to become active (low)
}
while (!txsta.TRMT); // Wait for TSR to be empty
txreg = TX_BYTE; // Move byte to send into TXREG
txsta.TXEN = 1; // Start transmission
while (!txsta.TRMT); // Wait for TSR to be empty - indicates sending is complete
}

_CTS is a mask to get the reading from portc for the pin they are labelling CTS#

CTS# (connects to RTS# on TTL cable)
RTS# (connects to CTS# on TTL cable)

and this function is called to send each individual byte - both when sending commands and sending values

eg:

serial_sendbyte('O'); // Send 'O'
serial_sendbyte('P'); // Send 'P'
serial_sendbyte('W'); // Send 'W'
serial_sendbyte(' '); // Send ' '
serial_sendbyte('h'); // Send 'h'
serial_sendbyte('e'); // Send 'e'
serial_sendbyte('l'); // Send 'l'
serial_sendbyte('l'); // Send 'l'
serial_sendbyte('o'); // Send 'o'
serial_sendbyte('.'); // Send '.'
serial_sendbyte('t'); // Send 't'
serial_sendbyte('x'); // Send 'x'
serial_sendbyte('t'); // Send 't'
serial_sendbyte(0x0D); // Send carriage return

to open file to write - and then waits for a 5 byte response ("D:>" + 0x0D)

and writing to the file is done like this

serial_sendbyte('W'); // Send 'W'
serial_sendbyte('R'); // Send 'R'
serial_sendbyte('F'); // Send 'F'
serial_sendbyte(' '); // Send ' '
serial_sendbyte(0x00); // Send 0x00 - Number of bytes to write MSB
serial_sendbyte(0x00); // Send 0x00
serial_sendbyte(0x00); // Send 0x00
serial_sendbyte(0x0E); // Send 0x0E - Number of bytes to write LSB
serial_sendbyte(0x0D); // Send carriage return
serial_sendbyte('H'); // Send 'H'
serial_sendbyte('e'); // Send 'e'
serial_sendbyte('l'); // Send 'l'
serial_sendbyte('l'); // Send 'l'
serial_sendbyte('o'); // Send 'o'
serial_sendbyte(' '); // Send ' '
serial_sendbyte('W'); // Send 'W'
serial_sendbyte('o'); // Send 'o'
serial_sendbyte('r'); // Send 'r'
serial_sendbyte('l'); // Send 'l'
serial_sendbyte('d'); // Send 'd'
serial_sendbyte('!'); // Send '1'
serial_sendbyte(0x0D); // Send carriage return
serial_sendbyte(0x0A); // Send line feed
serial_sendbyte(0x0D); // Send carriage return

and then checks for 5 byte response again ("D:>" + 0x0D)

What we need to do is write the single byte write routine that checks the handshake from the device for each byte, and then it should work more reliably.

I will look at this at some point, but do not have the time or the need at the moment (my usb memory stick project went away)

HTH
HTH

I don't think changing to printing characters individually is going to solve anything. I'll keep it as an idea for later though.

When I get the time I'm going to look into reading that prompt sent back from the VDIP via serial. I believe that is the correct way to do things. I was probably doing something wrong before and that is why it wasn't working.

The code you linked to above does check for the prompt by waiting until the PIC's Serial input buffer has 5 bytes in it. Then it waits an arbitrary 10 ms.

I'm going to try to specifically wait for the "D" ":" or ">" characters before writing again.

Something like this might work...

//goes after code that writes the line to the file
char c = Serial.read();
   while ( (c != 'D') && (c != ':') && (c != '>') ){c = Serial.read()}

Ok, I think I figured it out...

This is what I get for not reading all the documentation.

SoftwareSerial (and AFSerial) have a read() that returns a char. I expected hardware serial to do the same but it's read() returns an int. This is why my conditional code before didn't work.

So, I am going to try...

Serial.flush() //empties the arduino's serial input buffer (128 bytes long btw)
//do the file writing stuff here
while (Serial.available() < 5){} //sit in a loop and wait for their to be 5 bytes in the serial input buffer
//the 5 bytes are the prompt D:\> and a carriage return.

One could also do a conditional for the int equivalent of the prompt, but i'm not sure how to do that. Ideas?

I think you may end up having to do both. Maybe they are being overly cautious, but given that they made the device they should have a good idea of what is a reliable way to write to it. This code was not available when i first got the example running last year or i probably would have bitten the bullet and done it then.

People have been having problems with writing consistently to files - occasional fails in the writing of numbers etc... even with long delays between writes - I suspect the only way to get it to work solidly is to implement the handshaking, but see what you find once you are waiting for the prompt.

I added a 2 second delay between line writes...

I'm starting to think there is something wrong with my digit counting code:

int numberofdigits2(int value){ 
  
 int digits = 1;
 while (value/10 > 0){
  value = value/10;
  digits++; 
 }
 return digits; 
}

am I having a brain fart?

I found this on the forums:

long int charsInVar(long int i)
{
  long int r = 1;
  long int temp;
  temp = i;
  while (temp >= 10)  //tanks to d mellis and nick for this bit
  {
  r++;
  temp/=10;
  }

return r;
}

Hey guys,

I've been working on a data logging system with the Vdrive 2 and we actually called vinculum and asked about taking control of the flow from inside of my own micro-controller. Apparently that can not be done on the vdrive 2 through Cts Rts. instead you have to use what they call Xon/Xoff controls(BTW if you break the hardware handshake the vdrive2 will simply continually look for a monitor ). I haven't had time to look into Xon/Xoff but according to the tech, we would have to write special firmware to handle non standard characters.

I like the while loop idea, as an interim to flow control, it seems like it has promise if your not concerned with time between writes(or you are actually logging the write times).

as far as i can tell the issue arises from the two sources one for the vdrive's serial buffer(which we have no control over) and the other from the arduino's baud rate. Vinculum is claiming that we need to increase the baud rate of the arduino and then their buffer will clear faster with the hardware handshake enabled. I don't think the arduino can go much faster if at all from the 9600 baud, and I'm not sure if I buy that doing this will actually help the problem, but that's next on my list to research and test as soon as i get some free time.

Carlo and Don

The hardware serial can go much faster than 9600 - from the Serial.begin() documentation

For communicating with the computer, use one of these rates: 300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, or 115200

I used 9600 when I first tried it as I was avoiding implementing the flow control so thought it best to send stuff fairly slowly.

Did they have a speed that they recommended as being a 'natural' one for the vdip?

I looked at their pic code again - it tries to use 115200, 57600, 19200 and if none of those are possible defaults to 9600.

No, they didn't. They did say that the vdrive2 defaults to 9600 baud for reverse compatibility. I believe we are going to have to either change the boot loader or send it a message during setup to change that rate. there is something in the host control documentation about setting the baud rate with dos commands.

here is the firmware documentation which discous's dos comands, this should be valid for all Viniculum device sense they all use the same firmware.
page 29 covers changing the baud rate.
http://www.vinculum.com/documents/fwspecs/Vinculum%20Firmware%20User%20Manual%20V2.4%20Rev%203.pdf

I also just found a guide to changing/reprogramming the firmware, in here it talks about picking a baud rate for programing and says a 1m is the most optimum baud rate. I'm sure they were talking about changing the code on the vdip at 1m not writing to a usb device but it does say that flash memory can not go faster then 1m. so that might be our speed limit. anyways thats around page 5
http://www.vinculum.com/documents/appnotes/ANVNC1L-01-VinculumBootloader.pdf

I think everything we need to know to figure this out is in those two documents, its just a matter of sifting through them now.
So it may need to actually be done in the boot loader itself.

Sorry for the late response, I've been side tracked by finals.

Don

this should be valid for all Viniculum device sense they all use the same firmware.

Ah, no they don't. There are several flavors of the firmware (a glance at the firmware download page shows 6), and I wouldn't count on them being 100% compatible.

Most likely the stuff we'll deal with has the VDAP firmware, but check. The way things are changing, I'd make sure the version number of the firmware and the version number of the firmware documentation match as well.

-j

I did some testing tonight to see how much I could force through the device without error. If I use a 60 ms delay between writes I get almost no errors. This translates to about 112 milliseconds between writes. ~9 times a second isn't good at all for logging a moving vehicle. For reference ~10 Hz is the rate you would expect from OBD II. OBD II is considered to have a fairly low sample rate.

Next I'll try out tweaking the baud rate, i guess.

I know no on bumps threads on this forum...but has anyone come up with anything new for the VDIP? Got it working reliably?