; *************************************************************************** ; OpenZengRealPlayers(OZRP) controller firmware for PIC16F873/876 (ver1.4) ; ; (c) Junichi Akita (akita@fun.ac.jp) ; ; -Input Device : 12 PlayStation PADs with 3 MultiTaps ; -Output Data : serial data of chaning PADs (115.2kbps) ; ; CIRCUIT DIAGRAM ; PIC PS(1) PS(2) PS(3) MAX232 DSUB9(female) ; 2(PA0)----------6-----6-----6 1- 3:0.1uF ; 3(PA1)----------7-----7-----7 4- 5:0.1uF ; 4(PA2)----------2-----2-----2 16- 2:0.1uF ; 21(PB0)----------1 15- 6:0.1uF ; 22(PB1)----------------1 16-15:0.1uF ; 23(PB2)----------------------1 ; 24(PB3)----------9 ; 25(PB4)----------------9 ; 26(PB5)----------------------9 14------------2 ; 17(PC6)-------------------------------11 ; 9-10:20MHzOSC ; +5V-----1&20-------------5-----5-----5--------16 ; GND-----8&19-------------4-----4-----4--------15------------5 ; note: PIC = PIC16F873/876 ; PS(1) = PlayStationControllerConnector#1 (for PAD0-PAD3) ; PS(2) = PlayStationControllerConnector#2 (for PAD4-PAD7) ; PS(3) = PlayStationControllerConnector#3 (for PAD8-PAD11) ; MAX232 = RS232C-TTL level converter ; DSUB9 = serial port for connection with PC ; ; * see http://lillith.sk.tsukuba.ac.jp/~kashima/games/ps_jpn.txt ; for details of PlayStationController connector pin assign and protocols ; * see http://www.microchip.co.jp/30292a-j.pdf for details of PIC16F873/876 ; * see http://pdfserv.maxim-ic.com/arpdf/1798J.pdf for details of MAX232 ; ; PAD number assignment ; PS(1)-----MultiTap--+--A : PAD0 ; +--B : PAD1 ; +--C : PAD2 ; +--D : PAD3 ; PS(2)-----MultiTap--+--A : PAD4 ; +--B : PAD5 ; +--C : PAD6 ; +--D : PAD7 ; PS(3)-----MultiTap--+--A : PAD8 ; +--B : PAD9 ; +--C : PAD10 ; +--D : PAD11 ; ; OutputData format (RS232C@115.2kbps) ; 7 bytes for one change of each PAD ; 1st : upper 4bits=PAD type, lower 4bits=PAD number(0-11) ; 2nd : raw PAD data #1 (example: 7bit=left buttom pressed for normal pad) ; 3rd : raw PAD data #2 (example: 0bit=L2 button for normal pad) ; 4th : raw PAD data #3 (example: right handle horizontal for analog pad) ; 5th : raw PAD data #4 ; 6th : raw PAD data #5 ; 7th : raw PAD data #6 ; * see http://lillith.sk.tsukuba.ac.jp/~kashima/games/ps_jpn.txt ; for details of raw PAD data ; ; NOTIFICATION FOR ASSEMBLING AND WRITING: ; - compiler : pa.exe (http://mypaso.com/pic/pa/) ; - writer : PIC-PGMv2, etc. (RB3 should be configured as GPIO, not LVPGM) ; *************************************************************************** include 16f877.h .osc HS .wdt off .pwrt on .bod off .protect off PSEL equ porta.0 ; PA0 : CSEL [2] PCLK equ porta.1 ; PA1 : CCLK [3] PCMD equ porta.2 ; PA2 : CCMD [4] PDAT1 equ portb.0 ; PB0 : CDAT1 [21] PDAT2 equ portb.1 ; PB1 : CDAT2 [22] PDAT3 equ portb.2 ; PB2 : CDAT3 [23] PACK1 equ portb.3 ; PB3 : CACK1 [24] PACK2 equ portb.4 ; PB4 : CACK2 [25] PACK3 equ portb.5 ; PB5 : CACK3 [26] org 20h ; (in bank 0) CDAT ds 3 ; DAT from PAD[i] CCMD ds 1 ; CMD for PADs COUNT ds 1 FSR0 ds 1 FSR1 ds 1 CCOUNT ds 1 TMP ds 1 NSTAT ds 1 PADID ds 12 ; PAD ID PADA ds 12 ; current PAD status A PADB ds 12 ; current PAD status B PADC ds 12 ; current PAD status C PADD ds 12 ; current PAD status D PADE ds 12 ; current PAD status E PADF ds 12 ; current PAD status F W_TMP ds 1 ; *context saving, should be in 0x70-0x7f S_TMP ds 1 ; *context saving, should be in 0x70-0x7f org 0a0h ; (in bank 1) PADA0 ds 12 ; previous PAD status A PADB0 ds 12 ; previous PAD status B PADC0 ds 12 ; previous PAD status C PADD0 ds 12 ; previous PAD status D PADE0 ds 12 ; previous PAD status E PADF0 ds 12 ; previous PAD status F SFLAG ds 1 SCOUNT ds 1 ; note: end of bank 1 should be lower than 0xf0, because of PIC's memory map ; system architecture constants SCYCLE equ 10 ; multiples of TMR2 interrupt for each pad scan NPAD equ 12 ; number of pads NBYTE equ 6 ; number of bytes for each pad org 0 goto init ; interrupt (TMR2) routine org 4 ; context saving movwf W_TMP swapf status, 0 movwf S_TMP bsf rp0 decfsz SCOUNT, 1 goto iend movlw 0ffh movwf SFLAG movlw SCYCLE movwf SCOUNT iend bcf rp0 bcf tmr2if ; context recovering swapf S_TMP, 0 movwf status swapf W_TMP, 1 swapf W_TMP, 0 retfie ; ---- ; communicate with PADs; send CMD and receive DAT1-3 ; ---- padcom movlw 8 movwf COUNT clrf CDAT[0] clrf CDAT[1] clrf CDAT[2] comloop bcf PCLK call ccwait btfsc CCMD, 0 bsf PCMD btfss CCMD, 0 bcf PCMD rrf CCMD, 1 rrf CDAT[0], 1 btfsc PDAT1 bsf CDAT[0], 7 btfss PDAT1 bcf CDAT[0], 7 rrf CDAT[1], 1 btfsc PDAT2 bsf CDAT[1], 7 btfss PDAT2 bcf CDAT[1], 7 rrf CDAT[2], 1 btfsc PDAT3 bsf CDAT[2], 7 btfss PDAT3 bcf CDAT[2], 7 bsf PCLK call ccwait decfsz COUNT, 1 goto comloop ; wait for 100us (ACK time) movlw 125 movwf TMP w100lp nop decfsz TMP, 1 goto w100lp return ccwait movlw 10 movwf TMP ccwait0 decfsz TMP, 1 goto ccwait0 return ; ---- ; subroutine of scanning status of all PADs ; ---- scanpad bcf PSEL ; for MultiTap movlw 01h movwf CCMD call padcom movlw 42h movwf CCMD call padcom movlw 01h movwf CCMD call padcom ; for PAD.A via MultiTap movlw 42h movwf CCMD call padcom movf CDAT[0], 0 movwf PADID[0] movf CDAT[1], 0 movwf PADID[4] movf CDAT[2], 0 movwf PADID[8] clrf CCMD call padcom clrf CCMD call padcom movf CDAT[0], 0 movwf PADA[0] movf CDAT[1], 0 movwf PADA[4] movf CDAT[2], 0 movwf PADA[8] clrf CCMD call padcom movf CDAT[0], 0 movwf PADB[0] movf CDAT[1], 0 movwf PADB[4] movf CDAT[2], 0 movwf PADB[8] clrf CCMD call padcom movf CDAT[0], 0 movwf PADC[0] movf CDAT[1], 0 movwf PADC[4] movf CDAT[2], 0 movwf PADC[8] clrf CCMD call padcom movf CDAT[0], 0 movwf PADD[0] movf CDAT[1], 0 movwf PADD[4] movf CDAT[2], 0 movwf PADD[8] clrf CCMD call padcom movf CDAT[0], 0 movwf PADE[0] movf CDAT[1], 0 movwf PADE[4] movf CDAT[2], 0 movwf PADE[8] clrf CCMD call padcom movf CDAT[0], 0 movwf PADF[0] movf CDAT[1], 0 movwf PADF[4] movf CDAT[2], 0 movwf PADF[8] ; for PAD.B via MultiTap movlw 42h movwf CCMD call padcom movf CDAT[0], 0 movwf PADID[1] movf CDAT[1], 0 movwf PADID[5] movf CDAT[2], 0 movwf PADID[9] clrf CCMD call padcom clrf CCMD call padcom movf CDAT[0], 0 movwf PADA[1] movf CDAT[1], 0 movwf PADA[5] movf CDAT[2], 0 movwf PADA[9] clrf CCMD call padcom movf CDAT[0], 0 movwf PADB[1] movf CDAT[1], 0 movwf PADB[5] movf CDAT[2], 0 movwf PADB[9] clrf CCMD call padcom movf CDAT[0], 0 movwf PADC[1] movf CDAT[1], 0 movwf PADC[5] movf CDAT[2], 0 movwf PADC[9] clrf CCMD call padcom movf CDAT[0], 0 movwf PADD[1] movf CDAT[1], 0 movwf PADD[5] movf CDAT[2], 0 movwf PADD[9] clrf CCMD call padcom movf CDAT[0], 0 movwf PADE[1] movf CDAT[1], 0 movwf PADE[5] movf CDAT[2], 0 movwf PADE[9] clrf CCMD call padcom movf CDAT[0], 0 movwf PADF[1] movf CDAT[1], 0 movwf PADF[5] movf CDAT[2], 0 movwf PADF[9] ; for PAD.C via MultiTap movlw 42h movwf CCMD call padcom movf CDAT[0], 0 movwf PADID[2] movf CDAT[1], 0 movwf PADID[6] movf CDAT[2], 0 movwf PADID[10] clrf CCMD call padcom clrf CCMD call padcom movf CDAT[0], 0 movwf PADA[2] movf CDAT[1], 0 movwf PADA[6] movf CDAT[2], 0 movwf PADA[10] clrf CCMD call padcom movf CDAT[0], 0 movwf PADB[2] movf CDAT[1], 0 movwf PADB[6] movf CDAT[2], 0 movwf PADB[10] clrf CCMD call padcom movf CDAT[0], 0 movwf PADC[2] movf CDAT[1], 0 movwf PADC[6] movf CDAT[2], 0 movwf PADC[10] clrf CCMD call padcom movf CDAT[0], 0 movwf PADD[2] movf CDAT[1], 0 movwf PADD[6] movf CDAT[2], 0 movwf PADD[10] clrf CCMD call padcom movf CDAT[0], 0 movwf PADE[2] movf CDAT[1], 0 movwf PADE[6] movf CDAT[2], 0 movwf PADE[10] clrf CCMD call padcom movf CDAT[0], 0 movwf PADF[2] movf CDAT[1], 0 movwf PADF[6] movf CDAT[2], 0 movwf PADF[10] ; for PAD.D via MultiTap movlw 42h movwf CCMD call padcom movf CDAT[0], 0 movwf PADID[3] movf CDAT[1], 0 movwf PADID[7] movf CDAT[2], 0 movwf PADID[11] clrf CCMD call padcom clrf CCMD call padcom movf CDAT[0], 0 movwf PADA[3] movf CDAT[1], 0 movwf PADA[7] movf CDAT[2], 0 movwf PADA[11] clrf CCMD call padcom movf CDAT[0], 0 movwf PADB[3] movf CDAT[1], 0 movwf PADB[7] movf CDAT[2], 0 movwf PADB[11] clrf CCMD call padcom movf CDAT[0], 0 movwf PADC[3] movf CDAT[1], 0 movwf PADC[7] movf CDAT[2], 0 movwf PADC[11] clrf CCMD call padcom movf CDAT[0], 0 movwf PADD[3] movf CDAT[1], 0 movwf PADD[7] movf CDAT[2], 0 movwf PADD[11] clrf CCMD call padcom movf CDAT[0], 0 movwf PADE[3] movf CDAT[1], 0 movwf PADE[7] movf CDAT[2], 0 movwf PADE[11] clrf CCMD call padcom movf CDAT[0], 0 movwf PADF[3] movf CDAT[1], 0 movwf PADF[7] movf CDAT[2], 0 movwf PADF[11] bsf PSEL ; wait for 16ms movlw 80 movwf CCMD w16lp1 movlw 200 movwf TMP w16lp2 nop decfsz TMP, 1 goto w16lp2 nop decfsz CCMD, 1 goto w16lp1 return ; ---- ; send 1 byte in TMP via USART, and wait until it finishes ; ---- tx1data movf TMP, 0 movwf txreg ; transmit one byte bsf rp0 txwloop btfss trmt goto txwloop bcf rp0 return ; ---- ; initialization of ports, USART, etc. ; ---- init bsf rp0 movlw 00h movwf trisa movlw 7fh movwf trisb movlw 80h movwf trisc bsf csrc bsf brgh ; high baud rate mode bcf rp0 btfsc portb, 6 goto set1152 bsf rp0 movlw 32 ; 32 : 38400bps@f=20MHz goto cont set1152 bsf rp0 movlw 10 ; 10 : 115200bps@f=20MHz cont movwf spbrg bsf txen ; enable TX bcf rbpu ; enable pull-up for PORTB movlw 06h movwf adcon1 bcf rp0 bsf spen ; enable USART bsf PSEL bsf PCMD bsf PCLK ; initialization of TMR2 movlw 7ah ; 1/16 for post-scaler, 1/16 for pre-scaler movwf t2con ; Fosc/4=0.2us, 0.2us*16=3.2us, 3.2us*195=624us ; 624us*16=9.984ms (= cycle of TMR2 interrupt) bsf rp0 clrf SFLAG movlw SCYCLE movwf SCOUNT movlw 195 movwf pr2 bsf tmr2ie ; enable TMR2 interrupt bcf rp0 clrf tmr2 bsf peie ; enable peripheral interrupt ; ---- ; scan pads at first, and copy their status as the previous status ; ---- call scanpad movlw NPAD*NBYTE movwf COUNT movlw PADA[0] movwf FSR1 movlw PADA0[0] movwf FSR0 cploop movf FSR1, 0 movwf fsr movf indf, 0 movwf TMP movf FSR0, 0 movwf fsr movf TMP, 0 bsf rp0 movwf indf bcf rp0 incf FSR1, 1 incf FSR0, 1 decfsz COUNT, 1 goto cploop bsf gie ; enable global interrupt bsf tmr2on ; start TMR2 ; --- ; begining of main loop ; --- main bsf rp0 stloop btfss SFLAG, 0 goto stloop clrf SFLAG bcf rp0 call scanpad ; ---- ; finding changes of PAD status for all PADs ; if any change is found, send the PAD values of 7 bytes via USART and ; update the previous status value ; ---- ; scan the change of all pad status movlw 0 movwf CCOUNT scloop movlw PADA[0] movwf FSR1 movlw PADA0[0] movwf FSR0 movf CCOUNT, 0 addwf FSR1, 1 addwf FSR0, 1 movlw NBYTE movwf NSTAT scloop2 movf FSR1, 0 movwf fsr movf indf, 0 movwf TMP movf FSR0, 0 movwf fsr bsf rp0 movf indf, 0 bcf rp0 subwf TMP, 0 btfss z goto changed movlw NPAD addwf FSR1, 1 addwf FSR0, 1 decfsz NSTAT, 1 goto scloop2 goto nochg changed ; ---- ; in case of status change of PAD[CCOUNT], ; send PAD#&type, PADA[] - PADF[] via USART ; ---- movlw PADID[0] movwf fsr movf CCOUNT, 0 addwf fsr, 1 movf indf, 0 andlw 0f0h movwf TMP ; TMP[7:4] is PAD type movf CCOUNT, 0 andlw 00fh ; W[3:0] is PAD# number iorwf TMP, 1 call tx1data movlw 0 movwf NSTAT movlw PADA[0] movwf fsr movf CCOUNT, 0 addwf fsr, 1 txdloop movf indf, 0 movwf TMP call tx1data movlw NPAD addwf fsr, 1 incf NSTAT, 1 movlw NBYTE subwf NSTAT, 0 btfss z goto txdloop ; ---- ; copy current pad status as previous pad status when any change occured ; ---- movlw NBYTE movwf NSTAT movlw PADA[0] movwf FSR1 movlw PADA0[0] movwf FSR0 movf CCOUNT, 0 addwf FSR1, 1 addwf FSR0, 1 cploop2 movf FSR1, 0 movwf fsr movf indf, 0 movwf TMP movf FSR0, 0 movwf fsr movf TMP, 0 bsf rp0 movwf indf bcf rp0 movlw NPAD addwf FSR1, 1 addwf FSR0, 1 decfsz NSTAT, 1 goto cploop2 nochg incf CCOUNT, 1 movlw NPAD subwf CCOUNT, 0 btfss z goto scloop goto main