Delay routine not working

Status
Not open for further replies.

gregmcc

Member
I've tried the delay generator from piclist and I can't seem to get it working. It compiles without errors but the delay doesn't seem to work:

Code:
	LIST	p=16F628		;tell assembler what chip we are using

#include <p16F628.inc>
	__CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _LVP_OFF & _BODEN_ON & _MCLRE_OFF

	org	0x0000			;org sets the origin, 0x0000 for the 16F628,
					;this is where the program starts running	
				movlw 7
				movwf CMCON

				clrf PORTA
				clrw
				tris PORTA ; porta all output
				clrf PORTB
				movlw 0xf0 
				tris PORTB
				bsf STATUS, RP0 ; bank 1
				bcf OPTION_REG, NOT_RBPU ;internal pullups on port B enabled
				bcf STATUS, RP0 ;bank 0

	

Loop	
	movlw	0xff
	movwf	PORTA			;set all bits on
	movwf	PORTB

	call Delay

	movlw	0x00
	movwf	PORTA			;set all bits on
	movwf	PORTB

        call Delay

	goto Loop

Delay
; Delay = 2 seconds
; Clock frequency = 4 MHz

; Actual delay = 2 seconds = 2000000 cycles
; Error = 0 %

	cblock
	d1
	d2
	d3
	endc

	;1999996 cycles
	movlw	0x11
	movwf	d1
	movlw	0x5D
	movwf	d2
	movlw	0x05
	movwf	d3
Delay_0
	decfsz	d1, f
	goto	$+2
	decfsz	d2, f
	goto	$+2
	decfsz	d3, f
	goto	Delay_0

			;4 cycles (including call)
	return
end

If however I use the following delay code from Nigels blinking lights tutorial it works fine:

Code:
	LIST	p=16F628		;tell assembler what chip we are using

#include <p16F628.inc>
	__CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _LVP_OFF & _BODEN_ON & _MCLRE_OFF

	cblock 	0x20 			;start of general purpose registers
		count1 			;used in delay routine
		counta 			;used in delay routine 
		countb 			;used in delay routine
	endc

	org	0x0000			;org sets the origin, 0x0000 for the 16F628,
					;this is where the program starts running	
				movlw 7
				movwf CMCON

				clrf PORTA
				clrw
				tris PORTA ; porta all output
				clrf PORTB
				movlw 0xf0 
				tris PORTB
				bsf STATUS, RP0 ; bank 1
				bcf OPTION_REG, NOT_RBPU ;internal pullups on port B enabled
				bcf STATUS, RP0 ;bank 0

	

Loop	
	movlw	0xff
	movwf	PORTA			;set all bits on
	movwf	PORTB

	call Delay			
	call Delay	
	call Delay	
	call Delay	
	call Delay
	call Delay	
	call Delay	
	call Delay				; end of 2 secs

	movlw	0x00
	movwf	PORTA			;set all bits on
	movwf	PORTB

	call Delay			
	call Delay	
	call Delay	
	call Delay	
	call Delay
	call Delay	
	call Delay	
	call Delay
	goto Loop


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
end
 
That's what you get for not writing your own code, or at least not understanding it. The way cblock is used is wrong in your program. The article on the Piclist probably assumed readers to know how to properly use cblocks... From MPASM's Help File, cblock section :

cblock - Define a Block of Constants
Syntax
cblock [expr]
label[:increment][,label[:increment]]
endc
Description
Defines a list of named sequential symbols. The purpose of this directive is to assign address offsets to many labels. The list of names end when an endc directive is encountered.

expr indicates the starting value for the first name in the block. If no expression is found, the first name will receive a value one higher than the final name in the previous cblock. If the first cblock in the source file has no expr, assigned values start with zero.
 
Joel, thanks for the reply. I've got it to work using:

Code:
	cblock 0x20
	d1
	d2
	d3
	endc

but if "the first cblock in the source file has no expr, assigned values start with zero" and in the code I have:

Code:
	movlw	0x11
	movwf	d1
	movlw	0x5D
	movwf	d2
	movlw	0x05
	movwf	d3

then whats the difference? why does it work with the 0x20? What am I missing?
 

d1, d2 and d3 are variables that you would normally define with equ. Using a cblock is just like using equ, only you don't have to type equ three times and write 3 sequential memory addresses. You tell it the first address, in your case 0x20, and it's gonna increment that number for each line in the cblock after the first variable name. So d2 is given the address 0x21 and d3 0x22.

In the Piclist code, since there is no expr (which means no starting address, unlike Nigel's code which specifies 0x20), d1 is then given address 0x00, d2 0x01 and d3 0x02. This is bad.

Your program is probably gonna wreak havoc writing to these addresses.
For example, take your code

Code:
	movlw	0x5D
	movwf	d2

Remember, d2 points to address 0x02. You will write 0x5D to this location in the above code. The 16F628A datasheet states that address 0x02 contains PCL. Writing to it will make your program execution jump to the instruction at address 0x005D you just wrote to d2, which actually points to PCL instead of a free data location!
 
I have tried to understand how many cycles the code takes but could not get exactly the required value of 1,999,996 cycles.

Code:
Delay
			;1999996 cycles
	movlw	0x11
	movwf	d1
	movlw	0x5D
	movwf	d2
	movlw	0x05
	movwf	d3
Delay_0
	decfsz	d1, f
	goto	$+2
	decfsz	d2, f
	goto	$+2
	decfsz	d3, f
	goto	Delay_0

			;4 cycles (including call)
	return

My calculation is Delay_0 takes 1,999,984 cycles, setting up d3..d1 takes 6 cycles, return/call takes 4. Total is 1,999,994. But I guess that's close enough.

Thanks
 
eblc1388 said:
My calculation is Delay_0 takes 1,999,984 cycles, setting up d3..d1 takes 6 cycles, return/call takes 4. Total is 1,999,994. But I guess that's close enough.

How do you come up with 1,999,984 cycles? I can't even come close to that...

I don't know how to calculate the number of times decfsz takes 2 cycles instead of 1, that's what bugs me.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…