DIY CD32 joypad adapter for Sega 6-button pads

  • Thread starter Thread starter robinsonb5
  • Start date Start date
  • Replies Replies 8
  • Views Views 5427

robinsonb5

New member
AmiBayer
Joined
Jul 27, 2011
Posts
842
Country
England
Region
Norfolk
Tonight I've got the first of my planned CD32-controller projects working.

The PIC I've used here is a 16F887 which with 40 pins is way larger than I need for this project, but the smaller chips I've ordered haven't arrived yet!
(The 887 will probably eventually get used in a two-player project of some kind. Emulating *two* CD32 pads in a single PIC should be a fun challenge!)

What I like about these chips is that (a) they're cheap (amazingly, cheaper than the two discrete logic chips that are normally needed in a CD32 pad!), and (b) they're completely self-contained. Everything on the breadboard to the left of the chip is only there for diagnostics, and can now be dispensed with.

So far I've only handled the buttons - the directions aren't yet passed through, but that's a trivial addition.

Mapping-wise, the start-button obviously maps to the CD32's Play/Pause button, but the other mappings are slightly less obvious. I've mapped X and Z to the shoulder buttons, and then mapped B to Red, C to Blue, A to Green and Y to Yellow.

Once I've got the directions working and built a "real" on on stripboard I'll post the PIC source and pinouts in case anyone wants to have a go at making one :)
 

Attachments

  • SegaAdapter1.jpg
    SegaAdapter1.jpg
    123.8 KB · Views: 2
  • SegaAdapter2.jpg
    SegaAdapter2.jpg
    116 KB · Views: 6
hi mate great project you got going there could this be used on an arcade stick too as i am building one so far i am using 2 ps2 pads to usb for mame

and will be wiring it up for the amiga too but only 1 button

and i would love to use the other buttons

see here
https://www.amibay.com/showthread.php?t=20515
 
hi mate great project you got going there could this be used on an arcade stick too as i am building one so far i am using 2 ps2 pads to usb for mame

and will be wiring it up for the amiga too but only 1 button

and i would love to use the other buttons

Yup, very easily. In the case of an arcade stick the PIC wouldn't have to know about the direction lines, so you'd wire those directly, and just route seven of the fire buttons to the PIC, then wire the PIC to the Amiga's three fire button lines. The program in the PIC would obviously have to be slightly different, but it'd be a pretty simple change.

Yup, I saw that - nice project! :thumbsup:
 
Nice job, I'll definitely be having a go at building one of these.
 
At last - time to play with such projects! (So much geekery, so little time!)

Here's the PIC assembly source for the adapter, based on PIC16F886 - though it should be easy enough to adapt to similar chips:

Code:
; CD32 Serial Shift Register, software implementation for PIC16F88x 
; Copyright (C) 2011 by Alastair M. Robinson 
 
    processor 16f886 
    include <P16F886.INC> 
 
    __CONFIG    _CONFIG1, _INTOSCIO & _DEBUG_OFF  & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_ON 
    __CONFIG    _CONFIG2, _WRT_OFF & _BOR21V 
 
#DEFINE    BANK1    bsf    STATUS,RP0 
#DEFINE BANK0    bcf    STATUS,RP0 
 
RAMSTART         equ    0x20 
COMMONRAMSTART        equ    0xf0 
 
CD32_SEL        equ 0    ; In port B, to make use of edge-sensing interrupt. 
CD32_CLK        equ    4    ; The rest of the CD32 lines occupy port A 
CD32_DATA        equ    5 
CD32_UP            equ    0 
CD32_DOWN        equ    1 
CD32_LEFT        equ    2 
CD32_RIGHT        equ    3 
CD32_DIRECTIONMASK    equ    0x0f    ; 00001111 
CD32_BUTTONMASK        equ    0x30    ; 00110000 
 
Sega_SEL        equ    4    ; The Sega pad is wired to port B 
Sega_D0            equ    7    ; Up 
Sega_D1            equ    5    ; Down 
Sega_D2            equ    3    ; Left 
Sega_D3            equ    2    ; Btn 2 
Sega_D4            equ    6    ; Btn 1 
Sega_D5            equ    1    ; Right 
 
                    ; Sega bit allocations, mapping to CD32 serial shift register 
Sega_A            equ    4    ; Green 
Sega_B            equ    6    ; Red 
Sega_C            equ    7    ; Blue 
Sega_Start        equ    1    ; Play/Pause 
Sega_Down        equ 5    ; Yellow 
Sega_Up            equ    3    ; Right Shoulder 
Sega_Left        equ    2    ; Left Shoulder 
Sega_Right        equ    0    ; Zero 
Sega_DIRECTIONMASK    equ    0x2d    ; 00101101 
Sega_BUTTONMASK        equ    0xd2    ; 11010010 
 
