This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Delay Loop in C51

Dear Friends,
How to create a delay loop in C51.Say for example I need a delay loop for 35mS.How to do this.I tried a code taken from this forum.It is
void delay(void)
{
unsigned long msdl;
msdl = 35L * 1000L;
while(--msdl)
{
_nop_();
}
}
Logically I think it should produce a 35mS delay code.But When I see in the Performance Analyzer window the delay produced is 0.547275 seconds.
Can anybody help me in solving this problem.
Thanx in Advance

Parents Reply Children
  • I often find it useful to have a delay loop that delays "at least this long", but where I'm not terribly concerned with the upper bound. Other times, I need a loop that waits exactly some amount of time. Different requirements call for different solutions.

    For times on the order of 35 ms, hardware timers are often useful. I find cycle-counting software schemes more useful for very small intervals.

    For the OP's question, you also have to account for the loop overhead. 35000 _nop_s will indeed take 35 ms (assuming 1 usec / instruction cycle). But it also takes time to decrement the loop counter, jump, and so on. Particularly with a 32-bit counter, this takes a significant amount of time compared to just the NOP instruction.

    The usual method is to normalize the timing loop by measuring (or calculating) the overhead for each trip around the loop, and adjusting the number of loops accordingly. As Erik points out, this normalization depends on details of how the code generator happens to work, and thus you might have to renormalize every time you change compilers or optimization levels. Write the delay loop in assembler, and at least you remain in control of exactly which instructions get used.

  • you might have to renormalize every time you change compilers or optimization levels.
    A litle detail, often forgotten:
    you might have to renormalize every time you upgrade the revision of your compiler, change compilers or optimization levels.

    Every compiler manufacturer (hopefully) strives to make the generated code more efficient for each revision. E.g. Keil could go through all generated compares and see if CJNE/CY or SUBB was the fastest approach. None of that would constitute optimization just a better conversion.

    Erik

  • "you might have to renormalize every time you change compilers or optimization levels."
    Or memory model, or...



    A 'C' compiler gives you absolutely no guarantee whatsoever that any particular source line(s) will generate any specific sequence of machine instructions [1].

    eg, the compiler may choose to put certain variables into registers. You have no control of this choice. It is quite possible that apparently unrelated changes elsewhere in your code could affect the compiler's choice of which variables go into registers.
    If this means that your delay loop counter moves from XDATA to a register (or vice-versa), the delay could easily change by a factor of two or more!

    I'm sure there are other examples - especially at the higher optimisation levels.



    [1] Apart from specific language extensions like _nop()_

  • ""you might have to renormalize every time you change compilers or optimization levels."
    Or memory model, or...



    A 'C' compiler gives you absolutely no guarantee whatsoever that any particular source line(s) will generate any specific sequence of machine instructions [1].

    eg, the compiler may choose to put certain variables into registers. You have no control of this choice. It is quite possible that apparently unrelated changes elsewhere in your code could affect the compiler's choice of which variables go into registers.
    If this means that your delay loop counter moves from XDATA to a register (or vice-versa), the delay could easily change by a factor of two or more!

    I'm sure there are other examples - especially at the higher optimisation levels.



    [1] Apart from specific language extensions like _nop()_"


    For the code given these issues can mostly be addressed by:
    1) Compile the delay code at optimisation level 0.
    2) Explicitly specify the memory space for your variables.
    3) Declare all variables as volatile.
    4) Write your own routines to increment and compare multibyte data types (hint: use a union) to avoid library calls.

    It would be an interesting exercise (well, I think so anyway) to run some tests along these lines using a really old version of the compiler and the latest. I'd put a really small bet on that one could come up with an implementation that would compile to the same code.

    I occasionally use the above techniques when I need to make sure that I don't see a large change in execution times between builds, and sometimes to generate faster code than the compiler. Yes, really.

    All: Please note, before responding with angry posts full of uppercase and aggressive HTML, that I do in the general case recommend the use of timers and assembler for delay loops.