something faster than serial???

i have a project that relies on millis() timers to trigger several motors at precise timing. more specifically i have a robot that plays a drum set. she works wonderfully.

i have also developed a remote control for my machine that plugs in with a serial connection. both my robot and remote are using mega boards.

calling Serial.available() with the new remote slows down the robot enough to play beats out of time even when data is not being transmitted.

I have already limited the serial.available() calls to opportune moments in the program with no success.
with troubleshooting i have determined this is not a programming issue

is there any other method or modules that make the reading and writing process faster and more seamless for communication between two boards?

I have a robot that plays a drum set. she works wonderfully.

Nice one! ++Karma;

Please post a video of her playing :slight_smile:

You might be able to improve on the speed of reading and writing to the serial port if you write your own code to access the serial registers. You will need to study data sheet for the ATMega micro controller and learn how to manipulate the registers to read and write data to serial.

You might want to measure how long Serial.available() takes to execute; set an output pin high just before you call it, set it low again just after and use an oscilloscope on the pin to measure the time it takes. If nothing else, this will give you an indication of what you are working with in terms of timing changes you need to achieve.

It is possible that your creation is using the processor to its maximum capability, in which case the answer might be a more powerful one.

Is 4..8 microseconds (or less) that critical? If you don't have a scope or logic analyser, below code can give you a ballpark figure.

void setup()
{
  Serial.begin(57600);
}

void loop()
{
  uint32_t startTime = micros();
  if (Serial.available() > 0)
  {
    Serial.write(Serial.read());
  }
  uint32_t duration = micros() - startTime;
  Serial.print("Lapsed time: ");
  Serial.println(duration);
}

Result without sending anything from PC

Lapsed time: 4
Lapsed time: 4
Lapsed time: 4
...
...

taterking:
calling Serial.available() with the new remote slows down the robot enough to play beats out of time even when data is not being transmitted.

Without seeing your program it is hard to advise.

You have not even told us what baud rate you are using.

...R

You mention reading and writing to serial, but your question focuses on Serial.available() , which does neither of those, but only tells you how many bytes of data are in the serial buffer. Your problem is more likely in how you are reading or writing to serial, which can block execution of other code, depending on how you are doing it.

here is a video of the bot.

Yes, the robot is pushing the limits of the board so now proficiency is very important.
i didnt post code because its over a thousand lines.

the problem of missing timing happens when no serial data is sent!
but when i comment out this line:
//while{Serial3.available( so stuff );}
the problem is solved.

I have a feeling there must be something extra happening in the available() function.
I have looked into perry's advise and googled some info about reading the registers directly.

i dont care about the length that available returns. hopefully it's simple enough to check the one first register. thanks perry. hope you enjoy the video.
i appreciate the other comments as well.

later I will post whether or not this approach helps

taterking:
but when i comment out this line:

//while{Serial3.available( so stuff );}

the problem is solved.

I have a feeling there must be something extra happening in the available() function.

It's much more likely the fault of the WHILE - but without seeing our program ....

WHILE and FOR must be used with great restraint in a program that needs to be responsive.

How come you have "over a thousand lines" of code before you ran into this problem?

And if you think I may be too lazy to study 1000 lines of code you are probably right. Maybe you can write a shorter program that illustrates the problem.

...R

If you write faster to Serial than the bytes are transmitted out, it will block. Likewise if you try to do a Serial.print() with a string longer than the buffer can hold (32 bytes, iirc) it blocks until enough bytes have been transmitted that the remainder fits. So don't try to send more than can be transmitted.

Serial.available() should be really fast, anytime. I seriously doubt that this specific function can cause any significant delays in your code.

Even at 2400 bps or something likewise silly slow the data may come in slowly but the reading by Serial.read() is very fast, as by the time Serial.available() returns a value of 1 or higher those bytes have been received already, and are stored in memory. The Serial.read() basically just copies it from there.

OTOH your data handling code is as fast as you make it. If that's inefficient (e.g. wait for the next byte to arrive, instead of buffering and moving on) you will see issues.

