; PlayStation Pad -> Pseudo Radio Controller Transmitter ; ver1.1 (c) Junichi Akita ; (this source is written for MPASM, Microchip Assemble) ; ; Connections: ; PS Analog Padr PIC16F84A [X'tal:19.660MHz] ; 1(DAT)----------p---PB0 ; 2(CMD)--------------PB1 ; 4(GND)--------------GND ; 5(+3V)--------------VDD(+5V) ; 6(SEL)--------------PB2 ; 7(CLK)--------------PB3 ; 9(ACK)----------p---PB4 ; PB5------------>--Radio TX ; [p : pull-up to +5V via 1kohm] ; ; * for details of PS controller, see below: ; http://www.vector.co.jp/soft/data/game/se020797.html list p=16F84A #include __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC CDAT equ 0 ; PB0(i) CCMD equ 1 ; PB1(o) CSEL equ 2 ; PB2(o) CCLK equ 3 ; PB3(o) CACK equ 4 ; PB4(i) TX0 equ 5 ; PB5(o) ; nuber of 4byte cycles per one PWM cycle NCYCLE equ 7 ; variables W_TMP equ 0x0c S_TMP equ 0x0d TXD0 equ 0x0e TXD1 equ 0x0f TXD2 equ 0x10 TXD3 equ 0x11 CTXD equ 0x12 CRXD equ 0x13 LVAL equ 0x14 RVAL equ 0x15 ID equ 0x16 COUNT equ 0x17 TCOUNT equ 0x18 TXD equ 0x19 NTXD equ 0x1a CYCLE equ 0x1b WAIT equ 0x1c WAIT2 equ 0x1d WMAP equ 0x1e ; start up org 0 goto main ;------------------------------------------ ; interrupt routine ; * this interrupt routine should be called every 1/4800=208.3us org 4 movwf W_TMP movf STATUS, w movwf S_TMP ; send 1 byte of TXD in order movlw 0 subwf TCOUNT, w btfsc STATUS, Z goto bstart ; send START bit if TCOUNT==0 ; movlw 9 subwf TCOUNT, w btfsc STATUS, Z goto bstop ; send STOP bit if TCOUNT==9 ; btfss TXD, 0 bcf PORTB, TX0 btfsc TXD, 0 bsf PORTB, TX0 rrf TXD, f incf TCOUNT, f goto intend ; sending start bit bstart bcf PORTB, TX0 incf TCOUNT, f ; preparing data to send ljudge movlw 0x07 andwf LVAL, w ; absolute of left value -> W subwf CYCLE, w btfsc STATUS, C ; if |LVAL| > CYCLE -> motor ON goto rjudge lid0 btfss PORTA, 0 goto lid1 btfss LVAL, 3 bsf TXD0, 6 ; left motor as FWD btfsc LVAL, 3 bsf TXD0, 5 ; left motor as BWD lid1 btfss PORTA, 1 goto lid2 btfss LVAL, 3 bsf TXD0, 1 btfsc LVAL, 3 bsf TXD0, 0 lid2 btfss PORTA, 2 goto lid3 btfss LVAL, 3 bsf TXD1, 3 btfsc LVAL, 3 bsf TXD1, 2 lid3 btfss PORTA, 3 goto lid4 btfss LVAL, 3 bsf TXD2, 5 btfsc LVAL, 3 bsf TXD2, 4 lid4 btfss PORTA, 4 goto rjudge btfss LVAL, 3 bsf TXD2, 0 btfsc LVAL, 3 bsf TXD3, 6 rjudge movlw 0x07 andwf RVAL, w ; absolute of right value -> W subwf CYCLE, w btfsc STATUS, C goto restore rid0 btfss PORTA, 0 goto rid1 btfss RVAL, 3 bsf TXD0, 4 ; right motor as FWD btfsc RVAL, 3 bsf TXD0, 3 ; right motor as BWD rid1 btfss PORTA, 1 goto rid2 btfss RVAL, 3 bsf TXD1, 6 btfsc RVAL, 3 bsf TXD1, 5 rid2 btfss PORTA, 2 goto rid3 btfss RVAL, 3 bsf TXD1, 1 btfsc RVAL, 3 bsf TXD1, 0 rid3 btfss PORTA, 3 goto rid4 btfss RVAL, 3 bsf TXD2, 3 btfsc RVAL, 3 bsf TXD2, 2 rid4 btfss PORTA, 4 goto restore btfss RVAL, 3 bsf TXD3, 5 btfsc RVAL, 3 bsf TXD3, 4 restore movlw TXD0 movwf FSR movf NTXD, w addwf FSR, f movf INDF, w movwf TXD ; TXD <- TXD0 - TXD4 according to NTXD incf NTXD, f movlw 4 subwf NTXD, w btfss STATUS, Z goto intend clrf NTXD ; clear NTXD if NTXD==4 incf CYCLE, f ; inclement CYCLE, of 4 bytes are sent movlw NCYCLE subwf CYCLE, w btfsc STATUS, Z clrf CYCLE clrf TXD0 clrf TXD1 clrf TXD2 clrf TXD3 bsf TXD0, 7 ; initialize TXDn goto intend ; sending stop bit bstop bsf PORTB, TX0 movlw 0 movwf TCOUNT goto intend ; finishing interrupt routine intend movf S_TMP, w movwf STATUS swapf W_TMP, f swapf W_TMP, w bcf INTCON, T0IF retfie ;------------------------------------------ ; communicate with PS pad; send CTXD and receive CRXD ccom movlw 8 movwf COUNT clrf CRXD ccloop bcf PORTB, CCLK call ccwait btfsc CTXD, 0 bsf PORTB, CCMD btfss CTXD, 0 bcf PORTB, CCMD rrf CTXD, f rrf CRXD, f btfsc PORTB, CDAT bsf CRXD, 7 btfss PORTB, CDAT bcf CRXD, 7 bsf PORTB, CCLK call ccwait decfsz COUNT, f goto ccloop ; wait for 100us (ACK time) movlw 0x80 movwf WAIT w100lp nop decfsz WAIT, 1 goto w100lp return ; waiting half of clock cycle for PAD, 0.2us * 60 = 12us ccwait movlw 20 movwf WAIT ccwait0 decfsz WAIT, f goto ccwait0 return ; remap 0x00-0xff value from controller in CRXD to L/R VAL into W as follows: ; 0x00-0x0f : +7=0x07 <- 0 ; 0x10-0x1f : +6=0x06 <- 1 ; 0x20-0x2f : +5=0x05 <- 2 ; 0x30-0x3f : +4=0x04 <- 3 ; 0x40-0x4f : +3=0x03 <- 4 ; 0x50-0x5f : +2=0x02 <- 5 ; 0x60-0x6f : +1=0x01 <- 6 ; 0x70-0x8f : 0=0x00 ; 0x90-0x9f : -1=0x09 <- 9 ; 0xa0-0xaf : -2=0x0a <- a ; 0xb0-0xbf : -3=0x0b <- b ; 0xc0-0xcf : -4=0x0c <- c ; 0xd0-0xdf : -5=0x0d <- d ; 0xe0-0xef : -6=0x0e <- e ; 0xf0-0xff : -7=0x0f <- f remap movlw 0x90 subwf CRXD, w ; CRXD-0x90 -> W btfsc STATUS, C goto rminus ; if CRXD >= 0x90 movlw 0x70 subwf CRXD, w ; CRXD-0x70 btfss STATUS, C goto rplus ; if CRXD < 0x70 movlw 0x00 ; in case of ZERO return rminus rrf CRXD, f rrf CRXD, f rrf CRXD, f rrf CRXD, f movlw 0x0f andwf CRXD, w return rplus movlw 0x07 movwf WMAP rrf CRXD, f rrf CRXD, f rrf CRXD, f rrf CRXD, f movlw 0x07 andwf CRXD, w subwf WMAP, w ; 0x07 - CRXD -> W return ; main routine main bsf PORTB, TX0 bsf PORTB, CCLK bsf PORTB, CSEL bsf STATUS, RP0 movlw 0x1f movwf PORTA movlw 0x11 movwf PORTB movlw 0x81 movwf OPTION_REG ; 1:4 for TMR0, 19.6608MHz / (4*256 * 4) = 4800Hz bcf STATUS, RP0 clrf TXD0 clrf TXD1 clrf TXD2 clrf TXD3 bsf TXD0, 7 clrf TCOUNT clrf NTXD clrf CYCLE clrf TMR0 bsf INTCON, T0IE bsf INTCON, GIE ; main loop acq bsf PORTB, CCLK bcf PORTB, CSEL movlw 0x80 movwf WAIT w100lp2 nop decfsz WAIT, 1 goto w100lp2 ; 1st byte from PAD movlw 0x01 movwf CTXD call ccom ; 2nd byte from PAD movlw 0x42 movwf CTXD call ccom ;; check analog pad by detecting 0x3 for lower 4 bits of 2nd received data ; movlw 0x0f ; andwf CRXD, f ; movlw 0x03 ; subwf CRXD, w ; btfss STATUS, Z ; goto neg ; 3rd byte from PAD movlw 0x00 movwf CTXD call ccom ; 4th byte from PAD movlw 0x00 movwf CTXD call ccom ; 5th byte from PAD movlw 0x00 movwf CTXD call ccom ; 6th byte from PAD movlw 0x00 movwf CTXD call ccom ; 7th byte from PAD movlw 0x00 movwf CTXD call ccom call remap movwf LVAL ; 8th byte from PAD movlw 0x00 movwf CTXD call ccom ; 9th byte from PAD movlw 0x00 movwf CTXD call ccom call remap movwf RVAL neg bsf PORTB, CSEL ; wait 16ms for next SEL cycle movlw 0x50 ; = 80 movwf WAIT2 wait16a movlw 0xc8 ; = 200 movwf WAIT wait16b nop nop decfsz WAIT, f goto wait16b decfsz WAIT2, f goto wait16a goto acq END