Topic : Can't speed up a function

Forum : 8051

Original Post
Post Information Post
August 24, 2010 - 6:11pm
Guest

Perhaps someone can shed some light on this problem I'm having.

I am programming a AT89C2051 device to act as a simple function and delay controller. I have written the code and all works well with the exception of a delay function. I am not using the built in timers as my accuracy needs are not that critical.

So I wrote this:

void wait(void)

unsigned long x;
for (x = 0; x = 67000; x ++); /* should yield 67 ms delay */

void main(void)

my function....... ;
wait(); /* insert delay */
next function...... ;

My problem is that I cannot speed up this 'wait' routine. As written it will yield about 4 seconds of pause. I would like it down to about .5 seconds. I tried reducing the 67000 to 8000 but then my pause is around 20 us. Anything under ~67000 yields the same result. I have tried typing x as int, unsigned int, signed int, char, unsigned char, signed char with no difference. I can't seem to get the routine to run faster than 4 seconds delay.

I'm clocking the AT89C2051 at 11.0592 Mhz. This circuit is a slight mod from one I have used before and never saw this phenom. My previous circuit delayed about 65 ms. I tried using a new IC, crystal, caps, etc. with no joy.

Curious if anyone has any ideas on the cause. Oh, and I would rather not bother using the internal timers.

Thanks to all for listening!

Phil

Replies
Post Information Post
+1
0
-1
August 25, 2010 - 8:51am
Raisonance Support Team

Hi Phil,

The best thing to do is to look at the assembly code produced by the compiler.
Using a long is NOT a good idea, as it generates large code and is subject to strong optimizing patterns (which is probably what you observe).

The following is a better starting point, and is the code we use in our examples:

void delay(unsigned short microseconds)
{
    unsigned short i;

    while(microseconds--)
    {
        // The "magic number" 926 has been experimentally found to match a 1 ms period
        for(i = 926; i != 0; i--)
            ;
    }
}

In order to adjust the "magic" constant you need to perform a test with a scope to find the best value in your case.
Also be wary of compiler options: Changing them will make your code faster/slower.

Regards,

+1
0
-1
August 25, 2010 - 12:59pm
Guest

Bruno, Thank you so much for the explanation. Makes perfect sense.

I'll give that a try and see how I make out. One thing I did notice with the scope was that my waveform was not symmetrical. The high portion of my cycle was ~16ms and the low about ~9ms when cycling on and off using wait(). Very strange considering the timing parameter shouldn't arbitrarily change. But we all know about the uC phantoms, right?.

Thanks again Sir for that!

Phil

+1
0
-1
August 26, 2010 - 12:23pm
Raisonance Support Team

@pmetcalf,

Your waveform is probably not symmetrical because the calling code takes a longer time one way or another.
However these are constants, so I guess with larger delay values the problem will disappear as these delays will be negligible compared to the delay.

Regards,

+1
0
-1
August 28, 2010 - 7:11am
Guest

Try:

for (x = 0; x < 67000; x ++);

Cheers,

Bert

+1
0
-1
August 30, 2010 - 12:57pm
Guest

Thanks Bert!

Yeah that's the way I had it in my code. I just typed it in my message wrong.

All is working fine now!

Phil

+1
0
-1
September 9, 2010 - 10:33am
Guest

It is a fundamental feature of High Level Languages (HLLs) - including 'C' - that you have no control over nor guarantee of the execution timing! Hence you should not attempt to write timing loops in 'C' (apart, perhaps, from the most trivial "wait-a-bit" case)!

See:            8052.com/forum/read/162556

See also:    8052.com/forumchat/read/175943

+1
0
-1
September 9, 2010 - 1:03pm
Guest

Awneil, Yes I agree with that philosophy. Sometimes creating your own timing loops make the rest of the code unstable as designed. The code in this case is really rather simple and so I felt it prudent to just create a simple wait function. I have no need for interupts or timer functions in fact due to the simplicity.

The function is working quite nicely now. I decided to for-go the 'for' loop for a simpler 'while (x < y)'. About the worse case scenario for me now is that I lose a few ticks in between while my uC is figuring out what to do next. :)

Thanks for your input!

Phil

+1
0
-1
September 9, 2010 - 4:07pm
Guest

I think you missed the point!

The point is not about stability (although that's another issue, and applies whether you use LLL or HLL); the point is that you can never predict how long any piece of HLL code will take to run - so you can never create a known delay in a HLL.

If you want a known delay-loop wait, then you have to do it in assembler.

Of course, if the actual duration doesn't really matter, that's OK...

+1
0
-1
September 9, 2010 - 4:59pm
Guest

Agreed, and I caught your point first time around.

Awneil said "Of course, if the actual duration doesn't really matter, that's OK..."

That is the case in my design. Although I have opted for about 1 second delay, anything from .5 to 1.5 seconds would be fine. In practice, I have found the delay loop I am using to provide a delay of 960ms and it is quite consistent. Had I needed any more precision, I surely would have used the on-board timer.

Cheers