tmpval            equ    RAMSTART+0 
shiftcounter        equ    RAMSTART+1 
count1            equ    RAMSTART+2 
count2            equ    RAMSTART+3 
segastatus        equ    RAMSTART+4 
segatmp            equ    RAMSTART+5 
portalatch        equ    RAMSTART+6 
portatmp        equ    RAMSTART+7 
 
int_status        equ    COMMONRAMSTART+1 
int_w            equ    COMMONRAMSTART+2 
shiftreg        equ    COMMONRAMSTART+3 
 
 
    org 0x00 
    goto    start 
 
    org 0x04    ; Interrupt routine - very time critical since we're 
                ; simulating a serial shift register. 
 
    ; Save regs 
    movwf    int_w 
    swapf    STATUS,w 
    movwf    int_status 
 
    BANK1 
    bsf    TRISA,CD32_CLK 
    BANK0 
    ; The first bit should already be present since the 
    ; first bit represents the Blue button, which is the 
    ; data line's normal function.  FIXME - can we improve compatibility by not putting
    ; the Blue button on the line until this point, or would it be too slow? 
 
    ; We don't bother to watch the Select line, instead we 
    ; let the watchdog timer rescue us if the comms break down. 
waitclkhigh 
    btfss    PORTA,CD32_CLK 
    goto    waitclkhigh 
 
    ; Put next bit on the data line - inverted by transistor 
    btfss    shiftreg,6 
    bsf    PORTA,CD32_DATA 
    btfsc    shiftreg,6 
    bcf    PORTA,CD32_DATA 
 
waitclklow 
    btfsc    PORTA,CD32_CLK 
    goto    waitclklow 
 
    ; Shift 1 bit left 
    rlf    shiftreg,f 
 
    clrwdt 
 
    decfsz    shiftcounter,f 
    goto    waitclkhigh 
 
waitselhigh 
    btfss    PORTB,CD32_SEL 
    goto    waitselhigh 
 
    bcf    INTCON,INTF 
 
    ; Restore port A 
    BANK1 
    bcf    TRISA,CD32_CLK 
    BANK0 
    movf    portalatch,w 
    movwf    PORTA 
 
    ; Reset shift counter for next time 
    movlw    0x07 
    movwf    shiftcounter 
 
    ; Restore regs 
    swapf    int_status,w 
    movwf    STATUS 
    swapf    int_w,f 
    swapf    int_w,w 
    retfie 
 
 
; ************************************** 
 
start: 
    ; Set internal oscillator to 8MHz 
    movlw    0x70 
    banksel    OSCCON 
    movwf    OSCCON 
     
    ; Initialise port B for digital input, except for SEL pin 
    ; We also set port A to high Z 
    banksel    PORTA 
    clrf    PORTA 
    clrf    PORTB 
    clrf    PORTC 
 
    ; Get rid of any interference from ADCs 
    banksel    ANSEL 
    clrf    ANSEL 
    clrf    ANSELH 
    banksel TRISA 
    movlw    0xff 
    movwf    TRISB 
    bcf    TRISB,Sega_SEL 
    clrf    TRISA 
    clrf    TRISC 
 
    ; Enable weak pull-ups on Port B 
    banksel OPTION_REG 
    bcf    OPTION_REG,NOT_RBPU 
    bcf    OPTION_REG,INTEDG 
 
    banksel WPUB 
    movlw    0xfe 
    movwf    WPUB 
 
    banksel PORTA 
    movlw    0x07 
    movwf    shiftcounter 
 
    banksel WDTCON 
    movlw    0x1    ; Shortest WDT delay possible (without touching prescalers?) 
    movwf    WDTCON 
 
    banksel INTCON 
    bcf    INTCON,INTF 
    bsf    INTCON,INTE 
    bsf    INTCON,GIE 
 
    banksel PORTA 
    clrf    PORTA 
    bsf    PORTB,Sega_SEL 
    call    shortdelay2 
