Delay routines for the 68HC11 (in assembler)

Please note: the loop counter values in all routines are calculated for an E-Clock of 2 MHz.

delay100us.s

; ---------------------------------------------------------------------------
; Function	delay100us
; Description	delay for 100 microseconds (with E-Clk = 2 MHz)
; Last update	2005-10-16
; Stack usage	1 byte
; Cycle count	20 cycles (including 6 cycles from jsr) plus 5 cycles each
;		loop.
; Code size	8 bytes
; ---------------------------------------------------------------------------

delay100us:			; 2'000'000Hz * 0.0001s = 200 cycles to eat
	psha			; 3c
	ldaa	#36		; 2c ... (200-20)/5 = 36
_delay_100us_0:
	deca			; 2c
	bne	_delay_100us_0	; 3c
	pula			; 4c
	rts			; 5c plus jsr (6c)

delay.s

; ---------------------------------------------------------------------------
; Function	delay
; Description	delay for n milliseconds (give n in register a, n = 1..255
;		For n=0, the function will delay 256 ms)
; Last update	2005-10-16
; Notes		This works only for an E-Clock of 2 MHz.
;		If you don't mind a small timing error of 18 cycles (9 us)
;		but rather would like to save 5 bytes, just comment out
;		"ldx 328" and "bra _delay_1"
;		For 1 ms delay, we still have a timing error of 3 cycles.
;		And if an interupt occurs, timing also is not precise.
; Stack usage	2 bytes
; Code size	17 bytes
; ---------------------------------------------------------------------------

delay:
	pshx			; 2c?
	ldx	#328		; 3c make first inner loop shorter to compensate
	bra	_delay_1	; 3c the 24 cycles per function call (incl. jsr)
_delay_0:
	ldx	#332		; 3c ... 332*6 = 1992 cycles
_delay_1:
	dex			; 3c
	bne	_delay_1	; 3c
	deca			; 2c
	bne	_delay_0	; 3c plus 8 cycles (3+2+3) = 2000 cycles
	pulx			; 5c
	rts			; 5c plus jsr (6 cycles)

Both routines have the disadvantage of being inaccurate when interrupts occur. If you want to avoid this, you either could disable interrupts within the delay routine, or by using a timer as shown in the following example:


; ---------------------------------------------------------------------------
; Function	delay10ms
; Description	Delay for 10 milliseconds
; Last update	2005-10-16
; Notes		This works only for an E-Clock of 2 MHz.
; Stack usage	4 bytes
; Code size	? bytes
; ---------------------------------------------------------------------------

	include "hc11regs.i"

delay10ms:			; 20000 cycles to eat
	pshx			; 2c
	psha			;
	pshb			;
	ldx	#REGBASE
	ldaa	#$80
	staa	TFLG1,X		; 4c clear OC1F if it is allready set
	ldaa	#$00
	staa	TMSK2,X		; setup clock divider and interupt
	ldd	TCNT,X		; read counter value
	addd	#20000		;
	std	TOC1,X		; when TCNT==TOC1, OC1F will be raised
_delay10ms_l0:
	brclr	TFLG1,X,#$80,_delay10ms_l0
	ldaa	#$80
	staa	TFLG1,X		; clear OC1F
	;bclr	TFLG1,X,#$7f	; clear OC1F
	pulb
	pula
	pulx
	rts			; 5c plus jsr (6 cycles)

This still could be inaccurate, especially if the interrupt routine(s) take too much time (which they shouldn't).
If highest possible timing is important for you, you should disable interrupts when entering the delay routine (call sei before pshx) and disable them before rts or before waiting for the counter to overflow.