Pages: [1] 2 3 4   Go Down
Author Topic: Why is there a delay at the end of void Loop?  (Read 4576 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 43
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I hope this is the right to place to ask this ..

I was testing the speed of pin toggling and discovered that relying on void loop{} is actually slower than placing a 'goto back to start' to repeat the loop.
Here are the two versions:
Code:

#define L_PINDEF 0  // digital latch pin #8 (portb)
#define LATCH_ON() PORTB |= _BV(L_PINDEF)
#define LATCH_OFF() PORTB &= ~_BV(L_PINDEF)

void loop() {
  start:
  LATCH_ON();
  LATCH_OFF();
  LATCH_ON();
  LATCH_OFF();
 goto start;
} // with goto

void loop() {
  LATCH_ON();
  LATCH_OFF();
  LATCH_ON();
  LATCH_OFF();
} // without



The scope says 880Khz to repeat cycle without goto:



And 1.6MHz to repeat cycle with goto:



Any ideas why this may be?   smiley-confuse
Logged

Newcastle, England
Offline Offline
Sr. Member
****
Karma: 3
Posts: 489
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In hardware->arduino->cores->arduino lies the 'main.cpp' file:

Code:
#define ARDUINO_MAIN
#include <Arduino.h>

int main(void)
{
init();

setup();
   
for (;;)
loop();
       
return 0;
}


So after the function 'void loop()' has finished, the control returns to the above file. The above file then calls void loop() again, and so on. This takes time.

Onions.
Logged

My website: http://www.harryrabbit.co.uk/electronics/home.html Up and running now! (Feel free to look round!) smiley-grin

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

Nothing wrong with adding a goto then to squueze out an extra +- 500 ns?  smiley-grin
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 644
Posts: 50452
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Nothing wrong with adding a goto then to squueze out an extra +- 500 ns?
Yes, there is. There is no reason you can't use a more readable structure:
Code:
void loop() {
  while(1)
  {
    LATCH_ON();
    LATCH_OFF();
    LATCH_ON();
    LATCH_OFF();
  }
} // without goto
Logged

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

@KE7GKP: Doing some research into POV so I am looking for every extra Hz I can find.

While is defintely prettier   smiley

Although finding a label is easier in long code than tracing a {} pair? After several copy,paste procedures my indentation quickly goes to the dogs  smiley-sad
Logged

Leeds, UK
Offline Offline
Full Member
***
Karma: 0
Posts: 134
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

After several copy,paste procedures my indentation quickly goes to the dogs  smiley-sad

Auto-format will make short work of that for you smiley-wink
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 309
Posts: 26526
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
suspect that there is internal "housekeeping" to handle things like updating timers, running counters, pulsing PWM outputs, etc.  Arduino must have SOME of the "time slot" to handle those things.
There is no "time slot" - updating "micros" and "millis" is handled in interrupts or on-the-fly, and PWM outputs are handled by hardware.

To answer the original question, a simple "goto" will nearly always be faster than a "return from function" + "call to (same) function", but the latter won't get you despised by half the users who think that people who write "goto" in a C program should be drowned at birth.  smiley-razz
« Last Edit: June 26, 2011, 01:50:35 pm by AWOL » Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

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

@KE7GKP: Indeed there is a sensor to determine speed. I'm trying to get the maximum refresh rate as a math exercise which in turn would tell me how many LEDs at what speed can be considered.  An eventual POV calculator if you will. In the end project there will probably be no need to speed up the void Loop {}. Perhaps only to get the data read from the EEPROM a tad faster ..  smiley-wink

@AWOL: I was surprised to find goto in the reference actually. Is it a more recent addition or perhaps have I been in denial?  smiley
« Last Edit: June 26, 2011, 01:59:46 pm by JBMetal » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 644
Posts: 50452
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The goto statement has been part of C from the beginning, added to satisfy those people that barely got beyond BASIC programming, in my opinion. In 25 years of C/C++ coding, I've used goto exactly once, and that could have been avoided if I'd been thinking.
Logged

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

I see there is a performance hit for using functions though, them not being compiled inline and all that..   smiley-confuse
I wonder if goto can give a speed advantage there?
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 309
Posts: 26526
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
them not being compiled inline and all that..  
Have you examined the output from the compiler?
What evidence do you have to support your assertion?
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

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

I have had some interesting results posted on the POV math thread but there may have been some other factors involved. I'll quickly rewrite the code for both scenarios and see what the scope says ..
Logged

Seattle, WA
Offline Offline
God Member
*****
Karma: 11
Posts: 673
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ah!  Time to defend the lowly goto...

I was recently working on EtherCard::packetLoop, see tcpip.cpp, line 516.  Note the vast number of return statements.  Now I needed to add something in just before the method returned.  Doh!  So there are a few options at this point:

1. Put the code in before every return.
2. Refactor the whole thing to be a giant tangled mess of if/elses, even more than it already is.
3. Refactor even further to separate out into smaller methods.
4. Use a 'goto' in place of the returns, jumping to the new code just before the single return.

Generally, a goto is a good solution when there are a lot of error cases that need to halt further execution and you don't have exceptions available.
Logged


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

The results are in!  smiley

With goto statement 68KHz:


Using a function 63KHz:


Code snippet for goto:
Code:
void loop() {
  
  while (1)
  {
  
   goto ShiftNow;
   starthere:
   datab = 4;
  }
  
ShiftNow:  
   LATCH_OFF();
  SPI.transfer (scopedata);
  LATCH_ON();

  LATCH_OFF();
  SPI.transfer (dataa);
  LATCH_ON();
  
  LATCH_OFF();
  SPI.transfer (datab);
  LATCH_ON();
  
  LATCH_OFF();
  SPI.transfer (datac);
  LATCH_ON();
    
  LATCH_OFF();
  SPI.transfer (datad);
  LATCH_ON();
    
  LATCH_OFF();
  SPI.transfer (datae);
  LATCH_ON();
    
  LATCH_OFF();
  SPI.transfer (dataf);
  LATCH_ON();
    
  LATCH_OFF();
  SPI.transfer (datag);
  LATCH_ON();
  
  goto starthere;
}

Code snippet for function:
Code:
void ShiftNow()
{
    LATCH_OFF();
  SPI.transfer (scopedata);
  LATCH_ON();

  LATCH_OFF();
  SPI.transfer (dataa);
  LATCH_ON();
  
  LATCH_OFF();
  SPI.transfer (datab);
  LATCH_ON();
  
  LATCH_OFF();
  SPI.transfer (datac);
  LATCH_ON();
    
  LATCH_OFF();
  SPI.transfer (datad);
  LATCH_ON();
    
  LATCH_OFF();
  SPI.transfer (datae);
  LATCH_ON();
    
  LATCH_OFF();
  SPI.transfer (dataf);
  LATCH_ON();
    
  LATCH_OFF();
  SPI.transfer (datag);
  LATCH_ON();
}

void loop() {
  
  while (1)
  {
   ShiftNow();
  }

}

For more info on the testing parameters see http://arduino.cc/forum/index.php/topic,64615.msg471258.html#msg471258

PS: I personally wouldn't use goto unless I really needed to ..

EDIT: spelling
« Last Edit: June 26, 2011, 03:21:38 pm by JBMetal » Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 137
Posts: 6792
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

All of the typical infinite loop constructs ("while (1)", "for (;smiley-wink", goto, etc) end up producing a single branch instruction.
The delay "at the end of loop" in the original posting is the function return and call overhead.

See also: http://arduino.cc/forum/index.php/topic,4324.0.html for lots of discussion on generating the fastest possible square wave...
Logged

Pages: [1] 2 3 4   Go Up
Jump to: