;; Volkswagen CD Changer Emulator
;; For use on PIC16F84 at 4MHz running off 4 AA batteries (5VDC)
;;
;; Copyright © 2002, Edward Schlunder <zilym@yahoo.com>
; Note:	4MHz / 4 = 1MHz. 1/1MHz = 1us.
;       So each PIC instruction takes one microsecond long.
	
	LIST P=16F84, R=DEC
	__CONFIG _WDT_OFF & _PWRTE_ON & _CP_OFF & _XT_OSC
#include <p16f84.inc>
;--------------------------------------------------------------------------
; Connections
;--------------------------------------------------------------------------
; PIC16F84 Pin 1 RA2 -> VW Pin 2 SCLK to Head Unit
; PIC16F84 Pin 2 RA3 -> VW Pin 1 STX  to Head Unit
; 
; Make sure PIC and VW Head Unit have common GND.
;--------------------------------------------------------------------------
SCLK  EQU	2
STX  EQU	3
;--------------------------------------------------------------------------
; Variables
;--------------------------------------------------------------------------
ScratchPadRam   EQU     0x20
txreg  EQU	ScratchPadRam+0
;--------------------------------------------------------------------------
; Program Code
;--------------------------------------------------------------------------
	ORG	0
	goto	Start
;--------------------------------------------------------------------------
; Interrupt Service Routine
;--------------------------------------------------------------------------
	ORG	4
	retfie
;--------------------------------------------------------------------------
; Main Program
;--------------------------------------------------------------------------
Start
	clrf	INTCON  ; Disable all interrupts 
	clrf	STATUS  ; Force data bank 0
	clrf	PORTA  ; initialize port a to 0
	clrf	PORTB  ; initialize port b to 0
;	movlw	0x07  ; turn comparators off so port a
;	movwf	CMCON  ; can be used for i/o
	bsf	STATUS, RP0	; select data bank 1
	clrf	TRISA  ; Set port a as outputs
	clrf	TRISB  ; Set port b as outputs
	clrf	OPTION_REG	; PORTB pull-ups enable
	bcf	STATUS, RP0	; go back to data bank 0
	;bsf	INTCON, GIE	; Global Interrupt Enable
IdleLoop
	call	SendPacket
	call	msecWait	; wait 10ms between display packets
	call	msecWait
	call	msecWait
	call	msecWait
	call	msecWait
	call	msecWait
	call	msecWait
	call	msecWait
	call	msecWait
	call	msecWait
	goto	IdleLoop
;--------------------------------------------------------------------------
; msecWait - delays approximately one millisecond
;--------------------------------------------------------------------------
msecWait
	movlw	-249
msecWaitLoop
	addlw	1
	btfss	STATUS, Z
	goto	msecWaitLoop
	return
;--------------------------------------------------------------------------
; SendPacket - sends a display update packet to the head unit
;              currently hard coded to display "CD 1 Tr 1" on head unit
;--------------------------------------------------------------------------
SendPacket
	movlw	0x74
	call	SendByte
	movlw	0xBE  ; disc
	call	SendByte
	movlw	0xFE  ; track
	call	SendByte
	movlw	0xFF  ; ??
	call	SendByte
	movlw	0xFF
	call	SendByte
	movlw	0xFF  ; mode (scan/mix)
	call	SendByte
	movlw	0x8F
	call	SendByte
	movlw	0x7C
	call	SendByte
	return
;--------------------------------------------------------------------------
; SendByte - sends a byte to head unit.
;            load byte to send to head unit into W register before 
calling
;--------------------------------------------------------------------------
SendByte
	movwf	txreg
	movlw	-8
	bcf	INTCON, GIE	; disable interrupts, timing critical
BitLoop
	rlf	txreg, 1	; load the next bit into the carry flag
	bsf	PORTA, SCLK	; SCLK high
	bcf	PORTA, STX	; load the next bit onto STX
	btfsc	STATUS, C
	bsf	PORTA, STX
	bcf	PORTA, SCLK	; SCLK low
	addlw	1  ; 
	btfss	STATUS, Z
	goto	BitLoop
	bsf	INTCON, GIE	; re-enable interrupts
	
	movlw	-84  ; wait 335us for head unit to store sent byte
DelayLoop    
	addlw	1
	btfss	STATUS, Z
	goto	DelayLoop
	return
	END