Menu

Beware of WAIT code-bloat!

Help
joe rocci
2009-07-30
2013-05-30
  • joe rocci

    joe rocci - 2009-07-30

    Here are some interesting observations about the size of the assembly code (and by extension, the size of the object code) for various ways of using the WAIT statement. All were generated on a PIC18F877A specified at 20MHz:

    (I hope the text formatting comes out readable after this is Posted...here goes!...)

    Example 1) "WAIT 1 us":

    movlw    2
        movwf    DELAYTEMP
    DelayUS1
        decfsz    DELAYTEMP,F
        goto    DelayUS1

    Example 2) "WAIT 1000 us"

    movlw    255
        movwf    DELAYTEMP
    DelayUS1
        decfsz    DELAYTEMP,F
        goto    DelayUS1
        movlw    255
        movwf    DELAYTEMP
    DelayUS2
        decfsz    DELAYTEMP,F
        goto    DelayUS2
        movlw    255
        movwf    DELAYTEMP
    DelayUS3
        decfsz    DELAYTEMP,F
        goto    DelayUS3
        movlw    255
        movwf    DELAYTEMP
    DelayUS4
        decfsz    DELAYTEMP,F
        goto    DelayUS4
        movlw    255
        movwf    DELAYTEMP
    DelayUS5
        decfsz    DELAYTEMP,F
        goto    DelayUS5
        movlw    255
        movwf    DELAYTEMP
    DelayUS6
        decfsz    DELAYTEMP,F
        goto    DelayUS6
        movlw    135
        movwf    DELAYTEMP
    DelayUS7
        decfsz    DELAYTEMP,F
        goto    DelayUS7

    Example 3) "DIM time as word"
                         "time = 1000"
                         " Wait time us"

    movlw    232
        movwf    TIME
        movlw    3
        movwf    TIME_H
        movwf    SysWaitTempUS_H
        movf    TIME,W
        movwf    SysWaitTempUS
        call    Delay_US

    It seems that the code produced by WAIT is most compact when its argument is a byte-size literal, as shown in Example 1. For anything larger than a byte argument, the argument should be assigned to a word-size variable which is then passed to WAIT, as shown in Example 3 If you pass WAIT a word-size literal, the generated code can become quite huge, as shown in Example 2. Example 2 uses 500 bytes more code memory than Example 3

    BEWARE!!!

    Joe

     
    • joe rocci

      joe rocci - 2009-07-30

      PS:

      My bad typing in the part I used for my tests....it's a 16F877A, not an 18F877A

      Joe

       
    • joe rocci

      joe rocci - 2009-07-30

      Also my bad....

      I mean't to say that "WAIT 10000 us" would use 500 bytes more memory than the "WAIT time us" equivalent.

       
    • Hugh Considine

      Hugh Considine - 2009-08-08

      GCBASIC now has a longer delay, which it will insert when more than 770 clock cycles of delay are required. This should help with the bloat!

       
  • Alistair George

    Alistair George - 2009-11-28

    Trying to save space on PIC10f I did the following:
    sub ledwait
    wait 1 sec
    return
    Calling ledwait from main results in underflow error.
    Only way to use wait, is to put 'wait 1 sec' on every occurrence which is very expensive in memory resources.
    Any suggestions?
    Al

     
  • Hugh Considine

    Hugh Considine - 2009-11-28

    The problem there is that the 10F chips only have a very limited stack. There are 2 levels - calling ledwait from main uses a level, calling delay_s (the second delay sub) from ledwait uses another level, and the call from delay_s to delay_ms (the millisecond delay sub) uses a third. Since there are only 2 stack levels, there will be an overflow when delay_ms is called, and then an underflow when it tries to return from ledwait to main.

    The only solution to this is to not use the second length delay from a subroutine on the 10F. I'd really suggest upgrading to a 12F6xx if you want to program a small PIC with GCBASIC - it will program a 10F but there are many limitations.

     
  • Alistair George

    Alistair George - 2009-11-28

    Hmm, just wondering if PIC10F cpu defined that delayms could be reentrant with a counter to bring its effective delay the same as calling the ms delay sub?
    Thanks vm for the info. I'll work around it somehow, as the 10f is needed for one application we are doing here.
       

        sub ledwait

        'provides one second delay for 10f family
        count=0
        do
        wait 100 msec
        until ++count=11
        return

     
  • Alistair George

    Alistair George - 2009-11-28

    sri count=10

     
  • Hugh Considine

    Hugh Considine - 2009-11-28

    GCBASIC doesn't allow the ++ style increment used in C, so you'd have to increment count on the last line of the loop:

        sub ledwait
    'provides one second delay for 10f family
    count=0
    do
    wait 100 msec
    count += 1
    until count = 10
    end sub

    Another alternative is to use Wait 1000 ms. It'll generate almost the same amount of code as Wait 100 ms (one extra instruction to be exact), since the millisecond delay always uses 16 bits to store the delay length:

        sub ledwait
    'provides one second delay for 10f family
    wait 1000 ms
    end sub

     
  • kent_twt4

    kent_twt4 - 2009-11-28

    There is no context as to how the waits are being implemented.  But if Port pins are being toggled, then one could use something like:

        PulseOut GP1, 1000 ms

     
  • Mark D.

    Mark D. - 2010-06-23

    I am experiencing bizarre behavior using a ms wait and timer1 in a program on a PIC 16F690.    If i increase my wait from 25 ms to 75 ms my pulse length measurement bounces around all over the place.  does not make any sense since it has no functional relation to my measurement code where I start and stop timer1.  Any ideas on this?

    Thanks,
    Mark

    **********************************************************code

    '  initialize timer, prescaler 8
    initTimer1 OSC, PS1_8
    Dper = 0
    period = 0
    perL = 0
    perH = 0

    Do    'Main program Do
     
           per1 = period 
          
           clearTimer 1
           wait until pulseIn on

           StartTimer 1
         wait until pulseIn off

       StopTimer 1
       perH = TMR1H
       perL = TMR1L

       if perH < 11 then
         period = 0
       end if    
       if perH > 10 then
           period = ((perH-11)*256 + perL)/2
         end if 

     
           
         If period >= per1 then
           Dper = period - per1
         end if
         If period < per1 then
        Dper = per1 - period
         end if 

            
         set led0 off
          set led1 off
         set led2 off
         set led3 off
            
         if Dper > 3 then
         set Led0 on
         if Dper > 6 then
         set led1 on
         if Dper > 10 then
             set led2 on
             if Dper > 15 then
             set led3 on
             end if
         end if
         end if
         end if    
            
           wait 25 ms     

    loop

     
  • Frank

    Frank - 2010-06-24

    Maybe a 75ms delay tends to end some time in the middle of a pulse and you're pulse timing code sees a one and starts timing from somewhere in the middle. If you add a line to check the pulseIn line is low first like this -

    clearTimer 1
    wait until pulseIn off
    wait until pulseIn on
    StartTimer 1
    wait until pulseIn off
    etc
    

    the code will wait until there is a rising edge on pulseIn before starting its measurement. You might miss measuring some pulses though if thats whats happening.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.