; Scenix SX Code to communicate with a
; PAK-I or PAK-II from AWC
; This code would also work
; for the PAK-III or PAK-IV
; if you used it to send the right commands

; This program assumes the PAK-II is connected
; to RB.6 (clock) and RB.5 (data). The PAK-II's
; Port A pin 4 is connected to an LED which will blink
;

; 
;
		device	pins28,pages4,banks8,turbo,optionx,oschs,stackx

		reset	start			;goto 'start' on reset

; For a 10MHz Pak this macro should delay about 10uS
; While 8uS is about the minimum, the PAK
; spec calls for 20uS minimum pulse at 10MHz (50kbps)
; and 10uS minimum at 20MHz (100kbps)
; These routines should delay half of the minimum

; There are many ways you could write a pause
; routine and in a real program, you may
; want to do something different

; If you use a longer time, you might not need to
; delay after sending each byte -- however at "top"
; speed, allow a little time between bytes
; and be sure to "wait" on commands that provide
; busy status

; All times based on a 50MHz Turbo clock
; Your milage will vary if your speed is different

; PAK timing is not critical, so if an interrupt
; or something slows this down, no big deal
pakpause	macro	1
		mov tick,#\1
:lp0		djnz tick,:lp0
		endm
pakdelay	equ	$40    ; $40 for 20Mhz PAK; about $80 for 10Mhz PAK - higher is OK
pakbdelay	equ	$30    ; delay between bytes - $30 for 20MHz; $60 for 10MHz PAK

clk		equ	rb.6
dat		equ	rb.5
; TRIS bits for data bit high or data bit low
datahigh	equ	%10111111
datalow		equ	%10011111

tick		equ     9      ; used by delay routine
sbyte		equ 	10     ; communications byte
paki		equ 	11     ; loop counter for PAK library


out		equ	12     ; This is used by the example code


		org	0		

start
		; set clock to output
		mov !rb,#datahigh

		; set RB5 to use pull up resistor
		mode $e
		mov !rb,#%11011111
		mode $f  

; Always do a comm reset on the PAK before starting
		call pakreset

; Read PAK's ID just to prove it works
		mov w,#$8
		call pakxmit
		call pakwait	; wait for ready
		call pakrcv
; W should equal 2A for a PAK-II

; Change test pin to an output
		mov w,#$14   ; IODIR
		call pakxmit
		mov w,#$10
		call pakxmit

pakloop
		
		mov w,#22    ; write port command
		call pakxmit
		mov w,out
		call pakxmit	
; toggle bit so LED will blink
		xor out,#$10

; reuse paki and sbyte here to delay so people can see the blink
; Delay = 255*255*delay
		mov sbyte,#255
iloop
		mov paki,#255
ploop		
		pakpause 255
		djnz paki,ploop
		djnz sbyte,iloop
		jmp pakloop
		
; END of example code

; PAK LIBRARY BEGINS HERE

; Send a byte in W to the PAK
pakxmit		mov sbyte,w
		mov paki,#8     ; number of bits
:loop
		rl sbyte      ; MSB first
		jc :xone
		mov !rb,#datalow
		clrb dat         
:xone		call pakclk     ; pulse clock
		mov !rb,#datahigh
		djnz paki,:loop
		pakpause pakbdelay  ; give it some time between bytes
		ret


; wait loop -- only works with commands
; that bring the first bit in as 0
pakwait
:pakwaitloop
		jb dat,:pakwaitloop
		ret


; Receive a byte from the PAK
; if you need to wait for the PAK to be ready
; you must call pakwait first
; return is in W and sbyte (duplicates)
pakrcv

		clr sbyte
		mov paki,#8   ; 8 bits
:loop
		clc
		snb dat
		stc
		rl sbyte
		call pakclk    ; pulse clock
		djnz paki,:loop
		mov W,sbyte
		ret
		

; Generate a clock pulse (could be a macro)
pakclk
	setb clk
	pakpause pakdelay
	clrb clk
	pakpause pakdelay
	ret

; This routine resets the PAK using the data
; line reset sequence
; Lots of pauses to be sure -- shouldn't need
; to do this but once
pakreset
		clr rb
		mov !rb,#datalow  ; data out
		pakpause pakdelay
		setb clk             ; clock high
		pakpause pakdelay
		setb dat           ; data high
		pakpause pakdelay
		clrb clk	    ; clock low
		pakpause pakdelay
		mov !rb,#datahigh  ; back to input
		pakpause pakdelay
		ret