loop: 
    BANK0 
 
    call    getsega 
 
    ; Decode directions 
    movlw    CD32_DIRECTIONMASK 
    movwf    portatmp 
    btfss    segastatus,Sega_Up 
    bcf    portatmp,CD32_UP 
    btfss    segastatus,Sega_Down 
    bcf    portatmp,CD32_DOWN 
    btfss    segastatus,Sega_Left 
    bcf    portatmp,CD32_LEFT 
    btfss    segastatus,Sega_Right 
    bcf    portatmp,CD32_RIGHT 
 
    movf    segastatus,w 
    andlw    Sega_BUTTONMASK        ; On the first read, only A, B, C and Start are readable 
    movwf    tmpval 
    call    getsega 
    call    getsega 
    call    getsega 
    movf    segastatus,w 
    andlw    Sega_DIRECTIONMASK    ; Now we have X, Y and Z on the direction lines 
    iorwf    tmpval,w 
 
    iorlw    0x01            ; Set lowest bit of shift register, which is constant 
    movwf    shiftreg 
 
    ; Mirror Red and Blue status directly to PORTA 
 
    btfss    shiftreg,Sega_B        ; Red button on clock line 
    bcf    portatmp,CD32_CLK 
    btfsc    shiftreg,Sega_B 
    bsf    portatmp,CD32_CLK 
 
    btfss    shiftreg,Sega_C        ; Blue button on data line - inverted by transistor 
    bsf    portatmp,CD32_DATA 
    btfsc    shiftreg,Sega_C 
    bcf    portatmp,CD32_DATA 
 
    movf    portatmp,w 
    movwf    portalatch 
    movwf    PORTA 
 
    clrwdt 
 
    call    longdelay 
 
    goto    loop 
 
 
getsega    ; Return button status in segastatus 
    movlw    0xff 
    movwf    segastatus 
    movf    PORTB,w 
    movwf    segatmp 
 
    btfss    segatmp,Sega_D4    ; B button, map to Red 
    bcf    segastatus,Sega_B 
    btfss    segatmp,Sega_D5    ; C button, map to Blue 
    bcf    segastatus,Sega_C 
    btfss    segatmp,Sega_D0    ; Up 
    bcf    segastatus,Sega_Up 
    btfss    segatmp,Sega_D1    ; Down 
    bcf    segastatus,Sega_Down 
    btfss    segatmp,Sega_D2    ; Left 
    bcf    segastatus,Sega_Left 
    btfss    segatmp,Sega_D3    ; Right 
    bcf    segastatus,Sega_Right 
 
    bcf    PORTB,Sega_SEL    ; Drop select line 
    call    shortdelay2 
 
    movf    PORTB,w 
    movwf    segatmp 
 
    btfss    segatmp,Sega_D4    ; A button, map to Green 
    bcf    segastatus,Sega_A 
    btfss    segatmp,Sega_D5    ; Start button, map to Play / Pause 
    bcf    segastatus,Sega_Start 
 
    bsf    PORTB,Sega_SEL    ; Raise select line again 
    call    shortdelay2 
    return 
 
 
shortdelay2    ; Preserves W 
    movwf    count2 
    movlw    0x10 
    movwf    count1 
    clrwdt 
shortdelay2loop 
    decfsz    count1 
    goto    shortdelay2loop 
    movf    count2,w 
    return 
 
 
shortdelay    ; Preserves W 
    movwf    count2 
    movlw    0x3f 
    movwf    count1 
    clrwdt 
shortdelayloop 
    decfsz    count1 
    goto    shortdelayloop 
    movf    count2,w 
    return 
 
longdelay    ; Doesn't preserve W 
    movlw    0x18 
    movwf    count2 
longouterloop 
    movlw    0xff 
    movwf    count1 
    clrwdt 
longinnerloop 
    decfsz    count1 
    goto    longinnerloop 
    decfsz    count2 
    goto    longouterloop 
    return 
     
    END
Stripboard layout to follow.
 
Last edited:
As promised, stripboard layouts!

Two different layouts here, one with and one without the pulldown transistor. The transistor's only needed for certain stubborn motherboards which won't register a logic low from a CMOS microcontroller pin. (If you've had trouble with the right mouse button on a PC mouse adapter, yours is a stubborn one!)

Note that if you build the version without pulldown transistor, you'll need to reverse the sense of two tests in the code: exchange the "btfss" and "btfsc" on lines 86 and 88, and do the same again at lines 217 and 219.

(Not shown on the layouts, but hopefully obvious - you need to break each track of the stripboard between the legs of the chip!)
 

Attachments

  • SegaToCD32.jpg
    SegaToCD32.jpg
    82 KB · Views: 4
  • SegaToCD32+PullDown.jpg
    SegaToCD32+PullDown.jpg
    96.3 KB · Views: 6
hi mate which one did you send me to test

Neither! These are specifically for decoding a single 6-button Sega Megadrive pad, and making it usable on a CD32.

I'll make a new thread for the one I sent you when I get a moment :)
 
Back
Top Bottom