NES Mini Controller USB Adapter for attiny85
This code will work with an attiny85 (or probably whatever similar AVR microcontroller once the Makefile are changed and the pins constants adapted - SDA, SCL and the two Data for the V-USB part) hooked to a NES Mini Controller via I2C (or an SNES Mini Controller too!) and with the proper hardware required for a USB connection.
The first part acts as a generic USB gamepad using the V-USB library (it's a basic example modified to use a gamepad descriptor and send the proper report. Not an expert on this library, so maybe it can be improved, fixed or optimized; but as far as I'm concerned it does the work pretty well!).
The second part uses a custom handmade bunch of functions to communicate with the NES Mini Controller via I2C.
nesminicontrollerdrv.c implements the Controller poll. It reads from the proper register and fetch the bytes related to the pressed buttons. There are a few constants for each button that can be used to check which one was pressed (it allows multiple buttons pressed at the same time).
i2cattiny85/i2cattiny85.c contains some low-level functions to send and read bytes using the original SDA and SCL pins. It doesn't use anything related to the available AVR Two-Wire mode (it even uses the internal pull-up resistors that seems to work fine on the controllers!) and it's a "pure bit-banging implementation". It should also work with any other pin combination (I started it with the "original ones" while learning more about the protocol and how the micro implements it and, back then, wasn't pretty sure about the differences between the dedicated pins, the TWI and the bit-banging approach).
SNES Mini Controller Support
Now a SNES Mini Controller can be attached too! It works in a similar way, but need some extra init operations (fully compatible with the NES Mini one, but not required) and a more accurate timming operations (the read process on the NES Mini Controllers seems to be more "tolearant" when chainning multiple i2c operations, but the SNES Mini device requires a small delay between them).
By adding default SNES Mini support the USB device now sends TWO bytes instead of only ONE to be able to map all the SNES gamepad buttons (even if you're using a NES Mini Controller).
Can this thing work as an XInput gamepad?
Emulating a "regular" HID gamepad is cool but, it's possible to use V-USB to have a valid XInput device like the XBox Controllers?
Those controllers are full-speed USB devices, and the only types the V-USB library can handle are the low-speed ones so, maybe... not...?
Well, I tried a couple of things and manage to have a valid low-speed XInput device BUT with very limited support (only the "non-analogic" buttons). Also, I'm pretty sure this is a totally non-standard movement and it will eventually crash, fail or just stop working :_ D
I wrote a post about this on my website with some aditional documentation, links and some code comments.
Some extra considerations
Since I'm using an attiny85 I needed to change a few things in order to make the V-USB library work with it. This post helps me a lot.
Some changes need to be done to modify the CPU speed (also fuses!) among with the use of an Oscillator Calibration function.
The input pins are also different than the ones in the post, since one of those pins is also used as the SDA signal. To avoid conflicts between the "USB pins" and the "I2C pins" I changed one of the USB Data pins to another one. Check the usbconfig.h file for more info about how to re-arrange the 4 pins.
- Distinction between SNES and NES Mini Controllers in order to avoid doing unnecessary stuff (like the SNES init for the NES Mini Controller or the 2 bytes report instead of a single byte). Maybe with a "manual switch" in the board?
- Auto-detect when the controller has been plugged/unplugged once the device is already powered on (now you need to attach the controller first and then plug the usb adapter, otherwise won't work because of the snes init operation)
- Check the board design, probably some pull-up resistors for the i2c bus are required (there's some kind of "deadlock" when turning the device on without any controller attached)
- Add more controllers? Probably out of the scope of this particular project...
- Naming? It seems confusing to have a "NES project" that also supports SNES stuff and have a function called "snes_init"...
https://hackaday.io/project/176939-nes-mini-controller-usb-adapter-with-attiny85 This project on my hackaday.io page (with schematics and more info)
https://www.obdev.at/products/vusb/index.html The V-USB library, software implementation for low-speed USB device on AVR microcontrollers
https://www.ruinelli.ch/how-to-use-v-usb-on-an-attiny85 How to make the original V-USB library examples work in an attiny85
https://thewanderingengineer.com/2014/08/11/pin-change-interrupts-on-attiny85/ Pin change Interrupts on attiny85
https://en.wikipedia.org/wiki/I%C2%B2C The I2C page on Wikipedia
http://wiibrew.org/wiki/Wiimote/Extension_Controllers Info about the Nintendo Extension Controllers (like the Mini consoles or the Wii Nunchuk)
http://albertgonzalez.coffee/projects/snes_mini_arduino/ When I started tinkering with this Mini Controllers I did some stuff using Arduinos instead of "raw" AVR's. Here are some of the notes I wrote about connecting (S)NES Mini Controllers to an Arduino board.
http://eleccelerator.com/fusecalc/fusecalc.php?chip=attiny85 Fuse calculator