;***************************************************************************
; version date	    change						by
; ------ ---------  ---------------------------------------------------	----
; 1.0	 22/12/97   first version.					JPD
;		    tx:    1241.250 MHz
;		    rx:    1295.250 MHz
;		    shift: 54 MHz
; 2.0	 14/08/98   no boot when changing jumpers, and implemented
;		    4 freqs incl. the reversed				JPD
;***************************************************************************

;***************************************************************************
; The VCO-frequency Fvco is determined as follows:
;
;               3.2 MHz
; Fvco = Fr*N = ------- * 8 * n
;		  512
;
; where Fr the reference frequency which is equal to the crystal frequency
; devided by 512, and N the total division. The SDA3302 devides by 8 fixed
; also, so n equals the values to program the device with.
;
; When 3.2 MHz crystal frequency is used the reference frequency gets 
; Fr = 3200 kHz / 512 = 6.25 kHz and the final raster equals
; 8 * Fr = 50 kHz.
;***************************************************************************

		DSEG
		ORG	0008H
ByteCnt:        DS      1 
Xmit:           DS      8
PrevP1:		DS	1

		BSEG
NoAck:          DBIT    1

SCLPin          EQU     P1.6            	; I2C serial clock line.
SDAPin          EQU     P1.7            	; I2C serial data line.

		CSEG
		ORG	0000H
                LJMP    Start

		ORG	0100H

Start:          MOV     SP,#40H

		MOV	PrevP1,#0C0H
Loop:		MOV	A,P1			; get P1 in A
		ANL	A,#03CH			; leave only relevant bits
		MOV	R1,A			; save A in R1
		XRL	A,PrevP1		; any difference with previous P1?
		JNZ	M1			; branch if so
		MOV	PrevP1,R1		; else, update previous
		SJMP	Loop	

M1:		MOV	PrevP1,R1		; update previous
		MOV	A,R1			; 4 bits of P1 in A
		MOV	DPTR,#FreqTbl1		; get start of tbl1
                JB      ACC.5,M2                ; or if reversed,
		MOV	DPTR,#FreqTbl2		; get start of tbl2

M2:		CPL	A			; invert logic
                ANL     A,#0CH                  ; now leave only freqbits
                RR      A                       ; shift to match tbl
		MOV	R1,A			; save A in R1
		MOVC	A,@A+DPTR		; get freq
		INC	DPTR			; point to 2nd byte
		MOV	Xmit,A			; store 1st byte
		MOV	A,R1			; restore A
		MOVC	A,@A+DPTR		; get 2nd byte
		MOV	Xmit+1,A		; store it too
		ACALL	SetFreq			; and program ppll
		SJMP	Loop
		
FreqTbl1:	DB	060H,0F9H		; 1241.250
		DB	060H,0FCH		; 1241.400
		DB	061H,000H		; 1241.600
		DB	061H,004H		; 1241.800

FreqTbl2:	DB	065H,031H		; 1295.250
		DB	065H,034H		; 1295.400
		DB	065H,038H		; 1295.600
		DB	065H,03CH		; 1295.800


SetFreq:        MOV     A,#0C0H
                MOV     R0,#Xmit
                MOV     ByteCnt,#2
                ACALL   SendData
                RET


;****************************************************************************
;                               I2C-stuff
;****************************************************************************

BitDly:         NOP
                NOP                    ;NOPs to delay 5 microseconds (minus 4
                RET                    ;machine cycles for CALL and RET).

SCLHigh:        SETB    SCLPin         ;Set SCL from our end.
                JNB     SCLPin,$       ;Wait for pin to actually go high.
                RET

SendStart:      CLR     SDAPin         ;Begin I2C Start.
                ACALL   BitDly
                CLR     SCLPin
                ACALL   BitDly         ;Complete I2C Start.
                CLR     NoAck
                RET

