N64 - marcosassis/gamepaduino GitHub Wiki
[nintendo 64] N64 controller interface
for arduino compatible boards
use
download gamepad
library for arduino, unzip, rename folder to gamepad and move to libraries folder on arduino folder. then open examples N64_*. now, read this page, have fun, and please feedback me.
soon i'll provide here more information about pinout and plugging, as the same for the protocol. but for now you can just google and read the same sources i found, it's de boa.
then, here's basically "all you have to do"
(but you should read this entire page)
use as a joystick/gamepad USB HID device class
examples -> gamepad -> N64_usb_hid_*
this means that the pro micro
will be recognized by OS (any) as a device of class HID (Human Interface Device Class), of the USB (and HID) specifications
and happily arduino provide us with PluggableUSB interface, that is included in the default arduino environment.
this is used by this nice ArduinoJoystickLibrary. someday i'll interface directly from PluggableUSB, but now this library already provides an adaptor class for ArduinoJoystickLibrary. so as the license is the same, and one can easily download this from arduino built in library manager (this is almost all you have to do), this file is already included in gamepad_joystick_adapter.h
if you don't want to use the usb joystick capabilities of your board (or it doesn't have them, a pity), you still can use this nice N64 controller interface (soon it'll be tested on an arduino pro mini
, example and reports here) for inputting commands to your board (you always can control whatever you want with your original oldschool gamepad). see here for considerations. as gamepad_joystick_adapter
module is optional, if you won't use it, just don't include it.
setup on project64
check 'real N64 range' and set range to 100%. set keys and axes, that's it.
compatible boards
N64_gamepad
class/interface implementation is based on assembly bit banging and nop
counting, which seems to be initially made for arduino by andrew brown. so this means, at least theoretically, any arduino compatible board, with a compatible AVR MCU, running at exacts 16MHz should do. that's because the N64 is almost too fast for arduino and the machine cycles are literally counted in implementation, by assembly codes inserted on critical functions (never mess with these).
↑ this is for this N64_gamepad
general use class / interface / protocol implementation. you always can read()
then get any gamepad
inputs states (or only changes), and then decide what to do in loop (refer to this link for details). (todo: create [more] and link specific examples about this non OO way to use this library. but it's already easy, just refer to this link.) take a look at *_loop_printer
examples for how to print your (any) controller on loop and begin to familiarize yourself with gamepad
library.
for my ArduinoJoystickLibrary interface (USB HID) see supported boards of this library.
available pins
now available for N64 controller interface any usable pins of PORTD
no need to know bit masks, it's already encapsulated by library, just use these arduino pins values on constructor:
on general arduino boards they are equivalent to digital pins from 0 to 7.
on pro micro you can use digital pins 2,3,4 and 6 (hey, that's 4 players).
(todo someday: generalize this for other registers and test result with more than 4 controllers)
multiplayer
examples -> gamepad -> N64_usb_multiplayer
multiplayer
functionality depends on LinkedList library. please read
instructions and install this library.
multiplayer
is turn on by default. if you don't want to install LinkedList library and don't compile at all this functionality (let's say you have only 1 controller (for now)), you can opt-out multiplayer by define _GAMEPAD_SINGLEPLAYER
macro before include gamepad
files. more details
all you have to do
to play N64 games with a pro micro
board (or another ATmega32U4
based board, as arduino leonardo
) on your computer
is
- download&install
gamepad
library for arduino USB HID
: if you're willing to use it as a plug and play USB HID joystick/gamepad- download&install ArduinoJoystickLibrary (details)
- open example N64_usb_*player, plug pins and edit sketch accordingly
multiplayer
: if you have more than 1 controller of any kind (and/or plan to make your own)- download&install LinkedList (details)
- this is turn on by default and LinkedList is included internally, do more nothing, just use
multiplayer
class - if you don't want this module, it's easy to turn it off
- google for information about controller pinout and protocol (soon here)
- this N64 controller interface implementation requires your board to run at exactly 16MHz
- we use AVR assembly codes, clock cycles are literally counted
- available at the moment [pro micro]:
- pins: 2,3,4,6
- IDs: 1,2,3,4 †
- choose your favorite way of testing
- watch out for autocalibration: it works (soon an option to turn it off)
- just move your stick for all the limits and
N64_gamepad
class will automatically learn which are the limits of your (old and used, rubbed down, poor) N64 controller's stick - so you can set any
real N64 controller limits [100%]
settings on your N6 emulator controller input configurations, if you're using one, and just move your stick around on time or a couple (after power on or reset)
- just move your stick for all the limits and
- if your board serial communication LEDs are blinking as you press buttons, it's probably working
† (this turns on USB/HID IDs as hidReportId=gamepadobj.id+2
. so if you're plugging different boards on same computer with same IDs, they'll conflict.)
autocalibration
autocalibration for now is set(hardcoded) on the N64 controller class, but soon it'll be generalized. the way it's programmed, you have to reach controller limits one time for the N64 controller class know what is the maximum value for that controller in specific. then this limit is decremented (-1) to (dynamically) acknowledge some margin for values(outliers) difficult to reach. that yields the moss precise behavior for N64 analog sitck that i found for now and seems to be a nice default. it's incredible how simple this is and how sensible was the result.
this accounts for the enormous heterogeneity of how the controllers' sticks get flaccid or worn (aand the equally enormous tedious of doing this empirically and manually for each controller) (soon this will be a nice generic class (default, but optional), so you can derive from it and improve this method of mapping a specific N64 controller (original) into a USB HID gamepad - please, advanced user should play with this and feedback me about improvements or other ideas).
although autocalibraton is actually dynamically learning and setting limits of the analog stick all the time, i didn't notice anything strange on gameplay.
autocalibration and reset
as reset functionality is normal N64 controller interface and operation, when controller's analog stick is reset, autocalibration values does not make sense anymore and are reset too. this is done by "listening" to rise changes on reset
virtual button.
so, anytime you reset or start the N64 controller:
- just move your stick for all the limits and
N64_gamepad
class will automatically learn which are the limits of your N64 controller's stick
N64 controller reset
when console turns on, and so controller(s) is powered, they use this analog stick's initial position as the reference to calculate the shifting (x an y) of the analog stick along the gameplay. that's because N64 analog stick technology is differential, they use optical encoders (witch is great, but the mechanical assembly of this thing wastes out in few years), opposed to all rest of analog controllers that use potentiometers.
this zero position is considered from where the stick was when console started or controller reset.
so, you can also reset controller anytime by pressing start+R+L(at same time).
this will reset controller analog position, as if console has started.
reset
is a virtual pin (8) of N64 controller protocol operation that is sent whenever happened a reset.
this reset event will report both R
and L
pressed(1), but start
will report unpressed(0), although physically all 3 buttons are pressed. at same time reset
(virtual pin, index 8) will report pressed(1).
everything on this subtopic should be bold so: btw watch out this for your application.
this is normal N64 console/controller operation, if you never noticed, you can do in your videogame.
tests made
[although i don't think i have to, i'll notice that i'm not in anyway responsible for anything that you do to your stuff, using or not my code (no warranties implied). i can't know what you are doing, if you're doing it right. and most terribly, one can never really know what will be the right specific behavior of each item in all this industrially closed technology. all i know is what some nice people did by reverse engineering and hacking/making things, that i found online and did some tests and fancy code. i think it's minimal risk to use the codes and instructions in this repository. my philosophy [todo: evolve idea and write page] is to make non invasive mods, really avoid to damage (precious,unique) things. on the contrary, the idea is to preserve and salvage these masterpieces of game electronics. and more, expand the capabilities of these pieces beyond ever imagined limits, as modules in conjunct with other hardware/software. but of course this risk's ALWAYS entirely yours, about you. understanding. your. things. and sorry for this dense note without graphical highlight.]
tested on P64 with nice original N64 controllers (reporting values around 80, so-so). i honestly didn't notice anything bad on gameplay (really much time spent on "testing"), on the contrary, most games were almost perfect in most of time and aspects.
i think since my PC(Windows 7) is 64bit and has 8GB is able to emulate N64 very accurately. the only things i noticed seems to be because of the inherent (philosophic) imprecision of the emulation process (and reported buggy games).
we have to notice that, although i'm not yet measuring times (soon), the read rate (on these examples provided) is surely far faster than original average console-controller operation. yeah, we're exploring the most of the controllers and not damaging then (as ever: no warranties implied). this surely accounts for any imprecision in timing of the game reading inputs (that i think it would be very awkward if we put some nasty delay, greater or equal than this original read rate†, in that loop - how could one guarantee that every game cycle will find a fresh latched new input?).
† Timing:
Polling interval and the commands sequence depends of the game. In Star Fox 64, 0x00 and 0x01 commands are sent alternately, with intervals varying between 1ms and 20ms. For Rareware games, most commands sent are 0x01 and are about 16ms apart.
If you are interfacing with a Nintendo 64 controller, it sounds like 20ms ia a safe poll interval.[NO! we wan't more.]
i'm very, very familiar with some N64 games, and they really seemed very accurate, at least in the sense of input/controller. i can say that was(has been) a really engaging experience, funny and affectionate, nostalgic.
please feedback me about your own gameplay experience (and setup made). if you have any trouble or find bugs, please tell me.
history
based on andrew brown's greatly functional but poorly coded N64 controller interface for arduino
this code was re-written so many times among the community, but everything i found was as bad organized and not well generalized. you go for a nice tutorial, code is working great that way, but as ever on arduino world, any thing just a little bit more complex seems to be unreachable (that smells fairy tails). i'm not asking much, but just to change the pin on this great adaption of the previous code for usb enabled atmels, i mean on pro micro
, then one will have to know what is the pin mapping for this chip, how to manipulate the register and the right macro to use or correct values for bit mask for each pin - and that's no way trivial for a beginner. so people stay attached and reproduce a lot the same things.
so, i like this code, really much. it is elegant the way andrew explores the most of the processor, at the same time using a lot of this arduinish stuff people like (i like it too, of course). i got inspired and crazy to play multiplayer on Project64, which is showing to be an excellent ambient for testing... and playing. but for much time i stood stuck on not understanding all the things that this code does, so, i assembled this project some times using wires on the N64 controller plug†, just one. and played, of course, it's fun.
† (never damage yours, soon i'll post and link a nice tutorial for making a DIY custom gamepad plug)
at the time i didn't have my pro micro, but i was an active java programmer trying to get something funny and useful with that lot of stuff that i was learning in that language (though, but...). so i put my own simplest protocol to exchange button information via serial port, used the (at the time very incomplete) java robot API and that could trigger mouse and keypad commands. i mapped this (very empirical) on project64 and voilà, it was not perfect command mapping/timing (N64 was my infancy console), but i played a lot. (it was possible to make an awesome mapping (with some manual work, but very possible) thanks to great flexibility of P64.)
this java program was beautiful (it displays a N64 controller photo in a nice GUI) and i really liked making this programming exercise, but now i intend to use this same methodology again, but (hope) using a lightweight python script, and triggering usb-hid events. i'll learn what i need, write and put it to on this repo too.
then, not long ago, i bought my first pro micro and i've been thinking about all this. when adapting the adaptation of the adaptation of andrew's code (i'm f* serious), i got insane. i was doing this only to make this thing work on my stuff. and stood stuck on the same only pin to make my interface (hello mario kart 64 and goldeneye lovers). but ok, i was already using ArduinoJoystickLibrary and writing the basis for this library (gamepad abstract class and others) and just merged the joystick library example with N64 interface (very much ""adapted"" already) and then this became really insane, because the gameplay was great, and that was really usb, plug and play, no drivers, no scripts and thankgodness no java programs.
so this 'N64 controller -> arduino' code is an old friend of mine, long fun it already caused me. and long run too, now that i've finally refactored everything i could on this mess, i see how much i have learned.
so, thanks a lot, all of you, for sharing your own process of learning, understanding and making things. it's precious.
i'm in the process of writing a very honest gamepad library for arduino. i say honest because i'm using it, and intend to use for a lot of other projects, and i hope it'll be funny for other people too. the library is (from) a much more general creative process, but this N64 controller interface history was to me as inspirational as was with so many interesting codes. so, i intend to make some good interfaces, adapters or just understand from then and try to reproduce the idea with my own contributions. everything is work in progress, so lot of changes (and docs) are to come. feel free to ask me anything about this library.