please dont rip this site

SX Microcontroller Delay Program Flow Methods

Also:

James Cameron says:

These SXs are just too fast, we often need a way to have the processor wait around for a while. A series of NOP (no operation) instructions is straightforward, but wasteful of instruction memory. A counted loop is the next common trick, because that lets us tune it.

But what are some of the more exotic ways to delay?

  1. ) The Common NOP, a delay for one instruction cycle

    DELAY   nop     ; delay one cycle
    

    Advantages: extremely simple, obvious, maintainable, scaleable.
    Disadvantages: is it really there for a reason?

  2. ) The Common Loop, four times the initial value

    DELAY   mov     W, #95          ;1    380 cycle delay
            mov     COUNTER, W      ;2
            decsz   COUNTER         ;3 7 11 15
            jmp     $-1             ;4 8 12 16
            
    

    Advantages: fairly simple, maintainable, scaleable up to 1024 cycles (counter initialized with zero); after that go for a nested loop.
    Disadvantages: costs one file register; though there is a variant using just the W register.

  3. ) The Novel GOTO, three instruction cycles in one instruction

            jmp     $+1     ;three cycle delay
    

    Advantages: third the space of three NOPs.
    Disadvantages: obscure unless commented.

  4. ) The Call to Nowhere

            org     0
            jmp     MAIN
    delay6  ret     ;six cycle delay function
                    [...]
    DELAY   call    delay6
    

    Advantages: 1/6 the space of six NOPs, the RET can be reused by other code.
    Disadvantages: implementation separate from use, can look odd, uses one stack level.

    Scott Dattalo says:

    ...if you want a 4-cycle [ed: in compatible mode] single-instruction delay: call some_return_in_your_code Of course, you run the risk of stack overflow on [some processors]
  5. ) The Double Call to Nowhere, 12 cycles

            org     0
            jmp     MAIN
    delay12 call    delay6
    delay6  ret
                    [...]
    DELAY   call    delay12
    

    Advantages: looks simple, allows various size delays to be rapidly constructed during prototyping.
    Disadvantages: uses two stack levels.

    [ed: See the "Stack Recursive Delay" below]

  6. ) The Do Something Useful Extension to the Common Loop, six times the initial value

    DELAY   mov     W, #95          ;1
            mov     COUNTER, W      ;2
    
            mov     W, TRISM        ;3 9  15 fetch port direction mirror
            mov     !RB, w          ;4 10 16 reapply it
            decsz   COUNTER         ;5 11 17
            jmp     $-3             ;6 12 18
    

    Advantages: allows useful functionality to be placed within the delay.
    Disadvantages: increased convolution of code, lower maintainability.

  7. ) The Long Delay Using Timer, more of a technique than a code fragment, set the timer, wait for it to roll over.

    Advantages: immune to distortion by interrupts, easily scaled using a prescaler, even possible to tune the delay by modifying the preload value.
    Disadvantages: allocates a timer.

    Paul B. Webster says:

    I feel that many applications (real-time control, clocks) resolve to a fundamental "tick" or hierarchy thereof, often around a millisecond, which method {7} provides. Counting a thousand of these gives a second, at which point a train of countdowns (semaphores) can lead to various housekeeping actions i.e., if T1 then { T1--; if T1 == 0 then action1 };

    On the 1 ms "ticks" also, a debounce uses a counter which counts down from 20 (20 ms) to verify a keypress/ release. Other countdowns in ms are used for playing tunes or "tick", "Click" or "blip" noises.

    It is highly undesirable to pre-load or fiddle with the TMR0 when you are using it this way, firstly because it interferes with the prescaler in a very inconvenient fashion, and secondly as the 1 ms countdowns can be used for a 500 Hz tone while the TMR0 MSB can be copied to a port for a 1 kHz tone, bit 6 for a 2 kHz tone, etc., controlled as above in even numbers of milliseconds.

    You can similarly, wait on those individual bits by polling, for sub- delays. A sub-delay on bit 3 toggling could be used to time a phase accumulator (32 kHz clock) to generate quite a complete range of square wave tones.

    So, you may say that method "uses" a timer-counter, but I submit that in a well-designed application, you get an awful lot of "use" out of it!

  8. ) The Watchdog Delay, go to sleep and get woken by the watchdog.

    Advantages: extremely simple technique, can be varied by changing the WDT prescaler ratio.
    Disadvantages: difficult to calibrate.

    [ed: Set up a type of state machine that records where the processor should contine executing code after the reset. Make sure you clear it in your non-timed routines. Also see Using the watchdog timer to sense temperature]

  9. ) The Data EEPROM Delay, a typically 10ms delay that can be triggered by writing to data EEPROM and waiting for the interrupt.

    Advantages: tests the endurance of the EEPROM.
    Disadvantages: tests the endurance of the EEPROM.

Tony Nixon says:

Here's a a simple example [for the SX at 50Mhz], but it won't be accurate to the second, so you may have to tweak it. Perhaps you could use it as a basis for your code.
        mov     W, #x   ; x = hours delay
        mov     hours, W
        call    Hours_Delay

        ; rest of code continues

Hours_Delay
        call    Hour_Delay
        decsz   hours
        jmp     Hours_Delay
        ret

Hour_Delay
        mov     W, #60
        mov     mins, W
Rst_Loop
        mov     W, #60
        mov     secs, W
Hour_Loop
        call    Second_Delay
        ;
        ; maybe some processing in here
        ;
        decsz   secs
        jmp     Hour_Loop
        decsz   mins
        jmp     Rst_Loop
        ret

Second_Delay
        mov     W, #5           ;50e6 / 4 = 12 500 000 = 100*100*250*5
        mov     NbHi, W
        mov     W, #250
        mov     NbLo, W
        mov     W, #100
        mov     NaHi, W
        mov     W, #100
        mov     NaLo, W
