• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Improved K8LH fixed delay subsystem (PIC)

Status
Not open for further replies.

Mike - K8LH

Well-Known Member
Just wanted to pass along a new and improved K8LH PIC fixed delay subsystem for those PIC assembly language programmers who might be interested.

For those of you not familiar with my subsystem it was designed to be a general purpose replacement for the code generated by the PICLIST delay code generator, capable of generating precise delays in cycles, microseconds, or milliseconds using almost any clock (4, 8, 12, 16, or 20 MHz). It also allows you to subtract N number of cycles from the delay for isochronous code timing.

Basically I replaced the 4-cycle inner/outer timing loop in my old timing subroutine with Mike Bond's 4-word 5-cycle 16-bit timing loop and shaved three words off of the subroutine in the process. This also reduced timing subroutine "overhead" and associated minimum delay from 16 cycles to 11 cycles.

Code:
;
;  DelayCy() clock equate and macro delay operand multipliers
;
        radix   dec
clock   equ     4               ; 4, 8, 12, 16, 20 MHz
usecs   equ     clock/4         ; cycles/microsecond multiplier
msecs   equ     clock/4*1000    ; cycles/millisecond multiplier
;
;  DelayCy() macro generates four instructions
;
DelayCy macro   delay           ; 11..327690 cycle delay range
        movlw   high((delay-11)/5)+1
        movwf   DelayHi
        movlw   low ((delay-11)/5)
        call    uDelay-((delay-11)%5)
        endm
;
;  example code for simulation testing
;
SimTest DelayCy(10*msecs)       ; <- put simulator PC here
        nop                     ; <- put simulator break point here
;
;  uDelay(11..327690) subroutine     Mike McLaren, K8LH, Mar-09
;
;  9 words, 1 RAM variable, 14-bit core
;
        nop                     ; entry for (delay-11)%5 == 4     |B0
        nop                     ; entry for (delay-11)%5 == 3     |B0
        nop                     ; entry for (delay-11)%5 == 2     |B0
        nop                     ; entry for (delay-11)%5 == 1     |B0
uDelay  addlw   -1              ; subtract 5 cycle loop time      |B0
        skpc                    ; borrow? no, skip, else          |B0
        decfsz  DelayHi,F       ; done?  yes, skip, else          |B0
        goto    uDelay          ; do another loop                 |B0
        return                  ;                                 |B0
;
Then while studying the subsystem code I wondered if I could include some of the 'nop' instructions in the timing loop to increase the upper delay limit without affecting timing loop "overhead".

It turns out that each 'nop' included in the timing loop will increase the upper delay limit by 65536 cycles but you need one additional 'nop' at the top of the timing subroutine to handle the additional delay%loop subroutine entry point. Still, one additional word for each additional 65536 cycles isn't bad.

Code:
;
;  DelayCy() clock equate and macro delay operand multipliers
;
        radix   dec
clock   equ     8               ; 4, 8, 12, 16, 20 MHz
usecs   equ     clock/4         ; cycles/microsecond multiplier
msecs   equ     usecs*1000      ; cycles/millisecond multiplier
;
;  5 cycle loop delay range 11..327690 cycles
;  6 cycle loop delay range 11..393226 cycles
;  7 cycle loop delay range 11..458762 cycles
;  8 cycle loop delay range 11..524298 cycles
;
loop    equ     8               ; select 5..8 cycle loop
;
;  DelayCy() macro generates four instructions
;
DelayCy macro   delay           ; minimum 11 cycles
        movlw   high((delay-11)/loop)+1
        movwf   DelayHi
        movlw   low ((delay-11)/loop)
        call    uDelay-((delay-11)%loop)
        endm
;
;  example code for simulation testing
;
SimTest DelayCy(8*usecs)        ; <- put simulator PC here
        nop                     ; <- put simulator break point here
;
;  16 bit uDelay subroutine with adjustable 5..8 cycle loop time
;
;  12 words, 1 RAM variable, 14 bit core   ---  Mike, K8LH
;
        nop                     ; entry for (delay-11)%loop == 7  |B0
        nop                     ; entry for (delay-11)%loop == 6  |B0
        nop                     ; entry for (delay-11)%loop == 5  |B0
        nop                     ; entry for (delay-11)%loop == 4  |B0
        nop                     ; entry for (delay-11)%loop == 3  |B0
        nop                     ; entry for (delay-11)%loop == 2  |B0
        nop                     ; entry for (delay-11)%loop == 1  |B0
uDelay  addlw   -1              ; subtract "loop" cycle time      |B0
        skpc                    ; borrow? no, skip, else          |B0
        decfsz  DelayHi,F       ; done?  yes, skip, else          |B0
        goto    uDelay-loop+5   ; do another loop                 |B0
        return                  ;                                 |B0
;
Finally I modified the DelayCy() macro to handle larger delays by allowing it to call the timing subroutine multiple times. I won't bore you by posting this last version unless someone really wants to see it.

Regards, Mike
 

Mike - K8LH

Well-Known Member
Dear Admins,

I posted this in the wrong Forum. Please forgive me. Could you delete it please?

Thank you.

Mike
 
Status
Not open for further replies.

EE World Online Articles

Loading
Top