Wireless N64 controller?

Includes but not limited to: SNES, Genesis, Sega CD, PlayStation 1, Nintendo 64, Dreamcast, Game Gear and I guess the Virtual Boy.

Moderator:Moderators

User avatar
blaze3927
Portablizer
Posts:1114
Joined:Mon Dec 08, 2008 6:14 am
360 GamerTag:notjames
Location:Australia
Contact:
Re: Wireless N64 controller?

Post by blaze3927 » Mon Oct 10, 2011 5:20 am

YESSSSSSS

thanks a lot for going through the effort of instructions and schematics :)
Australian Kaillera server
[url]hhttp://i56.tinypic.com/ncb0wi.gif[/url]

User avatar
bassmasta
Posts:684
Joined:Sun Sep 06, 2009 8:56 pm
Steam ID:randomguy737
Contact:

Re: Wireless N64 controller?

Post by bassmasta » Mon Oct 10, 2011 6:43 pm

micro wrote:Thank you, thank you :mrgreen:
Instructions including schematics and hex files are online now (see video description).
Will you be making the source available, or just the hex files?

Great work btw.
zeturi wrote:If you're getting 404'd when trying to use the links in stickies, try this tutorial to find that juicy info.

User avatar
micro
Posts:13
Joined:Thu Feb 10, 2011 12:26 pm

Re: Wireless N64 controller?

Post by micro » Tue Oct 11, 2011 6:37 am

Sorry no, I don't plan on releasing the source because source code documentation isn't complete AND it's mixed in english/german :wink:
Tidying up the documentation would cost time & effort...

User avatar
frontispiece
Posts:9
Joined:Mon Nov 08, 2010 3:45 pm
Location:Vancouver, Canada

Re: Wireless N64 controller?

Post by frontispiece » Thu Oct 13, 2011 6:10 pm

@ micro:

No way, this is amazing! Our thread was only for N64, and you went ahead and did all of them. Very impressive.

I know you are not planning on cleaning up and releasing the source code - but now that you've solved it, would you do me a favour and please answer a question that was bugging me the WHOLE TIME I was working on the N64?

Here is the question:
How did you communicate between the receiver and the N64 itself? If I understand correctly, when the N64 turns on, it sends a bunch of 0x00 "are you there/what do you have plugged in" commands on the data line, and then 0x01 "what buttons are being pressed"? What did you do with the receiver's micro in order to fake a response and get the N64 to think that there was a genuine controller plugged in?

Thanks again, beautiful work! I hope you have time to answer, that question has been bugging me for months and was the reason I gave up on it ...

User avatar
micro
Posts:13
Joined:Thu Feb 10, 2011 12:26 pm

Re: Wireless N64 controller?

Post by micro » Fri Oct 14, 2011 2:26 am

No problem, here's the code for speaking to the N64 console: (but not including the wireless and button conversion stuff)
Spoiler:

Code: Select all

.nolist
.include "m8def.inc"
.list


.cseg
.org 0000
	rjmp init ;reset 
	rjmp isr0 ;int0
	reti ;int1
	reti ;timer2 comp
	reti ;timer2 overflow
	reti ;timer1 capture
	reti ;timer1 compare A
	reti; timer1 compare N
	reti ;timer1 overflow
	reti ;timer0 overflow
	reti ;SPI serial transfer complete
	reti ;USART rx complete
	reti ;USART DR empty
	reti ;USART tx complete
	reti ;ADC complete
	reti ;eeprom ready
	reti ;analog comparator
	reti ;two wire interface
	reti ;store program memory ready


init: ;INIT STACK
	ldi r16, HIGH(RAMEND)
	out SPH, r16 
	ldi r16, LOW(RAMEND) 
	out SPL, r16 


;VARIABLES FOR RECEIVED DATA
.equ COMMAND = SRAM_START
;VARIABLES TO SEND TO N64
.equ N64_BUTTONS1 = SRAM_START+1
.equ N64_BUTTONS2 = SRAM_START+2
.equ N64_X = SRAM_START+3
.equ N64_Y = SRAM_START+4



;CONFIG INT0 = low level
	ldi r16, 0b0000_0000
	out MCUCR, r16
	ldi r16, 0b0100_0000
	out GICR, r16
	sei


;MAIN LOOP: (empty)
main:
	nop		;r18 - r20 are reserved for isr0, don't use them
	rjmp main




