Jump to content

"Joystick 430" SNES to USB with the launchpad (proto boosterpack)

Recommended Posts

well as my first little project using the mecrimus interface  I have finished a working interface to take a SNES controller into the PC USB port.


I am using the 32.767 kHz self adjusting version of mecrimus that oPossum recoded.


anyway  the SNES controller is basically a 16bit shift register that originally ran at 5V on the SNES, but runs just as happy at the 3.6 that the MSP spits out.


this version of the interface uses Timer1_A3 to generate a 6us 50% PWM signal to drive the clock line on the shift register.  IT works by setting up a 17 step state machine and "enabling" the timer into "up mode".  each time interrupt it steps the state machine forward and reads the next bit and the clock from the timer drives the next bit out.  There was some interference issues because when a USB packet interrupted the cycle, the timer continued to run.  the only way i got around it was to disable the interrupts during the polling sequence (it only takes 98us so it doesn't mess with the USB link.  The SNES timing is a 12us latch pulse high, then a 6us low, 6 us high clock signal polling at 60Hz.  I am running it twice as fast (6 latch, 3 low, 3 high) polling at 120Hz and its working fine, you can probaly drive the shift register much faster than that, but it there wouldn't be any benefit.


anyway here is a

of me playing with it...  i apologize for rambling a bit but that is just my nature


The wiring diagram is simple, there are only 5 wires to the controller.

White - VCC (5V on SNES, but it doesn't complain at 3.6)

Yellow - P2.1 (Data Clock )

Orange - P2.0 (Data Latch)

Red - P1.4 (Serial Data from Controller)

Brown - GND


(for the controller only, the USB wiring is seperate, and is using my USB interface board i have been working on, although any wiring that works with mecrimus should work.)


I am going to clean up and play with it a little more, Here is how the code is at this point, but it will continue to change and evolve, but have fun :smile:


Link to post
Share on other sites

updated the code to use a crystal for the 32kHZ, my original was using an oscillator running at that rate.  not much difference, also made it zero out the joystick report if no controller detected.  Iwill probably switch it over to SimpleAVRs crystal free code he just posted to make life simpler


In playing with it i build a little boosterpack prototype so i didn't have alot of delicate wiring sitting on my desk while playing.... err *ahem* testing the interface :smile:




I have a vacation coming up from the 7th to the 31st, but if they are wanted i can assemble a few more of these boosters for the store if there is interest (the controller sockets are hard to come by, but i can get them if you guys want that in the it too), and the exact same schematic works for SNES or NES controllers, just the wiring colors change and I can source NES controller sockets easily enough(amazingly enough Digikey has them!!) so it works as a NES adapter as well.



I have schemes for a standalone version (with a 20tssop MCU msp430 built onto the board) i can get fabbed up as well if anyone wants one, once I get back,  built onto my (seemingly standard) 20mm square board, with the bonus that it is all single sided!



Link to post
Share on other sites

I was going to ask if you met or beat the snes polling time.

Just for prosperity, the SNES has two 4021 8bit shift registers (The NES only has one). You could even wire in four extra buttons, just need to adjust the code a bit to compensate. They work from 3v to 15v. You could even just use the same code for the NES without change really.


Nice job JW


A genesis version would be nice. The 3 button uses a simple quad 2-to-1 multiplex 74153 on 6 parallel pins (one select). Saturn does the same with two 74153, 4 data pins, and 2 select pins (arguably the same code).


The 6 button controllers are a bit harder, but I need to make one. Need. A dreamcast one would be nice but those require some strict high speed bus, and it's bidirectional, not just polled.

Link to post
Share on other sites

Hey JW, can you give this a try? I made changes for it to report two controllers. P1.5 is the 2nd Player data pin, it shares the latch and clock with Player1. If you don't have two controllers, just moving the data pin over should be enough to test it. Should show up as two separate controllers.


(Changes in Joystick430.h: Added two extern variables, changed names)

(Changes in Joystick430.c: Added two variables Changed variable names, added code to read p1.5 for Player2)

(Changes in J430_bbusb_protocol.c: Changed USB HID_Descriptor[] for two reports, changed IrqIn() for 7 bytes, adding report ids and changed variable names, changed form joystick to gamepad)

(Changes in J430_bbusb.c: Added P1DIR &= ~BIT5; //Player2 to make p1.5 input.)


I'm not sure if the hid_descriptor length is right, but I don't know if it was right before I changed it either. It said 42, but it should have been 43 (including the length byte). Does the code account for that somewhere else? Same for the string_descriptor0/1/2.


In any case, I left that as is (added report_id + id, so two bytes, then duplicated it all, so 88, plus length should be 89, but I left it as 88).




Link to post
Share on other sites

I will test it, the length byte is for the firmware, the message over the usb bus is 42. I will let you know later today :smile:. Oh if you have a spare genesis controller i could borow, i can add support for it

Oh I already have that figured out. It's simpler, no clocking, but takes 6 inputs + select pin, Figuring I could share the select pin, that leaves 1 free gpio when using two controllers. Only difference is that your nes/snes code uses a state machine/switch case and the timer. I'm so not able to wrap my head around timer code. I can easily do it with a simple for loop though. For both 3 and 6 button controllers. And even figure how to provide a user selectable 3 vs 6 button controller mode (have user hold x/y/z while plugging in the usb plug). Same can be done for the nes/snes difference, but honestly, the difference between the two is trivial compared to the genesis custom detection.

Link to post
Share on other sites

I will test it, the length byte is for the firmware, the message over the usb bus is 42. I will let you know later today :smile:. Oh if you have a spare genesis controller i could borow, i can add support for it

Well, I figure the IRQIN() length is for the firmware, but the first byte in the hid_descriptor is part of the usb standard. It's supposed to be the entire length of the descriptor in bytes, including the length byte. The hid_descriptor is 43 bytes in length, but the length byte is set to 42.


OIC said the blind man. The "length" byte is for the firmware to know how long, "blength" is for the usb descriptor first byte. The HID Descriptor doesn't require a blength since it uses end configuration type codes. That threw me off.

Link to post
Share on other sites

in order to get the computer to feed the data into the two functions (both controllers) you have to send 2 seperate reports, instead of putting both in the same one.


in doing this you cut your update rate per controller in half, but with just 2 its not an issue


void IrqIn(uint8_t *d)					//
{										// -- Mouse HID response
	*d++ = 4;							// Length
	*d++ = (Data_PID_ToggleIrqIn ^= (USB_PID_DATA0 ^ USB_PID_DATA1));// Data PID toggle
	*d++ = CtrlToggle;			                // Report ID
		case 1:{						// Report (1)
			*d++ = Ctrl1Byte0;			// Controller 1 Buttons
			*d++ = Ctrl1Byte1;			// Controller 1 DPad
		case 2:{						// Report (2)
			*d++ = Ctrl2Byte0;			// Controller 2 Buttons
			*d++ = Ctrl2Byte1;			// Controller 2 DPad
	CtrlToggle ^= 0x3;					// flip CtrlToggle between 1 and 2

descriptor length is 88 like you thought, but you have to change it in the Configuration descriptor blocks as well to get the computer to recognize it.


//==============HID Descriptor=======================================================================================
	   9,								// bLength
	0x21,								// bDescriptorType = HID
	0x10, 0x01,							// bcdHID (Class Spec Version 1.10)
	   0,								// bCountryCode
	   1,								// bNumDescriptors
	  34,								// bDescriptorType = Report
	  88, 0, (length of HID report descriptor)			// wDescriptorLength 

//==============Endpoint Descriptor==================================================================================
	   7,								// bLength
	   5,								// bDescriptorType = Endpoint
	0x81,								// bEndpointAddress = 1 IN
	   3,								// bmAttributes = Interrupt
	0x04, 0x00, (length of HID report)			        // wMaxPacketSize
	0x01								// bInterval (ms)

the HID report is 2 seperate 4 byte reports with the report ID identifier saying which one is which.

Link to post
Share on other sites

I hate when I miss the simple things ha. So i'm assuming that the dual setup worked otherwise?


Question, you are polling the controller at 120hz, how often is a usb report being sent (once per poll?)? What triggers the report being sent? Is it the "usbie = usbplus;" line in Joystick430.c? How long does it take the report to be sent?

Link to post
Share on other sites

other than those changes yeah.  It works :smile:


the report is being sent in response to a "IN" token from the PC, requesting data from the device.


the controller is polled each time "ReadyForTransmitIrqIn" is cleared and the firmware goes to build a new report

the state machine is run by calling my StartPoll(); function.


the time it takes to transmit the report is gonna be standard USB transmission time, since it is a "4 byte" message,


there will be an "In" transaction from the pc,  which is an "in" token packet (4 bytes), a "data" packet (4 bytes + length of HID report), and an "ACK" PC from the MSP430(2 bytes)


so 14 bytes at low speed will take around 75us to transmit... 

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...