Continue to Site

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.

  • 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.

"winpicprog" delay code precision

Status
Not open for further replies.

ahydra

New Member
Here's the delay code from the very good tutorials over at winpicprog.co.uk [specifically tutorial 1 ]:

Code:
Delay	movlw	d'250'			;delay 250 ms (4 MHz clock)
	movwf	count1
d1	movlw	0xC7
	movwf	counta
	movlw	0x01
	movwf	countb
Delay_0
	decfsz	counta, f
	goto	$+2
	decfsz	countb, f
	goto	Delay_0

	decfsz	count1	,f
	goto	d1
	retlw	0x00

I wanted to figure out how this worked, so I added up all the cycle counts for the instructions. The problem is that I don't think the number of cycles adds up to exactly 250000.

The initialisation (the MOVLW's and MOVWF's) requires 6 cycles. For the first 249 iterations of count1, we have:

0xC6 = 198 times a decfsz non-skip (1) and two goto's (4) = 990
plus one decfsz skip (2), a decfsz skip (2) [when countb is decremented, it becomes zero straight away], a decfsz non-skip [decrementing count1] (1), a goto (2) and four more initialisation cycles.

That's a total of 1001 cycles, meaning 249249 altogether. The last iteration gives us:

again 990 cycles
then 2, 2, decfsz skip (2), retlw (2) = 998 cycles.

Hence the entire routine takes 250253 cycles altogether - quite a large amount too many! Not to mention that the intial "call" procedure takes another 2 cycles to start with. I know that the code probably isn't meant to be 100% precise, but I had a go to see if it was possible to make an exact 250000 cycle routine [without a whole load of "nop"s :)].

OK, so I didn't manage to avoid nop's completely, but...
Code:
Delay	nop				; 2 cycles to call, plus initialisation delay of 4 + 4
	nop
	nop
	nop
	movlw	d'250'			; delay 250 ms (4 MHz clock)
	movwf	count1
d1	movlw	0xC5
	movwf	counta
	
Delay_0
	decfsz	counta, f
	goto	$+2			; delay 2 cycles
	goto	Delay_1
	goto	Delay_0
Delay_1
	nop				; delay 1 cycle
	decfsz	count1	,f
	goto	pre_ret
	nop				; delay 1 cycle
	retlw	0x00	
pre_ret
	nop				; delay 10 cycles
	nop
	nop
	nop
	nop
	nop				
	nop
	nop
	goto d1

I changed the 0xC7 to a 0xC5, so for the first 249 iterations we now get 196 lots of decfsz + goto + goto for 980, then decfsz skip + goto + nop + decfsz + goto + [pre_ret]8 nops + goto[/pre_ret] + 2 more initialisation cycles which should make 20 (total 1000).

On the last iteration we get 980, then decfsz skip, goto, nop, decfsz skip, nop, retlw which is 10. That's 249990 altogether; the last 10 instructions come from the initial call (2 cycles), then 4 nop's and 4 initialisation lines.

I'm completely new to PICs (not to programming though), so I've no idea if a 16F628's processor is precise enough for this effort to be even worth it! Still, let me know what you think.

ahydra
 
A PIC is as precise as it's system clock, so with a crystal clock it's as accurate as the crystal.

The delay code in the tutorials is all generated by the 'Delay Code Generator' from the PICList. It produces difficult code to follow, with intertwined loops, so I've never bothered to try and follow it - just plug the values in, and use the resultant code.

I spent enough time in the 70's creating delays by hand, and hand assembling the code :D
 
The code is using a 1mS delay generated by the delay code generator that is repeated 250 times and so it is around 250 cycles too long. Nigel didn't need a super accurate delay and so it is not a problem. Should you require a super accurate delay then the piclist delay generator will give you a delay of any period you require.

BTW, I have to congratulate you on calculating the actual cycles taken. Not many people can do that.


Mike.
 
You might take a look at the Delay sub-system described in the last post on this thread; delay routine

It's relatively small (a 12 word subroutine plus 4 words for each Delay macro call) and provides exact delays in cycles, microseconds, or milliseconds when using a 4, 8, 12, 16, or 20 MHz clock.

Here's an example of how you might use the delay sub-system to generate a 500 Hz "new press beep";

Code:
;
;  key press beep
;
;  by subtracting the number of instruction cycles in the loop from
;  the DelayCy() delay parameter we end up with an exact 500 Hz
;  tone independent of the clock frequency.  If you don't subtract
;  cycles from the delay parameter you would get the following tone
;  frequencies;
;
;  497.018 Hz with  4 MHz clock
;  498.504 Hz with  8 MHz clock
;  499.004 Hz with 12 MHz clock
;  499.251 Hz with 16 MHz clock
;  499.400 Hz with 20 MHz clock
;
DoBeep
        bsf     Beep,5          ; do 32 msec switch press beep    |B0
DoNext  movf    PORTA,W         ; read port A                     |B0
        xorlw   1<<Spkr         ; toggle speaker bit              |B0
        movwf   PORTA           ; toggle speaker pin              |B0
        DelayCy(1*msecs-6)      ; delay 1 msec minus 6 cycles     |B0
        decfsz  Beep,F          ; done?  yes, skip, else          |B0
        goto    DoNext          ; loop (toggle Spkr pin again)    |B0
        return                  ;                                 |B0
Happy Holidays. Mike
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top