DeLoop0
        decsz   NaLo            ;delay1 = NaLo*4 - 2
        jmp     DeLoop0         ;
        decsz   NaHi            ;delay2 = (NaLo*4 - 2) * NaHi + (NaHi*4 - 2) =
        jmp     DeLoop0         ;=  NaLo*NaHi*4 + NaHi*2 - 2
        decsz   NbLo            
        jmp     DeLoop0         
        decsz   NbHi            ;totaldelay ~= 4*NaLo*NaHi*NbLo*NbHi
        jmp     DeLoop0
        ret


Stack Recursive Delay

The name of the lable you call indicates the number of cycles (Convert cycles to time) that will be executed before returning. This uses an amazingly small number of bytes and is probably more effecient than inline loops or nop's if you are going a lot of little delays of varying times through out your code.

Delay131072     call    Delay16384      ; uses 6 stack levels
Delay114688     call    Delay16384
Delay98304      call    Delay16384
Delay81920      call    Delay16384
Delay65536      call    Delay16384
Delay49152      call    Delay16384
Delay32768      call    Delay16384

Delay16384      call    Delay2048       ;uses 5 stack levels
Delay14336      call    Delay2048
Delay12288      call    Delay2048
Delay10240      call    Delay2048
Delay8192       call    Delay2048
Delay6144       call    Delay2048
Delay4096       call    Delay2048

Delay2048       call    Delay256        ;uses 4 stack levels
Delay1792       call    Delay256
Delay1536       call    Delay256
Delay1280       call    Delay256
Delay1024       call    Delay256
Delay768        call    Delay256
Delay512        call    Delay256

Delay256        call    Delay32 ;uses 3 stack levels
Delay224        call    Delay32
Delay192        call    Delay32
Delay160        call    Delay32
Delay128        call    Delay32
Delay96         call    Delay32
Delay64         call    Delay32

Delay32         call    Delay8  ;uses 2 stack levels
Delay24         call    Delay8
Delay16         call    Delay8

Delay8          nop     ;uses 1 stack level
                nop
                ret

Macro Example

James Newton says:

I also wrote this god-awful macro for the Parallax SX key asembler that may be of use to someone: It produces the smallest and/or tightest loop delays inline when you call it with the value and units of time you wish to delay for; calculating the number of cycles based on the processor speed. The CpuMhz equate must be adjusted to what ever is right for your chip. It should probably be called CpuMips vice CpuMhz. The only redeming virtue is that it does not use anything other than w (on the SX you can decrement W); no stack use, no register use. :
        device  pins28, pages1, banks8, turbo, stackx, optionx, carryx
        reset reset_entry
CpuMhz = 50
temp    ds      1
usec    equ     -6
msec    equ     -3
sec     equ     1
cycles  equ     0

mynop   MACRO
        noexpand
        page $>>8
        ENDM

cyclefor MACRO 1
_cycles = \1
IF _cycles > 0
_temp   =       $//4
IF _temp = 2
 IF _cycles < 5
  REPT _cycles
   expand
   mynop
   noexpand
   ENDR
  _cycles = 0
 ELSE
  expand
  mynop
  noexpand
  _cycles = _cycles -1
  ENDIF
 ENDIF
IF _temp = 1
 IF _cycles < 6
  REPT _cycles
   expand
   mynop
   noexpand
   ENDR
  _cycles = 0
 ELSE
  expand
  mynop
  mynop
  noexpand
  _cycles = _cycles -2
  ENDIF
 ENDIF
IF _cycles > 3
        expand
         mov w, #_cycles / 3
         decsz 1        ;dec w
         clrb 2.1       ;modify PC to jump back
        noexpand
 _cycles = _cycles // 3 ;cycles left over
 ENDIF
IF _cycles > 0
  REPT  _cycles
        expand
         mynop
        noexpand
   ENDR
 ENDIF
ENDIF
        ENDM

reset_entry
        mov w,#$7F
        mov !OPTION,w

delayhelp MACRO
        ERROR 'USAGE: delay value, [usec,msec,sec,cycles]'
        ENDM

delay   MACRO   2
noexpand
IF (\2=usec OR \2=msec OR \2=sec) AND (\1<1000 AND \1>0)
 IF \2=sec
  _cycles = (\1 * 1000000 / (1000/CpuMhz))
  ENDIF
 IF \2=msec
  _cycles = (\1 * 1000 / (1000/CpuMhz))
  ENDIF
 IF \2=usec
  _cycles = (\1 / (1000/CpuMhz))
  ENDIF
 IF \2=cycles
  _cycles = \2
  ENDIF
 IF _cycles = 0
  expand
         ;delay less than one cycle at this processor speed'
  noexpand
 ELSE
  IF _cycles > 255
   REPT (_cycles / 256)
    cyclefor 256
    _cycles = _cycles - 256
    ENDR
   ENDIF
  cyclefor _cycles
  ENDIF

ELSE
        delayhelp
ENDIF
        ENDM

        delay 999, usec
        delay 200, usec
        delay 250, usec
        delay 10, usec
        delay 20, usec
        delay 100, msec


file: /Techref/scenix/lib/flow/delays_sx.htm, 12KB, , updated: 2004/6/10 13:40, local time: 2024/11/20 00:00,
TOP NEW HELP FIND: 
18.221.80.42:LOG IN

 ©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE!

<A HREF="http://linistepper.com/techref/scenix/lib/flow/delays_sx.htm"> SX Microcontroller Delay Program Flow Methods</A>

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type a nice message (short messages are blocked as spam) in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.


Link? Put it here: 
if you want a response, please enter your email address: 
Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
Did you find what you needed?