DIY Rumble Pak for the DS / DS Lite

intro

DIY RumblePak for Nintendo DS Lite

This was an attempt to make a RumblePak for my DS Lite. Sure you can buy them for a few $$$, but where is the fun in that?

I wanted the Rumble Pak to fit into the existing blanking plate of the DS Lite that slots into the GBA cartridge slot. This would make it blend in with the NDS and not stick out or have an odd colour. I could have used the PCB that is contained within the blanking plate, but didn't want to ruin it in case I had to send it back. I opted to dismantle an old Pokemon Pinball GBA cartridge and use the edge connector.

I would have used the offset motor from the Pokemon Cartridge, but it was simply too large...

The motor I used is tiny and was salvaged from an old Nokia 5100 phone. The offset weight had to be trimmed down because it was too big.

A Rumble is requested on the write /WR pin (GBA Pin 3). The pulse is approx 350ns long and needs to be stretched to about 20ms since the motor will not budge if you pulse it with 350ns.

I could have used a 74HC123 Dual Retriggerable Monostable (One-Shot), but I didn't have any. I did have a Microchip PIC12F675 though.

The PIC12F675 contains an internal oscillator and has an interrupt pin that will detect the 350ns pulse (minimum is 25ns), polling the Rumble Request input is not an option as the PIC will most certainly miss it since it's instruction cycle time is 1us.

The PIC is placed into sleep mode to preserve power, however this is probably not necessary because the offset motor consumes about 200mA everytime it spins.

This information is provided as information only, these are my experiences and yours may vary...please don't blame me if you toast your NDS...

step 1

Inside the DS Lite Slot 2 blanking plate

I could have used the small PCB inside the GBA Slot 2 blanking plate, but opted to use an old Pokemon Pinball board instead.

step 2

Getting the Pokemon Pinball board to fit

I cut the board with a junior hacksaw and then drilled the 2 holes for the plastic PCB supports tracing the outline of the original PCB.

 

step 3The PIC I chose
I used a PIC12F629, which is basically the same as the PIC12F675 except it doesn't have the analog to digital converter. As the ADC was not used I chose to use the PIC12F629 and save the PIC12F675 for future projects.

step 4

The offset motor

This is the vibrate motor salvaged from a Nokia 5100 phone. The offset weight had to be trimmed down because it was too big to fit in the blanking plate.


 

step 5

Circuit diagram

As mentioned before, a simple pulse stretcher like a 74HC123 could have been used, but I didn't have one so I used a PIC instead...

I was going to drive the motor from the PIC, but at 200mA, it is way more than the PIC san Sink (or Source). The transistor used can handle 600mA.

R3 (51Ohm) was added to slow the motor down. I would have used PWM from the PIC, but I had already soldered it to the board before noticing that the motor spun too fast.

R1 (10KOhm) tells the NDS that an Option Pak is installed. I assume that D1 pulled low indicated a RumblePak and that other Option Paks require other data lines to be pulled low.

C1 provides some decoupling.

There should be a diode across the motor, but it seemed to work fine without it and there just wasn't the space.

 


step 6

Source code for PIC

Included is the simple source. I doubt that anybody will make somethig so simple, but who knows....

 

DSRUMBLE.HEX

:020000040000FA
:0400000000002F28A5
:08000800A000030E8312A10009
:1000100022148B10210E8300A00E200E09008312E3
:100020008101A20100309F008316173081008312E6
:10003000073099008316FD3085008312FD3085005E
:100040008316FF309500831600309F008312003026
:100050009000831210308B008B1783120034FF2323
:10006000831690000F20221839286300000000003A
:1000700033288514810160300106031D3B2885105B
:0400800022103328EF
:02400E00C43FAD
:00000001FF

 

DSRumble.asm

 

;***********************************************************************************************************************************
;* Nintendo DS RumblePak
;* Basically all this is is a pulse stretcher. The NDS generates a negative 350ns pulse
;* on /WR (pin 3) whenever a rumble is requested.
;* AD1 (pin 7) must be tied low via a 10KOhm resistor
;* The motor consumes about 200mA so the PIC cannot drive it directly unfortunately
;*
;* Some a**ehole at Microchip decided to make the defaults for most of the I/O Pins not
;* function on power-up. There are a bunch of registers that need to be set to do the
;* basic function of toggling an I/O pin. These registers are ANSEL, CMCON and T1CON.
;* Whoever decided on this is a numpty.
;*
;* SJP
;* 14 July 2007
;*
;* Build with C:\Program Files\Microchip\MPASM Suite\MPASMWIN.exe
;*
;***********************************************************************************************************************************
; Revision History
; v1.00 14 July 2007 Initial Version

list p=12f675

__CONFIG _CP_OFF & _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF

; Include file, change directory if needed
include "p12F675.inc"

;***********************************************************************************************************************************
; Global variables
W_TEMP equ 0x20
STATUS_TEMP equ 0x21
m_interrupt_occured equ 0x22

;***********************************************************************************************************************************
; Defines

;***********************************************************************************************************************************
; SFR defines
OPTION_VAL equ B'00010111' ;TMR0 1:256
;prescaler assigned to TMR0
;don't care about TMR0 external transition
;internal transition,
;interrupt on falling edge of INT
;pullups enabled
ADCON0_VAL equ B'00000000' ;disable AD module
CMCON_VAL equ B'00000111' ;disable comparator
T1CON_VAL equ B'00000000' ;use bit 0 to enable timer IMPORTANT READ ABOVE

INTCON_VAL_INT equ B'00010000' ;only INT interrupt is enabled

;***********************************************************************************************************************************
; Port defines
MOTOR equ 1 ;(output) Motor output
WR1 equ 2 ;(input) Interrupt goes low on rumble request for 350ns
GPIO_TRISVAL equ B'11111101
GPIO_INITVAL equ B'11111101'

;***********************************************************************************************************************************
; Reset vector
org 0x000
nop
goto Startup

;***********************************************************************************************************************************
; Interrupt vector
org 0x004

; Save Context
MOVWF W_TEMP ;copy W to temp register, could be in either bank
SWAPF STATUS,W ;swap status to be saved into W
BCF STATUS,RP0 ;change to bank 0 regardless of current bank
MOVWF STATUS_TEMP ;save status to bank 0 register

bsf m_interrupt_occured,0 ;Rumble request occured

exit_INT
bcf INTCON,INTF

;Restore Context
SWAPF STATUS_TEMP,W ;swap STATUS_TEMP register into W, sets bank to original state
MOVWF STATUS ;move W into STATUS register
SWAPF W_TEMP,F ;swap W_TEMP
SWAPF W_TEMP,W ;swap W_TEMP into W
RETFIE ;return from interrupt

;***********************************************************************************************************************************
; Function : initialise
; Description : initialises all ports etc.
; Parameters : none
; Returns : 0

initialise
banksel GPIO

clrf TMR0
clrf m_interrupt_occured

;AD module
movlw ADCON0_VAL
movwf ADCON0

banksel OPTION_REG
movlw OPTION_VAL
movwf OPTION_REG

;Comparator module
banksel CMCON
movlw CMCON_VAL
movwf CMCON

;set GPIO port directions
banksel TRISIO
movlw GPIO_TRISVAL
movwf TRISIO

;init GPIO
banksel GPIO
movlw GPIO_INITVAL
movwf GPIO

; disable pullups
banksel WPU
movlw B'11111111'
movwf WPU

;AD module is disabled
banksel ANSEL
movlw B'00000000'
movwf ANSEL

;Timer 1
banksel T1CON
movlw T1CON_VAL
movwf T1CON
banksel GPIO

movlw INTCON_VAL_INT
movwf INTCON

bsf INTCON,GIE

banksel GPIO

retlw 0

;***********************************************************************************************************************************
; Entry Point : Startup
; Description : This is where the PIC starts up
; Parameters : none
; Returns : never returns
Startup
call 0x3FF ;calls RETLW with factory setting
banksel OSCCAL
movwf OSCCAL ;save oscillator calibration
call initialise

Main
btfsc m_interrupt_occured, 0
goto Rumble

sleep ;power down when not needed
nop
nop
goto Main ;loop back to main when woken up

Rumble
bsf GPIO, MOTOR ;turn motor on
clrf TMR0
loop
; movlw 027h ;delay approx 10ms (10ms / (1/(4Mhz/4) * 256))
movlw 060h ;delay approx 25ms (25ms / (1/(4Mhz/4) * 256))
xorwf TMR0,W
btfss STATUS, Z
goto loop
bcf GPIO, MOTOR ;turn motor off

bcf m_interrupt_occured,0
goto Main

;***********************************************************************************************************************************

end