SendStop:       CLR     SDAPin         ;Get SDA ready for stop.
                ACALL   SCLHigh        ;Set clock for stop.
                ACALL   BitDly
                SETB    SDAPin         ;Send I2C stop.
                ACALL   BitDly
                RET                    ;Bus should now be released.


; SendByte - sends one byte of data to an I2C slave device.
; Input         A     = data byte to be sent.
; Affected:     A, R2

SendByte:       MOV     R2,#8          ;Set bit count.
SBLoop:         RLC     A              ;Send one data bit.
                MOV     SDAPin,C       ;Put data bit on pin.
                ACALL   SCLHigh        ;Send clock.
                ACALL   BitDly
                CLR     SCLPin
                ACALL   BitDly
                DJNZ    R2,SBloop      ;Repeat until all bits sent.
                SETB    SDAPin         ;Release data line for acknowledge.
                ACALL   SCLHigh        ;Send clock for acknowledge.
                ACALL   BitDly
                JNB     SDAPin,SBEX    ;Check for valid acknowledge bit.
                SETB    NoAck          ;Set status for no acknowledge.
SBEX:           CLR     SCLPin         ;Finish acknowledge bit.
                ACALL   BitDly
                RET


; RcvByte - receives one byte of data from an I2C slave device.
; Output:       A     = data byte received
; Affected:     A, R2

RcvByte:        MOV     R2,#8           ;Set bit count.
RBLoop:         ACALL   SCLHigh         ;Read one data bit.
                ACALL   BitDly
                MOV     C,SDAPin        ;Get data bit from pin.
                RLC     A               ;Rotate bit into result byte.
                CLR     SCLPin
                ACALL   BitDly
                DJNZ    R2,RBLoop       ;Repeat until all bits received.
                PUSH    ACC             ;Save accumulator
                MOV     A,ByteCnt
                CJNE    A,#1,RBAck      ;Check for last byte of frame.
                SETB    SDAPin          ;Send no acknowledge on last byte.
                SJMP    RBAClk
RBAck:          CLR     SDAPin          ;Send acknowledge bit.
RBAClk:         ACALL   SCLHigh         ;Send acknowledge clock.
                POP     ACC             ;Restore accumulator
                ACALL   BitDly
                CLR     SCLPin
                SETB    SDAPin          ;Clear acknowledge bit.
                ACALL   BitDly
                RET


; SendData - sends one or more bytes of data to an I2C slave device.
; Input:        ByteCnt = count of bytes to be sent.
;               A       = slave address.
;               @R0     = data to be sent (the first data byte will be the 
;                         subaddress, if the I2C device expects one).
; Affected:     A, R0, R2

SendData:       ACALL   SendStart
                ACALL   SendByte        ;Send slave-address
                JB      NoAck,SDEX      ;Check for slave not responding
SDLoop:         MOV     A,@R0           ;Get data byte from buffer.
                ACALL   SendByte        ;Send next data byte.
                INC     R0              ;Advance buffer pointer.
                JB      NoAck,SDEX      ;Check for slave not responding.
                DJNZ    ByteCnt,SDLoop  ;All bytes sent?
SDEX:           ACALL   SendStop        ;Done, send an I2C stop.
                RET

; RcvData - receives one or more bytes of data from an I2C slave device.
; Input:        ByteCnt = count of bytes to be sent.
;               A       = slave address.
; Output:       @R0     = data received.
; Affected:     A, R0, R2
;
; Note: to receive with a subaddress, use SendData to set the subaddress
; first (no provision for repeated Start).

RcvData:        INC     A               ;Set for READ of slave.
                ACALL   SendStart       ;Acquire bus and send slave address.
                ACALL   SendByte
                JB      NoAck,RDEX      ;Check for slave not responding
RDLoop:         ACALL   RcvByte         ;Receive next data byte.
                MOV     @R0,A           ;Save data byte in buffer.
                INC     R0              ;Advance buffer pointer.
                DJNZ    ByteCnt,RDLoop  ;Repeat untill all bytes received.
RDEX:           ACALL   SendStop        ;Done, send an I2C stop.
                RET

                END