;-------------------ISR0------------------------
;-----------------------------------------------
isr0:
	in r20, sreg ;save status register
	rcall delay16 ;wait 16 = 1us
	rcall delay16 ;wait 16 = 1us

	ldi r18, 0xFF ;reset r18
	;***BIT 7
	sbis pind, 2 ;if data=1, skip
	cbr r18, 0b1000_0000 ;else, clear bit
	rcall delay62 ;wait 3,8125us
	;***BIT 6
	sbis pind, 2 ;if data=1, skip
	cbr r18, 0b0100_0000 ;else, clear bit
	rcall delay62 ;wait 3,8125us
	;***BIT 5
	sbis pind, 2 ;if data=1, skip
	cbr r18, 0b0010_0000 ;else, clear bit
	rcall delay62 ;wait 3,8125us
	;***BIT 4
	sbis pind, 2 ;if data=1, skip
	cbr r18, 0b0001_0000 ;else, clear bit
	rcall delay62 ;wait 3,8125us
	;***BIT 3
	sbis pind, 2 ;if data=1, skip
	cbr r18, 0b0000_1000 ;else, clear bit
	rcall delay62 ;wait 3,8125us
	;***BIT 2
	sbis pind, 2 ;if data=1, skip
	cbr r18, 0b0000_0100 ;else, clear bit
	rcall delay62 ;wait 3,8125us
	;***BIT 1
	sbis pind, 2 ;if data=1, skip
	cbr r18, 0b0000_0010 ;else, clear bit
	rcall delay62 ;wait 3,8125us
	;***BIT 0
	sbis pind, 2 ;if data=1, skip
	cbr r18, 0b0000_0001 ;else, clear bit
	rcall delay62 ;wait 3,8125us

	sts COMMAND, r18
	rcall delay16
	rcall delay16
	rcall delay16
	rcall delay16

;***CHECK COMMAND SENT BY N64
	ldi r19, 0x00
	lds r18, COMMAND
	sub r18, r19
	breq send_status

	ldi r19, 0x01
	lds r18, COMMAND
	sub r18, r19
	breq send_buttons

	ldi r19, 0xFF
	lds r18, COMMAND
	sub r18, r19
	breq send_status


isr0_end:
	out sreg, r20 ;write back status register
	reti
;--------------------------------------------------------
;---------ISR0 END---------------------------------------



;----------------SEND STATUS----------------------------
;---------------------------------------------------------
send_status:
	ldi r18, 0x05
	nop
	rcall send_a_byte
	ldi r18, 0x00
	nop
	rcall send_a_byte
	ldi r18, 0x02
	nop
	rcall send_a_byte
	rcall stop_bit
	rjmp isr0_end



;---------------SEND BUTTONS-------------------------------
;-----------------------------------------------------------
send_buttons:
	lds r18, n64_buttons1
	rcall send_a_byte
	lds r18, n64_buttons2
	rcall send_a_byte
	lds r18, n64_x
	rcall send_a_byte
	lds r18, n64_y
	rcall send_a_byte
	rcall stop_bit
	rjmp isr0_end



;-------------SEND A BYTE TO N64------------------------------
;-------------------------------------------------------------
send_a_byte:
	ldi r19, 8
next_bit:
	sbi ddrd, 2 ;data is always low at the beginning of the bit
	rcall delay7
	nop
	nop
	nop
	nop
	nop
	sbrs r18, 7 ;skip if you want to send a "1"
	rjmp little_detour ;branch to little_detour for a "0"
	cbi ddrd, 2 ;1 us elapsed, set data high now if you want to send a "1"
	nop ;compensation nop
on_with_the_show:
	rcall delay14
	rcall delay14
	nop
	cbi ddrd, 2 ;3 us elapsed now, data gets high now for a "0", and stays high for a "1" of course
	lsl r18 ;leftshift databyte
	dec r19 ;decrease count
	breq byte_end ;if count=0, byte is complete
	nop
	rcall delay7
	nop
	rjmp next_bit
little_detour:
	rjmp on_with_the_show
byte_end:
	ret



;-------------------STOP BIT-------------------------
;----------------------------------------------------
stop_bit:
	nop
	nop
	nop
	sbi ddrd, 2
	rcall delay14
	cbi ddrd, 2
	ret


	
;--------------MISC DELAY ROUTINES-----------------
;--------------------------------------------------
delay7:
	ret
delay14:
	rcall delay7
	ret
delay16:
	rcall delay7
	nop
	nop
	ret
delay62:
	rcall delay16
	rcall delay16
	rcall delay16
	rcall delay7
	ret
If the N64 console pulls the data line low it will trigger the interrupt service routine 0 and the MCU will record the command. After the command has been sent, the MCU checks the command and it will start to send the appropriate answer (status or buttons data).

In the beginning I thought the 0xFF command just resets the controller, but evilteddy taught me that this command should also be answered with the status bytes. So thanks again for this tip :mrgreen:
In the end I don't think my code differs very much from evilteddy's.

Post Reply