Pages: [1]   Go Down
Author Topic: Strange Communication Delay in Serial Bus, mitigated by adding Serial.print().  (Read 1390 times)
0 Members and 1 Guest are viewing this topic.
Finland
Offline Offline
Newbie
*
Karma: 0
Posts: 45
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi. I am working with a rs485 project. Been writing a protocol to suite my needs. Nice progress done too.. Anyway..
My protocol sends a data, to be precise, non-ascii data (or partially ascii) over rs485. This data contains a dual header: 1 header with checksums and sender's id and receiver's id. If checksum doesn't match, receiving is ignored (as only one can talk at a time on rs485 and multiple devices cannot be answering that checksum didn't match and it just might be that it's the receiver's id that has malformed, even though it's double sent)..
And then there's the message part that can also be checksumed. If checksum of message is not correct, receiver can inform that we didn't quite get that..

Answering is a 2 bytes, actually 4 is sent.. But 2 identical are needed the receipt to be complete. Very simple fixed bytes, 1 one value that allows an answer in form of message sending described before..
---
So this is the theory, and I've got it working. I have also tryied to get speeds up, so I am using 115200.. To simplify writing of my code, I've created similar system as serial messaging is, but a bit more complex..
And also a library for receipts..

So, when a command is received, it's parsed to parts: command and x arguments. Then this command is checked agains known commands and then void set for that command is executed..
Most of my commands, especially during this test phase, just have simple content: sendReceipt(ACK);

When I watch the process from my computer, I see what my master program is asking from devices.. And then it acts upon the answers, possibly asking more or starting the questioning from the beginning..
And now we come the strangest point..

Getting a receipt for some commands takes much longer time. I was first thinking that it's because they are in the command stack as last and strcmp is done for every other command until this point is reached; no..
It wasn't that. Then I added this before sendReceipt(ACK); :
Code:
Serial.print("Received command X - now sending receipt..\r\n");
and another similar to this debug line after sendreceipt.. As I wanted to see
if it's my receipt function that eats time.. It isn't. My master program received receipt lightning fast after I added these debug lines. I removed the later line, so the void starts with Serial.println.. And it's still fast. I remove it.. And a major slowdown..

Just wondering.. What is causing this? I would think that sending data to serial would slow down instead of speeding up..
« Last Edit: January 12, 2013, 03:35:53 am by jake1981 » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 11
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I would need to see the rest of your code to be sure, but something similar happened to me with some serial communication.

Essentially, I didn't have a long enough delay in my serial receive function. I had a serial interrupt handler function that would get called before my loop() was handled if there was serial data on the line. In that function, I had a while loop checking whether Serial.available() (or something like that) and processing the data as it came in, and what would happen is that when there wasn't a byte immediately available, it would pop out of the function and run loop() again. As soon as I added a delay(1) inside that loop, it gave enough time for the next byte to arrive, and then it wouldn't pop out of the function, but would keep processing until there was genuinely no more data to be read. So, if something similar is occurring with your system, the Serial.print() creates enough of a delay that it allows more data to come in, allowing your Serial.available() to evaluate to true and continue processing.

Obviously, since I haven't seen your code, all I can do is speculate. Post your code, and we can help you debug more effectively.

Also, a bit of friendly advice. You may get more responses if your subject lines were more descriptive. Say, in your case, "Strange Communication Delay in Serial Bus, mitigated by adding Serial.print(). WTF" Also, a TL;DR is always helpful. smiley
Logged

Finland
Offline Offline
Newbie
*
Karma: 0
Posts: 45
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sounds reasonable. I'll try that a bit later..

Maybe even use another way, as I wouldn't really want to add a delay.. Get millis() when there is a byte available and check again when millis() differences that value..

If you wish, I can send you my full source code, but it's a mess as this project is not even nearly complete smiley
But if you want it, send me your email address as a private message and I'll gladly send you my project files, although, you might not be able to do a lot with it if you don't have all the similar hardware-

What is TL;DR ?
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17294
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Often a problem using RS-485 external translator chips on an arduino using the hardware serial library is the need to have a dedicated output pin to flip the translator chip from rec mode to tx mode and then back to rec mode any time you wish to send something out the link, and having to control this output bit in your sketch independent of the hardware serial library. And as the hardware serial uses software buffering and interrupts to output characters this can cause timing problems such that you chop off one or more of the output characters. This problem would be somewhat baud rate dependent but there are crude solutions like adding a delay right after sending data but before you switch the RS-485 chip to rec mode, but too long a delay could chop off any quick responding rec data coming in from a slave.

 So show some code where you are sending data and controlling the RS-485 direction bit.

Lefty
Logged

Finland
Offline Offline
Newbie
*
Karma: 0
Posts: 45
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Okay. Here's some:

Code:
int rs485read(int msDelay) {
  unsigned long roundrobin, timeout, mNow = millis();
 
  roundrobin = timeout = mNow + msDelay;
  if ( roundrobin > mNow ) roundrobin = 0;
 
  if ( roundrobin != 0 )
    while ( millis() > roundrobin )
      if ( Serial1.available() != 0 )
        return Serial1.read();

  while ( millis() < timeout ) 
      if ( Serial1.available() != 0 )
        return Serial1.read();
 
  return -1; 
 
}

void rs485write(unsigned char sym) {
  while ( Serial1.available() != 0 )
    Serial1.read();
  digitalWrite(RTS, HIGH);
  Serial1.write(sym);
  Serial1.flush();
/*  delayMicroseconds(85);*/
  digitalWrite(RTS, LOW); 
}

void rs485sendBuf(unsigned char *symbols, int size) {
  while ( Serial1.available() != 0 )
    Serial1.read();
  digitalWrite(RTS, HIGH);
  Serial1.write(symbols, size);
  Serial1.flush();
/*  delayMicroseconds(120);*/
  digitalWrite(RTS, LOW); 
}
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17294
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your use of the serial.flush command does help as that effectively delays the sketch until the hardware serial library software transmit buffer is emptied, but as the hardware UART still has a single character hardware buffer, it's still possible to chop off the very last character you wish to send, hence the possible need for a delay of at least one full character time (at the baud rate being used) before outputting the direction control output bit.

Lefty
Logged

Finland
Offline Offline
Newbie
*
Karma: 0
Posts: 45
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Oh..

Code:
#define RTS 9

unsigned long cmillis, lastread, nextscan, roundrobintimer = 0;

setup partially:
Code:
 // Setup serial output
  Serial.begin(115200);

  // Setup rs485
  digitalWrite(RTS, LOW);
  pinMode(RTS, OUTPUT);
  digitalWrite(RTS, LOW);
  Serial1.begin(115200);
  Serial1.flush();

  setupCommands();

  setupGraphics();

  drawWindow();
  drawScreen();
  nextscan = millis() + 2000;
  lastread = millis();

loop:
Code:
void loop() {
  cmillis = millis();

//  if ( lastread != cmillis ) {
    while ( Serial1.available() != 0 )
      COM.receive(Serial1.read());
//    lastread = millis();
//  }

  if (( roundrobintimer != 0 ) && ( cmillis < roundrobintimer )) roundrobintimer = 0;
  if (( infoRoundRobin != 0 ) && ( cmillis < infoRoundRobin )) infoRoundRobin = 0;
  
  if (( infoRoundRobin == 0 ) && ( infoTimer != 0 ) && ( cmillis > infoTimer )) {
    drawBottomBar();
    infoTimer = 0;
  }

  if (( roundrobintimer == 0 ) && ( cmillis > nextscan )) {
    if (!loginInProgress) readFingerPrint();

    roundrobintimer = nextscan;
    nextscan = cmillis + 700;
    roundrobintimer = nextscan > roundrobintimer ? 0 : roundrobintimer;
  }
}
Logged

Finland
Offline Offline
Newbie
*
Karma: 0
Posts: 45
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So to be sure.. I should add some microsecond delay.. Damn it's hard to calculate.. if 115200 baud rate is used, 115200 bytes is transferred in a second, or is it bits?
What is the symbol rate at 115200..?
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17294
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So to be sure.. I should add some microsecond delay.. Damn it's hard to calculate.. if 115200 baud rate is used, 115200 bytes is transferred in a second, or is it bits?
What is the symbol rate at 115200..?

Character rate is 1/10 the baud rate when using 8 bit/one start/one stop bit configuration.

Lefty
Logged

Finland
Offline Offline
Newbie
*
Karma: 0
Posts: 45
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So in 1 second 11520 bytes is sent..? That's quite a lot.. Sure it ain't bits?
Logged

Forum Administrator
Milano, Italy
Offline Offline
Sr. Member
*****
Karma: 23
Posts: 292
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


1 sec = 1000 msec = 1000000 usec

in 1 sec (1000000 usec) I send 115200 bits so the time to send 1 bit is:

1000000 / 115200 = 8.68055 usec

to send a complete frame (1 start + 8 data + 1 stop) of 10 bits we need:
 8.68055 * 10 = 86.8055 usec

If I did the calc right a delayMicroseconds(87) should be enough.

Logged

C.

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17294
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


1 sec = 1000 msec = 1000000 usec

in 1 sec (1000000 usec) I send 115200 bits so the time to send 1 bit is:

1000000 / 115200 = 8.68055 usec

to send a complete frame (1 start + 8 data + 1 stop) of 10 bits we need:
 8.68055 * 10 = 86.8055 usec

If I did the calc right a delayMicroseconds(87) should be enough.



Yea but I though I've read that delayMicroseconds has 4usec step resolution so maybe 91 or 92 would be a more conservative value to use?

Lefty
Logged

Finland
Offline Offline
Newbie
*
Karma: 0
Posts: 45
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks. 92 microsecond delay still is very short delay, so I'll use that..
Logged

Pages: [1]   Go Up
Jump to: