Go Down

Topic: something faster than serial??? (Read 764 times) previous topic - next topic

taterking

Oct 15, 2019, 07:31 am Last Edit: Oct 15, 2019, 07:37 am by taterking
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?
Building robots to take over the world.

PerryBebbington

#1
Oct 15, 2019, 07:56 am Last Edit: Oct 15, 2019, 07:58 am by PerryBebbington
Quote
I have a robot that plays a drum set. she works wonderfully.
Nice one! ++Karma;

Please post a video of her playing :)

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.

sterretje

#2
Oct 15, 2019, 09:25 am Last Edit: Oct 15, 2019, 11:29 am by sterretje
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.

Code: [Select]
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

Code: [Select]
Lapsed time: 4
Lapsed time: 4
Lapsed time: 4
...
...
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

Robin2

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
Two or three hours spent thinking and reading documentation solves most programming problems.

david_2018

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.

taterking

#5
Oct 15, 2019, 06:11 pm Last Edit: Oct 15, 2019, 06:16 pm by taterking
here is a video of the bot.
https://youtu.be/rWCM-tnX_bk

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:
Code: [Select]
//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.
https://engeeknyer.wordpress.com/2012/01/27/direct-access-to-avr-registers/

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
   
Building robots to take over the world.

Robin2

#6
Oct 15, 2019, 06:28 pm Last Edit: Oct 15, 2019, 06:30 pm by Robin2
but when i comment out this line:
Code: [Select]
//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
Two or three hours spent thinking and reading documentation solves most programming problems.

wvmarle

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.
Quality of answers is related to the quality of questions. Good questions will get good answers. Useless answers are a sign of a poor question.

cattledog

Quote
here is a video of the bot.
https://youtu.be/rWCM-tnX_bk
Fabulous work. +1

Blackfin

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.

wvmarle

That's one really cool project indeed!
Quality of answers is related to the quality of questions. Good questions will get good answers. Useless answers are a sign of a poor question.

PerryBebbington

#11
Oct 15, 2019, 07:45 pm Last Edit: Oct 16, 2019, 12:59 pm by PerryBebbington
Taterking, thanks for posting the video, that is AWESOME !!!!  :) :) :) :) :)
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:

Quote
calling Serial.available()
Is not the same as:
Code: [Select]
//while{Serial3.available( so stuff );}
 As has already been mentioned that while makes a huge difference.

I suggest you try instead:

Code: [Select]
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:
Code: [Select]
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 :-)

wvmarle

Code: [Select]
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:

Code: [Select]
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
}
Quality of answers is related to the quality of questions. Good questions will get good answers. Useless answers are a sign of a poor question.

westfw

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


Code: [Select]
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;
    }

taterking

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.


Building robots to take over the world.

Go Up