;---------------------------------------------------------------------------------------------
; CLOCK/TIMING INFORMATION:
;---------------------------------------------------------------------------------------------
;
; PS/2 bus clock low time = 40 us +/- 25% (30 us - 50 us)
; PS/2 bus clock high time = 40 us +/- 25% (30 us - 50 us)
; RC osc @ 20pF/5k = 4.61 MHz +/- 25% (3.50 MHz - 5.76 MHz)
; 1 instruction cycle @ 4.61 MHz (RC) = 0.87 us +/- 25% (0.65 us - 1.09 us)
; Optimum PS/2 bus clock low time @4.61MHz = 45.97 instruction cycles
; Actual PS/2 bus clock low time = 46 instruction cycles
; Actual PS/2 bus clock low time @4.61MHz (RC) = 40.0us +/- 25% (30us-50us)
; Actual PS/2 bus clock frequency @461MHz (RC) = 12.5 kHz +/- 25% (10.0kHz-16.7kHz)
;---------------------------------------------------------------------------------------------
; HEADER:
;---------------------------------------------------------------------------------------------
TITLE "PS/2 Device Routines"
SUBTITLE "By Adam Chapweske"
LIST P=16F84
INCLUDE "p16f84.inc"
RADIX DEC
ERRORLEVEL -224, 1
__CONFIG _CP_OFF & _WDT_OFF & _RC_OSC
;---------------------------------------------------------------------------------------------
; DEFINES:
;---------------------------------------------------------------------------------------------
#DEFINE DATA PORTB, 7
#DEFINE CLOCK PORTB, 6
;---------------------------------------------------------------------------------------------
; RAM ALLOCATION:
;---------------------------------------------------------------------------------------------
cblock
TEMP0
RECEIVE
PARITY
COUNTER
endc
;---------------------------------------------------------------------------------------------
;Required Routines & Macros:
;---------------------------------------------------------------------------------------------
; MACROS:
;---------------------------------------------------------------------------------------------
Delay macro Time ;Delay "Cycles" instruction cycles
if (Time==1)
nop
exitm
endif
if (Time==2)
goto $ + 1
exitm
endif
if (Time==3)
nop
goto $ + 1
exitm
endif
if (Time==4)
goto $ + 1
goto $ + 1
exitm
endif
if (Time==5)
goto $ + 1
goto $ + 1
nop
exitm
endif
if (Time==6)
goto $ + 1
goto $ + 1
goto $ + 1
exitm
endif
if (Time==7)
goto $ + 1
goto $ + 1
goto $ + 1
nop
exitm
endif
if (Time%4==0)
movlw (Time-4)/4
call Delay_Routine
exitm
endif
if (Time%4==1)
movlw (Time-5)/4
call Delay_Routine
nop
exitm
endif
if (Time%4==2)
movlw (Time-6)/4
call Delay_Routine
goto $ + 1
exitm
endif
if (Time%4==3)
movlw (Time-7)/4
call Delay_Routine
goto $ + 1
nop
exitm
endif
endm
;---------------------------------------------------------------------------------------------
; DELAY:
;---------------------------------------------------------------------------------------------
;Delays 4w+4 cycles (including call,return, and movlw) (0=256)
Delay_Routine addlw -1 ;Precise delays used in I/O
btfss STATUS, Z
goto Delay_Routine
return
;--------------------------------------------------------------------------------
;ByteOut:
;Sends a byte in w to the host. Returns 0xFE if inhibited during transmission. Returns 0xFF if host interrupts to send its own data. Returns 0x00 if byte sent successfully.
;---------------------------------------------------------------------------------------------
; OUTPUT ONE BYTE: - TIMING IS CRITICAL!!!
;---------------------------------------------------------------------------------------------
ByteOut movwf TEMP0
InhibitLoop btfss CLOCK ;Test for inhibit (si la ligne CLOCK est à 1 on sort de la boucle InhibitLoop)
goto InhibitLoop
Delay 50 ;attente
btfss CLOCK ;nouveau test
goto InhibitLoop ;la ligne est à zéro
btfss DATA ;Check for request-to-send (test PORTB,7)
retlw 0xFF ;la sous routine retourne FF (le PC(maître) a mis la ligne à 0
; pour envoyer une donnée)
clrf PARITY ;la ligne est à l'état haut et accepte l'envoi, le bit de parité est mis à zéro)
movlw 0x08 ;Nombre de bits à envoyer en w
movwf COUNTER ;mis en mémoire
movlw 0x00 ;0 dans w
call BitOut ;Start bit (0) envoi du start bit
btfss CLOCK ;Test for inhibit on teste si la ligne est toujours disponible
goto ByteOutEnd ;si la ligne n'est pas libre on va à la sous routine de fin de byte
Delay 4 ;attente
;sous routine d'émission d'un octet
ByteOutLoop movf TEMP0, w ;TEMP0 en w
xorwf PARITY, f ;OU exclusif (0 si 1 et 1) entre w et f, résultat en f
;la première fois PARITY est à O et XOR avec w ==> w en f
;puis TEMPO est décalé à Dte.
;le XOR avec w correspond à une addition avec report à chaque boucle dont le résultat
;est stocké dans PARITY. La fonction BitOut envoie le bit 0 (pair ou impair)
;de cet octet
call BitOut ;sortie d'un bit (paramètre en w)
btfss CLOCK ;Test for inhibit
goto ByteOutEnd ;si la ligne n'est pas libre on va à la sous routine de fin de byte
rrf TEMP0, f ;rotation à droite de TEMPO à travers la carry
decfsz COUNTER, f ;decrémentation du compteur et saut de l'instruction suivante si zéro
goto ByteOutLoop ;on n'a pas encore envoyé tout l'octet
Delay 2 ;l'octet a été envoyé
comf PARITY, w ;complémentation du bit de parité, résultat dans w
call BitOut ;Parity bit: envoi du bit de parité inversé
btfss CLOCK ;Test for inhibit
goto ByteOutEnd ;si la ligne n'est pas libre on va à la sous routine de fin de byte
Delay 5 ;la ligne est libre, attente
movlw 0xFF ;FF en w
call BitOut ;envoi Stop bit (1)
Delay 48
retlw 0x00 ;Returns 0x00 if byte sent successfully
ByteOutEnd bsf STATUS, RP0 ;sélectionne banque 1
bsf DATA ;met PORTB, 7 à 1
bsf CLOCK ;met PORTB, 6 à 1
bcf STATUS, RP0 ;sélectionne banque 0
retlw 0xFE ;Returns 0xFE if inhibited during transmission
BitOut bsf STATUS, RP0 ;sélectionne banque 1
andlw 0x01 ;and 01 et w affecte Z
btfss STATUS, Z ;teste Z du status, saute l'instruction suivante si Z=1
bsf DATA ;met PORTB, 7 à 1
btfsc STATUS, Z ;teste Z du status, saute l'instruction suivante si Z=0
bcf DATA ;met PORTB, 7 à 0
Delay 21 ;attente CLOCK à l'état haut pour respecter le timing d'envoi
bcf CLOCK ;met CLOCK à 0 (signal d'horloge état bas)
Delay 45 ;attente CLOCK à l'état bas
bsf CLOCK ;met CLOCK à 1
bcf STATUS, RP0 ;sélectionne banque 0
Delay 5
return
;--------------------------------------------------------------------------------------------
;ByteIn:
;Reads a byte from the host. Result in "RECEIVE" register. Returns 0xFE in w if host aborts transmission.
;Returns 0xFF in w if framing/parity error detected. Returns 0x00 in w if byte received successfully.
;---------------------------------------------------------------------------------------------
; READ ONE BYTE: - TIMING IS CRITICAL!!!
;---------------------------------------------------------------------------------------------
ByteIn btfss CLOCK ;Wait for start bit
goto ByteIn
btfsc DATA ;Teste l'état de la ligne et saute l'instruction suivante si 0 (start bit)
goto ByteIn
movlw 0x08 ;intialisation du compteur et du bit de parité
movwf COUNTER
clrf PARITY
Delay 28
ByteInLoop call BitIn ;Data bits (au retour le bit correspondant est en w (00 ou 80)
btfss CLOCK ;Test for inhibit saute l'instruction suivante si CLOCK à 1
retlw 0xFE ;transmission avortée
bcf STATUS, C ;Carry à 0 dans status
rrf RECEIVE, f ;Rotation à Dte avec Carry de l'octet RECEIVE en mémoire
;le LSB (Bit 0)est reçu en premier
iorwf RECEIVE, f ;OU inclusif entre w et RECEIVE résultat en f
;vient ajouter 1 bit de poids supérieur à chaque fois
xorwf PARITY,f ;addition avec report dans PARITY
decfsz COUNTER, f ;décrémentation du compteur et sortie de la boucle quand Z=0
goto ByteInLoop
Delay 1
call BitIn ;Parity bit (réception du bit de parité)
btfss CLOCK ;Test for inhibit
retlw 0xFE ;transmission avortée
xorwf PARITY, f ;OU exclusif avec PARITY, résultat en f
Delay 5
;Acquisition du Stop bit
ByteInLoop1 Delay 1
call BitIn ;Stop bit (DATA=1 ==> w=80)
btfss CLOCK ;Test for inhibit
retlw 0xFE ;transmission avortée
xorlw 0x00 ;OU exclusif w avec 00
btfsc STATUS, Z ;si résultat=0 sauter l'instruction suivante
clrf PARITY ;PARITY=0 (le stop bit a été détecté, on réinitialise PARITE pour la réception suivante)
btfsc STATUS, Z ;Stop bit=1? oui on sort de la boucle
goto ByteInLoop1 ;No--keep clocking.
;Acknowledge (accusé de réception des données)
bsf STATUS, RP0 ;sélection banque 1
bcf DATA ;DATA = 0
Delay 11
bcf CLOCK ;CLOCK = 0
Delay 45
bsf CLOCK ;CLOCK = 1
Delay 7
bsf DATA ;DATA = 1
bcf STATUS, RP0 ;sélection banque 0
btfss PARITY, 7 ;Parité correcte? (test sur le bit 7) saute l'instruction suivante si oui
retlw 0xFF ;No--return error
Delay 45
retlw 0x00 ;Returns 0x00 in w if byte received successfully
BitIn Delay 8
bsf STATUS, RP0 ;sélectionne banque 1
bcf CLOCK ;met la CLOCK à 0
Delay 45
bsf CLOCK ;met la CLOCK à 1
bcf STATUS, RP0 ;sélectionne banque 0
Delay 21
btfsc DATA ;teste la ligne DATA saute si 0
retlw 0x80 ;w=80h si DATA=1
retlw 0x00 ;w=00h si DATA=0
end