cblock 0x70
delayhi ; DelayCy() subsystem variable
endc
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; K8LH DelayCy() subsystem macro generates four instructions ~
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
radix dec
clock equ 4 ; 4, 8, 12, 16, 20 (MHz), etc.
usecs equ clock/4 ; cycles/microsecond multiplier
msecs equ usecs*1000 ; cycles/millisecond multiplier
dloop equ 16 ; loop size, minimum 5 cycles
;
; -- loop -- -- delay range -- -- memory overhead ----------
; 5-cyc loop, 11..327690 cycles, 9 words (+4 each macro call)
; 6-cyc loop, 11..393226 cycles, 10 words (+4 each macro call)
; 7-cyc loop, 11..458762 cycles, 11 words (+4 each macro call)
; 8-cyc loop, 11..524298 cycles, 12 words (+4 each macro call)
;
DelayCy macro cycles ; range, see above
if (cycles<11)|(cycles>(dloop*65536+10))
error " DelayCy range error "
else
movlw high((cycles-11)/dloop)+1
movwf delayhi
movlw low ((cycles-11)/dloop)
; rcall uLoop-(((cycles-11)%dloop)*2) ; (18F version)
call uLoop-((cycles-11)%dloop) ; (16F version)
endif
endm
;******************************************************************
; reset vector *
;******************************************************************
org 0x000
v_reset
DelayCy(1000*msecs-3) ; delay 1 second minus 3 cycles
nop ; insert break point here
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; K8LH DelayCy() subsystem 16-bit uLoop subroutine ~
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
a = dloop-1
while a > 0
nop ; (cycles-11)%dloop entry points |??
a -= 1
endw
uLoop addlw -1 ; subtract 'dloop' loop time |??
skpc ; borrow? no, skip, else |??
decfsz delayhi,F ; done? yes, skip, else |??
; bra uLoop-dloop*2+10 ; do another loop (18F version) |
goto uLoop-dloop+5 ; do another loop (16F version) |??
return ; |??
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
end
goto uLoop-dloop+5 ; do another loop (16F version) |??
; 1 second delay constants for 4 MHz clock
Dly1S_CountH equ d'4'
Dly1S_CountL equ d'36'
Tweak_Count equ d'43'
; 1 ms delay constants for 4 MHz clock
Delay1msLong equ d'1'
Delay1msShort equ d'72'
Delay1S ; 2 cycles for subroutine call from main program
bank0 ; 1 cycle
clrf acc2 ; 1 cycle
clrf acc3 ; 1 cycle
movlw Dly1S_CountH ; 1 cycle
movwf r3 ; 1 cycle
movlw Dly1S_CountL ; 1 cycle
movwf r2 ; 1 cycle
; Main Loop execution count = 256*(Dly1S_CountH - 1) + (256 - Dly1S_CountL)
; Dly1S_CountH must not be zero (0 actually counts as 256)
; therefore with values 4 & 36, loop executes 256*(4 - 1)+ (256 - 36) = 988 times
; Total cycles = 11 + 1012*LoopCount + 4*TweakCount + (0,1 or 2 nop padding)
Delay1S_Lp
call Delay1mS ; 997 cycles - this 1ms delay routine is thoroughly debugged
; At Fmax (50 MHz) it takes approx. 1.3ms (1300 cycles) to overflow the timer
; So the overflow bit must be checked after every execution of Delay1mS
btfsc intcon,T0IF ; 1 cycle
goto Dly1sOflw2 ; 2 cycles if branch taken, 1 cycle if not
;No overflow branch -
pad 3 cycles here so both branches match
nop ; 1 cycle
Goto $+1 ; 2 cycle nop
goto Dly1sCont ; 2 cycles
;Timer overflow handler branch
Dly1sOflw2 ;2 cycles for goto to get here
bcf intcon,T0IF ; 1 cycle, clear TMR0 o-flow bit
incf acc2,f ; 1 cycle
btfsc status,z ; 1 cycle
incf acc3,f ; 1 cycle
Dly1sCont ;Convergence point for above branches
;Decrement 16 bit loop counter and test for zero
decf r3,f ; 1 cycle
incfsz r2,f ;1 cycle
incf r3,f ; 1 cycle
movf r2,w ; 1 cycle
iorwf r3,w ; 1 cycle
btfss status,z ; 1 cycle
goto Delay1S_Lp ; 2 cycles
; -1 cycle (Adjust for skipped goto on final iteration)
;Main delay loop is complete. Finish with short adjustment loop
movlw Tweak_Count ; 1 cycle
movwf r2 ; 1 cycle
Dly1S_twk ;Final tweak loop
decfsz r2,f ; 1 cycle
goto Dly1S_twk ; 2 cycles
; -1 cycle (Adjust for skipped goto on final iteration)
nop ; 1 cycle
return ; 2 cycles
Delay1mS ; 00002 cycles for subroutine call
movlw Delay1msLong ; 00001 cycle - load long delay count
call delay ; 00774 cycles
movlw Delay1msShort ; 00001 cycle - load short delay count
movwf dlyctrL ; 00001 cycle
decfsz dlyctrL,f ; 3cycles/iteration
; = 00216 total cycles (00744 for 4MHz)
goto $-1 ; -0001 cycle for loop exit
nop ; 00001 cycle short tweak
Return ; 00002 cycles, total 997 cycles
; Variable Delay subroutine: delay cycles = 770*w+4
delay
; 00002 cyc for entry call
movwf dlyctrH ; 00001 cyc, w contains delay value
subloop
decfsz dlyctrL,f ; 00768 cyc for loop * w
goto $-1 ; -0001 cyc for loop exit * w
decfsz dlyctrH,f ; 00001 * w
goto subloop ; 00002 * w
; -0001 for loop exit
return ; 00002
I wonder if you're using 'relocatable' code rather than 'absolute' code?Error[151] : Operand contains unresolvable labels or is too complex
I use isochronous code in a 1-mS loop in order to account for TMR0 overflows in my frequency counter, too. I gate the counter by toggling the T0CKI pin data direction between 'input' and 'output' and the TMR0 prescaler is set to 256. Here's an excerpt from a counter that uses a 200-mS gate time (5-Hz resolution) and a 24-bit counter;Unfortunately, I wouldn't be able to use your code without significant modifications, because the delay routine needs to include code to check the TMR0 overflow bit approximately every 1 ms. With a 1 second gate time, the counter will overflow several hundred times when measuring an input frequency of 50 MHz. So the overflows must be detected and counted.
;
; count frequency for precisely 200 msecs (5 Hz resolution)
;
NewCount
clrf TMR0 ; clear TMR0 and prescaler |B0
clrf countl ; clear 24 bit counter registers |B0
clrf counth ; |B0
clrf countu ; |B0
movlw high(200)+1 ; |B0
movwf msctrh ; |B0
movlw low(200) ; |B0
movwf msctrl ; gate timer = 200 msecs |B0
movlw TRISA ; |B0
movwf FSR ; setup indirect access to TRISA |B0
bsf INDF,4 ; TRISA.4 (T0CKI) = 1, gate "on" |B0
GateLoop
setz ; set Z = 1 |B0
btfsc INTCON,TMR0IF ; TMR0 overflow? no, skip, else |B0
incf countu,F ; bump CountU, Z = 0 |B0
skpz ; TMR0 overflow? no, skip, else |B0
bcf INTCON,TMR0IF ; clear TMR0 interrupt flag |B0
DelayCy(1*msecs-10) ; delay 1 msec minus 10 cycles |B0
decf msctrl,F ; |B0
skpnz ; |B0
decfsz msctrh,F ; |B0
goto GateLoop ; loop again |B0
bcf INDF,4 ; TRISA.4 = 0, gate "off" |B0
btfsc INTCON,TMR0IF ; TMR0 overflow? no, skip, else |B0
incf countu,F ; bump CountU |B0
bcf INTCON,TMR0IF ; clear TMR0 interrupt flag |B0
;
; toggle T0SE to flush the prescaler & retrieve the count
;
movf TMR0,W ; |B0
movwf counth ; save TMR0 value |B0
Flush bsf STATUS,RP0 ; bank 1 |B1
bcf OPTION_REG,T0SE ; clock on rising edge |B1
bsf OPTION_REG,T0SE ; clock on falling edge |B1
bcf STATUS,RP0 ; bank 0 |B0
decf countl,F ; decrement counter LSB |B0
movf counth,W ; |B0
xorwf TMR0,W ; prescaler overflow into TMR0? |B0
bz Flush ; no, clock it again |B0
;
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?