A line like while (Serial.available()) { } is normally redundant as normally there will be no more than one byte in the buffer when you read it. Unless Serial is very fast (1 Mbps or so) and your program has lots and lots of other things to do, then you may have more bytes in the buffer. Even so, the while loop is probably not the way to go about it.

here is a video of the bot.
https://youtu.be/rWCM-tnX_bk

Fabulous work. +1

cattledog:
Fabulous work. +1

++1. That was very cool.

taterking, if you want to post your code we can try to help.

I suspect you'll be able to do what you want but like Robin2 said, it's hard to help when you can't examine the problem.

That's one really cool project indeed!

Taterking, thanks for posting the video, that is AWESOME !!!! :slight_smile: :slight_smile: :slight_smile: :slight_smile: :slight_smile:
Have some more Karma from me!

Back to your problem, I think you've been given most of the answer, but first of all it is really important when asking for help to be specific and accurate when posing the question;
This:

calling Serial.available()

Is not the same as:

//while{Serial3.available( so stuff );}

As has already been mentioned that while makes a huge difference.

I suggest you try instead:

if (Serial3.available < 0) {
   //read 1 byte only, save it, check if anything needs to be done with the byte and bytes previously received before then return to the main program
}

You might even just save the byte, set a flag to say it's there and then return without doing anything with it, the read the flag when there's more time available and do something then.

EDIT: As wvmarle points out below, the code above will not work. What I meant to post was:

if (Serial3.available > 0) {
   //read 1 byte only, save it, check if anything needs to be done with the byte and bytes previously received before then return to the main program
}

wvmarle ++Karma; for spotting my silly mistake :slight_smile:

PerryBebbington:

if (Serial3.available < 0) {

//read 1 byte only, save it, check if anything needs to be done with the byte and bytes previously received before then return to the main program
}

That will never work.
Better chance:

if (Serial3.available()) {
   //read 1 byte only, save it, check if anything needs to be done with the byte and bytes previously received before then return to the main program
}

So I checked, and Serial.available() should actually be pretty cheap:

int HardwareSerial::available(void) {
 312:   fc 01           movw    r30, r24
  return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE;
 314:   91 8d           ldd     r25, Z+25       ; 0x19
 316:   22 8d           ldd     r18, Z+26       ; 0x1a
 318:   89 2f           mov     r24, r25
 31a:   90 e0           ldi     r25, 0x00       ; 0
 31c:   80 5c           subi    r24, 0xC0       ; 192
 31e:   9f 4f           sbci    r25, 0xFF       ; 255
 320:   82 1b           sub     r24, r18
 322:   91 09           sbc     r25, r1
}
 324:   8f 73           andi    r24, 0x3F       ; 63  (clever and fast "divide" !)
 326:   99 27           eor     r25, r25
 328:   08 95           ret
  :
  :
   while (Serial2.available() <=  0) {
 a52:   85 ea           ldi     r24, 0xA5       ; 165
 a54:   92 e0           ldi     r25, 0x02       ; 2
 a56:   5d dc           rcall   .-1862          ; 0x312 <HardwareSerial::available()>
 a58:   18 16           cp      r1, r24
 a5a:   19 06           cpc     r1, r25
 a5c:   d4 f7           brge    .-12            ; 0xa52 <main+0x228>
 a5e:   82 e4           ldi     r24, 0x42       ; 66
      continue;
    }

OK so today with everyone's advice steering me away from serial.available() as a possible problem, I found and corrected my issue. everyone was correct.... it actually wasn't a problem with reading the serial buffer. it was a button problem on the new remote control panel causing the timing issue. pry would have taken forever for me to find the problem without advice that i was looking in the wrong direction

I have also re written my serial.read section of code based on wvmarle's serial explanation of speed and
reading serial data. i'm used to serial writing slowing things down and didn't consider that reading is faster when it's buffered.

Anyways, now my new control panel speaks magically to the bot with no hesitation.

karma for everyone donating info i used to troubleshoot my connection and write my final code!
Thank you.

Sounds great, good luck with completing your project!